# 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 не понимает. **Исправление:** ```bash 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. **Исправление:** ```c 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`: ```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`: ```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мкс. **Решение:** ```c // В 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()` добавить: ```c 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 КБ. Для экономии можно отключить: ```makefile ENABLE_FMRADIO = 0 # -2 КБ ENABLE_SPECTRUM = 0 # -5 КБ ``` --- ## 4. Инструкция по сборке ```bash # Тулчейн 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) ```bash # Установка 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 ```bash 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 ```bash # Выключить → зажать 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. Отладочные команды ```bash # Размер секций 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 ":" # Проверка переполнения SIZE=$(wc -c < firmware.bin) [ $SIZE -gt 61440 ] && echo "OVERFLOW!" || echo "OK: $SIZE / 61440" ```