Features: - VFO mode with direct frequency input - POCSAG decoder (512/1200 baud) with BCH(31,21) correction - Full-screen Spectrum analyzer - FM Radio receiver - RSSI signal indicator overlay - Custom boot splash (UA1ZBE / POCSAG pager / build date) Architecture: - app/mode.c — mode dispatcher (VFO/POCSAG/Spectrum/FM) - app/boot_splash.c — 2-second boot splash - app/pocsag/ — POCSAG decoder + BCH correction - app/display_rssi.c — RSSI indicator - main.c — entry point with custom init - syscalls.c — bare-metal _sbrk stub Build: arm-none-eabi-gcc -Os -flto -Wall -Werror -Wextra Size: 57.9KB Flash / 3.6KB RAM Controls: - 0-9: Direct frequency input (VFO) - SK2: POCSAG mode - SK1: Spectrum analyzer - 0: FM Radio - EXIT: Return to VFO - F/*: Toggle 512/1200 baud (in POCSAG)
8.2 KiB
UA1ZBE Custom Firmware — Полная документация
1. Обзор архитектуры
Прошивка заменяет стандартное меню и создаёт три режима: VFO, POCSAG, Spectrum + FM.
Точка входа: main.c
Main()
├── SYSTICK_Init(), BOARD_Init()
├── BK4819_Init()
├── SETTINGS_InitEEPROM()
├── RADIO_ConfigureChannel()
├── BOOT_SplashShow() ← 2 сек заставка
├── RSSI_Init()
├── MODE_Init() ← VFO режим по умолчанию
└── while(1):
├── APP_Update()
├── if (gNextTimeslice):
│ ├── RSSI_Update()
│ └── MODE_TimeSlice10ms()
└── if (gNextTimeslice_500ms):
└── MODE_TimeSlice500ms()
Диспетчер режимов: app/mode.c
MODE_TimeSlice10ms()
├── MODE_VFO:
│ └── APP_TimeSlice10ms() ← оригинальный VFO цикл
│ └── RSSI_Draw() ← overlay индикатор
├── MODE_POCSAG:
│ └── POCSAG_FeedSample() × 80 ← аудио сэмплинг
│ └── POCSAG_Process()
│ └── pocsag_draw()
├── MODE_SPECTRUM:
│ └── MODE_Switch(MODE_VFO) ← после возврата из spectrum
└── MODE_FM:
└── FM_Play()
2. Все ошибки при создании и их исправления
Ошибка 1: static_assert не работает в C99
error: expected declaration specifiers or '...' before '(' token
static_assert(ARRAY_SIZE(ProcessKeysFunctions) == DISPLAY_N_ELEM);
Причина: static_assert — C11 feature. В -std=c99 недоступен.
Исправление: Заменил -std=c99 на -std=gnu11 в Makefile.
Ошибка 2: [[fallthrough]] не поддерживается GCC 9
error: expected expression before '[' token
[[fallthrough]];
Причина: Атрибут [[fallthrough]] — синтаксис C23. GCC 9.2.1 не понимает.
Исправление:
sed -i 's/\[\[fallthrough\]\]/__attribute__((fallthrough))/g' \
radio.c audio.c app/menu.c app/dtmf.c app/chFrScanner.c
Ошибка 3: SYSTICK_GetTickCounter() не существует
Причина: В egzumer нет этой функции.
Исправление: В pocsag.c использован собственный статический счётчик s_tick_counter, инкрементируемый при каждом вызове POCSAG_FeedSample().
Ошибка 4: Сравнение uint8_t >= 576 — всегда false
error: comparison is always false due to limited range of data type
if (s_preamble_alt_count >= POCSAG_PREAMBLE_MIN_BITS)
Причина: s_preamble_alt_count был uint8_t (макс 255), а POCSAG_PREAMBLE_MIN_BITS = 576.
Исправление:
static uint16_t s_preamble_alt_count; // было uint8_t
Ошибка 5: dBmCorrTable undeclared
error: 'dBmCorrTable' undeclared (first use in this function)
Причина: Таблица в ui/main.c, но нет extern в заголовке.
Исправление: Добавил в display_rssi.c:
extern const int8_t dBmCorrTable[7];
Ошибка 6: display_rssi.h не найден
fatal error: display_rssi.h: No such file or directory
Исправление: Заменил #include "display_rssi.h" на #include "app/display_rssi.h" везде.
Ошибка 7: sizeof к неполному типу
error: invalid application of 'sizeof' to incomplete type 'char[]'
Исправление: Добавил #include "app/dtmf.h" в main.c — там полное объявление extern char gDTMF_String[15].
Ошибка 8: 40+ undefined reference
undefined reference to `gScreenToDisplay'
undefined reference to `GUI_SelectNextDisplay'
undefined reference to `GENERIC_Key_F', `ACTION_Scan'...
Причина: Исключил модули, но app/app.c и app/main.c их используют.
Исправление: Вернул в Makefile: ui/ui.o, ui/inputbox.o, ui/menu.o, ui/welcome.o, ui/scanner.o, app/menu.o, app/generic.o, app/action.o, app/dtmf.o
Ошибка 9: _sbrk undefined
undefined reference to `_sbrk'
Исправление: Создал syscalls.c:
caddr_t _sbrk(int incr) {
(void)incr;
return (caddr_t)0;
}
Ошибка 10: UI_DisplayReleaseKeys / UI_DisplayScanner
Исправление: Добавил ui/welcome.o и ui/scanner.o.
3. Известные проблемы для доработки
3.1. POCSAG — недостаточно сэмплов
Проблема: POCSAG_FeedSample() вызывается ~1 раз/10мс. Для 1200 бод нужно ~1 раз/125мкс.
Решение:
// В mode.c, case MODE_POCSAG:
for (int i = 0; i < 80; i++) {
uint16_t audio = BK4819_GetVoiceAmplitudeOut();
POCSAG_FeedSample(audio);
SYSTEM_DelayUs(125);
}
3.2. Нет отображения текста POCSAG сообщений
Решение: В pocsag_draw() добавить:
static pocsag_msg_t last_msg;
if (POCSAG_GetMessage(&last_msg)) {
UI_PrintStringSmallNormal(last_msg.text, 0, 120, 28);
}
3.3. Дублирование APP_TimeSlice
MODE_TimeSlice10ms() вызывает APP_TimeSlice10ms(), что дублирует обработку.
Решение: Разделить — для VFO вызывать APP_TimeSlice10ms(), для POCSAG — только CheckRadioInterrupts().
3.4. Flash на пределе (94.3%)
Осталось ~3.5 КБ. Для экономии можно отключить:
ENABLE_FMRADIO = 0 # -2 КБ
ENABLE_SPECTRUM = 0 # -5 КБ
4. Инструкция по сборке
# Тулчейн
sudo apt-get install gcc-arm-none-eabi
# Сборка
cd uv-k5-firmware-custom
make clean && make
# Результат
arm-none-eabi-size firmware
# text data bss dec hex filename
# 57708 204 3364 61276 ef5c firmware
5. Инструкция по прошивке
Вариант 1: SWD (J-Link)
# Установка OpenOCD
sudo apt-get install openocd
# Подключение:
# J-Link Pin 1 (VTref) — 3.3V
# J-Link Pin 2 (GND) — GND
# J-Link Pin 7 (SWDIO) — SWDIO на плате
# J-Link Pin 9 (SWCLK) — SWCLK на плате
make flash
# Или вручную:
openocd -f interface/jlink.cfg -f dp32g030.cfg \
-c "write_image firmware.bin 0; shutdown;"
Вариант 2: UART
git clone https://github.com/piotr02/k5prog.git
cd k5prog && make && sudo cp k5prog /usr/local/bin/
# Включить рацию с зажатой SK2
k5prog -f firmware.bin -p /dev/ttyUSB0 -w
Вариант 3: USB
# Выключить → зажать PTT+SK2 → включить
k5prog -f firmware.bin -w
6. Структура файлов
| Файл | Назначение |
|---|---|
Makefile |
Конфигурация сборки, флаги |
main.c |
Точка входа, инициализация, главный цикл |
syscalls.c |
Заглушка _sbrk для bare-metal |
app/boot_splash.c |
Заставка UA1ZBE / 2 сек |
app/display_rssi.c |
RSSI индикатор в dBm |
app/mode.c |
Диспетчер режимов |
app/pocsag/pocsag.c |
POCSAG декодер |
app/pocsag/bch31.c |
BCH(31,21) коррекция |
7. Отладочные команды
# Размер секций
arm-none-eabi-size -A firmware | sort -n -k2 | tail -20
# Символы
arm-none-eabi-nm --size-sort firmware | tail -30
# Дизассемблер
arm-none-eabi-objdump -d firmware | grep -A20 "<POCSAG_FeedSample>:"
# Проверка переполнения
SIZE=$(wc -c < firmware.bin)
[ $SIZE -gt 61440 ] && echo "OVERFLOW!" || echo "OK: $SIZE / 61440"