Add comprehensive MicroPython New Port Development Guide

This guide provides detailed instructions for creating new MicroPython ports, based on analysis of the Alif port development and patterns from existing ports.
Andrew Leech
2025-06-14 09:42:18 +10:00
parent 32eeeb398e
commit c4a0ed1690

@@ -0,0 +1,829 @@
# MicroPython New Port Development Guide
This comprehensive guide walks through creating a new MicroPython port, using the Alif port development as a case study. The guide is based on analysis of commit `ccc5935234` and subsequent development commits.
## Overview
A MicroPython port adapts the core MicroPython runtime to a specific hardware platform. This involves:
- **Hardware Abstraction Layer (HAL)**: Interfacing with hardware-specific drivers
- **Build System**: Integrating with toolchains and hardware SDKs
- **Board Support**: Defining board-specific configurations
- **Peripheral Support**: Implementing machine module interfaces for hardware peripherals
## Prerequisites
Before starting, ensure you have:
- Target hardware documentation and SDK/drivers
- Cross-compilation toolchain (typically `arm-none-eabi-` for ARM Cortex-M)
- Understanding of your hardware's memory layout, peripherals, and boot process
- MicroPython source code and build environment
## Development Phases
The Alif port development followed this logical progression:
1. **Foundation** - Core infrastructure and basic I/O
2. **System Services** - Timing, interrupts, memory management
3. **Peripheral Support** - Progressive addition of hardware interfaces
4. **Advanced Features** - Multi-core, networking, etc.
---
## Phase 1: Foundation (Essential Files)
### Step 1: Create Port Directory Structure
```bash
mkdir ports/YOUR_PORT
cd ports/YOUR_PORT
```
Create these essential directories:
- `boards/` - Board-specific configurations
- `mcu/` - MCU-specific files (linker scripts, pin definitions)
- `modules/` - Port-specific Python modules
### Step 2: Core Configuration Files
#### A. `mpconfigport.h` (Port Configuration)
**Purpose**: Defines which MicroPython features are enabled for your port.
**Common Pattern Analysis**:
- All ports include `mpconfigboard.h` for board-specific overrides
- Use `MICROPY_CONFIG_ROM_LEVEL` for feature sets (MINIMAL/BASIC/EXTRA/FULL)
- Define platform string: `#define MICROPY_PY_SYS_PLATFORM "yourport"`
**Template from Alif**:
```c
// Options controlling how MicroPython is built, overriding defaults in py/mpconfig.h
#include <stdint.h>
#include <alloca.h>
// board specific definitions
#include "mpconfigboard.h"
#ifndef MICROPY_CONFIG_ROM_LEVEL
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_FULL_FEATURES)
#endif
// Hardware features
#define MICROPY_HW_ENABLE_UART_REPL (1)
#define MICROPY_HW_ENABLE_USBDEV (1)
// USB configuration
#define MICROPY_HW_USB_CDC (1)
#define MICROPY_HW_USB_VID (0xf055)
#define MICROPY_HW_USB_PID (0x9802)
// Memory and performance
#define MICROPY_ALLOC_PATH_MAX (128)
#define MICROPY_QSTR_BYTES_IN_HASH (1)
// MicroPython emitters (for ARM Cortex-M)
#define MICROPY_EMIT_THUMB (1)
#define MICROPY_EMIT_THUMB_ARMV7M (1)
#define MICROPY_EMIT_INLINE_THUMB (1)
// Core Python features
#define MICROPY_ENABLE_GC (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
#define MICROPY_SCHEDULER_DEPTH (8)
// Platform identification
#define MICROPY_PY_SYS_PLATFORM "yourport"
// Extended modules
#define MICROPY_PY_MACHINE (1)
#define MICROPY_PY_MACHINE_INCLUDEFILE "ports/yourport/modmachine.c"
#define MICROPY_VFS (1)
// Type definitions
typedef intptr_t mp_int_t;
typedef uintptr_t mp_uint_t;
typedef intptr_t mp_off_t;
// Board hooks (define these as no-ops initially)
#ifndef MICROPY_BOARD_STARTUP
#define MICROPY_BOARD_STARTUP()
#endif
#ifndef MICROPY_BOARD_EARLY_INIT
#define MICROPY_BOARD_EARLY_INIT()
#endif
```
#### B. `mpconfigport.mk` (Build Configuration)
**Purpose**: Makefile variables for the port.
```makefile
# MicroPython features
MICROPY_VFS_FAT = 1
MICROPY_VFS_LFS2 = 1
# Optimization
COPT = -Os -DNDEBUG
# Floating point
MICROPY_FLOAT_IMPL = double
```
#### C. `qstrdefsport.h` (Port-Specific Strings)
**Purpose**: Define port-specific interned strings (QSTRs).
```c
// qstr definitions for this port
// Example entries:
// Q(Pin)
// Q(UART)
// Q(I2C)
```
### Step 3: Hardware Abstraction Layer
#### A. `mphalport.h` (HAL Interface)
**Purpose**: Defines the hardware abstraction interface.
**Common Pattern**: All ports define these core macros:
- `MICROPY_BEGIN_ATOMIC_SECTION()` / `MICROPY_END_ATOMIC_SECTION()`
- Pin manipulation macros
- Timing functions
**Template from Alif**:
```c
#include "py/ringbuf.h"
#include "shared/runtime/interrupt_char.h"
#include "irq.h"
// Atomic sections (critical sections)
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state)
// Event handling for efficient wait
#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) \
do { \
if ((TIMEOUT_MS) < 0) { \
__WFE(); \
} else { \
/* TODO: implement timeout */ \
} \
} while (0)
// Declare pin type and manipulation functions
extern const mp_obj_type_t pin_type;
typedef struct _pin_obj_t {
mp_obj_base_t base;
qstr name;
// ... hardware-specific fields
} pin_obj_t;
```
#### B. `mphalport.c` (HAL Implementation)
**Purpose**: Implements the hardware abstraction functions.
**Key Functions** (analyze STM32/RP2 implementations):
- `mp_hal_delay_ms()` / `mp_hal_delay_us()`
- `mp_hal_ticks_ms()` / `mp_hal_ticks_us()`
- `mp_hal_stdout_tx_strn()` (debug output)
- `mp_hal_stdin_rx_chr()` (console input)
### Step 4: Main Entry Point
#### `main.c` (Application Entry)
**Purpose**: Main application loop and MicroPython initialization.
**Common Pattern Analysis** (all ports follow this structure):
```c
#include "py/runtime.h"
#include "py/gc.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#include "py/stackctrl.h"
#include "shared/runtime/pyexec.h"
// Hardware-specific includes
#include "your_hardware_headers.h"
// Memory layout (defined in linker script)
extern uint8_t __StackTop, __StackLimit;
extern uint8_t __GcHeapStart, __GcHeapEnd;
void _start(void) {
// 1. Hardware initialization
SystemInit(); // Clock setup, etc.
// 2. Board-specific startup
MICROPY_BOARD_STARTUP();
// 3. Initialize interrupt system
SysTick_Config(SystemCoreClock / 1000);
// 4. Early hardware init
MICROPY_BOARD_EARLY_INIT();
// 5. Initialize peripherals
uart_init(); // For REPL
flash_init(); // For filesystem
// 6. Set up MicroPython memory management
mp_stack_set_top(&__StackTop);
mp_stack_set_limit(&__StackTop - &__StackLimit - 1024);
gc_init(&__GcHeapStart, &__GcHeapEnd);
// 7. Main execution loop
for (;;) {
// Initialize MicroPython runtime
mp_init();
// Initialize subsystems
readline_init0();
// Execute boot scripts
pyexec_frozen_module("_boot.py", false);
// Execute user scripts
int ret = pyexec_file_if_exists("boot.py");
if (ret & PYEXEC_FORCED_EXIT) {
goto soft_reset_exit;
}
// Main REPL loop
for (;;) {
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
if (pyexec_raw_repl() != 0) break;
} else {
if (pyexec_friendly_repl() != 0) break;
}
}
soft_reset_exit:
mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
gc_sweep_all();
mp_deinit();
}
}
// Required MicroPython callbacks
void gc_collect(void) {
gc_collect_start();
gc_helper_collect_regs_and_stack();
gc_collect_end();
}
void nlr_jump_fail(void *val) {
mp_printf(&mp_plat_print, "FATAL: uncaught exception %p\n", val);
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(val));
for (;;) {
__WFE();
}
}
```
### Step 5: Build System
#### A. `Makefile` (Build Configuration)
**Purpose**: Defines how to build the port.
**Common Pattern Analysis**:
- Board selection: `BOARD ?= DEFAULT_BOARD`
- Include core makefiles: `include ../../py/mkenv.mk`
- Cross-compiler: `CROSS_COMPILE ?= arm-none-eabi-`
- Git submodules for dependencies
**Build System Architecture Choices**:
1. **Pure Make** (STM32, SAMD, Alif)
- Traditional approach for bare-metal ports
- Direct control over build process
- No external build system dependencies
2. **Make wrapping CMake** (ESP32, RP2)
- Required when vendor SDKs mandate CMake
- Make provides consistent user interface
- CMake handles vendor-specific complexity
**ESP32 Example**:
```makefile
# Makefile for MicroPython on ESP32.
# This is a simple, convenience wrapper around idf.py (which uses cmake).
all:
$(Q)idf.py $(IDFPY_FLAGS) -B $(BUILD) build
```
**RP2 Example**:
```makefile
# Makefile for micropython on Raspberry Pi RP2
# This is a simple wrapper around cmake
all:
$(Q)[ -e $(BUILD)/Makefile ] || cmake -S . -B $(BUILD) -DPICO_BUILD_DOCS=0 ${CMAKE_ARGS}
$(Q)$(MAKE) $(MAKE_ARGS) -C $(BUILD)
```
**Key Insight**: The Make wrapper pattern allows MicroPython to maintain a consistent `make` interface across all ports while accommodating vendor requirements. Users always run `make BOARD=xxx` regardless of underlying build system.
**Template from Alif (Pure Make)**:
```makefile
################################################################################
# Initial setup of Makefile environment
BOARD ?= DEFAULT_BOARD
BOARD_DIR ?= boards/$(BOARD)
BUILD ?= build-$(BOARD)
ifeq ($(wildcard $(BOARD_DIR)/.),)
$(error Invalid BOARD specified: $(BOARD_DIR))
endif
include ../../py/mkenv.mk
include mpconfigport.mk
include $(BOARD_DIR)/mpconfigboard.mk
# qstr definitions (must come before including py.mk)
QSTR_DEFS += qstrdefsport.h
# include py core make definitions
include $(TOP)/py/py.mk
include $(TOP)/extmod/extmod.mk
################################################################################
# Project specific settings
CROSS_COMPILE ?= arm-none-eabi-
GIT_SUBMODULES += lib/tinyusb
# Include paths
INC += -I.
INC += -I$(TOP)
INC += -I$(BUILD)
INC += -I$(BOARD_DIR)
# Source files
SRC_C = \
main.c \
mphalport.c \
modmachine.c \
machine_pin.c \
# Hardware-specific sources
SRC_C += \
your_hardware_drivers.c \
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
all: $(BUILD)/firmware.elf
$(BUILD)/firmware.elf: $(OBJ)
$(ECHO) "LINK $@"
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
include $(TOP)/py/mkrules.mk
```
### Step 6: Board Configuration
#### A. `boards/YOUR_BOARD/mpconfigboard.h`
**Purpose**: Board-specific hardware definitions.
```c
// Board-specific configuration
#define MICROPY_HW_BOARD_NAME "Your Board Name"
#define MICROPY_HW_MCU_NAME "Your MCU"
// Pin definitions
#define MICROPY_HW_UART_REPL_TX pin_A9
#define MICROPY_HW_UART_REPL_RX pin_A10
// Flash configuration
#define MICROPY_HW_FLASH_SIZE_MB (2)
// Enable features for this board
#define MICROPY_HW_ENABLE_USB (1)
#define MICROPY_HW_ENABLE_SDCARD (0)
```
#### B. `boards/YOUR_BOARD/mpconfigboard.mk`
**Purpose**: Board-specific build settings.
```makefile
MCU_SERIES = your_mcu_series
CMSIS_MCU = YOUR_MCU_DEFINE
STARTUP_FILE = lib/your_sdk/startup_your_mcu.s
# Linker script
LD_FILES = mcu/your_mcu.ld
```
---
## Phase 2: System Services
### Step 7: Interrupt and Timing System
#### A. `irq.h` (Interrupt Priorities)
**Purpose**: Define interrupt priority levels.
```c
// IRQ priority definitions
#define IRQ_PRI_SYSTICK (1)
#define IRQ_PRI_UART (6)
#define IRQ_PRI_USB (6)
#define IRQ_PRI_PENDSV (15) // Lowest priority
```
#### B. `pendsv.c` & `pendsv.h` (PendSV Handler)
**Purpose**: Handle deferred processing (background tasks).
**Pattern**: Used by networking, Bluetooth, and other async operations.
### Step 8: Memory Management
#### A. Linker Script (`mcu/your_mcu.ld`)
**Purpose**: Define memory layout for the target MCU.
```ld
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 512K
}
/* Stack at top of RAM */
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
__StackLimit = __StackTop - 64K;
/* Heap for MicroPython GC */
__GcHeapStart = _end;
__GcHeapEnd = __StackLimit;
```
---
## Phase 3: Basic Machine Module
### Step 9: Machine Module Foundation
#### A. `modmachine.c` (Machine Module)
**Purpose**: Implements the `machine` module.
**Common Pattern** (analyze STM32 implementation):
```c
#include "py/runtime.h"
#include "extmod/modmachine.h"
// Forward declarations for machine classes
extern const mp_obj_type_t machine_pin_type;
static mp_obj_t machine_reset(void) {
NVIC_SystemReset();
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
static mp_obj_t machine_unique_id(void) {
// Return unique device ID
return mp_obj_new_bytes((const byte*)&your_unique_id, sizeof(your_unique_id));
}
static MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
static const mp_rom_map_elem_t machine_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_machine) },
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
// Machine classes
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) },
};
static MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
const mp_obj_module_t machine_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&machine_module_globals,
};
MP_REGISTER_MODULE(MP_QSTR_machine, machine_module);
```
### Step 10: Pin Support
#### A. `machine_pin.c` (GPIO Implementation)
**Purpose**: Implement `machine.Pin` class for GPIO control.
**Common Pattern Analysis** (study STM32/RP2 implementations):
```c
#include "py/runtime.h"
#include "py/mphal.h"
#include "extmod/modmachine.h"
typedef struct _machine_pin_obj_t {
mp_obj_base_t base;
qstr name;
uint32_t pin_id;
// Hardware-specific fields
GPIO_TypeDef *gpio;
uint32_t pin_mask;
} machine_pin_obj_t;
// Pin mapping table
const machine_pin_obj_t machine_pin_obj[] = {
{{&machine_pin_type}, MP_QSTR_A0, 0, GPIOA, GPIO_PIN_0},
{{&machine_pin_type}, MP_QSTR_A1, 1, GPIOA, GPIO_PIN_1},
// ... more pins
};
static void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "Pin(%q)", self->name);
}
mp_obj_t machine_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_id, ARG_mode, ARG_pull, ARG_value };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = GPIO_MODE_INPUT} },
{ MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// Get pin object
machine_pin_obj_t *pin = pin_find(args[ARG_id].u_obj);
// Configure pin
if (args[ARG_mode].u_int != GPIO_MODE_INPUT) {
machine_pin_config(pin, args[ARG_mode].u_int, args[ARG_pull].u_obj);
}
return MP_OBJ_FROM_PTR(pin);
}
// Pin methods: value(), init(), etc.
static mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) {
machine_pin_obj_t *self = MP_OBJ_TO_PTR(args[0]);
if (n_args == 1) {
// Get value
return MP_OBJ_NEW_SMALL_INT(HAL_GPIO_ReadPin(self->gpio, self->pin_mask));
} else {
// Set value
HAL_GPIO_WritePin(self->gpio, self->pin_mask, mp_obj_is_true(args[1]));
return mp_const_none;
}
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value);
static const mp_rom_map_elem_t machine_pin_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_pin_value_obj) },
// ... more methods
};
static MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table);
MP_DEFINE_CONST_OBJ_TYPE(
machine_pin_type,
MP_QSTR_Pin,
MP_TYPE_FLAG_NONE,
make_new, machine_pin_make_new,
print, machine_pin_print,
locals_dict, &machine_pin_locals_dict
);
```
---
## Phase 4: Storage and Filesystem
### Step 11: Flash Storage
**Purpose**: Implement storage backend for filesystem.
**Common Pattern**: Implement a flash driver that provides:
- Block read/write interface
- Sector erase functionality
- Integration with `extmod/vfs.c`
Study the Alif `ospi_flash.c` and `alif_flash.c` implementations.
### Step 12: USB MSC Support
**Purpose**: Expose filesystem over USB Mass Storage.
**Dependencies**: TinyUSB integration (see `usbd.c`, `msc_disk.c`)
---
## Phase 5: Peripheral Support
### Step 13: Adding Peripheral Classes
For each peripheral (UART, I2C, SPI, ADC, etc.), follow this pattern:
#### A. Update Build System
1. **Add source file to Makefile**:
```makefile
SRC_C += machine_i2c.c
```
2. **Add hardware driver** (if needed):
```makefile
ALIF_SRC_C += drivers/source/i2c.c
```
#### B. Enable in Configuration
**In `mpconfigport.h`**:
```c
#define MICROPY_PY_MACHINE_I2C (MICROPY_HW_ENABLE_HW_I2C)
#define MICROPY_PY_MACHINE_I2C_TRANSFER_WRITE1 (1)
```
#### C. Implement Peripheral Class
**Pattern Analysis** (from Alif I2C implementation):
1. **Define object structure**:
```c
typedef struct _machine_i2c_obj_t {
mp_obj_base_t base;
uint32_t i2c_id;
I2C_Type *i2c; // Hardware registers
mp_hal_pin_obj_t scl; // Pin objects
mp_hal_pin_obj_t sda;
uint32_t freq; // Configuration
uint32_t timeout;
} machine_i2c_obj_t;
```
2. **Create instance table**:
```c
static machine_i2c_obj_t machine_i2c_obj[] = {
#if defined(MICROPY_HW_I2C0_SCL)
[0] = {{&machine_i2c_type}, 0, (I2C_Type *)I2C0_BASE, MICROPY_HW_I2C0_SCL, MICROPY_HW_I2C0_SDA},
#endif
// ... more instances
};
```
3. **Implement standard methods**:
- `make_new()` - Object construction and hardware initialization
- `print()` - String representation
- Protocol methods (e.g., `transfer()` for I2C)
4. **Register with machine module**:
```c
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
```
---
## Phase 6: Advanced Features
### Step 14: Networking Support
If your hardware supports networking:
1. **Enable in configuration**:
```c
#define MICROPY_PY_NETWORK (1)
#define MICROPY_PY_SOCKET (1)
```
2. **Implement network interface** in `mpnetworkport.c`
3. **Add LWIP integration** (if using LWIP stack)
### Step 15: Bluetooth Support
For Bluetooth-enabled hardware:
1. **Choose Bluetooth stack** (BTstack, NimBLE)
2. **Implement HCI transport** in `mpbthciport.c`
3. **Enable in configuration**:
```c
#define MICROPY_PY_BLUETOOTH (1)
```
### Step 16: Multi-core Support
For multi-core MCUs (like Alif Ensemble):
1. **Implement Open-AMP backend** (`mpmetalport.c`, `mpremoteprocport.c`)
2. **Add core-specific configurations**
3. **Handle inter-core communication**
---
## Phase 7: Testing and Validation
### Step 17: Testing Strategy
1. **Unit Tests**: Run MicroPython test suite
```bash
cd ports/unix
make test_full
```
2. **Hardware-in-Loop**: Test on actual hardware
```bash
cd ports/yourport
make BOARD=YOUR_BOARD
# Flash and test on hardware
```
3. **Peripheral Tests**: Create hardware-specific test scripts
### Step 18: Documentation
1. **README.md**: Build instructions, supported features
2. **Board documentation**: Pin assignments, jumper settings
3. **API documentation**: Port-specific extensions
---
## Common Pitfalls and Best Practices
### Build System Choice
- **Start with pure Make** unless vendor SDK requires otherwise
- **Use Make wrappers** when vendor tools (ESP-IDF, Pico SDK) mandate CMake
- **Document build dependencies** clearly in README
- **Maintain consistent user interface** - always support `make BOARD=xxx`
### Vendor SDK Integration
- **Document all external dependencies** clearly
- **Provide simplified build options** where possible
- **Don't require vendor IDEs** for basic builds
- **Version lock vendor dependencies** to ensure reproducibility
When vendor SDKs require CMake:
- ESP32: ESP-IDF uses CMake internally via `idf.py`
- RP2: Pico SDK is CMake-based
- Solution: Wrap vendor tools with Make for consistency
### Memory Management
- **Always define proper memory regions** in linker script
- **Test with different heap sizes** - GC pressure reveals bugs
- **Use `MP_REGISTER_ROOT_POINTER`** for global objects
### Interrupt Handling
- **Keep ISRs minimal** - defer work to PendSV/main loop
- **Use proper priorities** - timing-critical > user code > background tasks
- **Test interrupt nesting** scenarios
### Hardware Integration
- **Follow existing peripheral patterns** - don't reinvent APIs
- **Handle hardware quirks gracefully** (see Alif I2C zero-length transfer workaround)
- **Add proper error handling** and timeouts
### Build System
- **Use consistent naming** for boards and configurations
- **Minimize external dependencies** - prefer git submodules
- **Support both debug and release builds**
### Pin Configuration
- **Create comprehensive pin mapping** in `pins.csv`
- **Support alternate functions** for peripherals
- **Handle pin conflicts** (multiple peripherals on same pins)
---
## Maintenance and Evolution
### Keeping Up with MicroPython
- **Monitor MicroPython releases** for API changes
- **Participate in community** discussions
- **Contribute improvements** back to mainline
### Adding New Features
- **Follow established patterns** from other ports
- **Add comprehensive tests** for new functionality
- **Document changes** thoroughly
### Performance Optimization
- **Profile with real workloads**
- **Optimize critical paths** (GC, interrupt handling)
- **Consider hardware-specific optimizations** (DMA, etc.)
---
This guide provides a comprehensive roadmap for developing a new MicroPython port. The key is to start with a minimal working foundation and incrementally add features, following the patterns established by existing successful ports.