Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions radio/src/boards/generic_stm32/linker/definitions.ld
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,14 @@ _main_stack_start = _estack - MAIN_STACK_SIZE;

/* Higest heap address */
_heap_end = HEAP_ADDRESS;

/* Fastcode defaults for scripts that do not define the section
(bootloader): the startup copy loop becomes a no-op */
PROVIDE(_sfastcode = 0);
PROVIDE(_efastcode = 0);
PROVIDE(_fastcode_load = 0);

/* Same for scripts without a .text.shared section */
PROVIDE(_stext_shared = 0);
PROVIDE(_etext_shared = 0);
PROVIDE(_text_shared_load = 0);
61 changes: 58 additions & 3 deletions radio/src/boards/generic_stm32/linker/firmware.ld
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,59 @@ SECTIONS

_isr_load = LOADADDR(.isr_vector);

/* Hot interrupt-path code (USB device stack, MSC storage glue, SDIO
diskio) executed from RAM: on some TX16S units, instruction
fetches from the upper flash bank get corrupted under heavy
IRQ/DMA load (USB crash, EdgeTX#5899); claimed before .text so
these input sections land here. Requires non-LTO objects. */
.fastcode :
{
. = ALIGN(4);
_sfastcode = .;
*ll_usb*(.text .text.*)
*hal_pcd*(.text .text.*)
*usb_driver*(.text .text.*)
*usbd_conf*(.text .text.*)
*usbd_core*(.text .text.*)
*usbd_ioreq*(.text .text.*)
*usbd_ctlreq*(.text .text.*)
*usbd_msc*(.text .text.*)
*usbd_storage_msd*(.text .text.*)
*diskio_sdio*(.text .text.*)
. = ALIGN(4);
_efastcode = .;
} > REGION_BSS AT> REGION_TEXT_STORAGE

_fastcode_load = LOADADDR(.fastcode);

/* C++ comdat sections (templates, inline functions, operator
new/delete) from the std:: namespace are instantiated by both UI
and core objects, and the linker keeps a single copy whose home
object depends on link order. That copy must stay callable at
any time, so claim it here, before any target-specific pre-text
section can grab it through file patterns (see
pre_text_sections.ld). */
.text.shared (READONLY) :
{
. = ALIGN(4);
_stext_shared = .;
*(.text._ZSt* .text._ZNSt* .text._ZNKSt* .text._ZN9__gnu_cxx*)
*(.text._Znwj .text._Znwm .text._Znaj .text._Znam)
*(.text._ZdlPv* .text._ZdaPv*)
*(.rodata._ZSt* .rodata._ZNSt* .rodata._ZNKSt*)
*(.rodata._ZTVSt* .rodata._ZTVNSt*)
. = ALIGN(4);
_etext_shared = .;
} > REGION_TEXT AT> REGION_TEXT_STORAGE

_text_shared_load = LOADADDR(.text.shared);

/* Target-specific output sections that must claim their input
sections before the .text catch-all (e.g. TX16S UI code
relegated to flash bank 2, see
stm32f429_sdram/pre_text_sections.ld) */
INCLUDE pre_text_sections.ld

/* Main code section */
.text (READONLY) :
{
Expand All @@ -52,7 +105,8 @@ SECTIONS

INCLUDE common_sections.ld

/* Assets in FLASH only */
/* Assets in FLASH only (REGION_ASSETS: same as REGION_TEXT_STORAGE
on most targets, flash bank 2 on TX16S/F429) */
.flash (READONLY) :
{
. = ALIGN(4);
Expand All @@ -61,9 +115,10 @@ SECTIONS

. = ALIGN(4);
_eflash = .;
} > REGION_TEXT_STORAGE
} > REGION_ASSETS

