Files
uv-k5-ua1zbe-firmware/DOCUMENTATION.md
ua1zbe a1206d6fd4 UA1ZBE Custom Firmware v1.0
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)
2026-04-12 00:44:05 +03:00

8.2 KiB
Raw Permalink Blame History

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. Инструкция по прошивке

# Установка 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"