Introduction
This is a new type of posting here- one that is mostly generated by a commercial grade LLM. I have been using them a lot to augment my terrible coding skills- but increasingly I’ve been using them as research tools to deep dive on specific technical issues and having a Q&A session and found the results to be very nice. I’m posting there here as a reference for myself as much as a possible aid to others, but I’m not implying that I did anything more than prompt the conversation to where I wanted it to go. I feel like 3 or 4 hours of research were condensed and outlined into a very reasonable and readable summary of just the sort of information I was looking for. So here you go.
Recently there has been discussion in the FujiNet Discord around RP2040, the new RP2350, PIOs, and macroblocks- and there is even code already in FujiNet supporting both the RP2040 and ESP32 (for Mac68k). I wanted to understand more about what is going on inside these pico pis and when someone says “macroblock” I could have some semblance of understanding about that. I thing I got there by the end of this chat, perhaps you will as well.
PIOs, Macroblocks, State-machines, and Speed
Raspberry Pi design team
- Core Team Members:
- Eben Upton: Founder and CEO of Raspberry Pi. He’s been the driving force behind the Raspberry Pi project since its inception.
- James Adams: Chief Operating Officer and Hardware Lead. He’s been instrumental in the design of many Raspberry Pi products, including the RP2040.
- Gordon Hollingworth: Chief Product Officer, overseeing product development and strategy.
- Roger Thornton: Principal Hardware Engineer, involved in the design of various Pi products.
- Extended Team:
The core team is supported by a larger group of engineers, software developers, and other professionals. While not all names are public, the team includes experts in various fields such as:
- Hardware design
- Software engineering
- Firmware development
- Manufacturing and supply chain management
- Community management and education
- Role and Responsibilities:
- Conceptualizing new Raspberry Pi products
- Designing hardware architectures
- Developing custom chips (like the RP2040)
- Creating and maintaining software and operating systems
- Ensuring manufacturability and managing supply chains
- Engaging with the community and incorporating feedback
Influences on Their Designs
- Educational Mission:
- The primary goal of Raspberry Pi has always been to promote computer science education.
- This influences decisions to keep products affordable and accessible to students and educators.
- Community Feedback:
- The Pi community is very active, and their feedback often influences future designs.
- Features or improvements frequently requested by users are often considered for new models.
- Technological Advancements:
- The team stays abreast of the latest developments in semiconductor technology, ARM architectures, and other relevant fields.
- They often push the boundaries of what’s possible in small, affordable computers.
- Market Trends:
- While primarily focused on education, the team also considers broader market trends, especially as Raspberry Pi has found applications in industrial and commercial settings.
- Manufacturing Realities:
- Decisions are influenced by what’s feasible to manufacture at scale while maintaining quality and keeping costs low.
- Power Efficiency:
- There’s a continuous drive to improve performance while maintaining or reducing power consumption.
- Backwards Compatibility:
- The team often strives to maintain compatibility with existing Pi ecosystems, influencing hardware and software design decisions.
- Open Source Philosophy:
- The commitment to open source hardware and software influences many design and implementation choices.
- Emerging Use Cases:
- As Raspberry Pi products find new applications (e.g., in IoT, robotics), these use cases influence future designs.
- Personal Passions:
- Team members’ personal interests and expertise in areas like retro computing or specific technical challenges often spark innovative features.
Design Philosophy
The Raspberry Pi team often emphasizes:
- Simplicity and elegance in design
- Providing powerful features at an accessible price point
- Creating flexible platforms that can be used in diverse applications
- Encouraging tinkering and experimentation
It’s worth noting that the Raspberry Pi Foundation, which oversees the commercial Raspberry Pi entity, is a UK-based charity. This non-profit status and educational mission significantly influence the overall direction and decisions of the design team.
The team’s work has had a substantial impact on the maker community, education, and even industrial applications. Their approach to design, balancing innovation with accessibility, has been a key factor in the widespread adoption of Raspberry Pi products.
Eben Upton’s background
Early Life and Education
- Born: April 5, 1978, in Griffithstown, Wales.
- Education:
- Attended King’s College School in Cambridge
- Earned a BA in Physics and Engineering from the University of Cambridge (1999)
- Completed a PhD in Computer Science at the University of Cambridge (2007)
- Later earned an MBA from Cambridge Judge Business School (2016)
Early Career
- IBM: Worked as a software engineer (1999–2001)
- Ideaworks3D (now Marmalade): Worked on mobile game development (2001–2004)
- Alphamosaic: Joined as an ASIC architect, working on mobile multimedia processors (2004–2006)
- Broadcom: After Broadcom acquired Alphamosaic, Upton continued there as an SoC architect (2006–2013)
Design Experience
Upton’s design skills developed through a combination of formal education and practical experience:
- His physics and engineering background provided a strong foundation in hardware principles.
- Computer science studies deepened his understanding of software and hardware interaction.
- Work at Ideaworks3D exposed him to the challenges of resource-constrained computing environments.
- Experience at Alphamosaic and Broadcom gave him hands-on experience with chip design and architecture.
Creation of Raspberry Pi
The idea for Raspberry Pi emerged from several factors:
- University Admissions Concern
- While working as Director of Studies in Computer Science at St John’s College, Cambridge (2004–2007), Upton noticed a decline in the skills of computer science applicants.
- Childhood Inspiration
- Upton grew up using computers like the BBC Micro, which were designed for learning and tinkering.
- He wanted to recreate that experience for a new generation.
- Affordability and Accessibility
- Upton aimed to create a computer that was both powerful enough to be useful and cheap enough to be accessible to students.
- Educational Mission
- The primary goal was to improve computer science education and increase the number of students pursuing the field.
- Maker Movement
- The rising maker culture influenced the design to be open and hackable.
Founding Raspberry Pi
- Initial Concept: Around 2006, Upton began thinking about a low-cost, programmable computer for kids.
- Team Formation: He gathered a team of trustees, including Jack Lang, Pete Lomas, and others.
- Raspberry Pi Foundation: Established as a UK-based charity in 2008.
- First Product: The Raspberry Pi Model B was launched on February 29, 2012.
Leadership and Vision
- As CEO of Raspberry Pi Trading (the commercial arm), Upton has driven the organization’s growth and product development.
- He’s maintained a focus on education while also embracing the wider applications of Raspberry Pi in hobbyist and industrial markets.
- Upton has been a strong advocate for computer science education and digital making.
Awards and Recognition
- Received a CBE (Commander of the Order of the British Empire) in the 2016 Birthday Honours for services to business and education.
- Named one of the 100 most connected men in Britain by GQ magazine in 2015.
- Awarded the Royal Academy of Engineering’s Silver Medal in 2013.
Upton’s Approach to Design
- User-Centric: Focuses on creating products that meet real educational and hobbyist needs.
- Simplicity: Emphasizes clean, straightforward designs that are powerful yet accessible.
- Community-Driven: Actively engages with and responds to the Raspberry Pi community.
- Innovation within Constraints: Balances feature set with cost to maintain affordability.
- Long-Term Vision: Develops products with an eye towards long-term educational impact.
Eben Upton’s journey from a curious student to the creator of one of the most influential educational computing platforms is marked by a combination of technical expertise, educational passion, and entrepreneurial spirit. His work with Raspberry Pi has not only impacted computer science education but has also significantly influenced the maker movement and IoT development worldwide.
PIO Macroblocks
Breakdown of the PIO (Programmable I/O) macroblock in the original RP2040 chip used in Raspberry Pi Pico boards. This is a fascinating and unique feature of the RP2040 microcontroller.
The PIO macroblock is a programmable I/O subsystem that provides flexible, high-speed I/O capabilities. Here are the key points about the PIO macroblock
-
Purpose: It’s designed to offload I/O tasks from the main CPU cores, allowing for efficient and deterministic handling of various I/O protocols.
- Structure
- The RP2040 has two identical PIO blocks.
- Each PIO block contains four state machines that can run independently.
- Functionality
- Each state machine can execute simple programs written in a custom PIO assembly language.
- These programs can generate or sample digital signals with very precise timing.
- They can handle various serial protocols, pulse generation, and signal sampling tasks.
- Flexibility
- PIOs can be programmed to implement a wide range of interfaces, including SPI, I2C, UART, PWM, and many others.
- They can also create custom protocols or handle specialized timing-sensitive I/O tasks.
- Performance
- PIO operations can run at up to the system clock speed (125 MHz in the RP2040).
- They provide deterministic timing, which is crucial for many I/O protocols.
- Integration
- PIOs are tightly integrated with the chip’s DMA (Direct Memory Access) controller, allowing for efficient data transfer without CPU intervention.
- Programming
- PIO programs are typically short (up to 32 instructions) and are written in a simple, specialized assembly language.
- The SDK provides tools and examples for programming the PIOs.
The PIO macroblock is one of the standout features of the RP2040, setting it apart from many other microcontrollers in its class. It provides a level of I/O flexibility and performance that would typically require an FPGA or more complex microcontroller architecture.
Design and Origin
The PIO macroblocks were designed by the team at Raspberry Pi, specifically for the RP2040 microcontroller. They are not a standard feature found in other microcontrollers, which makes them quite unique to the RP2040.
The primary architects behind the RP2040, including the PIO blocks, were James Adams and the hardware team at Raspberry Pi. Eben Upton, the founder of Raspberry Pi, has also spoken about the design process and the decision to include PIOs.
Usage Outside RP2040
The PIO macroblocks were still primarily associated with the RP2040 and haven’t been widely adopted in other microcontrollers or systems outside of the Raspberry Pi ecosystem. However, their concept has generated interest in the embedded systems community.
Some similar concepts exist in other systems
– FPGAs often have programmable I/O blocks, though these are typically more complex and flexible than PIOs.
– Some microcontrollers have programmable logic cells (PLCs) or configurable logic blocks (CLBs), which can be used for custom I/O operations, though these are generally less specialized than PIOs.
Reasons for Inclusion in RP2040
Raspberry Pi included PIO macroblocks in the RP2040 design for several key reasons:
-
Flexibility: PIOs allow the RP2040 to adapt to a wide range of I/O protocols without requiring dedicated hardware for each protocol.
-
Performance: By offloading I/O tasks to dedicated hardware, the main CPU cores are freed up for other tasks, improving overall system performance.
-
Timing Precision: PIOs can handle timing-critical I/O operations with high precision, which is crucial for many interfaces.
-
Cost-Effectiveness: Instead of including multiple dedicated peripherals, the programmable nature of PIOs allows one piece of hardware to serve many purposes.
-
Innovation: PIOs enable developers to create custom I/O protocols or implement lesser-known protocols without needing a custom chip.
-
Education: The PIO system provides an excellent learning tool for understanding low-level I/O operations and simple processor design.
Use Cases for PIOs
PIOs are particularly useful for:
- Implementing various serial protocols (SPI, I2C, UART, etc.)
- Generating precise PWM signals
- Interfacing with unusual or proprietary hardware
- Creating timing-sensitive control signals
- Sampling analog signals with precise timing
- Implementing software-defined radio protocols
- Emulating retro hardware interfaces (like our floppy disk example)
Impact on the Maker Community
The inclusion of PIOs has made the RP2040 popular among hobbyists and professionals working on projects that require precise timing or unusual I/O configurations. It’s particularly valued in retrocomputing projects, custom peripheral development, and educational settings.
Future Prospects
While PIOs are currently unique to the RP2040, their success could potentially influence future microcontroller designs. The concept of flexible, programmable I/O systems might be adopted or adapted by other manufacturers in the future.
The PIO system represents an innovative approach to I/O handling in microcontrollers, balancing flexibility, performance, and cost. It’s a key feature that sets the RP2040 apart in the microcontroller market and has contributed significantly to its popularity in certain application domains.
Use Case: Floppy
Using the PIO state machines to sample a floppy port from an older Macintosh is a great example of how versatile the RP2040’s PIO system can be. Let’s break this down into a detailed example.
First, let’s consider what we’re dealing with in terms of a Macintosh floppy port:
- It typically uses the GCR (Group Code Recording) encoding.
- The data rate is around 500 kbit/s for double-density disks.
- We need to handle both reading and potentially writing operations.
Here’s how we could use the PIO to sample this floppy port:
.program floppy_sampler
.side_set 1 opt
; Pin assignments:
; - IN pin 0: Data input from floppy drive
; - SET pin 0: Motor control (optional)
; - SIDE-SET pin 0: Index pulse (optional)
.wrap_target
wait 1 pin 0 side 0 ; Wait for rising edge on data pin
in pins, 1 side 0 ; Sample the data pin
push side 0 ; Push the sampled bit to FIFO
; Delay to match the 500 kbit/s data rate
; Assuming 125 MHz system clock, we need 250 cycles between bits
mov x, y side 0 ; Reset delay counter (y should be pre-loaded with 246)
delay_loop:
jmp x-- delay_loop side 0 ; Delay loop (3 cycles per iteration, 246 * 3 = 738 cycles)
; The above instructions (wait, in, push, mov) plus the delay loop
; should total to about 750 cycles (6 µs, matching 500 kbit/s)
.wrap
Now, let’s break down this PIO program and explain how to use it:
- Program Structure:
- The program waits for a rising edge on the data pin, samples it, and pushes the bit to the FIFO.
- It then introduces a delay to match the 500 kbit/s data rate.
- Pin Assignments:
- Input pin 0 is used for data from the floppy drive.
- We’ve included optional pins for motor control and index pulse.
- Timing:
- The program is designed to sample at 500 kbit/s, matching the Macintosh floppy data rate.
- We use a delay loop to achieve the correct timing, assuming a 125 MHz system clock.
-
Usage in C/C++:
To use this PIO program, you’d need to set it up in your main C/C++ code. Here’s a sketch of how that might look:
#include "hardware/pio.h"
#include "hardware/dma.h"
// Assume the PIO program is loaded into pio_floppy_sampler.pio
void setup_floppy_sampler() {
PIO pio = pio0;
uint sm = 0;
uint offset = pio_add_program(pio, &floppy_sampler_program);
pio_sm_config c = floppy_sampler_program_get_default_config(offset);
sm_config_set_in_pins(&c, 0); // Set input pin
sm_config_set_sideset_pins(&c, 1); // Set side-set pin for index pulse
// Set up FIFO to DMA transfer
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
// Set up DMA
int dma_chan = dma_claim_unused_channel(true);
dma_channel_config dma_config = dma_channel_get_default_config(dma_chan);
channel_config_set_transfer_data_size(&dma_config, DMA_SIZE_8);
channel_config_set_read_increment(&dma_config, false);
channel_config_set_write_increment(&dma_config, true);
dma_channel_configure(
dma_chan,
&dma_config,
buffer, // Destination buffer
&pio->rxf[sm], // Source: PIO RX FIFO
BUFFER_SIZE, // Transfer count
true // Start immediately
);
}
- Considerations:
- You’ll need to handle the motor control and any other floppy drive signals separately.
- This example only handles reading. Writing would require a separate PIO program.
- You might need to adjust the timing based on the exact model of Macintosh and floppy drive.
- Error checking and handling (e.g., for index pulses) would need to be added for a robust solution.
- Next Steps:
- Implement the GCR decoding in software after sampling the raw bits.
- Add error detection and correction as needed.
- Implement a state machine for the overall floppy read process (motor on/off, track seeking, etc.)
This example demonstrates how the PIO can be used to precisely time I/O operations, offloading the bit-level work from the main CPU. It’s particularly useful for interfaces like this where timing is critical.
Breakdown the ARM vs PIO components
Inside the chip the RP2040 ARM core runs your code. Let me explain how it works and how you could implement GCR (Group Code Recording) decoding:
- RP2040 Architecture:
The RP2040 has two main components that run code:- Dual-core ARM Cortex-M0+ processors: These run your main application code.
- PIO (Programmable I/O) blocks: These run simple, specialized programs for I/O operations.
- Running Your Code:
- Your main application code (typically written in C/C++) runs on the ARM cores.
- The PIO program we discussed earlier runs on one of the PIO state machines.
-
Implementing GCR Decoding:
For GCR decoding, you have two main options:
Option 1: Software Decoding (on ARM cores)
– Use the PIO to sample raw bits from the floppy drive.
– Implement GCR decoding in C/C++ running on the ARM cores.
Option 2: Hardware-Assisted Decoding (using PIO)
– Extend the PIO program to partially decode GCR.
– Finish decoding in software if necessary.
Let’s explore Option 1 in more detail, as it’s more straightforward and flexible:
#include <stdint.h>
// GCR lookup table (5-bit GCR to 4-bit data)
const uint8_t gcr_lookup[32] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x08, 0x00, 0x01, 0xFF, 0x0C, 0x04, 0x05,
0xFF, 0xFF, 0x02, 0x03, 0xFF, 0x0F, 0x06, 0x07,
0xFF, 0x09, 0x0A, 0x0B, 0xFF, 0x0D, 0x0E, 0xFF
};
// Function to decode a GCR byte
uint8_t decode_gcr_byte(uint8_t gcr_byte) {
uint8_t high_nibble = gcr_lookup[gcr_byte >> 3];
uint8_t low_nibble = gcr_lookup[gcr_byte & 0x1F];
if (high_nibble == 0xFF || low_nibble == 0xFF) {
// Invalid GCR code
return 0xFF;
}
return (high_nibble << 4) | low_nibble;
}
// Function to decode a buffer of GCR data
void decode_gcr_buffer(uint8_t* input, uint8_t* output, size_t input_size) {
for (size_t i = 0; i < input_size; i += 2) {
uint8_t decoded = decode_gcr_byte(input[i]);
if (decoded != 0xFF) {
*output++ = decoded;
}
}
}
// Main GCR decoding function
void process_floppy_data(uint8_t* raw_data, size_t raw_data_size) {
uint8_t decoded_data[raw_data_size / 2]; // Allocate conservatively
decode_gcr_buffer(raw_data, decoded_data, raw_data_size);
// Further processing of decoded_data...
}
Here’s how you would use this GCR decoding implementation:
- PIO Sampling:
- Use the PIO program we discussed earlier to sample raw bits from the floppy drive.
- The PIO pushes these bits into its FIFO, which is then transferred to a buffer in RAM via DMA.
- Main Application:
- Once a buffer of raw data is filled, your main application (running on the ARM cores) processes it.
- Call the
process_floppy_data
function with the buffer of raw data.
- GCR Decoding:
- The
decode_gcr_buffer
function converts the GCR-encoded data to normal bytes. - It uses a lookup table (
gcr_lookup
) to efficiently convert 5-bit GCR codes to 4-bit data.
- The
- Further Processing:
- After decoding, you can process the data further (e.g., handle sector headers, data fields, etc.).
This approach allows you to:
- Use the PIO for precise timing-sensitive sampling.
- Leverage the ARM cores for more complex processing (GCR decoding).
- Easily modify or extend the decoding process in software.
To integrate this with the PIO sampling:
- Set up a DMA transfer from the PIO FIFO to a buffer in RAM.
- Use an interrupt to notify when the buffer is full.
- In the interrupt handler, start processing the buffer with
process_floppy_data
. - Meanwhile, set up the next DMA transfer to an alternate buffer to continue sampling.
This double-buffering approach allows continuous sampling and processing.
ESP + PICO
Combining an RP2040 with an ESP32 to create a WiFi-enabled floppy disk emulator for an older Macintosh is an interesting and complex project. This setup would leverage the strengths of both microcontrollers: the RP2040’s precise I/O capabilities and the ESP32’s built-in WiFi functionality. Let’s break down how this could work:
System Architecture:
- RP2040:
- Interfaces directly with the Macintosh floppy port
- Handles timing-critical operations (reading/writing floppy signals)
- Manages the low-level floppy disk protocol
- ESP32:
- Provides WiFi connectivity
- Communicates with a remote server
- Acts as a bridge between the RP2040 and the network
- Server:
- Stores disk images
- Handles requests for reads/writes to these images
Communication Flow:
Macintosh <-> RP2040 <-> ESP32 <-> WiFi <-> Server
Implementation Details:
graph TD
A[Macintosh] <-->|Floppy Signals| B[RP2040]
B <-->|UART/SPI| C[ESP32]
C <-->|WiFi| D[Server]
subgraph RP2040 Tasks
B1[PIO for Floppy I/O]
B2[GCR Encoding/Decoding]
B3[Track/Sector Management]
end
subgraph ESP32 Tasks
C1[WiFi Management]
C2[HTTP Client]
C3[Data Buffering]
end
subgraph Server Tasks
D1[Disk Image Storage]
D2[RESTful API]
D3[User Management]
end
Detailed Component Roles:
- RP2040:
- Use PIO to emulate floppy disk signals (as discussed earlier)
- Implement GCR encoding/decoding
- Handle track seeking, sector reading/writing
- Communicate with ESP32 via UART or SPI
- ESP32:
- Manage WiFi connection
- Implement HTTP client to communicate with server
- Buffer data between RP2040 and server
- Handle any encryption/authentication for secure communication
- Server:
- Store disk images (e.g., .img or .dsk files)
- Provide RESTful API for read/write operations
- Manage user authentication and disk image access
Data Flow Example:
When the Macintosh requests to read a sector:
1. RP2040 receives the request via its floppy interface
2. RP2040 sends sector request to ESP32
3. ESP32 sends HTTP request to server
4. Server responds with sector data
5. ESP32 forwards data to RP2040
6. RP2040 encodes data (GCR) and sends to Macintosh
Code Outline:
Here’s a basic outline of how the RP2040 and ESP32 might interact:
// RP2040 Code (main.c)
#include "pico/stdlib.h"
#include "hardware/uart.h"
void handle_floppy_request() {
// Use PIO to handle floppy I/O
// Implement floppy protocol (seek, read, write)
}
void communicate_with_esp32() {
// Send/receive data via UART
}
int main() {
// Initialize PIO for floppy emulation
// Set up UART for ESP32 communication
while (1) {
handle_floppy_request();
communicate_with_esp32();
}
}
// ESP32 Code (main.cpp)
#include <WiFi.h>
#include <HTTPClient.h>
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
}
void loop() {
if (Serial.available()) {
// Read request from RP2040
String request = Serial.readStringUntil('\n');
// Send HTTP request to server
HTTPClient http;
http.begin("http://server/api/floppy");
int httpCode = http.POST(request);
if (httpCode > 0) {
String response = http.getString();
// Send response back to RP2040
Serial.println(response);
}
http.end();
}
}
// Server Code (Python with Flask)
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/floppy', methods=['POST'])
def handle_floppy_request():
data = request.json
# Process request (read/write disk image)
# Return response
return jsonify({"sector_data": "..."})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Challenges and Considerations:
- Latency: WiFi introduces latency. You’ll need to implement buffering and predictive reading to maintain performance.
- Timing: Ensuring the RP2040 can maintain precise timing while communicating with the ESP32.
- Power: Both chips will need appropriate power management.
- Error Handling: Robust error handling for network issues, data corruption, etc.
- Security: Implementing encryption and authentication for data transfer.
Potential Enhancements:
- Caching frequently accessed sectors on the ESP32 or RP2040 to reduce latency.
- Implementing a web interface on the ESP32 for configuration and disk image selection.
- Adding support for multiple virtual floppy drives.
This project combines low-level hardware interfacing with network communications, making it a complex but fascinating endeavor. It would allow older Macintosh computers to access a potentially unlimited library of disk images over WiFi, breathing new life into vintage hardware.
end