.text_end_section : {} > REGION_TEXT AT > REGION_TEXT_STORAGE
_firmware_length = LOADADDR(.text_end_section) - LOADADDR(.firmware_header);
/* .flash is the highest LMA of the image on every target */
_firmware_length = (LOADADDR(.flash) + SIZEOF(.flash)) - LOADADDR(.firmware_header);
_firmware_version = _text_load;
}
1 change: 1 addition & 0 deletions radio/src/boards/generic_stm32/linker/stm32f20x/layout.ld
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ REGION_ALIAS("REGION_BOOTLOADER", FLASH);
REGION_ALIAS("REGION_ISR_VECT", FLASH);
REGION_ALIAS("REGION_TEXT", FLASH);
REGION_ALIAS("REGION_TEXT_STORAGE", FLASH);
REGION_ALIAS("REGION_ASSETS", FLASH);

REGION_ALIAS("REGION_DATA", RAM);
REGION_ALIAS("REGION_BSS", RAM);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* No target-specific pre-text sections (see firmware.ld) */
1 change: 1 addition & 0 deletions radio/src/boards/generic_stm32/linker/stm32f40x/layout.ld
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ REGION_ALIAS("REGION_BOOTLOADER", FLASH);
REGION_ALIAS("REGION_ISR_VECT", FLASH);
REGION_ALIAS("REGION_TEXT", FLASH);
REGION_ALIAS("REGION_TEXT_STORAGE", FLASH);
REGION_ALIAS("REGION_ASSETS", FLASH);

REGION_ALIAS("REGION_DATA", CCM);
REGION_ALIAS("REGION_BSS", CCM);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* No target-specific pre-text sections (see firmware.ld) */
1 change: 1 addition & 0 deletions radio/src/boards/generic_stm32/linker/stm32f413/layout.ld
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ REGION_ALIAS("REGION_BOOTLOADER", FLASH);
REGION_ALIAS("REGION_ISR_VECT", FLASH);
REGION_ALIAS("REGION_TEXT", FLASH);
REGION_ALIAS("REGION_TEXT_STORAGE", FLASH);
REGION_ALIAS("REGION_ASSETS", FLASH);

REGION_ALIAS("REGION_DATA", RAM);
REGION_ALIAS("REGION_BSS", RAM);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* No target-specific pre-text sections (see firmware.ld) */
20 changes: 15 additions & 5 deletions radio/src/boards/generic_stm32/linker/stm32f429_sdram/layout.ld
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,29 @@ EXTRAM_SIZE = DEFINED(__EXTRAM_SIZE__) ? __EXTRAM_SIZE__ : 8192K;
/* Highest heap address */
HEAP_ADDRESS = EXTRAM_START + EXTRAM_SIZE;

/* Specify the memory areas */
/* Specify the memory areas.

The 2MB flash is split at the hardware bank boundary: on some
STM32F42x units (flash rev < 3), USB D+ (PA12) switching noise
corrupts reads from bank 2 (ST errata, EdgeTX#5899). Restricting
FLASH to bank 1 turns any overflow of code into a link error;
only cold UI code/rodata and assets are placed in bank 2 (see
pre_text_sections.ld) and must not be accessed while a USB
session is active. */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K
CCM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
SDRAM(xrw) : ORIGIN = EXTRAM_START, LENGTH = EXTRAM_SIZE
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* bank 1 */
FLASH_BANK2 (rx) : ORIGIN = 0x08100000, LENGTH = 1024K /* bank 2 */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K
CCM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
SDRAM(xrw) : ORIGIN = EXTRAM_START, LENGTH = EXTRAM_SIZE
}

REGION_ALIAS("REGION_BOOTLOADER", FLASH);
REGION_ALIAS("REGION_ISR_VECT", FLASH);
REGION_ALIAS("REGION_TEXT", FLASH);
REGION_ALIAS("REGION_TEXT_STORAGE", FLASH);
REGION_ALIAS("REGION_ASSETS", FLASH_BANK2);

