diff --git a/.gitmodules b/.gitmodules index 11b93a5..ded024e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "ChibiOS"] path = ChibiOS - url = https://github.com/edy555/ChibiOS.git - branch = I2SFULLDUPLEX + url = https://github.com/PhysicistJohn/chibios.git + branch = codex/integration-tinysa-21.11.5 diff --git a/ChibiOS b/ChibiOS index ade76de..db35f6d 160000 --- a/ChibiOS +++ b/ChibiOS @@ -1 +1 @@ -Subproject commit ade76dea89cd093650552328e881252a06486094 +Subproject commit db35f6df137058c612dc13e4488ac923219d881a diff --git a/Makefile b/Makefile index 85410be..a906bad 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,9 @@ endif # Compiler options here. ifeq ($(USE_OPT),) ifeq ($(TARGET),F303) -USE_OPT = -Og -fno-inline-small-functions -ggdb -fomit-frame-pointer -falign-functions=16 --specs=nano.specs -fstack-usage -std=c11 +USE_OPT = -Og -fno-inline-small-functions -ggdb -fomit-frame-pointer -falign-functions=16 --specs=nano.specs -fstack-usage -fsingle-precision-constant -std=c11 +# The legacy ChibiOS rules appended -fsingle-precision-constant for hard-FPU +# builds. Keep that numeric behavior explicit when using the 21.11.x rules. #USE_OPT+=-fstack-protector-strong else USE_OPT = -Og -fno-inline-small-functions -ggdb -fomit-frame-pointer -falign-functions=16 --specs=nano.specs -fstack-usage -fsingle-precision-constant @@ -93,7 +95,9 @@ endif ifeq ($(TARGET),F303) USE_FPU = hard USE_PROCESS_STACKSIZE = 0x480 - USE_EXCEPTIONS_STACKSIZE = 0x200 + # The fault reporter renders through the LCD/printf stack. Reserve room for + # its assembly veneer, an extended exception frame, and a nested ISR frame. + USE_EXCEPTIONS_STACKSIZE = 0x400 endif # @@ -115,6 +119,8 @@ endif #CHIBIOS = ../ChibiOS-RT CHIBIOS = ChibiOS PROJ = . +# ChibiOS 21.11.x keeps its license policy header in a dedicated include. +include $(CHIBIOS)/os/license/license.mk # Startup files. ifeq ($(TARGET),F303) @@ -130,13 +136,13 @@ include $(CHIBIOS)/os/hal/ports/STM32/STM32F0xx/platform.mk include NANOVNA_STM32_F072/board.mk endif -include $(CHIBIOS)/os/hal/osal/rt/osal.mk +include $(CHIBIOS)/os/hal/osal/rt-nil/osal.mk # RTOS files (optional). include $(CHIBIOS)/os/rt/rt.mk ifeq ($(TARGET),F303) -include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk +include $(CHIBIOS)/os/common/ports/ARMv7-M/compilers/GCC/mk/port.mk else -include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v6m.mk +include $(CHIBIOS)/os/common/ports/ARMv6-M/compilers/GCC/mk/port.mk endif # Other files (optional). #include $(CHIBIOS)/test/rt/test.mk @@ -156,6 +162,7 @@ endif ifeq ($(TARGET),F303) CSRC = $(STARTUPSRC) \ $(KERNSRC) \ + $(OSLIBSRC) \ $(PORTSRC) \ $(OSALSRC) \ $(HALSRC) \ @@ -170,6 +177,7 @@ CSRC = $(STARTUPSRC) \ else CSRC = $(STARTUPSRC) \ $(KERNSRC) \ + $(OSLIBSRC) \ $(PORTSRC) \ $(OSALSRC) \ $(HALSRC) \ @@ -205,10 +213,11 @@ TCSRC = # option that results in lower performance and larger code size. TCPPSRC = -# List ASM source files here -ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM) +# ChibiOS startup and port assembly is preprocessed (.S), not plain assembly. +ASMSRC = +ASMXSRC = $(STARTUPASM) $(PORTASM) $(OSALASM) -INCDIR = $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \ +INCDIR = $(LICINC) $(STARTUPINC) $(KERNINC) $(OSLIBINC) $(PORTINC) $(OSALINC) \ $(HALINC) $(PLATFORMINC) $(BOARDINC) \ $(STREAMSINC) @@ -266,7 +275,7 @@ CPPWARN = -Wall -Wextra -Wundef # List all user C define here, like -D_DEBUG=1 ifeq ($(TARGET),F303) - UDEFS = -DARM_MATH_CM4 -DVERSION=\"$(VERSION)\" -DTINYSA_F303 -D__FPU_USED -DST7796S -DTINYSA4 + UDEFS = -DARM_MATH_CM4 -DVERSION=\"$(VERSION)\" -DTINYSA_F303 -DST7796S -DTINYSA4 #Enable if install external 32.768kHz clock quartz on PC14 and PC15 pins on STM32 CPU UDEFS+= -DVNA_USE_LSE # Use R as usb pullup @@ -292,19 +301,12 @@ ULIBS = -lm # End of user defines ############################################################################## -RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC +RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk +include $(RULESPATH)/arm-none-eabi.mk include $(RULESPATH)/rules.mk #include $(CHIBIOS)/memory.mk -ifeq ($(TARGET),F303) -clean: - rm -f -rf build/tinySA4.* build/lst/*.* build/obj/*.* -else -clean: - rm -f -rf build/$(PROJECT).* build/lst/*.* build/obj/*.* -endif - flash: build/$(PROJECT).bin -@printf "reset dfu\r" >/dev/cu.usbmodem401 # mac -@printf "reset dfu\r" >/dev/ttyACM0 # linux @@ -323,4 +325,3 @@ else @etags *.[ch] NANOVNA_STM32_F072/*.[ch] $(shell find ChibiOS/os/hal/ports/STM32/STM32F0xx ChibiOS/os -name \*.\[ch\] -print) endif @ls -l TAGS - diff --git a/NANOVNA_STM32_F072/adc.c b/NANOVNA_STM32_F072/adc.c index d61068f..3aa3fa6 100644 --- a/NANOVNA_STM32_F072/adc.c +++ b/NANOVNA_STM32_F072/adc.c @@ -80,7 +80,7 @@ int16_t adc_vbat_read(void) // Vbat measure averange count = 2^VBAT_AVERAGE #define VBAT_AVERAGE 4 // Measure vbat every 5 second -#define VBAT_MEASURE_INTERVAL S2ST(5) +#define VBAT_MEASURE_INTERVAL TIME_S2I(5) static int16_t vbat_raw = 0; static systime_t vbat_time = -VBAT_MEASURE_INTERVAL-1; diff --git a/NANOVNA_STM32_F072/board.c b/NANOVNA_STM32_F072/board.c index 0e71d6f..2de30f8 100644 --- a/NANOVNA_STM32_F072/board.c +++ b/NANOVNA_STM32_F072/board.c @@ -14,15 +14,41 @@ limitations under the License. */ -#include "hal.h" - -#if HAL_USE_PAL || defined(__DOXYGEN__) -/** - * @brief PAL setup. - * @details Digital I/O ports static configuration as defined in @p board.h. - * This variable is used by the HAL when initializing the PAL driver. - */ -const PALConfig pal_default_config = { +#include "hal.h" +#include "stm32_gpio.h" + +typedef struct { + uint32_t moder; + uint32_t otyper; + uint32_t ospeedr; + uint32_t pupdr; + uint32_t odr; + uint32_t afrl; + uint32_t afrh; +} gpio_setup_t; + +typedef struct { +#if STM32_HAS_GPIOA + gpio_setup_t PAData; +#endif +#if STM32_HAS_GPIOB + gpio_setup_t PBData; +#endif +#if STM32_HAS_GPIOC + gpio_setup_t PCData; +#endif +#if STM32_HAS_GPIOD + gpio_setup_t PDData; +#endif +#if STM32_HAS_GPIOE + gpio_setup_t PEData; +#endif +#if STM32_HAS_GPIOF + gpio_setup_t PFData; +#endif +} gpio_config_t; + +static const gpio_config_t gpio_default_config = { #if STM32_HAS_GPIOA {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR, VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH}, @@ -59,8 +85,40 @@ const PALConfig pal_default_config = { {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR, VAL_GPIOI_ODR, VAL_GPIOI_AFRL, VAL_GPIOI_AFRH} #endif -}; -#endif +}; + +static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) { + gpiop->OTYPER = config->otyper; + gpiop->OSPEEDR = config->ospeedr; + gpiop->PUPDR = config->pupdr; + gpiop->ODR = config->odr; + gpiop->AFRL = config->afrl; + gpiop->AFRH = config->afrh; + gpiop->MODER = config->moder; +} + +static void stm32_gpio_init(void) { + rccResetAHB(STM32_GPIO_EN_MASK); + rccEnableAHB(STM32_GPIO_EN_MASK, true); +#if STM32_HAS_GPIOA + gpio_init(GPIOA, &gpio_default_config.PAData); +#endif +#if STM32_HAS_GPIOB + gpio_init(GPIOB, &gpio_default_config.PBData); +#endif +#if STM32_HAS_GPIOC + gpio_init(GPIOC, &gpio_default_config.PCData); +#endif +#if STM32_HAS_GPIOD + gpio_init(GPIOD, &gpio_default_config.PDData); +#endif +#if STM32_HAS_GPIOE + gpio_init(GPIOE, &gpio_default_config.PEData); +#endif +#if STM32_HAS_GPIOF + gpio_init(GPIOF, &gpio_default_config.PFData); +#endif +} static bool needDFU(void) { // Magick data in memory before reset @@ -105,7 +163,8 @@ void __early_init(void) { } //si5351_setup(); - stm32_clock_init(); + stm32_gpio_init(); + stm32_clock_init(); } /* diff --git a/NANOVNA_STM32_F303/adc.c b/NANOVNA_STM32_F303/adc.c index 9f06461..a380e54 100644 --- a/NANOVNA_STM32_F303/adc.c +++ b/NANOVNA_STM32_F303/adc.c @@ -36,54 +36,67 @@ static adcsample_t samplesVBAT[ADC_GRP_NUM_CHANNELS_VBAT]; static adcsample_t samples[1]; static const ADCConversionGroup adcgrpcfgVBAT = { - FALSE, - ADC_GRP_NUM_CHANNELS_VBAT, - NULL, - NULL, - ADC_CFGR_CONT | ADC_CFGR1_RES_12BIT, // CFGR1 - ADC_TR(0, 0), // ADC watchdog threshold TR1 - {0, ADC_SMPR2_SMP_AN16(ADC_VBAT_SMP_TIME) | ADC_SMPR2_SMP_AN17(ADC_VBAT_SMP_TIME)/*| ADC_SMPR2_SMP_AN18(ADC_VBAT_SMP_TIME)*/}, // SMPR - {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN17) | ADC_SQR1_SQ2_N(ADC_CHANNEL_IN18)/*| ADC_SQR1_SQ3_N(ADC_CHANNEL_IN16)*/, 0, 0, 0} // CHSELR + .circular = false, + .num_channels = ADC_GRP_NUM_CHANNELS_VBAT, + .end_cb = NULL, + .error_cb = NULL, + .cfgr = ADC_CFGR_CONT | ADC_CFGR_RES_12BITS, + .tr1 = ADC_TR(0, 0), + .tr2 = ADC_TR_DISABLED, + .tr3 = ADC_TR_DISABLED, + .awd2cr = 0U, + .awd3cr = 0U, + .smpr = {0, ADC_SMPR2_SMP_AN16(ADC_VBAT_SMP_TIME) | + ADC_SMPR2_SMP_AN17(ADC_VBAT_SMP_TIME)}, + .sqr = {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN17) | + ADC_SQR1_SQ2_N(ADC_CHANNEL_IN18), 0, 0, 0} }; static const ADCConversionGroup adcgrpcfgVersion = { - FALSE, - 1, - NULL, - NULL, - ADC_CFGR1_RES_12BIT, // CFGR1 - ADC_TR(0, 0), // ADC watchdog threshold TR1 - {ADC_SMPR1_SMP_AN1(ADC_TOUCH_XY_SMP_TIME), 0}, /* SMPR[2] */ - {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN1), 0, 0, 0} /* SQR[4] */ + .circular = false, + .num_channels = 1, + .end_cb = NULL, + .error_cb = NULL, + .cfgr = ADC_CFGR_RES_12BITS, + .tr1 = ADC_TR(0, 0), + .tr2 = ADC_TR_DISABLED, + .tr3 = ADC_TR_DISABLED, + .awd2cr = 0U, + .awd3cr = 0U, + .smpr = {ADC_SMPR1_SMP_AN1(ADC_TOUCH_XY_SMP_TIME), 0}, + .sqr = {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN1), 0, 0, 0} }; static const ADCConversionGroup adcgrpcfgTouch = { - TRUE, // Enables the circular buffer mode for the group. - 1, // Number of the analog channels belonging to the conversion group. - NULL, // adccallback_touch - NULL, // adcerrorcallback_touch - // CFGR - ADC_CFGR_EXTEN_0 // rising edge of external trigger - - | ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_0 // EXT4 0x1001 event (TIM1_TRGO) -// | ADC_CFGR_EXTSEL_2 // EXT4 0x100 event (TIM3_TRGO) - - - | ADC_CFGR_AWD1EN, // Enable Analog watchdog check interrupt - ADC_TR(0, TOUCH_THRESHOLD), // Analog watchdog threshold TR1, interrupt on touch press - {ADC_SMPR1_SMP_AN4(ADC_TOUCH_SMP_TIME), 0}, // SMPR[2] - {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN4), 0, 0, 0} // SQR[4] + .circular = true, + .num_channels = 1, + .end_cb = NULL, + .error_cb = NULL, + .cfgr = ADC_CFGR_EXTEN_0 | ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_0 | + ADC_CFGR_AWD1EN, + .tr1 = ADC_TR(0, TOUCH_THRESHOLD), + .tr2 = ADC_TR_DISABLED, + .tr3 = ADC_TR_DISABLED, + .awd2cr = 0U, + .awd3cr = 0U, + .smpr = {ADC_SMPR1_SMP_AN4(ADC_TOUCH_SMP_TIME), 0}, + .sqr = {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN4), 0, 0, 0} }; static ADCConversionGroup adcgrpcfgXY = { - FALSE, - 1, - NULL, /* adccallback_touch */ - NULL, /* adcerrorcallback_touch */ - ADC_CFGR1_RES_12BIT, /* CFGR */ - ADC_TR(0, 0), /* TR1 */ - {ADC_SMPR1_SMP_AN3(ADC_TOUCH_XY_SMP_TIME) | ADC_SMPR1_SMP_AN4(ADC_TOUCH_XY_SMP_TIME), 0}, /* SMPR[2] */ - {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN3), 0, 0, 0} /* SQR[4] */ + .circular = false, + .num_channels = 1, + .end_cb = NULL, + .error_cb = NULL, + .cfgr = ADC_CFGR_RES_12BITS, + .tr1 = ADC_TR(0, 0), + .tr2 = ADC_TR_DISABLED, + .tr3 = ADC_TR_DISABLED, + .awd2cr = 0U, + .awd3cr = 0U, + .smpr = {ADC_SMPR1_SMP_AN3(ADC_TOUCH_XY_SMP_TIME) | + ADC_SMPR1_SMP_AN4(ADC_TOUCH_XY_SMP_TIME), 0}, + .sqr = {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN3), 0, 0, 0} }; void adc_init(void) @@ -120,7 +133,7 @@ int16_t adc_vbat_read(void) // Vbat measure averange count = 2^VBAT_AVERAGE #define VBAT_AVERAGE 4 // Measure vbat every 5 second -#define VBAT_MEASURE_INTERVAL S2ST(5) +#define VBAT_MEASURE_INTERVAL TIME_S2I(5) static int16_t vbat_raw = 0; static systime_t vbat_time = -VBAT_MEASURE_INTERVAL-1; @@ -219,7 +232,7 @@ uint16_t adc_multi_read(uint32_t chsel, uint16_t *result, uint32_t count) VNA_ADC->IER = 0; VNA_ADC->TR = ADC_TR(0, 0); VNA_ADC->SMPR = ADC_SMPR_SMP_1P5; - VNA_ADC->CFGR1 = ADC_CFGR1_RES_12BIT; + VNA_ADC->CFGR = ADC_CFGR_RES_12BITS; VNA_ADC->CHSELR = chsel; diff --git a/NANOVNA_STM32_F303/board.c b/NANOVNA_STM32_F303/board.c index 6ca71af..36571f0 100644 --- a/NANOVNA_STM32_F303/board.c +++ b/NANOVNA_STM32_F303/board.c @@ -15,14 +15,40 @@ */ #include "hal.h" +#include "stm32_gpio.h" -#if HAL_USE_PAL || defined(__DOXYGEN__) -/** - * @brief PAL setup. - * @details Digital I/O ports static configuration as defined in @p board.h. - * This variable is used by the HAL when initializing the PAL driver. - */ -const PALConfig pal_default_config = { +typedef struct { + uint32_t moder; + uint32_t otyper; + uint32_t ospeedr; + uint32_t pupdr; + uint32_t odr; + uint32_t afrl; + uint32_t afrh; +} gpio_setup_t; + +typedef struct { +#if STM32_HAS_GPIOA + gpio_setup_t PAData; +#endif +#if STM32_HAS_GPIOB + gpio_setup_t PBData; +#endif +#if STM32_HAS_GPIOC + gpio_setup_t PCData; +#endif +#if STM32_HAS_GPIOD + gpio_setup_t PDData; +#endif +#if STM32_HAS_GPIOE + gpio_setup_t PEData; +#endif +#if STM32_HAS_GPIOF + gpio_setup_t PFData; +#endif +} gpio_config_t; + +static const gpio_config_t gpio_default_config = { #if STM32_HAS_GPIOA {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR, VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH}, @@ -60,7 +86,39 @@ const PALConfig pal_default_config = { VAL_GPIOI_ODR, VAL_GPIOI_AFRL, VAL_GPIOI_AFRH} #endif }; + +static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) { + gpiop->OTYPER = config->otyper; + gpiop->OSPEEDR = config->ospeedr; + gpiop->PUPDR = config->pupdr; + gpiop->ODR = config->odr; + gpiop->AFRL = config->afrl; + gpiop->AFRH = config->afrh; + gpiop->MODER = config->moder; +} + +static void stm32_gpio_init(void) { + rccResetAHB(STM32_GPIO_EN_MASK); + rccEnableAHB(STM32_GPIO_EN_MASK, true); +#if STM32_HAS_GPIOA + gpio_init(GPIOA, &gpio_default_config.PAData); +#endif +#if STM32_HAS_GPIOB + gpio_init(GPIOB, &gpio_default_config.PBData); +#endif +#if STM32_HAS_GPIOC + gpio_init(GPIOC, &gpio_default_config.PCData); #endif +#if STM32_HAS_GPIOD + gpio_init(GPIOD, &gpio_default_config.PDData); +#endif +#if STM32_HAS_GPIOE + gpio_init(GPIOE, &gpio_default_config.PEData); +#endif +#if STM32_HAS_GPIOF + gpio_init(GPIOF, &gpio_default_config.PFData); +#endif +} // extern void si5351_setup(void); @@ -129,6 +187,7 @@ void __early_init(void) { #endif } // si5351_setup(); + stm32_gpio_init(); stm32_clock_init(); } diff --git a/NANOVNA_STM32_F303/board.h b/NANOVNA_STM32_F303/board.h index 6c1432b..8890769 100644 --- a/NANOVNA_STM32_F303/board.h +++ b/NANOVNA_STM32_F303/board.h @@ -27,8 +27,6 @@ #define BOARD_NANOVNA_STM32_F303 #define BOARD_NAME "tinySA ULTRA" -#include -//#include "..\nanovna.h" /* * Board frequencies. */ diff --git a/NANOVNA_STM32_F303/mcuconf.h b/NANOVNA_STM32_F303/mcuconf.h index 8ce881d..f7e5709 100644 --- a/NANOVNA_STM32_F303/mcuconf.h +++ b/NANOVNA_STM32_F303/mcuconf.h @@ -32,6 +32,7 @@ */ #define STM32F3xx_MCUCONF +#define STM32F303_MCUCONF /* * HAL driver system settings. @@ -111,9 +112,9 @@ //#define STM32_ADC_ADC4_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) #define STM32_ADC_ADC12_DMA_PRIORITY 2 //#define STM32_ADC_ADC34_DMA_PRIORITY 2 -#define STM32_ADC_ADC12_IRQ_PRIORITY 2 +#define STM32_ADC_ADC12_IRQ_PRIORITY 3 //#define STM32_ADC_ADC34_IRQ_PRIORITY 5 -#define STM32_ADC_ADC12_DMA_IRQ_PRIORITY 2 +#define STM32_ADC_ADC12_DMA_IRQ_PRIORITY 3 //#define STM32_ADC_ADC34_DMA_IRQ_PRIORITY 5 //#define STM32_ADC_ADC12_CLOCK_MODE ADC_CCR_CKMODE_ADCCK //#define STM32_ADC_ADC12_CLOCK_MODE ADC_CCR_CKMODE_AHB_DIV2 @@ -157,10 +158,10 @@ #define STM32_GPT_USE_TIM2 FALSE #define STM32_GPT_USE_TIM3 FALSE #define STM32_GPT_USE_TIM4 TRUE -#define STM32_GPT_TIM1_IRQ_PRIORITY 2 -#define STM32_GPT_TIM2_IRQ_PRIORITY 2 -#define STM32_GPT_TIM3_IRQ_PRIORITY 2 -#define STM32_GPT_TIM4_IRQ_PRIORITY 2 +#define STM32_GPT_TIM1_IRQ_PRIORITY 3 +#define STM32_GPT_TIM2_IRQ_PRIORITY 3 +#define STM32_GPT_TIM3_IRQ_PRIORITY 3 +#define STM32_GPT_TIM4_IRQ_PRIORITY 3 /* * I2C driver system settings. @@ -184,8 +185,8 @@ STM32_I2S_MODE_RX) #define STM32_I2S_SPI2_MODE (STM32_I2S_MODE_SLAVE | \ STM32_I2S_MODE_RX ) -#define STM32_I2S_SPI1_IRQ_PRIORITY 2 -#define STM32_I2S_SPI2_IRQ_PRIORITY 2 +#define STM32_I2S_SPI1_IRQ_PRIORITY 3 +#define STM32_I2S_SPI2_IRQ_PRIORITY 3 #define STM32_I2S_SPI1_DMA_PRIORITY 1 #define STM32_I2S_SPI2_DMA_PRIORITY 1 #define STM32_I2S_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) @@ -233,14 +234,14 @@ #define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) #define STM32_SPI_SPI1_DMA_PRIORITY 1 #define STM32_SPI_SPI2_DMA_PRIORITY 1 -#define STM32_SPI_SPI1_IRQ_PRIORITY 2 -#define STM32_SPI_SPI2_IRQ_PRIORITY 2 +#define STM32_SPI_SPI1_IRQ_PRIORITY 3 +#define STM32_SPI_SPI2_IRQ_PRIORITY 3 #define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") /* * ST driver system settings. */ -#define STM32_ST_IRQ_PRIORITY 2 +#define STM32_ST_IRQ_PRIORITY 3 #define STM32_ST_USE_TIMER 2 /* diff --git a/chconf.h b/chconf.h index 682a459..84e37ce 100644 --- a/chconf.h +++ b/chconf.h @@ -29,6 +29,9 @@ #define _CHCONF_H_ #define _CHIBIOS_RT_CONF_ +#define _CHIBIOS_RT_CONF_VER_7_0_ + +#define CH_CFG_SMP_MODE FALSE /*===========================================================================*/ /** @@ -49,6 +52,8 @@ * setting also defines the system tick time unit. */ #define CH_CFG_ST_FREQUENCY 10000 +#define CH_CFG_INTERVALS_SIZE 32 +#define CH_CFG_TIME_TYPES_SIZE 32 /** * @brief Time delta constant for the tick-less mode. @@ -140,6 +145,7 @@ * @note The default is @p TRUE. */ #define CH_CFG_USE_TM FALSE +#define CH_CFG_USE_TIMESTAMP FALSE /** * @brief Threads registry APIs. @@ -305,6 +311,20 @@ */ #define CH_CFG_USE_MEMPOOLS FALSE +#define CH_CFG_USE_OBJ_FIFOS FALSE +#define CH_CFG_USE_PIPES FALSE +#define CH_CFG_USE_OBJ_CACHES FALSE +#define CH_CFG_USE_DELEGATES FALSE +#define CH_CFG_USE_JOBS FALSE +#define CH_CFG_USE_FACTORY FALSE +#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8 +#define CH_CFG_FACTORY_OBJECTS_REGISTRY FALSE +#define CH_CFG_FACTORY_GENERIC_BUFFERS FALSE +#define CH_CFG_FACTORY_SEMAPHORES FALSE +#define CH_CFG_FACTORY_MAILBOXES FALSE +#define CH_CFG_FACTORY_OBJ_FIFOS FALSE +#define CH_CFG_FACTORY_PIPES FALSE + /** * @brief Dynamic Threads APIs. * @details If enabled then the dynamic threads creation APIs are included @@ -417,6 +437,18 @@ */ /*===========================================================================*/ +#define CH_CFG_SYSTEM_EXTRA_FIELDS \ + /* No custom system fields.*/ + +#define CH_CFG_SYSTEM_INIT_HOOK() { \ +} + +#define CH_CFG_OS_INSTANCE_EXTRA_FIELDS \ + /* No custom instance fields.*/ + +#define CH_CFG_OS_INSTANCE_INIT_HOOK(oip) { \ +} + /** * @brief Threads descriptor structure extension. * @details User fields added to the end of the @p thread_t structure. @@ -522,6 +554,9 @@ /* Trace code here.*/ \ } +#define CH_CFG_RUNTIME_FAULTS_HOOK(mask) { \ +} + /** @} */ /*===========================================================================*/ diff --git a/chprintf.c b/chprintf.c index 07f52f4..df1a474 100644 --- a/chprintf.c +++ b/chprintf.c @@ -630,7 +630,13 @@ static msg_t put(void *ip, uint8_t b) { return MSG_OK; } -static const struct printStreamVMT vmt = {NULL, NULL, put, NULL}; +static const struct printStreamVMT vmt = { + .instance_offset = 0U, + .write = NULL, + .read = NULL, + .put = put, + .get = NULL +}; void printObjectInit(printStream *ps, int size, uint8_t *buffer){ ps->vmt = &vmt; ps->buffer = buffer; diff --git a/docs/CHIBIOS_21_11_5_PORT.md b/docs/CHIBIOS_21_11_5_PORT.md new file mode 100644 index 0000000..8caf507 --- /dev/null +++ b/docs/CHIBIOS_21_11_5_PORT.md @@ -0,0 +1,63 @@ +# ChibiOS 21.11.5 port + +This branch ports both firmware targets from the historical tinySA ChibiOS +fork to the official ChibiOS `ver21.11.5` release. + +The draft currently pins the public integration commit +`db35f6df137058c612dc13e4488ac923219d881a` from +`PhysicistJohn/chibios`. It contains two focused commits on top of the release +tag: + +1. restore the standalone STM32F0 TIM14 GPT interrupt service; +2. preserve active USBv1 endpoint-zero PMA buffers when configuration + endpoints are rebuilt. + +Those fixes are also proposed independently to current ChibiOS in PRs #84 and +#85 and to `stable-21.11.x` in draft PRs #86 and #87. The temporary fork URL +will be replaced with the canonical ChibiOS URL and merged stable commit before +this port is marked ready. + +## Port changes + +- Adopt the RT7/HAL9 configuration markers, OS library settings, build rules, + Cortex-M port paths, and license include required by ChibiOS 21.11.5. +- Raise kernel-aware F303 interrupt priorities to respect the RT7 + fast-interrupt reservation. +- Migrate board GPIO initialization, DMA allocation, ADC group definitions, + PAL line events, USB serial hooks, endpoint configuration, PWM configuration, + queue reset calls, time conversions, and thread diagnostics. +- Update the project-local F303 ADC LLD while retaining its tinySA-specific + behavior. +- Convert custom `BaseSequentialStream` VMTs to the current layout, including + the required `instance_offset` field. +- Preserve the legacy hard-FPU build's `-fsingle-precision-constant` behavior + explicitly. ChibiOS 21.11.x no longer adds it automatically; omitting it + promotes unsuffixed sweep constants to software double precision and causes + a measurable self-test sweep regression. +- Split the F303 HardFault entry into an assembly-only MSP/PSP veneer and an + ordinary non-returning C reporter, while reserving a 1 KiB exception stack. + +## Build + +With an Arm GNU toolchain on `PATH`: + +```sh +git submodule update --init --recursive +make TARGET=F303 -j8 +make clean +make TARGET=F072 -j8 +``` + +## Qualification boundary + +The predecessor RC5 image using the same application port and equivalent +ChibiOS fixes was exercised on a tinySA Ultra+ ZS407. Its exact DFU write and +readback, USB runtime, warm reset retention, cold boot, and all fourteen +built-in self-tests passed. A fresh official-versus-candidate comparison had +one first-cold measured-level threshold failure in case 2; three repeats, +including a second cold run, passed. Physical forced-fault injection was not +performed. + +The clean public branch has different commit identity and embedded version, so +it is a new binary. It must be rebuilt and receive a final physical smoke and +self-test run before this draft is promoted to ready. diff --git a/hal_adc_lld.c b/hal_adc_lld.c index bbc4edf..898db5d 100644 --- a/hal_adc_lld.c +++ b/hal_adc_lld.c @@ -444,7 +444,7 @@ void adc_lld_init(void) { #if STM32_ADC_DUAL_MODE ADCD1.adcs = ADC2; #endif - ADCD1.dmastp = STM32_DMA_STREAM(STM32_ADC_ADC1_DMA_STREAM); + ADCD1.dmastp = NULL; ADCD1.dmamode = ADC_DMA_SIZE | STM32_DMA_CR_PL(STM32_ADC_ADC1_DMA_PRIORITY) | STM32_DMA_CR_DIR_P2M | @@ -461,7 +461,7 @@ void adc_lld_init(void) { ADCD2.adcc = ADC123_COMMON; #endif ADCD2.adcm = ADC2; - ADCD2.dmastp = STM32_DMA_STREAM(STM32_ADC_ADC2_DMA_STREAM); + ADCD2.dmastp = NULL; ADCD2.dmamode = ADC_DMA_SIZE | STM32_DMA_CR_PL(STM32_ADC_ADC2_DMA_PRIORITY) | STM32_DMA_CR_DIR_P2M | @@ -483,7 +483,7 @@ void adc_lld_init(void) { #if STM32_ADC_DUAL_MODE ADCD3.adcs = ADC4; #endif - ADCD3.dmastp = STM32_DMA_STREAM(STM32_ADC_ADC3_DMA_STREAM); + ADCD3.dmastp = NULL; ADCD3.dmamode = ADC_DMA_SIZE | STM32_DMA_CR_PL(STM32_ADC_ADC3_DMA_PRIORITY) | STM32_DMA_CR_DIR_P2M | @@ -496,7 +496,7 @@ void adc_lld_init(void) { adcObjectInit(&ADCD4); ADCD4.adcc = ADC3_4_COMMON; ADCD4.adcm = ADC4; - ADCD4.dmastp = STM32_DMA_STREAM(STM32_ADC_ADC4_DMA_STREAM); + ADCD4.dmastp = NULL; ADCD4.dmamode = ADC_DMA_SIZE | STM32_DMA_CR_PL(STM32_ADC_ADC4_DMA_PRIORITY) | STM32_DMA_CR_DIR_P2M | @@ -524,13 +524,13 @@ void adc_lld_init(void) { rccEnableADC12(FALSE); rccResetADC12(); ADC1_2_COMMON->CCR = STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_MDMA; - rccDisableADC12(FALSE); + rccDisableADC12(); #endif #if STM32_ADC_USE_ADC3 || STM32_ADC_USE_ADC4 rccEnableADC34(FALSE); rccResetADC34(); ADC3_4_COMMON->CCR = STM32_ADC_ADC34_CLOCK_MODE | ADC_DMA_MDMA; - rccDisableADC34(FALSE); + rccDisableADC34(); #endif #endif @@ -538,7 +538,7 @@ void adc_lld_init(void) { rccEnableADC123(FALSE); rccResetADC123(); ADC123_COMMON->CCR = STM32_ADC_ADC123_CLOCK_MODE | ADC_DMA_MDMA; - rccDisableADC123(FALSE); + rccDisableADC123(); #endif } @@ -560,12 +560,11 @@ void adc_lld_start(ADCDriver *adcp) { if (adcp->state == ADC_STOP) { #if STM32_ADC_USE_ADC1 if (&ADCD1 == adcp) { - bool b; - b = dmaStreamAllocate(adcp->dmastp, - STM32_ADC_ADC1_DMA_IRQ_PRIORITY, - (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, - (void *)adcp); - osalDbgAssert(!b, "stream already allocated"); + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC1_DMA_STREAM, + STM32_ADC_ADC1_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); clkmask |= (1 << 0); #if defined(STM32F3XX) @@ -579,12 +578,11 @@ void adc_lld_start(ADCDriver *adcp) { #if STM32_ADC_USE_ADC2 if (&ADCD2 == adcp) { - bool b; - b = dmaStreamAllocate(adcp->dmastp, - STM32_ADC_ADC2_DMA_IRQ_PRIORITY, - (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, - (void *)adcp); - osalDbgAssert(!b, "stream already allocated"); + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC2_DMA_STREAM, + STM32_ADC_ADC2_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); clkmask |= (1 << 1); #if defined(STM32F3XX) @@ -598,12 +596,11 @@ void adc_lld_start(ADCDriver *adcp) { #if STM32_ADC_USE_ADC3 if (&ADCD3 == adcp) { - bool b; - b = dmaStreamAllocate(adcp->dmastp, - STM32_ADC_ADC3_DMA_IRQ_PRIORITY, - (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, - (void *)adcp); - osalDbgAssert(!b, "stream already allocated"); + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC3_DMA_STREAM, + STM32_ADC_ADC3_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); clkmask |= (1 << 2); #if defined(STM32F3XX) @@ -617,12 +614,11 @@ void adc_lld_start(ADCDriver *adcp) { #if STM32_ADC_USE_ADC4 if (&ADCD4 == adcp) { - bool b; - b = dmaStreamAllocate(adcp->dmastp, - STM32_ADC_ADC4_DMA_IRQ_PRIORITY, - (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, - (void *)adcp); - osalDbgAssert(!b, "stream already allocated"); + adcp->dmastp = dmaStreamAllocI(STM32_ADC_ADC4_DMA_STREAM, + STM32_ADC_ADC4_DMA_IRQ_PRIORITY, + (stm32_dmaisr_t)adc_lld_serve_dma_interrupt, + (void *)adcp); + osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream"); clkmask |= (1 << 3); #if defined(STM32F3XX) @@ -671,7 +667,8 @@ void adc_lld_stop(ADCDriver *adcp) { if (adcp->state == ADC_READY) { /* Releasing the associated DMA channel.*/ - dmaStreamRelease(adcp->dmastp); + dmaStreamFreeI(adcp->dmastp); + adcp->dmastp = NULL; /* Stopping the ongoing conversion, if any.*/ adc_lld_stop_adc(adcp); @@ -727,16 +724,16 @@ void adc_lld_stop(ADCDriver *adcp) { #if defined(STM32F3XX) if ((clkmask & 0x3) == 0) { - rccDisableADC12(FALSE); + rccDisableADC12(); } if ((clkmask & 0xC) == 0) { - rccDisableADC34(FALSE); + rccDisableADC34(); } #endif #if defined(STM32L4XX) if ((clkmask & 0x7) == 0) { - rccDisableADC123(FALSE); + rccDisableADC123(); } #endif } diff --git a/halconf.h b/halconf.h index 5ea5b6e..3a2caf3 100644 --- a/halconf.h +++ b/halconf.h @@ -28,6 +28,9 @@ #ifndef _HALCONF_H_ #define _HALCONF_H_ +#define _CHIBIOS_HAL_CONF_ +#define _CHIBIOS_HAL_CONF_VER_9_1_ + #include "mcuconf.h" /** diff --git a/ili9341.c b/ili9341.c index e775855..e920f08 100644 --- a/ili9341.c +++ b/ili9341.c @@ -526,7 +526,10 @@ void ili9341_init(void) LCD_CS_HIGH; } -static void ili9341_setWindow(uint8_t cmd, uint16_t x, uint16_t y, uint16_t w, uint16_t h){ +// Every DMA region starts here; keep command setup inlined on the rendering +// path without enabling strict aliasing for the legacy display code. +static void __attribute__((optimize("O3,no-strict-aliasing"))) +ili9341_setWindow(uint8_t cmd, uint16_t x, uint16_t y, uint16_t w, uint16_t h){ // Any LCD exchange start from this #ifdef __USE_DISPLAY_DMA__ dmaChannelWaitCompletionRxTx(); @@ -663,8 +666,11 @@ void ili9341_bulk_finish(void){ } #endif // Copy part of spi_buffer to region, no wait completion after if buffer count !=1 -#ifndef ili9341_bulk_continue -void ili9341_bulk_continue(int x, int y, int w, int h) +#ifndef ili9341_bulk_continue +// This runs once per dirty plot cell. Keep the DMA handoff inlined so a held +// self-test screen is not slower than the historical display pipeline. +void __attribute__((optimize("O3,no-strict-aliasing"))) +ili9341_bulk_continue(int x, int y, int w, int h) { ili9341_bulk_finish(); // Wait DMA ili9341_DMA_bulk(x, y, w, h, ili9341_get_cell_buffer()); // Send new cell data @@ -783,7 +789,10 @@ void ili9341_set_rotation(uint8_t r) send_command(ILI9341_MEMORY_ACCESS_CONTROL, 1, &r); } -void ili9341_blitBitmap(int x, int y, int width, int height, const uint8_t *b) +// Text drawing calls this once per glyph. Inline the DMA setup on this hot +// path while retaining the aliasing rules used by the rest of the release. +void __attribute__((optimize("O3,no-strict-aliasing"))) +ili9341_blitBitmap(int x, int y, int width, int height, const uint8_t *b) { pixel_t *buf = spi_buffer; uint8_t bits = 0; @@ -881,7 +890,13 @@ int lcd_printf(int16_t x, int16_t y, const char *fmt, ...) { // Init small lcd print stream struct lcd_printStreamVMT { _base_sequential_stream_methods - } lcd_vmt = {NULL, NULL, put_char, NULL}; + } lcd_vmt = { + .instance_offset = 0U, + .write = NULL, + .read = NULL, + .put = put_char, + .get = NULL + }; lcdPrintStream ps = {&lcd_vmt, x, y, x, y}; // Performing the print operation using the common code. va_list ap; @@ -1357,7 +1372,7 @@ static uint8_t SD_WaitNotBusy(uint32_t wait_time) { // Receive data block from SD static bool SD_RxDataBlock(uint8_t *buff, uint16_t len, uint8_t token) { // loop until receive read response token or timeout ~50ms - if (!SD_WaitDataToken(token, MS2ST(50))) { + if (!SD_WaitDataToken(token, TIME_MS2I(50))) { DEBUG_PRINT(" rx SD_WaitDataToken err\r\n"); return FALSE; } @@ -1408,7 +1423,7 @@ static bool SD_TxDataBlock(const uint8_t *buff, uint16_t len, uint8_t token) { } #if 1 // Wait busy (recommended timeout is 250ms (500ms for SDXC) set 250ms - resp = SD_WaitNotBusy(MS2ST(250)); + resp = SD_WaitNotBusy(TIME_MS2I(250)); if (resp == 0xFF) return TRUE; #else @@ -1427,7 +1442,7 @@ static uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg) { uint8_t buf[6]; volatile uint8_t r1; // wait SD ready after last Tx (recommended timeout is 250ms (500ms for SDXC) set 250ms - if ((r1 = SD_WaitNotBusy(MS2ST(500))) != 0xFF) { + if ((r1 = SD_WaitNotBusy(TIME_MS2I(500))) != 0xFF) { DEBUG_PRINT(" SD_WaitNotBusy CMD%d err, %02x\r\n", cmd-0x40, (uint32_t)r1); return 0xFF; } @@ -1707,7 +1722,7 @@ DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void* buff) { // Nothing to do for this command if each write operation to the media is completed // within the disk_write function. case CTRL_SYNC: - if (SD_WaitNotBusy(MS2ST(200)) == 0xFF) res = RES_OK; + if (SD_WaitNotBusy(TIME_MS2I(200)) == 0xFF) res = RES_OK; break; #if FF_USE_TRIM == 1 // Informs the device the data on the block of sectors is no longer needed and it can be erased. diff --git a/main.c b/main.c index 03ee392..119afa6 100644 --- a/main.c +++ b/main.c @@ -161,7 +161,8 @@ static THD_FUNCTION(Thread1, arg) while (1) { // START_PROFILE if (sweep_mode&(SWEEP_ENABLE|SWEEP_ONCE)) { - backup_t b; + /* Initialize the reserved byte covered by the checksum too. */ + backup_t b = {0}; b.data.frequency0 = setting.frequency0; b.data.frequency1 = setting.frequency1; if (setting.auto_attenuation) @@ -209,7 +210,7 @@ static THD_FUNCTION(Thread1, arg) { completed = sweep(true); #ifdef __USE_SD_CARD__ - if (setting.trigger_auto_save && (last_auto_save == 0 || chVTGetSystemTimeX() - last_auto_save > S2ST(30)) ) { // once every 30 seconds max + if (setting.trigger_auto_save && (last_auto_save == 0 || chVTGetSystemTimeX() - last_auto_save > TIME_S2I(30)) ) { // once every 30 seconds max uint16_t old_mode = config._mode; config._mode |= _MODE_AUTO_FILENAME; save_csv(1+(2<<0)); // frequencies + trace 1 @@ -455,7 +456,7 @@ VNA_SHELL_FUNCTION(cmd_restart) (void)argc; (void)argv; if (argc == 1) { - restart_interval = S2ST(my_atoi(argv[0])); + restart_interval = TIME_S2I(my_atoi(argv[0])); if (restart_interval) { restart_set_time = chVTGetSystemTimeX(); if (restart_set_time == 0) @@ -2418,7 +2419,7 @@ VNA_SHELL_FUNCTION(cmd_threads) #endif shell_printf("%08x|%08x|%08x|%08x|%4u|%4u|%9s|%12s"VNA_SHELL_NEWLINE_STR, stklimit, (uint32_t)tp->ctx.sp, max_stack_use, (uint32_t)tp, - (uint32_t)tp->refs - 1, (uint32_t)tp->prio, states[tp->state], + (uint32_t)tp->refs - 1, (uint32_t)tp->hdr.pqueue.prio, states[tp->state], tp->name == NULL ? "" : tp->name); tp = chRegNextThread(tp); } while (tp != NULL); @@ -2697,18 +2698,21 @@ void shell_update_speed(void){ } void shell_reset_console(void){ + osalSysLock(); // Reset I/O queue over USB (for USB need also connect/disconnect) if (usb_IsActive()){ if (config._mode & _MODE_SERIAL) - sduDisconnectI(&SDU1); + sduSuspendHookI(&SDU1); else sduConfigureHookI(&SDU1); } // Reset I/O queue over Serial // oqResetI(&SD1.oqueue); // iqResetI(&SD1.iqueue); - qResetI(&SD1.oqueue); - qResetI(&SD1.iqueue); + oqResetI(&SD1.oqueue); + iqResetI(&SD1.iqueue); + osalOsRescheduleS(); + osalSysUnlock(); } @@ -2886,7 +2890,7 @@ static void VNAShell_executeLine(char *line) int timeout_count = 0; msg_t result; do { - result = osalThreadEnqueueTimeoutS(&shell_thread, MS2ST(5000)); // 5 second timeout + result = osalThreadEnqueueTimeoutS(&shell_thread, TIME_MS2I(5000)); // 5 second timeout if (result == MSG_TIMEOUT) { timeout_count++; if (timeout_count > 3) { @@ -3004,6 +3008,7 @@ static PWMConfig pwmcfg = { {PWM_OUTPUT_DISABLED, NULL} }, 0, + 0, 0 }; @@ -3446,8 +3451,35 @@ int main(void) } } -/* The prototype shows it is a naked function - in effect this is just an -assembly function. */ +#ifdef TINYSA4 +void hard_fault_handler_c(uint32_t *sp, const uint32_t *callee) + __attribute__((noreturn, noinline)); +void HardFault_Handler(void) __attribute__((naked)); + +void HardFault_Handler(void) +{ + __asm volatile( + "tst lr, #4\n" + "ite eq\n" + "mrseq r0, msp\n" + "mrsne r0, psp\n" + "sub sp, sp, #32\n" + "str r4, [sp, #0]\n" + "str r5, [sp, #4]\n" + "str r6, [sp, #8]\n" + "str r7, [sp, #12]\n" + "mov r2, r8\n" + "str r2, [sp, #16]\n" + "mov r2, r9\n" + "str r2, [sp, #20]\n" + "mov r2, r10\n" + "str r2, [sp, #24]\n" + "mov r2, r11\n" + "str r2, [sp, #28]\n" + "mov r1, sp\n" + "b hard_fault_handler_c\n"); +} +#else void HardFault_Handler(void); void hard_fault_handler_c(uint32_t *sp) __attribute__((naked)); @@ -3460,22 +3492,27 @@ void HardFault_Handler(void) __asm volatile("mrs %0, psp \n\t" : "=r"(sp)); hard_fault_handler_c(sp); } +#endif +#ifdef TINYSA4 +void hard_fault_handler_c(uint32_t *sp, const uint32_t *callee) +#else void hard_fault_handler_c(uint32_t *sp) +#endif { #ifdef TINYSA4 uint32_t r0 = sp[0]; uint32_t r1 = sp[1]; uint32_t r2 = sp[2]; uint32_t r3 = sp[3]; - register uint32_t r4 __asm("r4"); - register uint32_t r5 __asm("r5"); - register uint32_t r6 __asm("r6"); - register uint32_t r7 __asm("r7"); - register uint32_t r8 __asm("r8"); - register uint32_t r9 __asm("r9"); - register uint32_t r10 __asm("r10"); - register uint32_t r11 __asm("r11"); + uint32_t r4 = callee[0]; + uint32_t r5 = callee[1]; + uint32_t r6 = callee[2]; + uint32_t r7 = callee[3]; + uint32_t r8 = callee[4]; + uint32_t r9 = callee[5]; + uint32_t r10 = callee[6]; + uint32_t r11 = callee[7]; uint32_t r12 = sp[4]; uint32_t lr = sp[5]; uint32_t pc = sp[6]; @@ -3516,7 +3553,7 @@ void hard_fault_handler_c(uint32_t *sp) #endif lcd_printf(x, y+=FONT_STR_HEIGHT, "%08x|%08x|%08x|%08x|%4u|%4u|%9s|%12s", stklimit, (uint32_t)tp->ctx.sp, max_stack_use, (uint32_t)tp, - (uint32_t)tp->refs - 1, (uint32_t)tp->prio, states[tp->state], + (uint32_t)tp->refs - 1, (uint32_t)tp->hdr.pqueue.prio, states[tp->state], tp->name == NULL ? "" : tp->name); tp = chRegNextThread(tp); } while (tp != NULL); @@ -3533,4 +3570,3 @@ void hard_fault_handler_c(uint32_t *sp) } - diff --git a/nanovna.h b/nanovna.h index 18fd053..0fa6496 100644 --- a/nanovna.h +++ b/nanovna.h @@ -984,6 +984,7 @@ extern int8_t marker_tracking; void plot_init(void); void update_grid(void); +void update_grid_if_changed(void); void request_to_redraw_grid(void); void redraw_frame(void); //void redraw_all(void); diff --git a/plot.c b/plot.c index 8ffe9fe..bdce5d7 100644 --- a/plot.c +++ b/plot.c @@ -110,19 +110,24 @@ float2int(float v) } #endif -void update_grid(void) +static void calculate_grid(int16_t *offset, int16_t *width, freq_t *span) { freq_t gdigit = 1000000000; freq_t fstart = get_sweep_frequency(ST_START) + (setting.frequency_offset - FREQUENCY_SHIFT); freq_t fspan = get_sweep_frequency(ST_SPAN); freq_t grid; + bool time_domain = fspan == 0; - if (fspan == 0) { + if (time_domain) { fspan = setting.actual_sweep_time_us; // Time in uS fstart = 0; } + if (fspan == 0) + fspan = 1; if (config.gridlines == 0) { grid = fspan/10; + if (grid == 0) + grid = 1; } else { if (config.gridlines < 3) config.gridlines = 6; @@ -139,21 +144,54 @@ void update_grid(void) gdigit /= 10; } } - grid_span = grid; - if (grid > 1000) { - grid_offset = (WIDTH) * ((fstart % grid) / 100) / (fspan / 100); - grid_width = (WIDTH) * (grid / 100) / (fspan / 1000); + *span = grid; + if (time_domain) { + // The zero-span x axis is measured in microseconds. Keep the full ratio + // until the final division so 5-20 ms sweeps do not shift by whole pixels. + *offset = (int16_t)((uint64_t)WIDTH * (fstart % grid) / fspan); + *width = (int16_t)((uint64_t)WIDTH * 10U * grid / fspan); + } else if (grid > 1000) { + *offset = (WIDTH) * ((fstart % grid) / 100) / (fspan / 100); + *width = (WIDTH) * (grid / 100) / (fspan / 1000); } else { - grid_offset = (WIDTH) * ((fstart % grid)) / (fspan); - grid_width = (WIDTH) * (grid) / (fspan/10); + *offset = (WIDTH) * ((fstart % grid)) / (fspan); + *width = (WIDTH) * (grid) / (fspan/10); } + if (*width < 1) + *width = 1; if (config.gridlines == 0) - grid_offset = 0; + *offset = 0; +} + +static void apply_grid(int16_t offset, int16_t width, freq_t span) +{ + grid_offset = offset; + grid_width = width; + grid_span = span; // if (setting.waterfall) set_level_meter_or_waterfall(); redraw_request |= REDRAW_FREQUENCY | REDRAW_AREA; } +void update_grid(void) +{ + int16_t offset; + int16_t width; + freq_t span; + calculate_grid(&offset, &width, &span); + apply_grid(offset, width, span); +} + +void update_grid_if_changed(void) +{ + int16_t offset; + int16_t width; + freq_t span; + calculate_grid(&offset, &width, &span); + if (offset != grid_offset || width != grid_width || span != grid_span) + apply_grid(offset, width, span); +} + #if 0 static int rectangular_grid(int x, int y) @@ -1509,7 +1547,13 @@ int cell_printf(int16_t x, int16_t y, const char *fmt, ...) { // Init small cell print stream struct cellprintStreamVMT { _base_sequential_stream_methods - } cell_vmt = {NULL, NULL, NULL, NULL}; + } cell_vmt = { + .instance_offset = 0U, + .write = NULL, + .read = NULL, + .put = NULL, + .get = NULL + }; screenPrintStream ps = {&cell_vmt, x, y}; // Select font and skip print if not on cell (at top/bottom) switch (*fmt++){ diff --git a/sa_core.c b/sa_core.c index 85013ab..f47659b 100644 --- a/sa_core.c +++ b/sa_core.c @@ -499,6 +499,9 @@ const freq_t fh_high[] = { 480000000, 960000000, 1920000000, 2880000000, 3840000 uint8_t in_selftest = false; uint8_t ignore_stored = false; +#ifdef TINYSA4 +static uint8_t factory_selftest_direct_scratch = false; +#endif uint8_t in_step_test = false; uint8_t in_calibration = false; uint8_t calibration_stage; @@ -3555,6 +3558,20 @@ deviceRSSI_t age[POINTS_COUNT]; // Array used for 1: calculating the age of static pureRSSI_t correct_RSSI; static pureRSSI_t correct_RSSI_freq; systime_t start_of_sweep_timestamp; + +#ifdef TINYSA4 +#if OSAL_ST_MODE != OSAL_ST_MODE_FREERUNNING +#error "The optimized sweep clock requires the ChibiOS free-running system timer" +#endif +#if CH_CFG_ST_TIMEDELTA == 0 +#error "The optimized sweep clock requires the port-backed ChibiOS system timer" +#endif +// Keep the timed sweep hot path on the current free-running timer backend. +// Re-audit this equivalence whenever the ChibiOS system-timer backend changes. +#define SWEEP_CLOCK_NOW() st_lld_get_counter() +#else +#define SWEEP_CLOCK_NOW() chVTGetSystemTimeX() +#endif static systime_t sweep_elapsed = 0; // Time since first start of sweeping, used only for auto attenuate uint8_t signal_is_AM = false; static uint8_t check_for_AM = false; @@ -3637,6 +3654,9 @@ bool depth_error = false; #endif +#ifdef TINYSA4 +__attribute__((optimize("O2,no-strict-aliasing"))) +#endif pureRSSI_t perform(bool break_on_operation, int i, freq_t f, int tracking) // Measure the RSSI for one frequency, used from sweep and other measurement routines. Must do all HW setup { int modulation_delay = 0; @@ -4761,7 +4781,7 @@ again: // Spur redu skip_LO_setting: if (i == 0 && t == 0) // if first point in scan (here is get 1 point data) - start_of_sweep_timestamp = chVTGetSystemTimeX(); // initialize start sweep time + start_of_sweep_timestamp = SWEEP_CLOCK_NOW(); // initialize start sweep time if (MODE_OUTPUT(setting.mode)) { // No substepping and no RSSI in output mode if (break_on_operation && operation_requested) // break subscanning if requested @@ -4893,7 +4913,7 @@ again: // Spur redu if (setting.trigger == T_SINGLE) { set_trigger(T_DONE); } - start_of_sweep_timestamp = chVTGetSystemTimeX(); + start_of_sweep_timestamp = SWEEP_CLOCK_NOW(); } TRACE(5); #ifdef TINYSA4 @@ -5067,6 +5087,9 @@ void reset_band(void) { #endif // main loop for measurement +#ifdef TINYSA4 +__attribute__((optimize("O2,no-strict-aliasing"))) +#endif static bool sweep(bool break_on_operation) { float RSSI; @@ -5187,6 +5210,7 @@ static bool sweep(bool break_on_operation) #endif setting.measure_sweep_time_us = 0; // start measure sweep time // start_of_sweep_timestamp = chVTGetSystemTimeX(); // Will be set in perform + uint8_t progress_mask = 0x3f; sweep_again: // stay in sweep loop when output mode and modulation on. @@ -5301,33 +5325,41 @@ static bool sweep(bool break_on_operation) } } } - systime_t local_sweep_time = sa_ST2US(chVTGetSystemTimeX() - start_of_sweep_timestamp); - if (setting.actual_sweep_time_us > ONE_SECOND_TIME) - local_sweep_time = setting.actual_sweep_time_us; if ( #ifdef TINYSA4 progress_bar && #endif - show_bar && (( local_sweep_time > ONE_SECOND_TIME && (i & 0x07) == 0) /* || ( local_sweep_time > ONE_SECOND_TIME*10)*/ ) ) + show_bar && (i & progress_mask) == 0) { - int pos = i * (WIDTH+1) / sweep_points; - ili9341_set_background(LCD_SWEEP_LINE_COLOR); - ili9341_fill(OFFSETX, CHART_BOTTOM+1, pos, 1); // update sweep progress bar - ili9341_set_background(LCD_BG_COLOR); - ili9341_fill(OFFSETX+pos, CHART_BOTTOM+1, WIDTH-pos, 1); - - if (local_sweep_time > 10 * ONE_SECOND_TIME) { - plot_into_index(measured); - redraw_request |= REDRAW_CELLS | REDRAW_BATTERY | REDRAW_INBETWEEN; - // plot trace and other indications as raster - draw_all(true); // flush markmap only if scan completed to prevent - } + // Expected long sweeps can use their known duration directly. For an + // expected fast sweep, sample every 64th point until an unexpected + // one-second overrun is observed, then resume the normal 8-point rate. + // This retains overrun progress while avoiding timer traffic in the + // common sub-second path. + systime_t local_sweep_time = setting.actual_sweep_time_us; + if (local_sweep_time <= ONE_SECOND_TIME) + local_sweep_time = sa_ST2US(SWEEP_CLOCK_NOW() - start_of_sweep_timestamp); + if (local_sweep_time > ONE_SECOND_TIME) { + progress_mask = 0x07; + int pos = i * (WIDTH+1) / sweep_points; + ili9341_set_background(LCD_SWEEP_LINE_COLOR); + ili9341_fill(OFFSETX, CHART_BOTTOM+1, pos, 1); // update sweep progress bar + ili9341_set_background(LCD_BG_COLOR); + ili9341_fill(OFFSETX+pos, CHART_BOTTOM+1, WIDTH-pos, 1); + + if (local_sweep_time > 10 * ONE_SECOND_TIME) { + plot_into_index(measured); + redraw_request |= REDRAW_CELLS | REDRAW_BATTERY | REDRAW_INBETWEEN; + // plot trace and other indications as raster + draw_all(true); // flush markmap only if scan completed to prevent + } #ifdef __SWEEP_RESTART__ - if (MODE_OUTPUT(setting.mode) && (setting.level_sweep != 0 || get_sweep_frequency(ST_SPAN) != 0)) - refresh_sweep_menu(i); + if (MODE_OUTPUT(setting.mode) && (setting.level_sweep != 0 || get_sweep_frequency(ST_SPAN) != 0)) + refresh_sweep_menu(i); #endif + } } // ----------------------- debug avoid -------------------------------- if (debug_avoid) { @@ -5651,6 +5683,14 @@ static volatile int dummy; // add_to_peak_finding(actual_t, i); } +#if TRACES_MAX == 4 + // The factory test freezes two default scratch passes below. Preserve + // their exact AV_OFF result once, after ACTUAL processing is complete. + if (factory_selftest_direct_scratch) { + temp_t[i] = RSSI; + stored2_t[i] = RSSI; + } +#endif } } @@ -5688,14 +5728,20 @@ static volatile int dummy; // ---------------------- process measured actual sweep time ----------------- // For CW mode value calculated in SI4432_Fill if (setting.measure_sweep_time_us == 0) - setting.measure_sweep_time_us = sa_ST2US(chVTGetSystemTimeX() - start_of_sweep_timestamp); + setting.measure_sweep_time_us = sa_ST2US(SWEEP_CLOCK_NOW() - start_of_sweep_timestamp); // Update actual time on change on status panel uint32_t delta = abs((int)(setting.actual_sweep_time_us - setting.measure_sweep_time_us)); - if ((delta<<3) > setting.actual_sweep_time_us){ // update if delta > 1/8 + bool sweep_time_changed = (delta<<3) > setting.actual_sweep_time_us; + if (sweep_time_changed){ // update if delta > 1/8 redraw_request|=REDRAW_CAL_STATUS | REDRAW_FREQUENCY; } setting.actual_sweep_time_us = setting.measure_sweep_time_us; + // The zero-span x axis represents the sweep that just completed. Recompute + // its tuple every time; update_grid_if_changed() suppresses redraws while + // the exact grid geometry remains unchanged. + if (FREQ_IS_CW()) + update_grid_if_changed(); // Not possible reduce sweep time, it minimum! if (setting.sweep_time_us < setting.actual_sweep_time_us && setting.additional_step_delay_us == 0){ // Warning!! not correct set sweep time here, you get error!! @@ -5849,7 +5895,7 @@ static volatile int dummy; } else if (actual_max_level > target_level && setting.attenuate_x2 < 60) { delta = actual_max_level - target_level; } - if (chVTGetSystemTimeX() - sweep_elapsed > MS2ST(1000)){ + if (chVTGetSystemTimeX() - sweep_elapsed > TIME_MS2I(1000)){ if (( delta < -5 || delta > +5) || delta > 10 ) { setting.attenuate_x2 += delta + delta; if (setting.attenuate_x2 < 0) @@ -7117,6 +7163,7 @@ void selftest(int test) { bool no_wait = false; #ifdef TINYSA4 + factory_selftest_direct_scratch = false; bool old_ultra = config.ultra; config.ultra = true; // if (adc_vbat_read() < 3800) { @@ -7158,7 +7205,33 @@ void selftest(int test) } do { test_prepare(test_step); +#if TRACES_MAX == 4 + // Preserve any pre-existing frozen traces. For the normal factory setup, + // freeze both AV_OFF scratch passes and write their raw samples directly. + // Zero-span timing still measures this faster path, and its grid is + // refreshed from that completed measurement below. + bool old_temp_stored = setting.stored[TRACE_TEMP]; + bool old_stored2_stored = setting.stored[TRACE_STORED2]; + factory_selftest_direct_scratch = + !debug_spur && !debug_avoid && + !old_temp_stored && !old_stored2_stored && + setting.average[TRACE_TEMP] == AV_OFF && + setting.subtract[TRACE_TEMP] == 0 && + !setting.normalized[TRACE_TEMP] && + setting.average[TRACE_STORED2] == AV_OFF && + setting.subtract[TRACE_STORED2] == 0 && + !setting.normalized[TRACE_STORED2]; + if (factory_selftest_direct_scratch) { + setting.stored[TRACE_TEMP] = true; + setting.stored[TRACE_STORED2] = true; + } +#endif test_acquire(test_step); // Acquire test +#if TRACES_MAX == 4 + factory_selftest_direct_scratch = false; + setting.stored[TRACE_TEMP] = old_temp_stored; + setting.stored[TRACE_STORED2] = old_stored2_stored; +#endif test_status[test_step] = test_validate(test_step); // Validate test if (test_step == 2) { diff --git a/si5351.c b/si5351.c index 5a9a21c..c94574b 100644 --- a/si5351.c +++ b/si5351.c @@ -210,7 +210,7 @@ static bool si5351_wait_ready(void) { uint8_t status = 0xff; systime_t start = chVTGetSystemTime(); - systime_t end = start + MS2ST(1000); // 1000 ms timeout + systime_t end = start + TIME_MS2I(1000); // 1000 ms timeout while (chVTIsSystemTimeWithin(start, end)) { if(!si5351_read(0, &status)) @@ -230,7 +230,7 @@ static void si5351_wait_pll_lock(void) status = 0xff; // comm timeout if ((status & 0x60) == 0) return; - systime_t end = start + MS2ST(100); // 100 ms timeout + systime_t end = start + TIME_MS2I(100); // 100 ms timeout while (chVTIsSystemTimeWithin(start, end)) { if(!si5351_read(0, &status)) diff --git a/ui.c b/ui.c index b2847fd..b20b512 100644 --- a/ui.c +++ b/ui.c @@ -48,10 +48,10 @@ uistat_t uistat = { #define EVT_DOWN 0x20 #define EVT_REPEAT 0x40 -#define BUTTON_DOWN_LONG_TICKS MS2ST(500) // 500ms -#define BUTTON_DOUBLE_TICKS MS2ST(250) // 250ms -#define BUTTON_REPEAT_TICKS MS2ST( 40) // 40ms -#define BUTTON_DEBOUNCE_TICKS MS2ST( 2) // 2ms +#define BUTTON_DOWN_LONG_TICKS TIME_MS2I(500) // 500ms +#define BUTTON_DOUBLE_TICKS TIME_MS2I(250) // 250ms +#define BUTTON_REPEAT_TICKS TIME_MS2I(40) // 40ms +#define BUTTON_DEBOUNCE_TICKS TIME_MS2I(2) // 2ms /* lever switch assignment */ #define BIT_UP1 3 @@ -684,7 +684,7 @@ extern const char *states[]; #endif lcd_printf(x, y+=bFONT_STR_HEIGHT, "%08x|%08x|%08x|%08x|%4u|%4u|%9s|%12s", stklimit, (uint32_t)tp->ctx.sp, max_stack_use, (uint32_t)tp, - (uint32_t)tp->refs - 1, (uint32_t)tp->prio, states[tp->state], + (uint32_t)tp->refs - 1, (uint32_t)tp->hdr.pqueue.prio, states[tp->state], tp->name == NULL ? "" : tp->name); tp = chRegNextThread(tp); } while (tp != NULL); @@ -1599,10 +1599,12 @@ static const menuitem_t menu_calibrate_normal[]; #endif static const menuitem_t menu_calibrate[]; static const menuitem_t menu_sweep[]; +#ifdef TINYSA4 static const menuitem_t menu_settings[]; -static const menuitem_t menu_settings2[]; static const menuitem_t menu_lowoutput_settings[]; static const menuitem_t menu_lowoutput_settings_max[]; +#endif +static const menuitem_t menu_settings2[]; extern bool dirty; char range_text[20]; #ifdef TINYSA4 @@ -8382,10 +8384,9 @@ ui_process(void) } /* Triggered when the button is pressed or released. The LED4 is set to ON.*/ -static void extcb1(EXTDriver *extp, expchannel_t channel) +static void extcb1(void *arg) { - (void)extp; - (void)channel; + uint32_t channel = (uint32_t)(uintptr_t)arg; #ifdef __USE_SD_CARD__ if (channel == 12) SD_PowerOff(); @@ -8397,42 +8398,6 @@ static void extcb1(EXTDriver *extp, expchannel_t channel) // cur_button = READ_PORT() & BUTTON_MASK; } -static const EXTConfig extcfg = { - { - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1}, - {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1}, - {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, -#ifdef __WAIT_CTS_WHILE_SLEEPING__ - {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOB, extcb1}, -#else - {EXT_CH_MODE_DISABLED, NULL}, -#endif - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, -#ifdef __USE_SD_CARD__ - {EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOB, extcb1}, -#else - {EXT_CH_MODE_DISABLED, NULL}, -#endif - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL}, - {EXT_CH_MODE_DISABLED, NULL} - } -}; - void handle_touch_interrupt(void) { @@ -8442,8 +8407,24 @@ handle_touch_interrupt(void) void ui_init() { - // Activates the EXT driver 1. - extStart(&EXTD1, &extcfg); + /* HAL 9.1 routes STM32 EXTI through PAL line events. */ + palSetLineCallback(PAL_LINE(GPIOA, GPIOA_LEVER1), extcb1, + (void *)(uintptr_t)GPIOA_LEVER1); + palEnableLineEvent(PAL_LINE(GPIOA, GPIOA_LEVER1), PAL_EVENT_MODE_RISING_EDGE); + palSetLineCallback(PAL_LINE(GPIOA, GPIOA_PUSH), extcb1, + (void *)(uintptr_t)GPIOA_PUSH); + palEnableLineEvent(PAL_LINE(GPIOA, GPIOA_PUSH), PAL_EVENT_MODE_RISING_EDGE); + palSetLineCallback(PAL_LINE(GPIOA, GPIOA_LEVER2), extcb1, + (void *)(uintptr_t)GPIOA_LEVER2); + palEnableLineEvent(PAL_LINE(GPIOA, GPIOA_LEVER2), PAL_EVENT_MODE_RISING_EDGE); +#ifdef __WAIT_CTS_WHILE_SLEEPING__ + palSetLineCallback(LINE_RX_CTS, extcb1, (void *)(uintptr_t)9U); + palEnableLineEvent(LINE_RX_CTS, PAL_EVENT_MODE_RISING_EDGE); +#endif +#ifdef __USE_SD_CARD__ + palSetLineCallback(LINE_SD_CD, extcb1, (void *)(uintptr_t)12U); + palEnableLineEvent(LINE_SD_CD, PAL_EVENT_MODE_RISING_EDGE); +#endif // Init touch subsystem touch_init(); } diff --git a/usbcfg.c b/usbcfg.c index 398e3cb..254ea6a 100644 --- a/usbcfg.c +++ b/usbcfg.c @@ -297,8 +297,10 @@ static const USBEndpointConfig ep1config = { sduDataReceived, 0x0040, 0x0040, - &ep1instate, - &ep1outstate, + &ep1instate, + &ep1outstate, + 1, + NULL }; /** @@ -316,8 +318,10 @@ static const USBEndpointConfig ep2config = { NULL, 0x0010, 0x0000, - &ep2instate, - NULL, + &ep2instate, + NULL, + 1, + NULL }; /* @@ -327,10 +331,8 @@ static void usb_event(USBDriver *usbp, usbevent_t event) { extern SerialUSBDriver SDU1; switch (event) { - case USB_EVENT_RESET: - return; - case USB_EVENT_ADDRESS: - return; + case USB_EVENT_ADDRESS: + return; case USB_EVENT_CONFIGURED: chSysLockFromISR(); @@ -345,16 +347,21 @@ static void usb_event(USBDriver *usbp, usbevent_t event) { chSysUnlockFromISR(); return; - case USB_EVENT_SUSPEND: + case USB_EVENT_RESET: + case USB_EVENT_UNCONFIGURED: + case USB_EVENT_SUSPEND: chSysLockFromISR(); /* Disconnection event on suspend.*/ - sduDisconnectI(&SDU1); + sduSuspendHookI(&SDU1); chSysUnlockFromISR(); return; - case USB_EVENT_WAKEUP: - return; + case USB_EVENT_WAKEUP: + chSysLockFromISR(); + sduWakeupHookI(&SDU1); + chSysUnlockFromISR(); + return; case USB_EVENT_STALLED: return; }