Firmware
Firmware Architecture
Inside the RT-900 firmware — source tree, build system, task scheduling, and programming protocol. Essential reading for anyone building custom firmware.
Source Tree
| Directory | Purpose | Key Files |
|---|---|---|
| App/ | Application logic (menus, modes) | AppMain.c, AppMenu.c, AppScan.c, AppDtmf.c, AppFm.c, AppAlarm.c |
| BSP/ | Board support (GPIO, clocks) | Board initialization and peripheral setup |
| Core/ | Radio core logic | Radio.c (RF control), RadioTask.c (state machine), Functions.c |
| Driver/ | Hardware drivers | DevBK4819.c, st7735s.c, NorFlash.c, keyboard.c, Rda5807.c |
| Gui/ | Display rendering | DisplayMain.c, DisplayMenu.c, DisplayFm.c, LcdFillDot.c |
| CPS/ | Programming support | ProgromFlash.c (UART flash protocol) |
| Interface/ | Communication buses | I2C, UART low-level drivers |
| Libraries/ | CMSIS + STM32 HAL | Startup assembly, peripheral definitions, CMSIS core |
| Voice/ | Audio playback | Beep.c (tone generation), VoiceBroadcast.c (voice prompts) |
| Common/ | Shared types/utilities | Type definitions, common macros |
Total codebase: ~19,500 lines of C.
Build System
- Toolchain: arm-none-eabi-gcc (GCC ARM Embedded)
- CPU target:
-mcpu=cortex-m0 - Optimization:
-Os -flto(size-optimized with link-time optimization) - Linker script:
firmware.ld - Build: run
maketo producefirmware.bin - Output:
firmware.elf(debug),firmware.bin(flashable binary)
Firmware source is publicly available at github.com/pdrbsts/radtel-rt-900-firmware.
Task Loop
The firmware runs a cooperative multitasking loop driven by a 1ms SysTick interrupt:
| Interval | Task | Responsibility |
|---|---|---|
| 10ms | RF + Keys | BK4819 state machine, keyboard scan, radio control |
| 50ms | Display | LCD refresh, GUI updates |
| 100ms | Status | Battery monitoring, status updates |
| 500ms | Maintenance | Settings save, power management |
SysTick interrupt sets flags (g_10msFlag, g_50msFlag, etc.) which the main loop checks and services.
Startup Sequence
Board_Init()— configure GPIO, SPI, UART, timersST7735S_Init()— initialize color LCD over SPI2RadioConfig_Init()— load channel and VFO data from SPI flashRfic_Init()— initialize BK4819 RF chipUI_DisplayPowerOn()— show splash screenEnter main loop— begin task scheduling

CPS Programming Protocol
For programming the radio from a computer (firmware upload, channel read/write).
Connection: UART1 at 57600 baud, 8N1 (PA9=TX, PA10=RX)
Packet Format
| Field | Size | Description |
|---|---|---|
| Header | 1 byte | 0xA5 (sync marker) |
| Command | 1 byte | Command ID |
| Packet ID | 1 byte | Sequential counter |
| Length | 2 bytes | Data length (little-endian) |
| Data | variable | Command-specific payload |
Commands
| ID | Name | Description |
|---|---|---|
| 0x02 | Handshake | Initiate communication |
| 0x03 | Address | Set target flash address |
| 0x04 | Erase | Erase sector/block/chip |
| 0x06 | End | Terminate session |
| 0x57 | Write | Write data to flash |
- Erase modes:
0x01(full chip),0x02(4K sector),0x03(32K block),0x04(64K block) - Response codes:
0x59= OK,0x01–0x06= various errors - Write flow: handshake → set address → erase → write chunks → end → radio reboots
Note
The CPS protocol writes directly to the SPI NOR flash. This is how both firmware and channel data are programmed. A Web Serial implementation of this protocol would enable browser-based programming — similar to what rfsplatter already does for the UV-K5.