REGION_ALIAS("REGION_DATA", CCM);
REGION_ALIAS("REGION_BSS", RAM);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* TX16S / STM32F429 (EdgeTX#5899): on units with flash rev < 3,
USB D+ (PA12) switching noise corrupts reads from flash bank 2
(0x08100000 and above). All code and rodata that may be used
while a USB session is active must live in bank 1; this is
guaranteed by the FLASH region being restricted to bank 1
(overflow = link error).

UI code and its rodata are relegated to bank 2 here: they only
run while USB is inactive (the UI is frozen in USB modes).
Claimed before the .text catch-all so these input sections land
here; file-pattern matching requires non-LTO objects. Shared
C++ comdats are already pinned to bank 1 by .text.shared. */
/* Bank 1 pins: symbols living in UI objects but called from non-UI
tasks (mixer pulses, telemetry/logs timers, audio), found by the
bank1->bank2 call scan (bench/check_bank1.sh). Section names
follow the mangled symbol: a signature change silently un-pins,
the scan is the gatekeeper. Claimed before .uicode. */
.text.pinned :
{
. = ALIGN(4);
/* tick LVGL incremente par le hook SysTick (ISR, meme pendant l'USB) */
*(.text.lv_tick_inc)
/* helpers R9M inline (pulses, chaque cycle mixer) */
*(.text._Z17isModuleR9MAccessh .text._Z20isModuleR9MNonAccessh)
/* mailbox popup differee (timers telemetrie/logs) */
*(.text._Z24POPUP_WARNING_ON_UI_TASKPKcS0_)
/* popups bloquants, gardes par _usb_ui_frozen() (audio, PXX2) */
*(.text._Z13POPUP_WARNINGPKcS0_ .text._Z17POPUP_INFORMATIONPKc)
/* fonction speciale SET_SCREEN (mixer) */
*(.text._Z20setRequestedMainViewh)
/* appelee par pwrCheck (menusTask, toutes les 50 ms, gel compris) */
*(.text._Z23cancelShutdownAnimationv)
. = ALIGN(4);
} > REGION_TEXT AT> REGION_TEXT_STORAGE

.uicode :
{
. = ALIGN(4);
_suicode = .;
*colorlcd*(.text .text.* .rodata .rodata.*)
*lvgl*(.text .text.* .rodata .rodata.*)
*libopenui*(.text .text.* .rodata .rodata.*)
. = ALIGN(4);
_euicode = .;
} > REGION_ASSETS
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ MEMORY

REGION_ALIAS("REGION_BOOTLOADER", FLASH);
REGION_ALIAS("REGION_TEXT_STORAGE", NORFLASH);
REGION_ALIAS("REGION_ASSETS", NORFLASH);
REGION_ALIAS("REGION_TEXT", SDRAM);
REGION_ALIAS("REGION_ISR_VECT", DTCMRAM);
REGION_ALIAS("REGION_DATA", DTCMRAM);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* No target-specific pre-text sections (see firmware.ld) */
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ MEMORY

REGION_ALIAS("REGION_BOOTLOADER", FLASH);
REGION_ALIAS("REGION_TEXT_STORAGE", NORFLASH);
REGION_ALIAS("REGION_ASSETS", NORFLASH);
REGION_ALIAS("REGION_TEXT", PSRAM);
REGION_ALIAS("REGION_ISR_VECT", DTCMRAM);
REGION_ALIAS("REGION_DATA", RAM);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* No target-specific pre-text sections (see firmware.ld) */
8 changes: 4 additions & 4 deletions radio/src/bootloader/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ remove_definitions(-DUSB_SERIAL)

if(NOT NO_LTO)
message("-- Use LTO to compile bootloader")
target_compile_options(stm32cube_ll PRIVATE -flto)
target_compile_options(stm32usb PRIVATE -flto)
# stm32cube_ll, stm32usb, stm32usb_device_fw and
# stm32_drivers_w_dbg_fw are kept out of LTO: their objects must
# stay pattern-matchable by the .fastcode output section (hot
# USB/SD interrupt code executed from RAM, see firmware.ld)
target_compile_options(stm32usb_device_bl PRIVATE -flto)
target_compile_options(stm32usb_device_fw PRIVATE -flto)
target_compile_options(stm32_drivers PRIVATE -flto)
target_compile_options(stm32_drivers_w_dbg_fw PRIVATE -flto)
target_compile_options(stm32_drivers_w_dbg_bl PRIVATE -flto)
target_compile_options(board_bl PRIVATE -flto)
endif()
Expand Down
30 changes: 28 additions & 2 deletions radio/src/edgetx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@
#include "hal/watchdog_driver.h"
#include "hal/abnormal_reboot.h"
#include "hal/usb_driver.h"

#if defined(DIAG_BANK2_FENCE)
extern "C" void bank2FenceDumpPostMortem(void);
#endif

#if defined(STM32) && !defined(SIMU)
void usbSessionForceStop();
#else
inline void usbSessionForceStop() {}
#endif
#include "hal/audio_driver.h"
#include "hal/rgbleds.h"

Expand Down Expand Up @@ -1503,6 +1513,11 @@ void edgeTxInit()
if (!sdMounted())
sdInit();

#if defined(DIAG_BANK2_FENCE)
// report a bank 2 fence trap from the previous session, if any
bank2FenceDumpPostMortem();
#endif

#if !defined(COLORLCD)
if (!sdMounted()) {
g_eeGeneral.pwrOffSpeed = 2;
Expand Down Expand Up @@ -1805,6 +1820,10 @@ uint32_t pwrCheck()
}
if (get_tmr10ms() - pwr_press_time > PWR_PRESS_SHUTDOWN_DELAY()) {
#if defined(COLORLCD)
// End the USB session before any shutdown UI runs: the UI
// lives in flash bank 2, unreadable during USB traffic
// (PA12 errata, EdgeTX#5899). Same cleanup as an unplug.
usbSessionForceStop();
bool usbConfirmed = !usbPlugged() || getSelectedUsbMode() == USB_UNSELECTED_MODE;
bool modelConnectedConfirmed = !TELEMETRY_STREAMING() || g_eeGeneral.disableRssiPoweroffAlarm;
bool trainerConfirmed = !isTrainerConnected();
Expand Down Expand Up @@ -1914,14 +1933,21 @@ uint32_t pwrCheck()
return e_power_off;
}
else {
drawShutdownAnimation(pwrPressedDuration(), PWR_PRESS_SHUTDOWN_DELAY(), message);
#if defined(COLORLCD)
// no drawing while the USB session is active (UI in bank 2)
if (!usbPlugged() || getSelectedUsbMode() == USB_UNSELECTED_MODE)
#endif
drawShutdownAnimation(pwrPressedDuration(), PWR_PRESS_SHUTDOWN_DELAY(), message);
return e_power_press;
}
}
}
else {
#if defined(COLORLCD)
cancelShutdownAnimation();
// pinned to bank 1 on TX16S, and skipped while the USB session
// is active: menusTask polls this every 50ms (PA12 errata)
if (!usbPlugged() || getSelectedUsbMode() == USB_UNSELECTED_MODE)
cancelShutdownAnimation();
#endif
pwr_check_state = PWR_CHECK_ON;
pwr_press_time = 0;
Expand Down
17 changes: 17 additions & 0 deletions radio/src/gui/colorlcd/libui/popups.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "dialog.h"
#include "edgetx.h"
#include "etx_lv_theme.h"
#include "hal/usb_driver.h"
#include "hal/watchdog_driver.h"
#include "lvgl/src/hal/lv_hal_tick.h"
#include "mainwindow.h"
Expand All @@ -40,13 +41,29 @@ static void _run_popup_dialog(const char* title, const char* msg,
});
}

// While a USB session is active the UI is frozen (PA12/bank 2
// errata, EdgeTX#5899): a nested popup dialog must never run then.
// These two functions are pinned to flash bank 1 on TX16S (see
// stm32f429_sdram/pre_text_sections.ld) so callers from non-UI
// tasks (audio, telemetry) never fetch bank 2 code.
static inline __attribute__((always_inline)) bool _usb_ui_frozen()
{
#if defined(STM32) && !defined(SIMU)
return usbPlugged() && getSelectedUsbMode() != USB_UNSELECTED_MODE;
#else
return false;
#endif
}

void POPUP_INFORMATION(const char* message)
{
if (_usb_ui_frozen()) return;
_run_popup_dialog("Message", message);
}

void POPUP_WARNING(const char* message, const char* info)
{
if (_usb_ui_frozen()) return;
_run_popup_dialog("Warning", message, info);
}

Expand Down
Loading