summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/stm32/Makefile7
-rw-r--r--ports/stm32/adc.c55
-rw-r--r--ports/stm32/boards/stm32l152_af.csv117
-rw-r--r--ports/stm32/boards/stm32l152xe.ld37
-rw-r--r--ports/stm32/boards/stm32l1xx_hal_conf_base.h99
-rw-r--r--ports/stm32/dac.c2
-rw-r--r--ports/stm32/dma.c66
-rw-r--r--ports/stm32/dma.h14
-rw-r--r--ports/stm32/extint.c4
-rw-r--r--ports/stm32/extint.h2
-rw-r--r--ports/stm32/flash.c10
-rw-r--r--ports/stm32/machine_adc.c7
-rw-r--r--ports/stm32/modmachine.c4
-rw-r--r--ports/stm32/mpconfigboard_common.h10
-rw-r--r--ports/stm32/mphalport.c2
-rw-r--r--ports/stm32/mphalport.h2
-rw-r--r--ports/stm32/powerctrl.c6
-rw-r--r--ports/stm32/powerctrlboot.c68
-rw-r--r--ports/stm32/resethandler_m3.s75
-rw-r--r--ports/stm32/rtc.c17
-rw-r--r--ports/stm32/stm32.mk3
-rw-r--r--ports/stm32/stm32_it.c34
-rw-r--r--ports/stm32/timer.c34
-rw-r--r--ports/stm32/uart.c17
-rw-r--r--ports/stm32/uart.h2
25 files changed, 657 insertions, 37 deletions
diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index ee00d7717..4b4a9f0ce 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 712e9b3ad..02bbbb58d 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 000000000..a6f8e80c3
--- /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 000000000..32f844494
--- /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 000000000..b839fd29f
--- /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 36ef9387f..feadbe5c5 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 2dc6e8e8b..29306f1b2 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 70c7e6a00..37b8710c2 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 ca23261ca..fd7950de3 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 95e29c97f..fddcc2ae7 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 de537aba2..16af49c3c 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 000b478f8..1a478cd1c 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 acedac7a5..e1796d1cf 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 51bad18dd..b538f7823 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 619bde69b..092d63e1b 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 358d9cd25..5c587c016 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 f3f1837ec..c0a0595e5 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 555457c58..61d48ffe5 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 000000000..05a44306e
--- /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 aacfc3805..874e427cf 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 c55b243fe..b4f73a67f 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 2f89f67de..c26049921 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 7a6ccd4df..8816c218f 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 cea49f4ba..6d1240cf8 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 ec8a27591..61d1ac439 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;