From 427d72667f23ef8758fbfd2352dd28ba5565644a Mon Sep 17 00:00:00 2001 From: yn386 Date: Mon, 19 Sep 2022 17:56:31 +0900 Subject: [PATCH] stm32: Add support for STM32L1 MCUs. This change adds STM32L1 support to the STM32 port. --- ports/stm32/Makefile | 7 ++ ports/stm32/adc.c | 55 ++++++++- ports/stm32/boards/stm32l152_af.csv | 117 +++++++++++++++++++ ports/stm32/boards/stm32l152xe.ld | 37 ++++++ ports/stm32/boards/stm32l1xx_hal_conf_base.h | 99 ++++++++++++++++ ports/stm32/dac.c | 2 + ports/stm32/dma.c | 66 ++++++++++- ports/stm32/dma.h | 14 +++ ports/stm32/extint.c | 4 + ports/stm32/extint.h | 2 +- ports/stm32/flash.c | 10 +- ports/stm32/machine_adc.c | 7 +- ports/stm32/modmachine.c | 4 +- ports/stm32/mpconfigboard_common.h | 10 ++ ports/stm32/mphalport.c | 2 +- ports/stm32/mphalport.h | 2 + ports/stm32/powerctrl.c | 6 +- ports/stm32/powerctrlboot.c | 68 +++++++++++ ports/stm32/resethandler_m3.s | 75 ++++++++++++ ports/stm32/rtc.c | 17 +++ ports/stm32/stm32.mk | 3 +- ports/stm32/stm32_it.c | 34 ++++++ ports/stm32/timer.c | 34 ++++-- ports/stm32/uart.c | 17 ++- ports/stm32/uart.h | 2 +- 25 files changed, 657 insertions(+), 37 deletions(-) create mode 100644 ports/stm32/boards/stm32l152_af.csv create mode 100644 ports/stm32/boards/stm32l152xe.ld create mode 100644 ports/stm32/boards/stm32l1xx_hal_conf_base.h create mode 100644 ports/stm32/resethandler_m3.s diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index ee00d77173..4b4a9f0ce3 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -347,11 +347,18 @@ SRC_O += \ resethandler_m0.o \ shared/runtime/gchelper_m0.o else +ifeq ($(MCU_SERIES),l1) +CFLAGS += -DUSE_HAL_DRIVER +SRC_O += \ + resethandler_m3.o \ + shared/runtime/gchelper_m3.o +else SRC_O += \ system_stm32.o \ resethandler.o \ shared/runtime/gchelper_m3.o endif +endif HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\ hal.c \ diff --git a/ports/stm32/adc.c b/ports/stm32/adc.c index 712e9b3ade..02bbbb58db 100644 --- a/ports/stm32/adc.c +++ b/ports/stm32/adc.c @@ -118,6 +118,14 @@ #define ADC_CAL2 ((uint16_t *)(0x1FF1E840)) #define ADC_CAL_BITS (16) +#elif defined(STM32L1) + +#define ADC_SCALE_V (VREFINT_CAL_VREF / 1000.0f) +#define ADC_CAL_ADDRESS (VREFINT_CAL_ADDR) +#define ADC_CAL1 (TEMPSENSOR_CAL1_ADDR) +#define ADC_CAL2 (TEMPSENSOR_CAL2_ADDR) +#define ADC_CAL_BITS (12) + #elif defined(STM32L4) || defined(STM32WB) #define ADC_SCALE_V (VREFINT_CAL_VREF / 1000.0f) @@ -163,6 +171,8 @@ defined(STM32L476xx) || defined(STM32L496xx) || \ defined(STM32WB55xx) #define VBAT_DIV (3) +#elif defined(STM32L152xE) +// STM32L152xE does not have vbat. #else #error Unsupported processor #endif @@ -179,11 +189,17 @@ #define VREFIN_CAL ((uint16_t *)ADC_CAL_ADDRESS) #ifndef __HAL_ADC_IS_CHANNEL_INTERNAL +#if defined(STM32L1) +#define __HAL_ADC_IS_CHANNEL_INTERNAL(channel) \ + (channel == ADC_CHANNEL_VREFINT \ + || channel == ADC_CHANNEL_TEMPSENSOR) +#else #define __HAL_ADC_IS_CHANNEL_INTERNAL(channel) \ (channel == ADC_CHANNEL_VBAT \ || channel == ADC_CHANNEL_VREFINT \ || channel == ADC_CHANNEL_TEMPSENSOR) #endif +#endif typedef struct _pyb_obj_adc_t { mp_obj_base_t base; @@ -210,6 +226,10 @@ STATIC bool is_adcx_channel(int channel) { return IS_ADC_CHANNEL(channel) || channel == ADC_CHANNEL_TEMPSENSOR; #elif defined(STM32F0) || defined(STM32F4) || defined(STM32F7) return IS_ADC_CHANNEL(channel); + #elif defined(STM32L1) + // The HAL of STM32L1 defines some channels those may not be available on package + return __HAL_ADC_IS_CHANNEL_INTERNAL(channel) + || (channel < MP_ARRAY_SIZE(pin_adcall_table) && pin_adcall_table[channel]); #elif defined(STM32G0) || defined(STM32H7) return __HAL_ADC_IS_CHANNEL_INTERNAL(channel) || IS_ADC_CHANNEL(__HAL_ADC_DECIMAL_NB_TO_CHANNEL(channel)); @@ -225,7 +245,7 @@ STATIC bool is_adcx_channel(int channel) { STATIC void adc_wait_for_eoc_or_timeout(ADC_HandleTypeDef *adcHandle, int32_t timeout) { uint32_t tickstart = HAL_GetTick(); - #if defined(STM32F4) || defined(STM32F7) + #if defined(STM32F4) || defined(STM32F7) || defined(STM32L1) while ((adcHandle->Instance->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) { #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB) while (READ_BIT(adcHandle->Instance->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) { @@ -239,7 +259,7 @@ STATIC void adc_wait_for_eoc_or_timeout(ADC_HandleTypeDef *adcHandle, int32_t ti } STATIC void adcx_clock_enable(ADC_HandleTypeDef *adch) { - #if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) + #if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32L1) ADCx_CLK_ENABLE(); #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) __HAL_RCC_ADC12_CLK_ENABLE(); @@ -299,6 +319,12 @@ STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) { adch->Init.OversamplingMode = DISABLE; adch->Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE; adch->Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR; + #elif defined(STM32L1) + adch->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; + adch->Init.ScanConvMode = ADC_SCAN_DISABLE; + adch->Init.LowPowerAutoWait = DISABLE; + adch->Init.DataAlign = ADC_DATAALIGN_RIGHT; + adch->Init.DMAContinuousRequests = DISABLE; #elif defined(STM32G0) || defined(STM32G4) || defined(STM32L4) || defined(STM32WB) adch->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; adch->Init.ScanConvMode = ADC_SCAN_DISABLE; @@ -367,6 +393,12 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.OffsetRightShift = DISABLE; sConfig.OffsetSignedSaturation = DISABLE; + #elif defined(STM32L1) + if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) { + sConfig.SamplingTime = ADC_SAMPLETIME_384CYCLES; + } else { + sConfig.SamplingTime = ADC_SAMPLETIME_384CYCLES; + } #elif defined(STM32G0) if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) { sConfig.SamplingTime = ADC_SAMPLETIME_160CYCLES_5; @@ -555,7 +587,7 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ HAL_ADC_Start(&self->handle); } else { // for subsequent samples we can just set the "start sample" bit - #if defined(STM32F4) || defined(STM32F7) + #if defined(STM32F4) || defined(STM32F7) || defined(STM32L1) self->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART; #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB) SET_BIT(self->handle.Instance->CR, ADC_CR_ADSTART); @@ -665,7 +697,7 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i adc_config_channel(&adc->handle, adc->channel); // for the first sample we need to turn the ADC on // ADC is started: set the "start sample" bit - #if defined(STM32F4) || defined(STM32F7) + #if defined(STM32F4) || defined(STM32F7) || defined(STM32L1) adc->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART; #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB) SET_BIT(adc->handle.Instance->CR, ADC_CR_ADSTART); @@ -720,6 +752,8 @@ typedef struct _pyb_adc_all_obj_t { ADC_HandleTypeDef handle; } pyb_adc_all_obj_t; +float adc_read_core_vref(ADC_HandleTypeDef *adcHandle); + void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_mask) { switch (resolution) { @@ -762,7 +796,11 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m } int adc_get_resolution(ADC_HandleTypeDef *adcHandle) { + #if defined(STM32L1) + uint32_t res_reg = adcHandle->Instance->CR1 & ADC_CR1_RES_Msk; + #else uint32_t res_reg = ADC_GET_RESOLUTION(adcHandle); + #endif switch (res_reg) { #if !defined(STM32H7) @@ -814,6 +852,11 @@ float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) { return 0; } #else + #if defined(STM32L1) + // Update the reference correction factor before reading tempsensor + // because TS_CAL1 and TS_CAL2 of STM32L1 are at VDDA=3.0V + adc_read_core_vref(adcHandle); + #endif int32_t raw_value = adc_config_and_read_ref(adcHandle, ADC_CHANNEL_TEMPSENSOR); #endif float core_temp_avg_slope = (*ADC_CAL2 - *ADC_CAL1) / 80.0f; @@ -821,8 +864,12 @@ float adc_read_core_temp_float(ADC_HandleTypeDef *adcHandle) { } float adc_read_core_vbat(ADC_HandleTypeDef *adcHandle) { + #if defined(STM32L152xE) + mp_raise_NotImplementedError(MP_ERROR_TEXT("read_core_vbat not supported")); + #else uint32_t raw_value = adc_config_and_read_ref(adcHandle, ADC_CHANNEL_VBAT); return raw_value * VBAT_DIV * ADC_SCALE * adc_refcor; + #endif } float adc_read_core_vref(ADC_HandleTypeDef *adcHandle) { diff --git a/ports/stm32/boards/stm32l152_af.csv b/ports/stm32/boards/stm32l152_af.csv new file mode 100644 index 0000000000..a6f8e80c30 --- /dev/null +++ b/ports/stm32/boards/stm32l152_af.csv @@ -0,0 +1,117 @@ +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15, +,,SYS_AF,TIM2,TIM3/TIM4/TIM5,TIM9/TIM10/TIM11,I2C1/I2C2,SPI1/SPI2,SPI3,USART1/USART2/USART3,UART4/UART5,,,,,,,,ADC +PortA,PA0,,TIM2_CH1_ETR,TIM5_CH1,,,,,USART2_CTS,,,,,,,,EVENTOUT,ADC1_IN0 +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS,,,,,,,,EVENTOUT,ADC1_IN1 +PortA,PA2,,TIM2_CH3,TIM5_CH3,TIM9_CH1,,,,USART2_TX,,,,,,,,EVENTOUT,ADC1_IN2 +PortA,PA3,,TIM2_CH4,TIM5_CH4,TIM9_CH2,,,,USART2_RX,,,,,,,,EVENTOUT,ADC1_IN3 +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,USART2_CK,,,,,,,,EVENTOUT,ADC1_IN4 +PortA,PA5,,TIM2_CH1_ETR,,,,SPI1_SCK,,,,,,,,,,EVENTOUT,ADC1_IN5 +PortA,PA6,,,TIM3_CH1,TIM10_CH1,,SPI1_MISO,,,,,,,,,,EVENTOUT,ADC1_IN6 +PortA,PA7,,,TIM3_CH2,TIM11_CH1,,SPI1_MOSI,,,,,,,,,,EVENTOUT,ADC1_IN7 +PortA,PA8,MCO,,,,,,,USART1_CK,,,,,,,,EVENTOUT, +PortA,PA9,,,,,,,,USART1_TX,,,,,,,,EVENTOUT, +PortA,PA10,,,,,,,,USART1_RX,,,,,,,,EVENTOUT, +PortA,PA11,,,,,,SPI1_MISO,,USART1_CTS,,,,,,,,EVENTOUT, +PortA,PA12,,,,,,SPI1_MOSI,,USART1_RTS,,,,,,,,EVENTOUT, +PortA,PA13,JTMS/SWDIO,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA14,JTCK/SWCLK,,,,,,,,,,,,,,,EVENTOUT, +PortA,PA15,JTDI,TIM2_CH1_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT, +PortB,PB0,,,TIM3_CH3,,,,,,,,,,,,,EVENTOUT,ADC1_IN8 +PortB,PB1,,,TIM3_CH4,,,,,,,,,,,,,EVENTOUT,ADC1_IN9 +PortB,PB2,BOOT1,,,,,,,,,,,,,,,EVENTOUT, +PortB,PB3,JTDO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT, +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,,,,,,,,,EVENTOUT, +PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,,,,,,,EVENTOUT, +PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,,,,,,,EVENTOUT, +PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,,,,EVENTOUT, +PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,,,,,,,EVENTOUT, +PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,,,,,,,,,,,EVENTOUT, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,,,USART3_TX,,,,,,,,EVENTOUT, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,,,,,,EVENTOUT, +PortB,PB12,,,,TIM10_CH1,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,,,,,,,EVENTOUT,ADC1_IN18 +PortB,PB13,,,,TIM9_CH1,,SPI2_SCK/I2S2_CK,,USART3_CTS,,,,,,,,EVENTOUT,ADC1_IN19 +PortB,PB14,,,,TIM9_CH2,,SPI2_MISO,,USART3_RTS,,,,,,,,EVENTOUT,ADC1_IN20 +PortB,PB15,,,,TIM11_CH1,,SPI2_MOSI/I2S2_SD,,,,,,,,,,EVENTOUT,ADC1_IN21 +PortC,PC0,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN10 +PortC,PC1,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN11 +PortC,PC2,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN12 +PortC,PC3,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN13 +PortC,PC4,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN14 +PortC,PC5,,,,,,,,,,,,,,,,EVENTOUT,ADC1_IN15 +PortC,PC6,,,TIM3_CH1,,,I2S2_MCK,,,,,,,,,,EVENTOUT, +PortC,PC7,,,TIM3_CH2,,,,I2S3_MCK,,,,,,,,,EVENTOUT, +PortC,PC8,,,TIM3_CH3,,,,,,,,,,,,,EVENTOUT, +PortC,PC9,,,TIM3_CH4,,,,,,,,,,,,,EVENTOUT, +PortC,PC10,,,,,,,SPI3_SCK/I2S3_CK,USART3_TX,UART4_TX,,,,,,,EVENTOUT, +PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,,,,,,,EVENTOUT, +PortC,PC12,,,,,,,SPI3_MOSI/I2S3_SD,USART3_CK,UART5_TX,,,,,,,EVENTOUT, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT, +PortD,PD0,,,,TIM9_CH1,,SPI2_NSS/I2S2_WS,,,,,,,,,,EVENTOUT, +PortD,PD1,,,,,,SPI2_SCK/I2S2_CK,,,,,,,,,,EVENTOUT, +PortD,PD2,,,TIM3_ETR,,,,,,UART5_RX,,,,,,,EVENTOUT, +PortD,PD3,,,,,,SPI2_MISO,,USART2_CTS,,,,,,,,EVENTOUT, +PortD,PD4,,,,,,SPI2_MOSI/I2S2_SD,,USART2_RTS,,,,,,,,EVENTOUT, +PortD,PD5,,,,,,,,USART2_TX,,,,,,,,EVENTOUT, +PortD,PD6,,,,,,,,USART2_RX,,,,,,,,EVENTOUT, +PortD,PD7,,,,TIM9_CH2,,,,USART2_CK,,,,,,,,EVENTOUT, +PortD,PD8,,,,,,,,USART3_TX,,,,,,,,EVENTOUT, +PortD,PD9,,,,,,,,USART3_RX,,,,,,,,EVENTOUT, +PortD,PD10,,,,,,,,USART3_CK,,,,,,,,EVENTOUT, +PortD,PD11,,,,,,,,USART3_CTS,,,,,,,,EVENTOUT, +PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS,,,,,,,,EVENTOUT, +PortD,PD13,,,TIM4_CH2,,,,,,,,,,,,,EVENTOUT, +PortD,PD14,,,TIM4_CH3,,,,,,,,,,,,,EVENTOUT, +PortD,PD15,,,TIM4_CH4,,,,,,,,,,,,,EVENTOUT, +PortE,PE0,,,TIM4_ETR,TIM10_CH1,,,,,,,,,,,,EVENTOUT, +PortE,PE1,,,,TIM11_CH1,,,,,,,,,,,,EVENTOUT, +PortE,PE2,TRACECK,,TIM3_ETR,,,,,,,,,,,,,EVENTOUT, +PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,,,,,,,EVENTOUT, +PortE,PE4,TRACED1,,TIM3_CH2,,,,,,,,,,,,,EVENTOUT, +PortE,PE5,TRACED2,,,TIM9_CH1,,,,,,,,,,,,EVENTOUT, +PortE,PE6,TRACED3,,,TIM9_CH2,,,,,,,,,,,,EVENTOUT, +PortE,PE7,,,,,,,,,,,,,,,,EVENTOUT, +PortE,PE8,,,,,,,,,,,,,,,,EVENTOUT, +PortE,PE9,,TIM2_CH1_ETR,,,,,,,,,,,,,,EVENTOUT, +PortE,PE10,,TIM2_CH2,,,,,,,,,,,,,,EVENTOUT, +PortE,PE11,,TIM2_CH3,,,,,,,,,,,,,,EVENTOUT, +PortE,PE12,,TIM2_CH4,,,,SPI1_NSS,,,,,,,,,,EVENTOUT, +PortE,PE13,,,,,,SPI1_SCK,,,,,,,,,,EVENTOUT, +PortE,PE14,,,,,,SPI1_MISO,,,,,,,,,,EVENTOUT, +PortE,PE15,,,,,,SPI1_MOSI,,,,,,,,,,EVENTOUT, +PortF,PF0,,,,,,,,,,,,,,,,EVENTOUT, +PortF,PF1,,,,,,,,,,,,,,,,EVENTOUT, +PortF,PF2,,,,,,,,,,,,,,,,EVENTOUT, +PortF,PF3,,,,,,,,,,,,,,,,EVENTOUT, +PortF,PF4,,,,,,,,,,,,,,,,EVENTOUT, +PortF,PF5,,,,,,,,,,,,,,,,EVENTOUT, +PortF,PF6,,,TIM5_ETR,,,,,,,,,,,,,EVENTOUT, +PortF,PF7,,,TIM5_CH2,,,,,,,,,,,,,EVENTOUT, +PortF,PF8,,,TIM5_CH3,,,,,,,,,,,,,EVENTOUT, +PortF,PF9,,,TIM5_CH4,,,,,,,,,,,,,EVENTOUT, +PortF,PF10,,,,,,,,,,,,,,,,EVENTOUT, +PortF,PF11,,,,,,,,,,,,,,,,EVENTOUT, +PortF,PF12,,,,,,,,,,,,,,,,EVENTOUT, +PortF,PF13,,,,,,,,,,,,,,,,EVENTOUT, +PortF,PF14,,,,,,,,,,,,,,,,EVENTOUT, +PortF,PF15,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG0,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG1,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG2,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG3,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG4,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG5,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG6,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG7,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG8,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG9,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG10,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG11,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG12,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG13,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG14,,,,,,,,,,,,,,,,EVENTOUT, +PortG,PG15,,,,,,,,,,,,,,,,EVENTOUT, +PortH,PH0,,,,,,,,,,,,,,,,, +PortH,PH1,,,,,,,,,,,,,,,,, +PortH,PH2,,,,,,,,,,,,,,,,, diff --git a/ports/stm32/boards/stm32l152xe.ld b/ports/stm32/boards/stm32l152xe.ld new file mode 100644 index 0000000000..32f8444947 --- /dev/null +++ b/ports/stm32/boards/stm32l152xe.ld @@ -0,0 +1,37 @@ +/* + GNU linker script for STM32L152xE +*/ + +/* Specify the memory areas */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K /* entire flash */ + FLASH_FS (rx) : ORIGIN = 0x08064000, LENGTH = 112K /* sectors 100-127 */ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 81408 + FS_CACHE (xrw) : ORIGIN = 0x20013e00, LENGTH = 512 +} + +/* produce a link error if there is not this amount of RAM for these sections */ +_minimum_stack_size = 2K; +_minimum_heap_size = 16K; + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); + +/* Define the stack. The stack is full descending so begins just above last byte + of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; +_sstack = _estack - 16K; /* tunable */ + +/* RAM extents for the garbage collector */ +_ram_start = ORIGIN(RAM); +_ram_end = ORIGIN(RAM) + LENGTH(RAM); +_heap_start = _ebss; /* heap starts just after statically allocated memory */ +_heap_end = _sstack; + +/* Filesystem cache in RAM, and storage in flash */ +_micropy_hw_internal_flash_storage_ram_cache_start = ORIGIN(FS_CACHE); +_micropy_hw_internal_flash_storage_ram_cache_end = ORIGIN(FS_CACHE) + LENGTH(FS_CACHE); +_micropy_hw_internal_flash_storage_start = ORIGIN(FLASH_FS); +_micropy_hw_internal_flash_storage_end = ORIGIN(FLASH_FS) + LENGTH(FLASH_FS); diff --git a/ports/stm32/boards/stm32l1xx_hal_conf_base.h b/ports/stm32/boards/stm32l1xx_hal_conf_base.h new file mode 100644 index 0000000000..b839fd29f0 --- /dev/null +++ b/ports/stm32/boards/stm32l1xx_hal_conf_base.h @@ -0,0 +1,99 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_STM32L1XX_HAL_CONF_BASE_H +#define MICROPY_INCLUDED_STM32L1XX_HAL_CONF_BASE_H + +// Include various HAL modules for convenience +#include "stm32l1xx_hal_rcc.h" +#include "stm32l1xx_hal_gpio.h" +#include "stm32l1xx_hal_dma.h" +#include "stm32l1xx_hal_cortex.h" +#include "stm32l1xx_hal_adc.h" +#include "stm32l1xx_hal_comp.h" +#include "stm32l1xx_hal_crc.h" +#include "stm32l1xx_hal_dac.h" +#include "stm32l1xx_hal_flash.h" +#include "stm32l1xx_hal_i2c.h" +#include "stm32l1xx_hal_iwdg.h" +#include "stm32l1xx_hal_pwr.h" +#include "stm32l1xx_hal_rtc.h" +#include "stm32l1xx_hal_spi.h" +#include "stm32l1xx_hal_tim.h" +#include "stm32l1xx_hal_uart.h" +#include "stm32l1xx_hal_usart.h" +#include "stm32l1xx_hal_wwdg.h" +#include "stm32l1xx_hal_exti.h" +#include "stm32l1xx_ll_adc.h" +#include "stm32l1xx_ll_pwr.h" +#include "stm32l1xx_ll_rtc.h" +#include "stm32l1xx_ll_usart.h" + +// Enable various HAL modules +#define HAL_MODULE_ENABLED +#define HAL_ADC_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED +#define HAL_CRC_MODULE_ENABLED +#define HAL_DAC_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_EXTI_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +#define HAL_SPI_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +#define HAL_WWDG_MODULE_ENABLED + +// Oscillator values in Hz +#define HSE_VALUE (8000000) +#define HSI_VALUE (16000000) +#define HSI48_VALUE (48000000) +#define LSI_VALUE (37000) +#define LSE_VALUE (32768) +#define MSI_VALUE (2097000) + +// Oscillator timeouts in ms +#define HSE_STARTUP_TIMEOUT (100) +#define LSE_STARTUP_TIMEOUT (5000) + +// SysTick has the highest priority +#define TICK_INT_PRIORITY (0x00) + +// Miscellaneous HAL settings +#define DATA_CACHE_ENABLE 1 +#define INSTRUCTION_CACHE_ENABLE 1 +#define PREFETCH_ENABLE 1 +#define USE_SPI_CRC 0 +#define USE_RTOS 0 + +// HAL parameter assertions are disabled +#define assert_param(expr) ((void)0) + +#endif // MICROPY_INCLUDED_STM32L1XX_HAL_CONF_BASE_H diff --git a/ports/stm32/dac.c b/ports/stm32/dac.c index 36ef9387f8..feadbe5c58 100644 --- a/ports/stm32/dac.c +++ b/ports/stm32/dac.c @@ -261,6 +261,8 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp __HAL_RCC_DAC12_CLK_ENABLE(); #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32L4) __HAL_RCC_DAC1_CLK_ENABLE(); + #elif defined(STM32L1) + __HAL_RCC_DAC_CLK_ENABLE(); #else #error Unsupported Processor #endif diff --git a/ports/stm32/dma.c b/ports/stm32/dma.c index 2dc6e8e8b4..29306f1b27 100644 --- a/ports/stm32/dma.c +++ b/ports/stm32/dma.c @@ -80,7 +80,7 @@ typedef union { struct _dma_descr_t { #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) DMA_Stream_TypeDef *instance; - #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL) + #elif defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL) DMA_Channel_TypeDef *instance; #else #error "Unsupported Processor" @@ -398,6 +398,57 @@ static const uint8_t dma_irqn[NSTREAM] = { DMA1_Channel4_5_6_7_IRQn, }; +#elif defined(STM32L1) + +#define NCONTROLLERS (2) +#define NSTREAMS_PER_CONTROLLER (7) +#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER) + +#define DMA_SUB_INSTANCE_AS_UINT8(dma_request) (dma_request) + +#define DMA1_ENABLE_MASK (0x007f) // Bits in dma_enable_mask corresponding to DMA1 +#define DMA2_ENABLE_MASK (0x0f80) // Bits in dma_enable_mask corresponding to DMA2 + +// These descriptors are ordered by DMAx_Channel number, and within a channel by request +// number. The duplicate streams are ok as long as they aren't used at the same time. + +// DMA1 streams +const dma_descr_t dma_SPI_1_RX = { DMA1_Channel2, 2, dma_id_1, &dma_init_struct_spi_i2c }; +#if MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_1_TX = { DMA1_Channel2, 2, dma_id_1, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_1_TX = { DMA1_Channel3, 3, dma_id_2, &dma_init_struct_spi_i2c }; +#if MICROPY_HW_ENABLE_DAC +const dma_descr_t dma_DAC_2_TX = { DMA1_Channel3, 3, dma_id_2, &dma_init_struct_dac }; +#endif +const dma_descr_t dma_SPI_2_RX = { DMA1_Channel4, 4, dma_id_3, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_TX = { DMA1_Channel4, 4, dma_id_3, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, 5, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_2_RX = { DMA1_Channel5, 5, dma_id_4, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_TX = { DMA1_Channel6, 6, dma_id_5, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_I2C_1_RX = { DMA1_Channel7, 7, dma_id_6, &dma_init_struct_spi_i2c }; + +// DMA2 streams +const dma_descr_t dma_SPI_3_RX = { DMA2_Channel1, 3, dma_id_7, &dma_init_struct_spi_i2c }; +const dma_descr_t dma_SPI_3_TX = { DMA2_Channel2, 3, dma_id_8, &dma_init_struct_spi_i2c }; + +static const uint8_t dma_irqn[NSTREAM] = { + DMA1_Channel1_IRQn, + DMA1_Channel2_IRQn, + DMA1_Channel3_IRQn, + DMA1_Channel4_IRQn, + DMA1_Channel5_IRQn, + DMA1_Channel6_IRQn, + DMA1_Channel7_IRQn, + DMA2_Channel1_IRQn, + DMA2_Channel2_IRQn, + DMA2_Channel3_IRQn, + DMA2_Channel4_IRQn, + DMA2_Channel5_IRQn, + 0, + 0 +}; + #elif defined(STM32L4) #define NCONTROLLERS (2) @@ -705,7 +756,7 @@ volatile dma_idle_count_t dma_idle; #define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid -#if defined(STM32F0) || defined(STM32G0) || defined(STM32L0) +#if defined(STM32F0) || defined(STM32G0) || defined(STM32L0) || defined(STM32L1) #define DMA1_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA1EN) != 0) #if defined(DMA2) #define DMA2_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA2EN) != 0) @@ -1080,7 +1131,7 @@ void DMA1_Channel4_5_6_7_IRQHandler(void) { IRQ_EXIT(DMA1_Channel4_5_6_7_IRQn); } -#elif defined(STM32L4) || defined(STM32WB) +#elif defined(STM32L1) || defined(STM32L4) || defined(STM32WB) void DMA1_Channel1_IRQHandler(void) { IRQ_ENTER(DMA1_Channel1_IRQn); @@ -1166,6 +1217,7 @@ void DMA2_Channel5_IRQHandler(void) { } IRQ_EXIT(DMA2_Channel5_IRQn); } +#if !defined(STM32L1) void DMA2_Channel6_IRQHandler(void) { IRQ_ENTER(DMA2_Channel6_IRQn); if (dma_handle[dma_id_12] != NULL) { @@ -1180,6 +1232,7 @@ void DMA2_Channel7_IRQHandler(void) { } IRQ_EXIT(DMA2_Channel7_IRQn); } +#endif #endif @@ -1260,7 +1313,7 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint3 #if defined(STM32G0) || defined(STM32G4) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL) dma->Init.Request = dma_descr->sub_instance; #else - #if !defined(STM32F0) + #if !defined(STM32F0) && !defined(STM32L1) dma->Init.Channel = dma_descr->sub_instance; #endif #endif @@ -1284,7 +1337,7 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint32_t dir dma_enable_clock(dma_id); - #if defined(STM32G0) || defined(STM32G4) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL) + #if defined(STM32G0) || defined(STM32G4) || defined(STM32H7) || defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL) // Always reset and configure the H7 and G0/G4/H7/L0/L4/WB/WL DMA peripheral // (dma->State is set to HAL_DMA_STATE_RESET by memset above) // TODO: understand how L0/L4 DMA works so this is not needed @@ -1410,7 +1463,7 @@ static void dma_idle_handler(uint32_t tick) { } #endif -#if defined(STM32F0) || defined(STM32G4) || defined(STM32L0) || defined(STM32L4) +#if defined(STM32F0) || defined(STM32G4) || defined(STM32L0) || defined(STM32L1) || defined(STM32L4) void dma_nohal_init(const dma_descr_t *descr, uint32_t config) { DMA_Channel_TypeDef *dma = descr->instance; @@ -1436,6 +1489,7 @@ void dma_nohal_init(const dma_descr_t *descr, uint32_t config) { #elif defined(STM32G4) uint32_t *dmamux_ctrl = (void *)(DMAMUX1_Channel0_BASE + 0x04 * descr->id); *dmamux_ctrl = (*dmamux_ctrl & ~(0x7f)) | descr->sub_instance; + #elif defined(STM32L1) #else DMA_Request_TypeDef *dma_ctrl = (void *)(((uint32_t)dma & ~0xff) + (DMA1_CSELR_BASE - DMA1_BASE)); // DMA1_CSELR or DMA2_CSELR uint32_t channel_number = (((uint32_t)dma & 0xff) - 0x08) / 20; // 0 through 6 diff --git a/ports/stm32/dma.h b/ports/stm32/dma.h index 70c7e6a005..37b8710c21 100644 --- a/ports/stm32/dma.h +++ b/ports/stm32/dma.h @@ -100,6 +100,20 @@ extern const dma_descr_t dma_I2C_2_RX; extern const dma_descr_t dma_I2C_1_TX; extern const dma_descr_t dma_I2C_1_RX; +#elif defined(STM32L1) +extern const dma_descr_t dma_SPI_1_RX; +extern const dma_descr_t dma_SPI_3_TX; +extern const dma_descr_t dma_SPI_1_TX; +extern const dma_descr_t dma_SPI_3_RX; +extern const dma_descr_t dma_DAC_1_TX; +extern const dma_descr_t dma_SPI_2_RX; +extern const dma_descr_t dma_I2C_2_TX; +extern const dma_descr_t dma_DAC_2_TX; +extern const dma_descr_t dma_SPI_2_TX; +extern const dma_descr_t dma_I2C_2_RX; +extern const dma_descr_t dma_I2C_1_TX; +extern const dma_descr_t dma_I2C_1_RX; + #elif defined(STM32L4) || defined(STM32WB) || defined(STM32WL) extern const dma_descr_t dma_ADC_1_RX; diff --git a/ports/stm32/extint.c b/ports/stm32/extint.c index ca23261ca7..fd7950de3e 100644 --- a/ports/stm32/extint.c +++ b/ports/stm32/extint.c @@ -210,7 +210,11 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = { #endif ETH_WKUP_IRQn, OTG_HS_WKUP_IRQn, + #if defined(STM32L1) + TAMPER_STAMP_IRQn, + #else TAMP_STAMP_IRQn, + #endif RTC_WKUP_IRQn, #endif diff --git a/ports/stm32/extint.h b/ports/stm32/extint.h index 95e29c97fd..fddcc2ae7a 100644 --- a/ports/stm32/extint.h +++ b/ports/stm32/extint.h @@ -43,7 +43,7 @@ #endif #define EXTI_ETH_WAKEUP (19) #define EXTI_USB_OTG_HS_WAKEUP (20) -#if defined(STM32F0) || defined(STM32G4) || defined(STM32L4) || defined(STM32WL) +#if defined(STM32F0) || defined(STM32G4) || defined(STM32L1) || defined(STM32L4) || defined(STM32WL) #define EXTI_RTC_TIMESTAMP (19) #define EXTI_RTC_WAKEUP (20) #elif defined(STM32H7) || defined(STM32WB) diff --git a/ports/stm32/flash.c b/ports/stm32/flash.c index de537aba21..16af49c3cf 100644 --- a/ports/stm32/flash.c +++ b/ports/stm32/flash.c @@ -117,6 +117,12 @@ static const flash_layout_t flash_layout[] = { { (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 }, }; +#elif defined(STM32L1) + +static const flash_layout_t flash_layout[] = { + { (uint32_t)FLASH_BASE, 0x200, 1024 }, +}; + #elif defined(STM32H7) static const flash_layout_t flash_layout[] = { @@ -264,7 +270,7 @@ int flash_erase(uint32_t flash_dest, uint32_t num_word32) { EraseInitStruct.Page = get_page(flash_dest); EraseInitStruct.Banks = get_bank(flash_dest); EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE; - #elif defined(STM32L0) + #elif defined(STM32L0) || defined(STM32L1) __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR); EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.PageAddress = flash_dest; @@ -286,6 +292,8 @@ int flash_erase(uint32_t flash_dest, uint32_t num_word32) { #if defined(STM32H7) __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS_BANK1 | FLASH_FLAG_ALL_ERRORS_BANK2); + #elif defined(STM32L1) + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR); #else __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); diff --git a/ports/stm32/machine_adc.c b/ports/stm32/machine_adc.c index 000b478f86..1a478cd1cf 100644 --- a/ports/stm32/machine_adc.c +++ b/ports/stm32/machine_adc.c @@ -42,7 +42,7 @@ #define ADCx_COMMON __LL_ADC_COMMON_INSTANCE(0) #endif -#if defined(STM32F0) || defined(STM32G0) || defined(STM32L0) || defined(STM32WL) +#if defined(STM32F0) || defined(STM32G0) || defined(STM32L0) || defined(STM32L1) || defined(STM32WL) #define ADC_STAB_DELAY_US (1) #define ADC_TEMPSENSOR_DELAY_US (10) #elif defined(STM32G4) @@ -68,6 +68,9 @@ #elif defined(STM32G0) || defined(STM32L0) || defined(STM32WL) #define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_12CYCLES_5 #define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_160CYCLES_5 +#elif defined(STM32L1) +#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_384CYCLES +#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_384CYCLES #elif defined(STM32L4) || defined(STM32WB) #define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_12CYCLES_5 #define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_247CYCLES_5 @@ -239,7 +242,7 @@ void adc_config(ADC_TypeDef *adc, uint32_t bits) { STATIC int adc_get_bits(ADC_TypeDef *adc) { #if defined(STM32F0) || defined(STM32G0) || defined(STM32L0) || defined(STM32WL) uint32_t res = (adc->CFGR1 & ADC_CFGR1_RES) >> ADC_CFGR1_RES_Pos; - #elif defined(STM32F4) || defined(STM32F7) + #elif defined(STM32F4) || defined(STM32F7) || defined(STM32L1) uint32_t res = (adc->CR1 & ADC_CR1_RES) >> ADC_CR1_RES_Pos; #elif defined(STM32G4) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB) uint32_t res = (adc->CFGR & ADC_CFGR_RES) >> ADC_CFGR_RES_Pos; diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index acedac7a59..e1796d1cf0 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -138,7 +138,7 @@ void machine_init(void) { if (state & RCC_SR_IWDGRSTF || state & RCC_SR_WWDGRSTF) { reset_cause = PYB_RESET_WDT; } else if (state & RCC_SR_PORRSTF - #if !defined(STM32F0) && !defined(STM32F412Zx) + #if !defined(STM32F0) && !defined(STM32F412Zx) && !defined(STM32L1) || state & RCC_SR_BORRSTF #endif ) { @@ -309,7 +309,7 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) { return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple); } else { // set - #if defined(STM32F0) || defined(STM32L0) || defined(STM32L4) || defined(STM32G0) + #if defined(STM32F0) || defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32G0) mp_raise_NotImplementedError(MP_ERROR_TEXT("machine.freq set not supported yet")); #else mp_int_t sysclk = mp_obj_get_int(args[0]); diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h index 51bad18dd5..b538f78235 100644 --- a/ports/stm32/mpconfigboard_common.h +++ b/ports/stm32/mpconfigboard_common.h @@ -370,6 +370,16 @@ #define MICROPY_HW_MAX_UART (5) #define MICROPY_HW_MAX_LPUART (1) +// Configuration for STM32L1 series +#elif defined(STM32L1) +#define MP_HAL_UNIQUE_ID_ADDRESS (UID_BASE) +#define PYB_EXTI_NUM_VECTORS (23) +#define MICROPY_HW_MAX_I2C (2) +// TODO: L1 has 9 timers but tim0 and tim1 don't exist. +#define MICROPY_HW_MAX_TIMER (11) +#define MICROPY_HW_MAX_UART (5) +#define MICROPY_HW_MAX_LPUART (0) + // Configuration for STM32L4 series #elif defined(STM32L4) diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c index 619bde69bf..092d63e1bb 100644 --- a/ports/stm32/mphalport.c +++ b/ports/stm32/mphalport.c @@ -87,7 +87,7 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { // This logic assumes that all the GPIOx_EN bits are adjacent and ordered in one register - #if defined(STM32F0) + #if defined(STM32F0) || defined(STM32L1) #define AHBxENR AHBENR #define AHBxENR_GPIOAEN_Pos RCC_AHBENR_GPIOAEN_Pos #elif defined(STM32F4) || defined(STM32F7) diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h index 358d9cd25d..5c587c016d 100644 --- a/ports/stm32/mphalport.h +++ b/ports/stm32/mphalport.h @@ -17,6 +17,8 @@ #define MICROPY_PLATFORM_VERSION "HAL1.6.0" #elif defined(STM32L0) #define MICROPY_PLATFORM_VERSION "HAL1.11.2" +#elif defined(STM32L1) +#define MICROPY_PLATFORM_VERSION "HAL1.10.3" #elif defined(STM32L4) #define MICROPY_PLATFORM_VERSION "HAL1.17.0" #elif defined(STM32WB) diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index f3f1837ece..c0a0595e5d 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -143,7 +143,7 @@ void powerctrl_check_enter_bootloader(void) { if (BL_STATE_GET_KEY(bl_state) == BL_STATE_KEY && (RCC->RCC_SR & RCC_SR_SFTRSTF)) { // Reset by NVIC_SystemReset with bootloader data set -> branch to bootloader RCC->RCC_SR = RCC_SR_RMVF; - #if defined(STM32F0) || defined(STM32F4) || defined(STM32G0) || defined(STM32G4) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) + #if defined(STM32F0) || defined(STM32F4) || defined(STM32G0) || defined(STM32G4) || defined(STM32L0) || defined(STM32L1) || defined(STM32L4) || defined(STM32WB) __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); #endif branch_to_bootloader(BL_STATE_GET_REG(bl_state), BL_STATE_GET_ADDR(bl_state)); @@ -286,7 +286,7 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk #endif -#if !defined(STM32F0) && !defined(STM32G0) && !defined(STM32L0) && !defined(STM32L4) +#if !defined(STM32F0) && !defined(STM32G0) && !defined(STM32L0) && !defined(STM32L1) && !defined(STM32L4) STATIC uint32_t calc_ahb_div(uint32_t wanted_div) { #if defined(STM32H7) @@ -708,7 +708,7 @@ void powerctrl_enter_stop_mode(void) { __HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI); #endif - #if !defined(STM32F0) && !defined(STM32G0) && !defined(STM32G4) && !defined(STM32L0) && !defined(STM32L4) && !defined(STM32WB) && !defined(STM32WL) + #if !defined(STM32F0) && !defined(STM32G0) && !defined(STM32G4) && !defined(STM32L0) && !defined(STM32L1) && !defined(STM32L4) && !defined(STM32WB) && !defined(STM32WL) // takes longer to wake but reduces stop current HAL_PWREx_EnableFlashPowerDown(); #endif diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c index 555457c582..61d48ffe5c 100644 --- a/ports/stm32/powerctrlboot.c +++ b/ports/stm32/powerctrlboot.c @@ -228,6 +228,74 @@ void SystemClock_Config(void) { #endif } +#elif defined(STM32L1) + +void SystemClock_Config(void) { + // Enable power control peripheral + __HAL_RCC_PWR_CLK_ENABLE(); + + // Set power voltage scaling + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + // Enable the FLASH 64-bit access + FLASH->ACR = FLASH_ACR_ACC64; + // Set flash latency to 1 because SYSCLK > 16MHz + FLASH->ACR |= MICROPY_HW_FLASH_LATENCY; + + #if MICROPY_HW_CLK_USE_HSI + // Enable the 16MHz internal oscillator + RCC->CR |= RCC_CR_HSION; + while (!(RCC->CR & RCC_CR_HSIRDY)) { + } + RCC->CFGR = RCC_CFGR_PLLSRC_HSI; + #else + // Enable the 8MHz external oscillator + RCC->CR |= RCC_CR_HSEBYP; + RCC->CR |= RCC_CR_HSEON; + while (!(RCC->CR & RCC_CR_HSERDY)) { + } + RCC->CFGR = RCC_CFGR_PLLSRC_HSE; + #endif + // Use HSI16 and the PLL to get a 32MHz SYSCLK + RCC->CFGR |= MICROPY_HW_CLK_PLLMUL | MICROPY_HW_CLK_PLLDIV; + RCC->CR |= RCC_CR_PLLON; + while (!(RCC->CR & RCC_CR_PLLRDY)) { + // Wait for PLL to lock + } + RCC->CFGR |= RCC_CFGR_SW_PLL; + + while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) { + // Wait for SYSCLK source to change + } + + SystemCoreClockUpdate(); + powerctrl_config_systick(); + + #if MICROPY_HW_ENABLE_USB + // Enable the 48MHz internal oscillator + RCC->CRRCR |= RCC_CRRCR_HSI48ON; + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; + SYSCFG->CFGR3 |= SYSCFG_CFGR3_ENREF_HSI48; + while (!(RCC->CRRCR & RCC_CRRCR_HSI48RDY)) { + // Wait for HSI48 to be ready + } + + // Select RC48 as HSI48 for USB and RNG + RCC->CCIPR |= RCC_CCIPR_HSI48SEL; + + // Synchronise HSI48 with 1kHz USB SoF + __HAL_RCC_CRS_CLK_ENABLE(); + CRS->CR = 0x20 << CRS_CR_TRIM_Pos; + CRS->CFGR = 2 << CRS_CFGR_SYNCSRC_Pos | 0x22 << CRS_CFGR_FELIM_Pos + | __HAL_RCC_CRS_RELOADVALUE_CALCULATE(48000000, 1000) << CRS_CFGR_RELOAD_Pos; + #endif + + // Disable the Debug Module in low-power mode due to prevent + // unexpected HardFault after __WFI(). + #if !defined(NDEBUG) + DBGMCU->CR &= ~(DBGMCU_CR_DBG_SLEEP | DBGMCU_CR_DBG_STOP | DBGMCU_CR_DBG_STANDBY); + #endif +} #elif defined(STM32WB) #include "stm32wbxx_ll_hsem.h" diff --git a/ports/stm32/resethandler_m3.s b/ports/stm32/resethandler_m3.s new file mode 100644 index 0000000000..05a44306e1 --- /dev/null +++ b/ports/stm32/resethandler_m3.s @@ -0,0 +1,75 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .syntax unified + .cpu cortex-m3 + .fpu softvfp + .thumb + + .section .text.Reset_Handler + .global Reset_Handler + .type Reset_Handler, %function + +Reset_Handler: + /* Save the first argument to pass through to stm32_main */ + mov r4, r0 + + /* Load the stack pointer */ + ldr r0, =_estack + mov sp, r0 + + /* Initialise the data section */ + ldr r1, =_sidata + ldr r2, =_sdata + ldr r3, =_edata + b .data_copy_entry +.data_copy_loop: + ldr r0, [r1] + adds r1, #4 + str r0, [r2] + adds r2, #4 +.data_copy_entry: + cmp r2, r3 + bcc .data_copy_loop + + /* Zero out the BSS section */ + movs r0, #0 + ldr r1, =_sbss + ldr r2, =_ebss + b .bss_zero_entry +.bss_zero_loop: + str r0, [r1] + adds r1, #4 +.bss_zero_entry: + cmp r1, r2 + bcc .bss_zero_loop + + /* Initialise the system and jump to the main code */ + bl SystemInit + mov r0, r4 + bl stm32_main + + .size Reset_Handler, .-Reset_Handler diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index aacfc3805e..874e427cff 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -91,6 +91,15 @@ STATIC bool rtc_need_init_finalise = false; #define RCC_BDCR_LSEON RCC_CSR_LSEON #define RCC_BDCR_LSERDY RCC_CSR_LSERDY #define RCC_BDCR_LSEBYP RCC_CSR_LSEBYP +#elif defined(STM32L1) +#define BDCR CR +#define RCC_BDCR_RTCEN RCC_CSR_RTCEN +#define RCC_BDCR_RTCSEL RCC_CSR_RTCSEL +#define RCC_BDCR_RTCSEL_0 RCC_CSR_RTCSEL_0 +#define RCC_BDCR_RTCSEL_1 RCC_CSR_RTCSEL_1 +#define RCC_BDCR_LSEON RCC_CSR_LSEON +#define RCC_BDCR_LSERDY RCC_CSR_LSERDY +#define RCC_BDCR_LSEBYP RCC_CSR_LSEBYP #endif void rtc_init_start(bool force_init) { @@ -664,7 +673,15 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { wucksel -= 1; } if (div <= 16) { + #if defined(STM32L1) + if (rtc_use_lse) { + wut = LSE_VALUE / div * ms / 1000; + } else { + wut = LSI_VALUE / div * ms / 1000; + } + #else wut = 32768 / div * ms / 1000; + #endif } else { // use 1Hz clock wucksel = 4; diff --git a/ports/stm32/stm32.mk b/ports/stm32/stm32.mk index c55b243fe5..b4f73a67f3 100644 --- a/ports/stm32/stm32.mk +++ b/ports/stm32/stm32.mk @@ -48,7 +48,7 @@ CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard SUPPORTS_HARDWARE_FP_SINGLE = 1 SUPPORTS_HARDWARE_FP_DOUBLE = 1 else -ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 g0 l0 wl)) +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 g0 l0 l1 wl)) CFLAGS_CORTEX_M += -msoft-float else CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard @@ -64,6 +64,7 @@ CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 CFLAGS_MCU_g0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0plus -mcpu=cortex-m0plus CFLAGS_MCU_g4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 CFLAGS_MCU_l0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0plus -mcpu=cortex-m0plus +CFLAGS_MCU_l1 = $(CFLAGS_CORTEX_M) -mtune=cortex-m3 -mcpu=cortex-m3 CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7 CFLAGS_MCU_wb = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4 diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 2f89f67deb..c260499218 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -520,11 +520,19 @@ void ETH_WKUP_IRQHandler(void) { } #endif +#if defined(STM32L1) +void TAMPER_STAMP_IRQHandler(void) { + IRQ_ENTER(TAMPER_STAMP_IRQn); + Handle_EXTI_Irq(EXTI_RTC_TIMESTAMP); + IRQ_EXIT(TAMPER_STAMP_IRQn); +} +#else void TAMP_STAMP_IRQHandler(void) { IRQ_ENTER(TAMP_STAMP_IRQn); Handle_EXTI_Irq(EXTI_RTC_TIMESTAMP); IRQ_EXIT(TAMP_STAMP_IRQn); } +#endif void RTC_WKUP_IRQHandler(void) { IRQ_ENTER(RTC_WKUP_IRQn); @@ -698,6 +706,12 @@ void TIM6_DAC_LPTIM1_IRQHandler(void) { timer_irq_handler(6); IRQ_EXIT(TIM6_DAC_LPTIM1_IRQn); } +#elif defined(STM32L1) +void TIM6_IRQHandler(void) { + IRQ_ENTER(TIM6_IRQn); + timer_irq_handler(6); + IRQ_EXIT(TIM6_IRQn); +} #else void TIM6_DAC_IRQHandler(void) { IRQ_ENTER(TIM6_DAC_IRQn); @@ -764,6 +778,26 @@ void TIM8_TRG_COM_TIM14_IRQHandler(void) { } #endif +#if defined(STM32L1) +void TIM9_IRQHandler(void) { + IRQ_ENTER(TIM9_IRQn); + timer_irq_handler(9); + IRQ_EXIT(TIM9_IRQn); +} + +void TIM10_IRQHandler(void) { + IRQ_ENTER(TIM9_IRQn); + timer_irq_handler(10); + IRQ_EXIT(TIM9_IRQn); +} + +void TIM11_IRQHandler(void) { + IRQ_ENTER(TIM9_IRQn); + timer_irq_handler(11); + IRQ_EXIT(TIM9_IRQn); +} +#endif + #if defined(STM32G0) void TIM14_IRQHandler(void) { IRQ_ENTER(TIM14_IRQn); diff --git a/ports/stm32/timer.c b/ports/stm32/timer.c index 7a6ccd4dfd..8816c218f5 100644 --- a/ports/stm32/timer.c +++ b/ports/stm32/timer.c @@ -431,7 +431,7 @@ STATIC mp_obj_t compute_percent_from_pwm_value(uint32_t period, uint32_t cmp) { #endif } -#if !defined(STM32L0) +#if !defined(STM32L0) && !defined(STM32L1) // Computes the 8-bit value for the DTG field in the BDTR register. // @@ -522,7 +522,7 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV4 ? 4 : self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV2 ? 2 : 1); - #if !defined(STM32L0) + #if !defined(STM32L0) && !defined(STM32L1) #if defined(IS_TIM_ADVANCED_INSTANCE) if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance)) #elif defined(IS_TIM_BREAK_INSTANCE) @@ -640,7 +640,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons args[ARG_div].u_int == 4 ? TIM_CLOCKDIVISION_DIV4 : TIM_CLOCKDIVISION_DIV1; - #if !defined(STM32L0) + #if !defined(STM32L0) && !defined(STM32L1) init->RepetitionCounter = 0; #endif @@ -772,7 +772,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons // init TIM HAL_TIM_Base_Init(&self->tim); - #if !defined(STM32L0) + #if !defined(STM32L0) && !defined(STM32L1) #if defined(IS_TIM_ADVANCED_INSTANCE) if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance)) #elif defined(IS_TIM_BREAK_INSTANCE) @@ -833,7 +833,7 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { TIM_ENTRY(5, TIM5_IRQn), #endif #if defined(TIM6) - #if defined(STM32F412Zx) + #if defined(STM32F412Zx) || defined(STM32L1) TIM_ENTRY(6, TIM6_IRQn), #elif defined(STM32G0) TIM_ENTRY(6, TIM6_DAC_LPTIM1_IRQn), @@ -858,14 +858,26 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = { #endif #endif #if defined(TIM9) + #if defined(STM32L1) + TIM_ENTRY(9, TIM9_IRQn), + #else TIM_ENTRY(9, TIM1_BRK_TIM9_IRQn), #endif + #endif #if defined(TIM10) + #if defined(STM32L1) + TIM_ENTRY(10, TIM10_IRQn), + #else TIM_ENTRY(10, TIM1_UP_TIM10_IRQn), #endif + #endif #if defined(TIM11) + #if defined(STM32L1) + TIM_ENTRY(11, TIM11_IRQn), + #else TIM_ENTRY(11, TIM1_TRG_COM_TIM11_IRQn), #endif + #endif #if defined(TIM12) TIM_ENTRY(12, TIM8_BRK_TIM12_IRQn), #endif @@ -936,7 +948,11 @@ STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, size_t n_args, siz memset(tim, 0, sizeof(*tim)); tim->base.type = &pyb_timer_type; tim->tim_id = tim_id; + #if defined(STM32L1) + tim->is_32bit = tim_id == 5; + #else tim->is_32bit = tim_id == 2 || tim_id == 5; + #endif tim->callback = mp_const_none; uint32_t ti = tim_instance_table[tim_id - 1]; tim->tim.Instance = (TIM_TypeDef *)(ti & 0xffffff00); @@ -1168,7 +1184,7 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma } oc_config.OCPolarity = TIM_OCPOLARITY_HIGH; oc_config.OCFastMode = TIM_OCFAST_DISABLE; - #if !defined(STM32L0) + #if !defined(STM32L0) && !defined(STM32L1) oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH; oc_config.OCIdleState = TIM_OCIDLESTATE_SET; oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET; @@ -1180,7 +1196,7 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma } else { pyb_timer_channel_callback(MP_OBJ_FROM_PTR(chan), chan->callback); } - #if !defined(STM32L0) + #if !defined(STM32L0) && !defined(STM32L1) // Start the complimentary channel too (if its supported) if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) { HAL_TIMEx_PWMN_Start(&self->tim, TIMER_CHANNEL(chan)); @@ -1203,7 +1219,7 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma oc_config.OCPolarity = TIM_OCPOLARITY_HIGH; } oc_config.OCFastMode = TIM_OCFAST_DISABLE; - #if !defined(STM32L0) + #if !defined(STM32L0) && !defined(STM32L1) if (oc_config.OCPolarity == TIM_OCPOLARITY_HIGH) { oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH; } else { @@ -1222,7 +1238,7 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma } else { pyb_timer_channel_callback(MP_OBJ_FROM_PTR(chan), chan->callback); } - #if !defined(STM32L0) + #if !defined(STM32L0) && !defined(STM32L1) // Start the complimentary channel too (if its supported) if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) { HAL_TIMEx_OCN_Start(&self->tim, TIMER_CHANNEL(chan)); diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index cea49f4ba1..6d1240cf8d 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -38,7 +38,7 @@ #include "irq.h" #include "pendsv.h" -#if defined(STM32F4) +#if defined(STM32F4) || defined(STM32L1) #define UART_RXNE_IS_SET(uart) ((uart)->SR & USART_SR_RXNE) #else #if defined(STM32G0) || defined(STM32H7) || defined(STM32WL) @@ -101,6 +101,11 @@ #define USART_CR2_IE_ALL (USART_CR2_IE_BASE) #define USART_CR3_IE_ALL (USART_CR3_IE_BASE | USART_CR3_WUFIE) +#elif defined(STM32L1) +#define USART_CR1_IE_ALL (USART_CR1_IE_BASE) +#define USART_CR2_IE_ALL (USART_CR2_IE_BASE) +#define USART_CR3_IE_ALL (USART_CR3_IE_BASE) + #elif defined(STM32L4) || defined(STM32WB) || defined(STM32WL) #define USART_CR1_IE_ALL (USART_CR1_IE_BASE | USART_CR1_EOBIE | USART_CR1_RTOIE | USART_CR1_CMIE) #define USART_CR2_IE_ALL (USART_CR2_IE_BASE) @@ -580,7 +585,7 @@ bool uart_init(pyb_uart_obj_t *uart_obj, huart.FifoMode = UART_FIFOMODE_ENABLE; #endif - #if !defined(STM32F4) + #if !defined(STM32F4) && !defined(STM32L1) huart.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; #endif @@ -1016,7 +1021,7 @@ STATIC bool uart_wait_flag_set(pyb_uart_obj_t *self, uint32_t flag, uint32_t tim // an interrupt and the flag can be set quickly if the baudrate is large. uint32_t start = HAL_GetTick(); for (;;) { - #if defined(STM32F4) + #if defined(STM32F4) || defined(STM32L1) if (self->uartx->SR & flag) { return true; } @@ -1071,7 +1076,7 @@ size_t uart_tx_data(pyb_uart_obj_t *self, const void *src_in, size_t num_chars, } else { data = *src++; } - #if defined(STM32F4) + #if defined(STM32F4) || defined(STM32L1) uart->DR = data; #else uart->TDR = data; @@ -1109,7 +1114,7 @@ void uart_irq_handler(mp_uint_t uart_id) { } // Capture IRQ status flags. - #if defined(STM32F4) + #if defined(STM32F4) || defined(STM32L1) self->mp_irq_flags = self->uartx->SR; bool rxne_is_set = self->mp_irq_flags & USART_SR_RXNE; bool did_clear_sr = false; @@ -1153,7 +1158,7 @@ void uart_irq_handler(mp_uint_t uart_id) { } // Clear other interrupt flags that can trigger this IRQ handler. - #if defined(STM32F4) + #if defined(STM32F4) || defined(STM32L1) if (did_clear_sr) { // SR was cleared above. Re-enable IDLE if it should be enabled. if (self->mp_irq_trigger & UART_FLAG_IDLE) { diff --git a/ports/stm32/uart.h b/ports/stm32/uart.h index ec8a27591c..61d1ac4397 100644 --- a/ports/stm32/uart.h +++ b/ports/stm32/uart.h @@ -103,7 +103,7 @@ size_t uart_tx_data(pyb_uart_obj_t *self, const void *src_in, size_t num_chars, void uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len); static inline bool uart_tx_avail(pyb_uart_obj_t *self) { - #if defined(STM32F4) + #if defined(STM32F4) || defined(STM32L1) return self->uartx->SR & USART_SR_TXE; #elif defined(STM32G0) || defined(STM32H7) || defined(STM32WL) return self->uartx->ISR & USART_ISR_TXE_TXFNF;