Skip to content

SDK Constraints

The Launchpad Pro SDK imposes several constraints that affect firmware development. Understanding these is essential for contributing to PolyBoard.

Processor

STM32F103RBT6 (ARM Cortex-M3)

  • 72 MHz clock
  • 128 KB Flash
  • 20 KB RAM

I/O

  • 64 pressure-sensitive pads
  • 32 control buttons
  • 100 RGB LEDs (6-bit per channel)
  • USB MIDI (2 ports)
  • DIN MIDI (in/out)
// BAD - will not link
char *buffer = malloc(100);
// GOOD - static allocation
static char buffer[100];

The stack is limited (~512 bytes). Avoid:

  • Large local arrays
  • Deep recursion
  • Passing large structs by value
// BAD - large stack allocation
void process(void) {
u32 buffer[256]; // 1KB on stack!
}
// GOOD - static or smaller allocations
static u32 buffer[256]; // In .bss section
void 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 bytes

The Cortex-M3 has no hardware FPU. Soft-float emulation is available but extremely slow.

// BAD - slow soft-float
float velocity_scale = value / 127.0f;
// GOOD - integer math
// Scale 0-127 to 0-63 using bit shift
u8 scaled = value >> 1;
// Or use fixed-point
// (value * 63 + 64) / 127 for better accuracy
// Division by powers of 2 - use shift
x / 2 → x >> 1
x / 4 → x >> 2
x / 8 → x >> 3
// Modulo by powers of 2 - use mask
x % 2 → x & 1
x % 4 → x & 3
x % 8 → x & 7

app_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 0xFF0000

LED updates are immediate - no vsync or double buffering:

// Updates may cause tearing if done during refresh
// PolyBoard mitigates this with LED caching
void 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 320

Three MIDI destinations available:

PortConstantDescription
USB StandaloneUSBSTANDALONEDirect USB connection
USB MIDIUSBMIDIVia DAW/host
DIN MIDIDINMIDI5-pin DIN connector

PolyBoard only saves to flash when exiting Setup mode:

// In app.c
if (is_in_setup_mode()) {
if (is_dirty()) {
flash_save();
clear_dirty();
}
exit_setup_mode();
}
  • Target: arm-none-eabi-gcc
  • Standard: C99
  • Optimization: -Os (size)
  • No standard library (-nostdlib)

Limited to:

  • stdint.h types via SDK typedefs (u8, u16, u32, s8, etc.)
  • No 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:

  1. LED indicators - Flash colors to show state
  2. MIDI output - Send debug values as MIDI CC
  3. Simulator - Use host-side tests
// Debug via LED
void 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);
}
}
ConstraintLimitMitigation
RAM20 KBStatic allocation, efficient data structures
Flash (code)~100 KB usableSize optimization (-Os)
Flash (user)1024 bytesCompact data structures
Stack~512 bytesAvoid large locals
Timer jitter<100µsFast callbacks
LED colors6-bit RGBScale from 8-bit
MIDI sysex320 bytesChunk large messages
Flash writes~10,000 cyclesSave only on setup exit