stm32: Add initial support for STM32L0xx MCUs.
This commit is contained in:
parent
fa5c0b819c
commit
23d9c6a0fd
|
@ -64,7 +64,7 @@ CFLAGS_CORTEX_M = -mthumb
|
|||
ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F765xx STM32F767xx STM32F769xx STM32H743xx))
|
||||
CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard
|
||||
else
|
||||
ifeq ($(MCU_SERIES),f0)
|
||||
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 l0))
|
||||
CFLAGS_CORTEX_M += -msoft-float
|
||||
else
|
||||
CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard
|
||||
|
@ -75,6 +75,7 @@ endif
|
|||
CFLAGS_MCU_f0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0 -mcpu=cortex-m0
|
||||
CFLAGS_MCU_f4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
|
||||
CFLAGS_MCU_f7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
|
||||
CFLAGS_MCU_l0 = $(CFLAGS_CORTEX_M) -mtune=cortex-m0plus -mcpu=cortex-m0plus
|
||||
CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
|
||||
CFLAGS_MCU_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
|
||||
|
||||
|
@ -200,7 +201,7 @@ SRC_LIBM = $(addprefix lib/libm/,\
|
|||
wf_lgamma.c \
|
||||
wf_tgamma.c \
|
||||
)
|
||||
ifeq ($(MCU_SERIES),f0)
|
||||
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f0 l0))
|
||||
SRC_LIBM += lib/libm/ef_sqrt.c
|
||||
else
|
||||
SRC_LIBM += lib/libm/thumb_vfp_sqrtf.c
|
||||
|
@ -289,12 +290,21 @@ SRC_O = \
|
|||
resethandler_m0.o \
|
||||
lib/utils/gchelper_m0.o
|
||||
else
|
||||
ifeq ($(MCU_SERIES),l0)
|
||||
CSUPEROPT = -Os # save some code space
|
||||
SRC_O = \
|
||||
$(STARTUP_FILE) \
|
||||
lib/stm32lib/CMSIS/STM32$(MCU_SERIES_UPPER)xx/Source/Templates/system_stm32$(MCU_SERIES)xx.o \
|
||||
resethandler_m0.o \
|
||||
lib/utils/gchelper_m0.o
|
||||
else
|
||||
SRC_O = \
|
||||
$(STARTUP_FILE) \
|
||||
system_stm32.o \
|
||||
resethandler.o \
|
||||
lib/utils/gchelper_m3.o
|
||||
endif
|
||||
endif
|
||||
|
||||
SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
|
||||
hal.c \
|
||||
|
@ -341,8 +351,10 @@ endif
|
|||
ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx))
|
||||
SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c)
|
||||
else
|
||||
ifneq ($(MCU_SERIES),$(filter $(MCU_SERIES),l0))
|
||||
SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_can.c)
|
||||
endif
|
||||
endif
|
||||
|
||||
SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\
|
||||
core/src/usbd_core.c \
|
||||
|
|
|
@ -70,7 +70,7 @@ typedef union {
|
|||
struct _dma_descr_t {
|
||||
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
|
||||
DMA_Stream_TypeDef *instance;
|
||||
#elif defined(STM32F0) || defined(STM32L4)
|
||||
#elif defined(STM32F0) || defined(STM32L0) || defined(STM32L4)
|
||||
DMA_Channel_TypeDef *instance;
|
||||
#else
|
||||
#error "Unsupported Processor"
|
||||
|
@ -310,6 +310,47 @@ static const uint8_t dma_irqn[NSTREAM] = {
|
|||
DMA2_Stream7_IRQn,
|
||||
};
|
||||
|
||||
#elif defined(STM32L0)
|
||||
|
||||
#define NCONTROLLERS (1)
|
||||
#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
|
||||
|
||||
// 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, DMA_REQUEST_1, dma_id_1, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_I2C_3_TX = { DMA1_Channel2, DMA_REQUEST_3, dma_id_1, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_SPI_1_TX = { DMA1_Channel3, DMA_REQUEST_1, dma_id_2, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_I2C_3_RX = { DMA1_Channel3, DMA_REQUEST_3, dma_id_2, &dma_init_struct_spi_i2c };
|
||||
#if MICROPY_HW_ENABLE_DAC
|
||||
const dma_descr_t dma_DAC_1_TX = { DMA1_Channel3, DMA_REQUEST_6, dma_id_2, &dma_init_struct_dac };
|
||||
#endif
|
||||
const dma_descr_t dma_SPI_2_RX = { DMA1_Channel4, DMA_REQUEST_1, dma_id_3, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_I2C_2_TX = { DMA1_Channel4, DMA_REQUEST_3, dma_id_3, &dma_init_struct_spi_i2c };
|
||||
#if MICROPY_HW_ENABLE_DAC
|
||||
const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, DMA_REQUEST_5, dma_id_3, &dma_init_struct_dac };
|
||||
#endif
|
||||
const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, DMA_REQUEST_1, dma_id_4, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_I2C_2_RX = { DMA1_Channel5, DMA_REQUEST_3, dma_id_4, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_I2C_1_TX = { DMA1_Channel6, DMA_REQUEST_3, dma_id_5, &dma_init_struct_spi_i2c };
|
||||
const dma_descr_t dma_I2C_1_RX = { DMA1_Channel7, DMA_REQUEST_3, dma_id_6, &dma_init_struct_spi_i2c };
|
||||
|
||||
static const uint8_t dma_irqn[NSTREAM] = {
|
||||
DMA1_Channel1_IRQn,
|
||||
DMA1_Channel2_3_IRQn,
|
||||
DMA1_Channel4_5_6_7_IRQn,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
#elif defined(STM32L4)
|
||||
|
||||
#define NCONTROLLERS (2)
|
||||
|
@ -459,9 +500,11 @@ volatile dma_idle_count_t dma_idle;
|
|||
|
||||
#define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid
|
||||
|
||||
#if defined(STM32F0)
|
||||
#if defined(STM32F0) || defined(STM32L0)
|
||||
#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)
|
||||
#endif
|
||||
#else
|
||||
#define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0)
|
||||
#define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0)
|
||||
|
@ -526,6 +569,44 @@ void DMA2_Stream5_IRQHandler(void) { IRQ_ENTER(DMA2_Stream5_IRQn); if (dma_handl
|
|||
void DMA2_Stream6_IRQHandler(void) { IRQ_ENTER(DMA2_Stream6_IRQn); if (dma_handle[dma_id_14] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_14]); } IRQ_EXIT(DMA2_Stream6_IRQn); }
|
||||
void DMA2_Stream7_IRQHandler(void) { IRQ_ENTER(DMA2_Stream7_IRQn); if (dma_handle[dma_id_15] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_15]); } IRQ_EXIT(DMA2_Stream7_IRQn); }
|
||||
|
||||
#elif defined(STM32L0)
|
||||
|
||||
void DMA1_Channel1_IRQHandler(void) {
|
||||
IRQ_ENTER(DMA1_Channel1_IRQn);
|
||||
if (dma_handle[dma_id_0] != NULL) {
|
||||
HAL_DMA_IRQHandler(dma_handle[dma_id_0]);
|
||||
}
|
||||
IRQ_EXIT(DMA1_Channel1_IRQn);
|
||||
}
|
||||
|
||||
void DMA1_Channel2_3_IRQHandler(void) {
|
||||
IRQ_ENTER(DMA1_Channel2_3_IRQn);
|
||||
if (dma_handle[dma_id_1] != NULL) {
|
||||
HAL_DMA_IRQHandler(dma_handle[dma_id_1]);
|
||||
}
|
||||
if (dma_handle[dma_id_2] != NULL) {
|
||||
HAL_DMA_IRQHandler(dma_handle[dma_id_2]);
|
||||
}
|
||||
IRQ_EXIT(DMA1_Channel2_3_IRQn);
|
||||
}
|
||||
|
||||
void DMA1_Channel4_5_6_7_IRQHandler(void) {
|
||||
IRQ_ENTER(DMA1_Channel4_5_6_7_IRQn);
|
||||
if (dma_handle[dma_id_3] != NULL) {
|
||||
HAL_DMA_IRQHandler(dma_handle[dma_id_3]);
|
||||
}
|
||||
if (dma_handle[dma_id_4] != NULL) {
|
||||
HAL_DMA_IRQHandler(dma_handle[dma_id_4]);
|
||||
}
|
||||
if (dma_handle[dma_id_5] != NULL) {
|
||||
HAL_DMA_IRQHandler(dma_handle[dma_id_5]);
|
||||
}
|
||||
if (dma_handle[dma_id_6] != NULL) {
|
||||
HAL_DMA_IRQHandler(dma_handle[dma_id_6]);
|
||||
}
|
||||
IRQ_EXIT(DMA1_Channel4_5_6_7_IRQn);
|
||||
}
|
||||
|
||||
#elif defined(STM32L4)
|
||||
|
||||
void DMA1_Channel1_IRQHandler(void) { IRQ_ENTER(DMA1_Channel1_IRQn); if (dma_handle[dma_id_0] != NULL) { HAL_DMA_IRQHandler(dma_handle[dma_id_0]); } IRQ_EXIT(DMA1_Channel1_IRQn); }
|
||||
|
@ -572,18 +653,21 @@ static void dma_enable_clock(dma_id_t dma_id) {
|
|||
dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
#if defined(DMA2)
|
||||
else {
|
||||
if (((old_enable_mask & DMA2_ENABLE_MASK) == 0) && !DMA2_IS_CLK_ENABLED()) {
|
||||
__HAL_RCC_DMA2_CLK_ENABLE();
|
||||
|
||||
// We just turned on the clock. This means that anything stored
|
||||
// in dma_last_channel (for DMA1) needs to be invalidated.
|
||||
// in dma_last_channel (for DMA2) needs to be invalidated.
|
||||
|
||||
for (int channel = NSTREAMS_PER_CONTROLLER; channel < NSTREAM; channel++) {
|
||||
dma_last_sub_instance[channel] = DMA_INVALID_CHANNEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dma_disable_clock(dma_id_t dma_id) {
|
||||
|
@ -599,7 +683,7 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, uint3
|
|||
dma->Instance = dma_descr->instance;
|
||||
dma->Init = *dma_descr->init;
|
||||
dma->Init.Direction = dir;
|
||||
#if defined(STM32L4) || defined(STM32H7)
|
||||
#if defined(STM32L0) || defined(STM32L4) || defined(STM32H7)
|
||||
dma->Init.Request = dma_descr->sub_instance;
|
||||
#else
|
||||
#if !defined(STM32F0)
|
||||
|
@ -705,7 +789,10 @@ static void dma_idle_handler(uint32_t tick) {
|
|||
}
|
||||
|
||||
static const uint32_t controller_mask[] = {
|
||||
DMA1_ENABLE_MASK, DMA2_ENABLE_MASK
|
||||
DMA1_ENABLE_MASK,
|
||||
#if defined(DMA2)
|
||||
DMA2_ENABLE_MASK,
|
||||
#endif
|
||||
};
|
||||
{
|
||||
int controller = (tick >> DMA_SYSTICK_LOG2) & 1;
|
||||
|
@ -719,9 +806,12 @@ static void dma_idle_handler(uint32_t tick) {
|
|||
dma_idle.counter[controller] = 0;
|
||||
if (controller == 0) {
|
||||
__HAL_RCC_DMA1_CLK_DISABLE();
|
||||
} else {
|
||||
}
|
||||
#if defined(DMA2)
|
||||
else {
|
||||
__HAL_RCC_DMA2_CLK_DISABLE();
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// Something is still active, but the counter never got
|
||||
// reset, so we'll reset the counter here.
|
||||
|
@ -731,7 +821,7 @@ static void dma_idle_handler(uint32_t tick) {
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(STM32F0) || defined(STM32L4)
|
||||
#if defined(STM32F0) || defined(STM32L0) || defined(STM32L4)
|
||||
|
||||
void dma_nohal_init(const dma_descr_t *descr, uint32_t config) {
|
||||
DMA_Channel_TypeDef *dma = descr->instance;
|
||||
|
|
|
@ -58,6 +58,21 @@ extern const dma_descr_t dma_SPI_6_RX;
|
|||
extern const dma_descr_t dma_SDIO_0;
|
||||
extern const dma_descr_t dma_DCMI_0;
|
||||
|
||||
#elif defined(STM32L0)
|
||||
|
||||
extern const dma_descr_t dma_SPI_1_RX;
|
||||
extern const dma_descr_t dma_I2C_3_TX;
|
||||
extern const dma_descr_t dma_SPI_1_TX;
|
||||
extern const dma_descr_t dma_I2C_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)
|
||||
|
||||
extern const dma_descr_t dma_ADC_1_RX;
|
||||
|
|
|
@ -139,12 +139,16 @@ STATIC mp_obj_t pyb_extint_callback_arg[EXTI_NUM_VECTORS];
|
|||
#endif
|
||||
|
||||
STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
|
||||
#if defined(STM32F0)
|
||||
#if defined(STM32F0) || defined(STM32L0)
|
||||
EXTI0_1_IRQn, EXTI0_1_IRQn, EXTI2_3_IRQn, EXTI2_3_IRQn,
|
||||
EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn,
|
||||
EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn,
|
||||
EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn,
|
||||
#if defined(STM32L0)
|
||||
PVD_IRQn,
|
||||
#else
|
||||
PVD_VDDIO2_IRQn,
|
||||
#endif
|
||||
RTC_IRQn,
|
||||
0, // internal USB wakeup event
|
||||
RTC_IRQn,
|
||||
|
|
|
@ -68,7 +68,7 @@ static const flash_layout_t flash_layout[] = {
|
|||
{ 0x08040000, 0x40000, 3 },
|
||||
};
|
||||
|
||||
#elif defined(STM32L4)
|
||||
#elif defined(STM32L0) || defined(STM32L4)
|
||||
|
||||
static const flash_layout_t flash_layout[] = {
|
||||
{ (uint32_t)FLASH_BASE, (uint32_t)FLASH_PAGE_SIZE, 512 },
|
||||
|
@ -170,7 +170,12 @@ void flash_erase(uint32_t flash_dest, uint32_t num_word32) {
|
|||
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
EraseInitStruct.PageAddress = flash_dest;
|
||||
EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE;
|
||||
#elif (defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE))
|
||||
#elif defined(STM32L0)
|
||||
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR);
|
||||
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
EraseInitStruct.PageAddress = flash_dest;
|
||||
EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE;
|
||||
#elif defined(STM32L4) && !defined(SYSCFG_MEMRMP_FB_MODE)
|
||||
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
|
||||
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
EraseInitStruct.Page = get_page(flash_dest);
|
||||
|
|
|
@ -489,7 +489,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_readchar_obj, pyb_uart_readchar);
|
|||
// uart.sendbreak()
|
||||
STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7)
|
||||
self->uartx->RQR = USART_RQR_SBKRQ; // write-only register
|
||||
#else
|
||||
self->uartx->CR1 |= USART_CR1_SBK;
|
||||
|
|
|
@ -56,6 +56,11 @@
|
|||
#include "uart.h"
|
||||
#include "wdt.h"
|
||||
|
||||
#if defined(STM32L0)
|
||||
// L0 does not have a BOR, so use POR instead
|
||||
#define RCC_CSR_BORRSTF RCC_CSR_PORRSTF
|
||||
#endif
|
||||
|
||||
#if defined(STM32L4)
|
||||
// L4 does not have a POR, so use BOR instead
|
||||
#define RCC_CSR_PORRSTF RCC_CSR_BORRSTF
|
||||
|
@ -300,7 +305,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(STM32L4)
|
||||
#if defined(STM32F0) || defined(STM32L0) || defined(STM32L4)
|
||||
mp_raise_NotImplementedError("machine.freq set not supported yet");
|
||||
#else
|
||||
mp_int_t sysclk = mp_obj_get_int(args[0]);
|
||||
|
|
|
@ -184,6 +184,15 @@
|
|||
#define MICROPY_HW_MAX_TIMER (17)
|
||||
#define MICROPY_HW_MAX_UART (8)
|
||||
|
||||
// Configuration for STM32L0 series
|
||||
#elif defined(STM32L0)
|
||||
|
||||
#define MP_HAL_UNIQUE_ID_ADDRESS (0x1FF80050)
|
||||
#define PYB_EXTI_NUM_VECTORS (30) // TODO (22 configurable, 7 direct)
|
||||
#define MICROPY_HW_MAX_I2C (3)
|
||||
#define MICROPY_HW_MAX_TIMER (22)
|
||||
#define MICROPY_HW_MAX_UART (4)
|
||||
|
||||
// Configuration for STM32L4 series
|
||||
#elif defined(STM32L4)
|
||||
|
||||
|
|
|
@ -119,6 +119,9 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) {
|
|||
#elif defined(STM32H7)
|
||||
#define AHBxENR AHB4ENR
|
||||
#define AHBxENR_GPIOAEN_Pos RCC_AHB4ENR_GPIOAEN_Pos
|
||||
#elif defined(STM32L0)
|
||||
#define AHBxENR IOPENR
|
||||
#define AHBxENR_GPIOAEN_Pos RCC_IOPENR_GPIOAEN
|
||||
#elif defined(STM32L4)
|
||||
#define AHBxENR AHB2ENR
|
||||
#define AHBxENR_GPIOAEN_Pos RCC_AHB2ENR_GPIOAEN_Pos
|
||||
|
|
|
@ -84,7 +84,31 @@ void powerctrl_check_enter_bootloader(void) {
|
|||
}
|
||||
}
|
||||
|
||||
#if !defined(STM32F0)
|
||||
#if defined(STM32L0)
|
||||
void SystemClock_Config(void) {
|
||||
// Enable power control peripheral
|
||||
__HAL_RCC_PWR_CLK_ENABLE();
|
||||
|
||||
// Use the 16MHz internal oscillator
|
||||
RCC->CR |= RCC_CR_HSION;
|
||||
while (!(RCC->CR & RCC_CR_HSIRDY)) {
|
||||
}
|
||||
const uint32_t sysclk_src = 1;
|
||||
|
||||
// Select SYSCLK source
|
||||
RCC->CFGR |= sysclk_src << RCC_CFGR_SW_Pos;
|
||||
while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != sysclk_src) {
|
||||
// Wait for SYSCLK source to change
|
||||
}
|
||||
|
||||
SystemCoreClockUpdate();
|
||||
|
||||
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);
|
||||
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(STM32F0) && !defined(STM32L0)
|
||||
|
||||
// Assumes that PLL is used as the SYSCLK source
|
||||
int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai) {
|
||||
|
@ -158,7 +182,7 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk
|
|||
|
||||
#endif
|
||||
|
||||
#if !(defined(STM32F0) || defined(STM32L4))
|
||||
#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4)
|
||||
|
||||
STATIC uint32_t calc_ahb_div(uint32_t wanted_div) {
|
||||
if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; }
|
||||
|
@ -333,7 +357,7 @@ void powerctrl_enter_stop_mode(void) {
|
|||
__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_MSI);
|
||||
#endif
|
||||
|
||||
#if !defined(STM32F0) && !defined(STM32L4)
|
||||
#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4)
|
||||
// takes longer to wake but reduces stop current
|
||||
HAL_PWREx_EnableFlashPowerDown();
|
||||
#endif
|
||||
|
@ -426,7 +450,7 @@ void powerctrl_enter_standby_mode(void) {
|
|||
|
||||
// Note: we only support RTC ALRA, ALRB, WUT and TS.
|
||||
// TODO support TAMP and WKUP (PA0 external pin).
|
||||
#if defined(STM32F0)
|
||||
#if defined(STM32F0) || defined(STM32L0)
|
||||
#define CR_BITS (RTC_CR_ALRAIE | RTC_CR_WUTIE | RTC_CR_TSIE)
|
||||
#define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TSF)
|
||||
#else
|
||||
|
|
|
@ -73,6 +73,17 @@ STATIC bool rtc_use_lse = false;
|
|||
STATIC uint32_t rtc_startup_tick;
|
||||
STATIC bool rtc_need_init_finalise = false;
|
||||
|
||||
#if defined(STM32L0)
|
||||
#define BDCR CSR
|
||||
#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) {
|
||||
RTCHandle.Instance = RTC;
|
||||
|
||||
|
@ -287,7 +298,7 @@ STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) {
|
|||
// Exit Initialization mode
|
||||
hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT;
|
||||
|
||||
#if defined(STM32L4) || defined(STM32H7)
|
||||
#if defined(STM32L0) || defined(STM32L4) || defined(STM32H7)
|
||||
hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMOUTTYPE;
|
||||
hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType);
|
||||
#elif defined(STM32F7)
|
||||
|
@ -539,7 +550,7 @@ mp_obj_t pyb_rtc_datetime(size_t n_args, const mp_obj_t *args) {
|
|||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_datetime);
|
||||
|
||||
#if defined(STM32F0)
|
||||
#if defined(STM32F0) || defined(STM32L0)
|
||||
#define RTC_WKUP_IRQn RTC_IRQn
|
||||
#endif
|
||||
|
||||
|
|
|
@ -427,6 +427,8 @@ STATIC mp_obj_t compute_percent_from_pwm_value(uint32_t period, uint32_t cmp) {
|
|||
#endif
|
||||
}
|
||||
|
||||
#if !defined(STM32L0)
|
||||
|
||||
// Computes the 8-bit value for the DTG field in the BDTR register.
|
||||
//
|
||||
// 1 tick = 1 count of the timer's clock (source_freq) divided by div.
|
||||
|
@ -486,6 +488,8 @@ STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks, mp_int_t brk)
|
|||
HAL_TIMEx_ConfigBreakDeadTime(&self->tim, &deadTimeConfig);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer) {
|
||||
if (mp_obj_get_type(timer) != &pyb_timer_type) {
|
||||
mp_raise_ValueError("need a Timer object");
|
||||
|
@ -514,6 +518,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(IS_TIM_ADVANCED_INSTANCE)
|
||||
if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance))
|
||||
#elif defined(IS_TIM_BREAK_INSTANCE)
|
||||
|
@ -531,6 +536,7 @@ STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_
|
|||
mp_printf(print, ", brk=BRK_OFF");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mp_print_str(print, ")");
|
||||
}
|
||||
}
|
||||
|
@ -630,11 +636,15 @@ 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)
|
||||
init->RepetitionCounter = 0;
|
||||
#endif
|
||||
|
||||
// enable TIM clock
|
||||
switch (self->tim_id) {
|
||||
#if defined(TIM1)
|
||||
case 1: __HAL_RCC_TIM1_CLK_ENABLE(); break;
|
||||
#endif
|
||||
case 2: __HAL_RCC_TIM2_CLK_ENABLE(); break;
|
||||
#if defined(TIM3)
|
||||
case 3: __HAL_RCC_TIM3_CLK_ENABLE(); break;
|
||||
|
@ -681,15 +691,32 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons
|
|||
#if defined(TIM17)
|
||||
case 17: __HAL_RCC_TIM17_CLK_ENABLE(); break;
|
||||
#endif
|
||||
#if defined(TIM18)
|
||||
case 18: __HAL_RCC_TIM18_CLK_ENABLE(); break;
|
||||
#endif
|
||||
#if defined(TIM19)
|
||||
case 19: __HAL_RCC_TIM19_CLK_ENABLE(); break;
|
||||
#endif
|
||||
#if defined(TIM20)
|
||||
case 20: __HAL_RCC_TIM20_CLK_ENABLE(); break;
|
||||
#endif
|
||||
#if defined(TIM21)
|
||||
case 21: __HAL_RCC_TIM21_CLK_ENABLE(); break;
|
||||
#endif
|
||||
#if defined(TIM22)
|
||||
case 22: __HAL_RCC_TIM22_CLK_ENABLE(); break;
|
||||
#endif
|
||||
}
|
||||
|
||||
// set IRQ priority (if not a special timer)
|
||||
if (self->tim_id != 5) {
|
||||
NVIC_SetPriority(IRQn_NONNEG(self->irqn), IRQ_PRI_TIMX);
|
||||
if (self->tim_id == 1) {
|
||||
#if defined(TIM1)
|
||||
NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX);
|
||||
#if defined(TIM8)
|
||||
#endif
|
||||
} else if (self->tim_id == 8) {
|
||||
#if defined(TIM8)
|
||||
NVIC_SetPriority(TIM8_CC_IRQn, IRQ_PRI_TIMX);
|
||||
#endif
|
||||
}
|
||||
|
@ -697,6 +724,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(IS_TIM_ADVANCED_INSTANCE)
|
||||
if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance)) {
|
||||
#elif defined(IS_TIM_BREAK_INSTANCE)
|
||||
|
@ -707,6 +735,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons
|
|||
config_deadtime(self, args[ARG_deadtime].u_int, args[ARG_brk].u_int);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// Enable ARPE so that the auto-reload register is buffered.
|
||||
// This allows to smoothly change the frequency of the timer.
|
||||
|
@ -726,6 +755,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, size_t n_args, cons
|
|||
// It assumes that timer instance pointer has the lower 8 bits cleared.
|
||||
#define TIM_ENTRY(id, irq) [id - 1] = (uint32_t)TIM##id | irq
|
||||
STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
||||
#if defined(TIM1)
|
||||
#if defined(STM32F0)
|
||||
TIM_ENTRY(1, TIM1_BRK_UP_TRG_COM_IRQn),
|
||||
#elif defined(STM32F4) || defined(STM32F7)
|
||||
|
@ -733,6 +763,7 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
|
|||
#elif defined(STM32L4)
|
||||
TIM_ENTRY(1, TIM1_UP_TIM16_IRQn),
|
||||
#endif
|
||||
#endif
|
||||
TIM_ENTRY(2, TIM2_IRQn),
|
||||
#if defined(TIM3)
|
||||
TIM_ENTRY(3, TIM3_IRQn),
|
||||
|
@ -1054,10 +1085,12 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma
|
|||
oc_config.Pulse = args[3].u_int;
|
||||
}
|
||||
oc_config.OCPolarity = TIM_OCPOLARITY_HIGH;
|
||||
oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH;
|
||||
oc_config.OCFastMode = TIM_OCFAST_DISABLE;
|
||||
#if !defined(STM32L0)
|
||||
oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH;
|
||||
oc_config.OCIdleState = TIM_OCIDLESTATE_SET;
|
||||
oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET;
|
||||
#endif
|
||||
|
||||
HAL_TIM_PWM_ConfigChannel(&self->tim, &oc_config, TIMER_CHANNEL(chan));
|
||||
if (chan->callback == mp_const_none) {
|
||||
|
@ -1065,10 +1098,12 @@ 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)
|
||||
// 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));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1085,14 +1120,16 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma
|
|||
if (oc_config.OCPolarity == 0xffffffff) {
|
||||
oc_config.OCPolarity = TIM_OCPOLARITY_HIGH;
|
||||
}
|
||||
oc_config.OCFastMode = TIM_OCFAST_DISABLE;
|
||||
#if !defined(STM32L0)
|
||||
if (oc_config.OCPolarity == TIM_OCPOLARITY_HIGH) {
|
||||
oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH;
|
||||
} else {
|
||||
oc_config.OCNPolarity = TIM_OCNPOLARITY_LOW;
|
||||
}
|
||||
oc_config.OCFastMode = TIM_OCFAST_DISABLE;
|
||||
oc_config.OCIdleState = TIM_OCIDLESTATE_SET;
|
||||
oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET;
|
||||
#endif
|
||||
|
||||
if (!IS_TIM_OC_POLARITY(oc_config.OCPolarity)) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid polarity (%d)", oc_config.OCPolarity));
|
||||
|
@ -1103,10 +1140,12 @@ 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)
|
||||
// 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));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1155,8 +1194,12 @@ STATIC mp_obj_t pyb_timer_channel(size_t n_args, const mp_obj_t *pos_args, mp_ma
|
|||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid polarity (%d)", enc_config.IC1Polarity));
|
||||
}
|
||||
// Only Timers 1, 2, 3, 4, 5, and 8 support encoder mode
|
||||
if (self->tim.Instance != TIM1
|
||||
&& self->tim.Instance != TIM2
|
||||
if (
|
||||
#if defined(TIM1)
|
||||
self->tim.Instance != TIM1
|
||||
&&
|
||||
#endif
|
||||
self->tim.Instance != TIM2
|
||||
#if defined(TIM3)
|
||||
&& self->tim.Instance != TIM3
|
||||
#endif
|
||||
|
@ -1426,15 +1469,18 @@ STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback)
|
|||
self->callback = mp_const_none;
|
||||
} else if (mp_obj_is_callable(callback)) {
|
||||
self->callback = callback;
|
||||
uint8_t tim_id = self->timer->tim_id;
|
||||
__HAL_TIM_CLEAR_IT(&self->timer->tim, TIMER_IRQ_MASK(self->channel));
|
||||
if (tim_id == 1) {
|
||||
#if defined(TIM1)
|
||||
if (self->timer->tim_id == 1) {
|
||||
HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);
|
||||
#if defined(TIM8) // STM32F401 doesn't have a TIM8
|
||||
} else if (tim_id == 8) {
|
||||
HAL_NVIC_EnableIRQ(TIM8_CC_IRQn);
|
||||
} else
|
||||
#endif
|
||||
} else {
|
||||
#if defined(TIM8) // STM32F401 doesn't have a TIM8
|
||||
if (self->timer->tim_id == 8) {
|
||||
HAL_NVIC_EnableIRQ(TIM8_CC_IRQn);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
HAL_NVIC_EnableIRQ(self->timer->irqn);
|
||||
}
|
||||
// start timer, so that it interrupts on overflow
|
||||
|
|
|
@ -76,6 +76,11 @@
|
|||
#define USART_CR2_IE_ALL (USART_CR2_IE_BASE)
|
||||
#define USART_CR3_IE_ALL (USART_CR3_IE_BASE | USART_CR3_RXFTIE | USART_CR3_TCBGTIE | USART_CR3_TXFTIE | USART_CR3_WUFIE)
|
||||
|
||||
#elif defined(STM32L0)
|
||||
#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)
|
||||
#define USART_CR3_IE_ALL (USART_CR3_IE_BASE | USART_CR3_WUFIE)
|
||||
|
||||
#elif defined(STM32L4)
|
||||
#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)
|
||||
|
@ -648,7 +653,7 @@ int uart_rx_char(pyb_uart_obj_t *self) {
|
|||
return data;
|
||||
} else {
|
||||
// no buffering
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7)
|
||||
int data = self->uartx->RDR & self->char_mask;
|
||||
self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set
|
||||
return data;
|
||||
|
@ -774,7 +779,7 @@ void uart_irq_handler(mp_uint_t uart_id) {
|
|||
uint16_t next_head = (self->read_buf_head + 1) % self->read_buf_len;
|
||||
if (next_head != self->read_buf_tail) {
|
||||
// only read data if room in buf
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
|
||||
#if defined(STM32F0) || defined(STM32F7) || defined(STM32L0) || defined(STM32L4) || defined(STM32H7)
|
||||
int data = self->uartx->RDR; // clears UART_FLAG_RXNE
|
||||
self->uartx->ICR = USART_ICR_ORECF; // clear ORE if it was set
|
||||
#else
|
||||
|
|
Loading…
Reference in New Issue