Processor
STM32F103RBT6 (ARM Cortex-M3)
- 72 MHz clock
- 128 KB Flash
- 20 KB RAM
The Launchpad Pro SDK imposes several constraints that affect firmware development. Understanding these is essential for contributing to PolyBoard.
Processor
STM32F103RBT6 (ARM Cortex-M3)
I/O
// BAD - will not linkchar *buffer = malloc(100);
// GOOD - static allocationstatic char buffer[100];The stack is limited (~512 bytes). Avoid:
// BAD - large stack allocationvoid process(void) { u32 buffer[256]; // 1KB on stack!}
// GOOD - static or smaller allocationsstatic u32 buffer[256]; // In .bss sectionvoid process(void) { // Use static buffer}User data storage is limited to 1024 bytes (USER_AREA_SIZE).
// Current PolyBoard usage:// FlashData = 4 (magic) + 1 (version) + 1 (page) + 2 (reserved)// + 4 * sizeof(Page)// ≈ 72 bytesThe Cortex-M3 has no hardware FPU. Soft-float emulation is available but extremely slow.
// BAD - slow soft-floatfloat velocity_scale = value / 127.0f;
// GOOD - integer math// Scale 0-127 to 0-63 using bit shiftu8 scaled = value >> 1;
// Or use fixed-point// (value * 63 + 64) / 127 for better accuracy// Division by powers of 2 - use shiftx / 2 → x >> 1x / 4 → x >> 2x / 8 → x >> 3
// Modulo by powers of 2 - use maskx % 2 → x & 1x % 4 → x & 3x % 8 → x & 7app_timer_event() is called every 1ms. Keep it fast:
void app_timer_event(void) { // GOOD: Quick flag check process_pending_render(); // ~3 cycles if no work
// BAD: Heavy computation // recalculate_all_notes(); // Would cause jitter}app_surface_event() should respond quickly for low-latency note triggering:
void app_surface_event(u8 type, u8 index, u8 value) { // Calculate note and send MIDI immediately // Don't do heavy work here}RGB values are 6-bit (0-63), not 8-bit:
#define MAXLED 63
// Color packing: 0x00RRGGBB (each channel 0-63)#define COLOR_WHITE 0x3F3F3FU // Not 0xFFFFFF#define COLOR_RED 0x3F0000U // Not 0xFF0000LED updates are immediate - no vsync or double buffering:
// Updates may cause tearing if done during refresh// PolyBoard mitigates this with LED cachingvoid set_pad_color(u8 index, u32 color) { if (led_cache[index] != color) { // Only update if changed led_cache[index] = color; PLOT_LED_FAST(TYPEPAD, index, color); }}System exclusive messages are limited to 320 bytes:
void hal_send_sysex(u8 port, const u8 *data, u16 length);// length must not exceed 320Three MIDI destinations available:
| Port | Constant | Description |
|---|---|---|
| USB Standalone | USBSTANDALONE | Direct USB connection |
| USB MIDI | USBMIDI | Via DAW/host |
| DIN MIDI | DINMIDI | 5-pin DIN connector |
PolyBoard only saves to flash when exiting Setup mode:
// In app.cif (is_in_setup_mode()) { if (is_dirty()) { flash_save(); clear_dirty(); } exit_setup_mode();}arm-none-eabi-gcc-Os (size)-nostdlib)Limited to:
stdint.h types via SDK typedefs (u8, u16, u32, s8, etc.)stdio.h, stdlib.h, string.h// SDK provides these types:typedef unsigned char u8;typedef unsigned short u16;typedef unsigned long u32;typedef signed char s8;typedef signed short s16;typedef signed long s32;No console output available. Debug using:
// Debug via LEDvoid debug_value(u8 value) { // Show value as binary on bottom row for (u8 i = 0; i < 8; i++) { u32 color = (value & (1 << i)) ? COLOR_RED : COLOR_BLACK; set_pad_color(i + 1, color); }}| Constraint | Limit | Mitigation |
|---|---|---|
| RAM | 20 KB | Static allocation, efficient data structures |
| Flash (code) | ~100 KB usable | Size optimization (-Os) |
| Flash (user) | 1024 bytes | Compact data structures |
| Stack | ~512 bytes | Avoid large locals |
| Timer jitter | <100µs | Fast callbacks |
| LED colors | 6-bit RGB | Scale from 8-bit |
| MIDI sysex | 320 bytes | Chunk large messages |
| Flash writes | ~10,000 cycles | Save only on setup exit |