From 153931d1caea65c73530ac8a0f6041ae32c6b4d5 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 31 Aug 2026 22:27:27 +0300 Subject: [PATCH] Move music analyzer out of the raster interrupt to fix flickering The AY volume-bar indicator (music_analizator) ran inside int_text_off, the same precisely-timed interrupt chain that switches between text and graphics video modes. Its DMA clear + page switching + drawing could overrun that timing budget on dynamic tracks, causing visible vertical stripe flicker. Moved it to the main loop (once per frame, after wait_frame) instead, leaving the player tick (pt_play) and its tempo timing untouched inside the interrupt. Also waits for the DMA clear to finish before drawing bars into the same memory (previously a write race). --- README.md | 5 ++++- _spg/ZIFI/zifi.spg | Bin 43520 -> 43520 bytes zifi.asm | 20 ++++++++++++++------ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9c36ce1..cb37acd 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,11 @@ AT+CIPSNTPTIME? — получить текущее врем **Сообщение о готовности.** После завершения всех этапов загрузки (подключение к Wi-Fi, синхронизация времени, папка загрузок) на экране появляется `"ZiFi is ready."` — раньше было не всегда понятно, можно ли уже пользоваться меню. +**Убрано мигание вертикальных полос при воспроизведении музыки.** (Ну почти убрана =))) Индикатор громкости AY-каналов (`music_analizator`) раньше рисовался прямо внутри прерывания, которое отвечает за точное по строкам переключение видеорежима текст/графика — и делал это вместе с DMA-очисткой экрана и переключением страниц памяти. На динамичных треках (больше эффектов — дольше выполняется код) это сбивало тайминг прерывания и давало заметные мигающие полосы на экране. Отрисовку индикатора вынесли из прерывания в обычный код главного цикла (раз в кадр, синхронно с `wait_frame`, но уже не в раст-критичной цепочке) — сам плеер и его тайминг (темп, высота нот) не тронуты. + **Мелкие исправления:** - обращение к порту `#EFF7` (общий системный регистр — управляет не только доступом к часам, но и видеорежимом/turbo/кэшем) переведено на read-modify-write вместо прямой перезаписи всего байта, чтобы не сбивать остальные настройки; -- исправлен баг в разборе двузначного GMT-смещения из `zifi.ini` (например `+10`) — были перепутаны местами разряды. +- исправлен баг в разборе двузначного GMT-смещения из `zifi.ini` (например `+10`) — были перепутаны местами разряды; +- DMA-очистка под индикатор громкости теперь дожидается завершения перед тем, как CPU начинает рисовать поверх той же области (была гонка записи). diff --git a/_spg/ZIFI/zifi.spg b/_spg/ZIFI/zifi.spg index fc00c59a299b3c79d68a0bd9af0e6d2d1b1ce839..c8690346771eaf3cb694b6319694da6022a35677 100644 GIT binary patch delta 6331 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 delta 6285 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