stm32: Add support for STM32F0 MCUs.

This commit is contained in:
Damien George 2018-05-28 18:10:53 +10:00
parent 4a7d157a5b
commit ea7e747979
18 changed files with 478 additions and 48 deletions

View File

@ -57,10 +57,15 @@ CFLAGS_CORTEX_M = -mthumb
ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32F767xx STM32F769xx STM32H743xx))
CFLAGS_CORTEX_M += -mfpu=fpv5-d16 -mfloat-abi=hard
else
ifeq ($(MCU_SERIES),f0)
CFLAGS_CORTEX_M += -msoft-float
else
CFLAGS_CORTEX_M += -mfpu=fpv4-sp-d16 -mfloat-abi=hard
endif
endif
# Options for particular MCU series
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_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
@ -155,7 +160,6 @@ SRC_LIBM = $(addprefix lib/libm_dbl/,\
else
SRC_LIBM = $(addprefix lib/libm/,\
math.c \
thumb_vfp_sqrtf.c \
acoshf.c \
asinfacosf.c \
asinhf.c \
@ -181,6 +185,11 @@ SRC_LIBM = $(addprefix lib/libm/,\
wf_lgamma.c \
wf_tgamma.c \
)
ifeq ($(MCU_SERIES),f0)
SRC_LIBM += lib/libm/ef_sqrt.c
else
SRC_LIBM += lib/libm/thumb_vfp_sqrtf.c
endif
endif
EXTMOD_SRC_C = $(addprefix extmod/,\
@ -197,7 +206,6 @@ DRIVERS_SRC_C = $(addprefix drivers/,\
SRC_C = \
main.c \
system_stm32.c \
stm32_it.c \
usbd_conf.c \
usbd_desc.c \
@ -252,10 +260,19 @@ SRC_C = \
adc.c \
$(wildcard boards/$(BOARD)/*.c)
ifeq ($(MCU_SERIES),f0)
SRC_O = \
$(STARTUP_FILE) \
system_stm32f0.o \
resethandler_m0.o \
gchelper_m0.o
else
SRC_O = \
$(STARTUP_FILE) \
system_stm32.o \
resethandler.o \
gchelper.o \
gchelper.o
endif
SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
hal.c \
@ -277,14 +294,19 @@ SRC_HAL = $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
hal_rcc_ex.c \
hal_rtc.c \
hal_rtc_ex.c \
hal_sd.c \
hal_spi.c \
hal_tim.c \
hal_tim_ex.c \
hal_uart.c \
)
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),f4 f7 h7 l4))
SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_,\
hal_sd.c \
ll_sdmmc.c \
ll_usb.c \
)
endif
ifeq ($(CMSIS_MCU),$(filter $(CMSIS_MCU),STM32H743xx))
SRC_HAL += $(addprefix $(HAL_DIR)/Src/stm32$(MCU_SERIES)xx_, hal_fdcan.c)

View File

@ -59,7 +59,15 @@
#define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE
#define ADC_NUM_CHANNELS (19)
#if defined(STM32F4)
#if defined(STM32F0)
#define ADC_FIRST_GPIO_CHANNEL (0)
#define ADC_LAST_GPIO_CHANNEL (15)
#define ADC_CAL_ADDRESS (0x1ffff7ba)
#define ADC_CAL1 ((uint16_t*)0x1ffff7b8)
#define ADC_CAL2 ((uint16_t*)0x1ffff7c2)
#elif defined(STM32F4)
#define ADC_FIRST_GPIO_CHANNEL (0)
#define ADC_LAST_GPIO_CHANNEL (15)
@ -104,7 +112,9 @@
#endif
#if defined(STM32F405xx) || defined(STM32F415xx) || \
#if defined(STM32F091xC)
#define VBAT_DIV (2)
#elif defined(STM32F405xx) || defined(STM32F415xx) || \
defined(STM32F407xx) || defined(STM32F417xx) || \
defined(STM32F401xC) || defined(STM32F401xE) || \
defined(STM32F411xE)
@ -159,7 +169,7 @@ STATIC bool is_adcx_channel(int channel) {
#if defined(STM32F411xE)
// The HAL has an incorrect IS_ADC_CHANNEL macro for the F411 so we check for temp
return IS_ADC_CHANNEL(channel) || channel == ADC_CHANNEL_TEMPSENSOR;
#elif defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
#elif defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
return IS_ADC_CHANNEL(channel);
#elif defined(STM32L4)
ADC_HandleTypeDef handle;
@ -174,7 +184,7 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) {
uint32_t tickstart = HAL_GetTick();
#if defined(STM32F4) || defined(STM32F7)
while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
#elif defined(STM32H7) || defined(STM32L4)
#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4)
while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
#else
#error Unsupported processor
@ -186,7 +196,7 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) {
}
STATIC void adcx_clock_enable(void) {
#if defined(STM32F4) || defined(STM32F7)
#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
ADCx_CLK_ENABLE();
#elif defined(STM32H7)
__HAL_RCC_ADC3_CLK_ENABLE();
@ -205,12 +215,14 @@ STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) {
adch->Init.Resolution = resolution;
adch->Init.ContinuousConvMode = DISABLE;
adch->Init.DiscontinuousConvMode = DISABLE;
#if !defined(STM32F0)
adch->Init.NbrOfDiscConversion = 0;
adch->Init.NbrOfConversion = 1;
#endif
adch->Init.EOCSelection = ADC_EOC_SINGLE_CONV;
adch->Init.ExternalTrigConv = ADC_SOFTWARE_START;
adch->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
#if defined(STM32F4) || defined(STM32F7)
#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
adch->Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
adch->Init.ScanConvMode = DISABLE;
adch->Init.DataAlign = ADC_DATAALIGN_RIGHT;
@ -271,7 +283,9 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
sConfig.Channel = channel;
sConfig.Rank = 1;
#if defined(STM32F4) || defined(STM32F7)
#if defined(STM32F0)
sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;
#elif defined(STM32F4) || defined(STM32F7)
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
#elif defined(STM32H7)
sConfig.SamplingTime = ADC_SAMPLETIME_8CYCLES_5;
@ -283,10 +297,10 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
#else
#error Unsupported processor
#endif
sConfig.Offset = 0;
HAL_ADC_ConfigChannel(adc_handle, &sConfig);
}
@ -443,7 +457,7 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
// for subsequent samples we can just set the "start sample" bit
#if defined(STM32F4) || defined(STM32F7)
ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
#elif defined(STM32H7) || defined(STM32L4)
#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4)
SET_BIT(ADCx->CR, ADC_CR_ADSTART);
#else
#error Unsupported processor
@ -553,7 +567,7 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i
// ADC is started: set the "start sample" bit
#if defined(STM32F4) || defined(STM32F7)
ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
#elif defined(STM32H7) || defined(STM32L4)
#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4)
SET_BIT(ADCx->CR, ADC_CR_ADSTART);
#else
#error Unsupported processor

View File

@ -177,7 +177,7 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, size_t n_args, const mp
__DAC_CLK_ENABLE();
#elif defined(STM32H7)
__HAL_RCC_DAC12_CLK_ENABLE();
#elif defined(STM32L4)
#elif defined(STM32F0) || defined(STM32L4)
__HAL_RCC_DAC1_CLK_ENABLE();
#else
#error Unsupported Processor

View File

@ -55,7 +55,7 @@ typedef enum {
struct _dma_descr_t {
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
DMA_Stream_TypeDef *instance;
#elif defined(STM32L4)
#elif defined(STM32F0) || defined(STM32L4)
DMA_Channel_TypeDef *instance;
#else
#error "Unsupported Processor"
@ -141,7 +141,46 @@ static const DMA_InitTypeDef dma_init_struct_dac = {
};
#endif
#if defined(STM32F4) || defined(STM32F7)
#if defined(STM32F0)
#define NCONTROLLERS (2)
#define NSTREAMS_PER_CONTROLLER (7)
#define NSTREAM (NCONTROLLERS * NSTREAMS_PER_CONTROLLER)
#define DMA_SUB_INSTANCE_AS_UINT8(dma_channel) (dma_channel)
#define DMA1_ENABLE_MASK (0x007f) // Bits in dma_enable_mask corresponfing to DMA1 (7 channels)
#define DMA2_ENABLE_MASK (0x0f80) // Bits in dma_enable_mask corresponding to DMA2 (only 5 channels)
// DMA1 streams
#if MICROPY_HW_ENABLE_DAC
const dma_descr_t dma_DAC_1_TX = { DMA1_Channel3, HAL_DMA1_CH3_DAC_CH1, DMA_MEMORY_TO_PERIPH, dma_id_3, &dma_init_struct_dac };
const dma_descr_t dma_DAC_2_TX = { DMA1_Channel4, HAL_DMA1_CH4_DAC_CH2, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_dac };
#endif
const dma_descr_t dma_SPI_2_TX = { DMA1_Channel5, HAL_DMA1_CH5_SPI2_TX, DMA_MEMORY_TO_PERIPH, dma_id_5, &dma_init_struct_spi_i2c};
const dma_descr_t dma_SPI_2_RX = { DMA1_Channel6, HAL_DMA1_CH6_SPI2_RX, DMA_PERIPH_TO_MEMORY, dma_id_6, &dma_init_struct_spi_i2c};
const dma_descr_t dma_SPI_1_RX = { DMA2_Channel3, HAL_DMA2_CH3_SPI1_RX, DMA_PERIPH_TO_MEMORY, dma_id_3, &dma_init_struct_spi_i2c};
const dma_descr_t dma_SPI_1_TX = { DMA2_Channel4, HAL_DMA2_CH4_SPI1_TX, DMA_MEMORY_TO_PERIPH, dma_id_4, &dma_init_struct_spi_i2c};
static const uint8_t dma_irqn[NSTREAM] = {
DMA1_Ch1_IRQn,
DMA1_Ch2_3_DMA2_Ch1_2_IRQn,
DMA1_Ch2_3_DMA2_Ch1_2_IRQn,
DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
DMA1_Ch2_3_DMA2_Ch1_2_IRQn,
DMA1_Ch2_3_DMA2_Ch1_2_IRQn,
DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
DMA1_Ch4_7_DMA2_Ch3_5_IRQn,
0,
0,
};
#elif defined(STM32F4) || defined(STM32F7)
#define NCONTROLLERS (2)
#define NSTREAMS_PER_CONTROLLER (8)
@ -381,8 +420,13 @@ volatile dma_idle_count_t dma_idle;
#define DMA_INVALID_CHANNEL 0xff // Value stored in dma_last_channel which means invalid
#if defined(STM32F0)
#define DMA1_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA1EN) != 0)
#define DMA2_IS_CLK_ENABLED() ((RCC->AHBENR & RCC_AHBENR_DMA2EN) != 0)
#else
#define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0)
#define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0)
#endif
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
@ -476,8 +520,10 @@ void dma_init_handle(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void
#if defined(STM32L4) || defined(STM32H7)
dma->Init.Request = dma_descr->sub_instance;
#else
#if !defined(STM32F0)
dma->Init.Channel = dma_descr->sub_instance;
#endif
#endif
// half of __HAL_LINKDMA(data, xxx, *dma)
// caller must implement other half by doing: data->xxx = dma
dma->Parent = data;
@ -517,6 +563,13 @@ void dma_init(DMA_HandleTypeDef *dma, const dma_descr_t *dma_descr, void *data){
HAL_DMA_DeInit(dma);
HAL_DMA_Init(dma);
NVIC_SetPriority(IRQn_NONNEG(dma_irqn[dma_id]), IRQ_PRI_DMA);
#if defined(STM32F0)
if (dma->Instance < DMA2_Channel1) {
__HAL_DMA1_REMAP(dma_descr->sub_instance);
} else {
__HAL_DMA2_REMAP(dma_descr->sub_instance);
}
#endif
} else {
// only necessary initialization
dma->State = HAL_DMA_STATE_READY;

View File

@ -28,7 +28,7 @@
typedef struct _dma_descr_t dma_descr_t;
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
extern const dma_descr_t dma_I2C_1_RX;
extern const dma_descr_t dma_SPI_3_RX;

View File

@ -133,6 +133,12 @@ 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)
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,
#else
EXTI0_IRQn, EXTI1_IRQn, EXTI2_IRQn, EXTI3_IRQn, EXTI4_IRQn,
EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn,
EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn,
@ -148,6 +154,7 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
OTG_HS_WKUP_IRQn,
TAMP_STAMP_IRQn,
RTC_WKUP_IRQn,
#endif
};
// Set override_callback_obj to true if you want to unconditionally set the
@ -282,7 +289,7 @@ void extint_enable(uint line) {
if (line >= EXTI_NUM_VECTORS) {
return;
}
#if defined(STM32F7) || defined(STM32H7)
#if defined(STM32F0) || defined(STM32F7) || defined(STM32H7)
// The Cortex-M7 doesn't have bitband support.
mp_uint_t irq_state = disable_irq();
if (pyb_extint_mode[line] == EXTI_Mode_Interrupt) {
@ -312,7 +319,7 @@ void extint_disable(uint line) {
return;
}
#if defined(STM32F7) || defined(STM32H7)
#if defined(STM32F0) || defined(STM32F7) || defined(STM32H7)
// The Cortex-M7 doesn't have bitband support.
mp_uint_t irq_state = disable_irq();
#if defined(STM32H7)

View File

@ -34,7 +34,13 @@ typedef struct {
uint32_t sector_count;
} flash_layout_t;
#if defined(STM32F4)
#if defined(STM32F0)
static const flash_layout_t flash_layout[] = {
{ FLASH_BASE, FLASH_PAGE_SIZE, (FLASH_BANK1_END + 1 - FLASH_BASE) / FLASH_PAGE_SIZE },
};
#elif defined(STM32F4)
static const flash_layout_t flash_layout[] = {
{ 0x08000000, 0x04000, 4 },
@ -153,7 +159,12 @@ void flash_erase(uint32_t flash_dest, uint32_t num_word32) {
FLASH_EraseInitTypeDef EraseInitStruct;
#if defined(STM32L4)
#if defined(STM32F0)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR);
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = flash_dest;
EraseInitStruct.NbPages = (4 * num_word32 + FLASH_PAGE_SIZE - 4) / FLASH_PAGE_SIZE;
#elif defined(STM32L4)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
// erase the sector(s)

View File

@ -262,7 +262,7 @@ int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) {
return num_acks;
}
#elif defined(STM32F7)
#elif defined(STM32F0) || defined(STM32F7)
int i2c_init(i2c_t *i2c, mp_hal_pin_obj_t scl, mp_hal_pin_obj_t sda, uint32_t freq) {
uint32_t i2c_id = ((uint32_t)i2c - I2C1_BASE) / (I2C2_BASE - I2C1_BASE);
@ -446,7 +446,7 @@ int i2c_write(i2c_t *i2c, const uint8_t *src, size_t len, size_t next_len) {
#endif
#if defined(STM32F4) || defined(STM32F7)
#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
int i2c_readfrom(i2c_t *i2c, uint16_t addr, uint8_t *dest, size_t len, bool stop) {
int ret;

View File

@ -37,7 +37,7 @@
STATIC const mp_obj_type_t machine_hard_i2c_type;
#if defined(STM32F4) || defined(STM32F7)
#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
typedef struct _machine_hard_i2c_obj_t {
mp_obj_base_t base;

View File

@ -110,7 +110,11 @@ void machine_init(void) {
uint32_t state = RCC->RCC_SR;
if (state & RCC_SR_IWDGRSTF || state & RCC_SR_WWDGRSTF) {
reset_cause = PYB_RESET_WDT;
} else if (state & RCC_SR_PORRSTF || state & RCC_SR_BORRSTF) {
} else if (state & RCC_SR_PORRSTF
#if !defined(STM32F0)
|| state & RCC_SR_BORRSTF
#endif
) {
reset_cause = PYB_RESET_POWER_ON;
} else if (state & RCC_SR_PINRSTF) {
reset_cause = PYB_RESET_HARD;
@ -140,11 +144,18 @@ STATIC mp_obj_t machine_info(size_t n_args, const mp_obj_t *args) {
// get and print clock speeds
// SYSCLK=168MHz, HCLK=168MHz, PCLK1=42MHz, PCLK2=84MHz
{
#if defined(STM32F0)
printf("S=%u\nH=%u\nP1=%u\n",
(unsigned int)HAL_RCC_GetSysClockFreq(),
(unsigned int)HAL_RCC_GetHCLKFreq(),
(unsigned int)HAL_RCC_GetPCLK1Freq());
#else
printf("S=%u\nH=%u\nP1=%u\nP2=%u\n",
(unsigned int)HAL_RCC_GetSysClockFreq(),
(unsigned int)HAL_RCC_GetHCLKFreq(),
(unsigned int)HAL_RCC_GetPCLK1Freq(),
(unsigned int)HAL_RCC_GetPCLK2Freq());
#endif
}
// to print info about memory
@ -267,6 +278,7 @@ STATIC NORETURN mp_obj_t machine_bootloader(void) {
}
MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader);
#if !(defined(STM32F0) || defined(STM32L4))
// get or set the MCU frequencies
STATIC mp_uint_t machine_freq_calc_ahb_div(mp_uint_t wanted_div) {
if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; }
@ -286,23 +298,28 @@ STATIC mp_uint_t machine_freq_calc_apb_div(mp_uint_t wanted_div) {
else if (wanted_div <= 8) { return RCC_HCLK_DIV8; }
else { return RCC_SYSCLK_DIV16; }
}
#endif
STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
// get
mp_obj_t tuple[4] = {
mp_obj_t tuple[] = {
mp_obj_new_int(HAL_RCC_GetSysClockFreq()),
mp_obj_new_int(HAL_RCC_GetHCLKFreq()),
mp_obj_new_int(HAL_RCC_GetPCLK1Freq()),
#if !defined(STM32F0)
mp_obj_new_int(HAL_RCC_GetPCLK2Freq()),
#endif
};
return mp_obj_new_tuple(4, tuple);
return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple);
} else {
// set
mp_int_t wanted_sysclk = mp_obj_get_int(args[0]) / 1000000;
#if defined(STM32L4)
#if defined(STM32F0) || defined(STM32L4)
mp_raise_NotImplementedError("machine.freq set not supported yet");
#endif
#else
mp_int_t wanted_sysclk = mp_obj_get_int(args[0]) / 1000000;
// default PLL parameters that give 48MHz on PLL48CK
uint32_t m = HSE_VALUE / 1000000, n = 336, p = 2, q = 7;
@ -458,6 +475,8 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
fail:;
void NORETURN __fatal_error(const char *msg);
__fatal_error("can't change freq");
#endif
}
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj, 0, 4, machine_freq);
@ -492,8 +511,10 @@ STATIC mp_obj_t machine_sleep(void) {
#else
#if !defined(STM32F0)
// takes longer to wake but reduces stop current
HAL_PWREx_EnableFlashPowerDown();
#endif
# if defined(STM32F7)
HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI);
@ -542,16 +563,22 @@ STATIC mp_obj_t machine_deepsleep(void) {
// Note: we only support RTC ALRA, ALRB, WUT and TS.
// TODO support TAMP and WKUP (PA0 external pin).
uint32_t irq_bits = RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE;
#if defined(STM32F0)
#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
#define CR_BITS (RTC_CR_ALRAIE | RTC_CR_ALRBIE | RTC_CR_WUTIE | RTC_CR_TSIE)
#define ISR_BITS (RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF)
#endif
// save RTC interrupts
uint32_t save_irq_bits = RTC->CR & irq_bits;
uint32_t save_irq_bits = RTC->CR & CR_BITS;
// disable RTC interrupts
RTC->CR &= ~irq_bits;
RTC->CR &= ~CR_BITS;
// clear RTC wake-up flags
RTC->ISR &= ~(RTC_ISR_ALRAF | RTC_ISR_ALRBF | RTC_ISR_WUTF | RTC_ISR_TSF);
RTC->ISR &= ~ISR_BITS;
#if defined(STM32F7)
// disable wake-up flags

View File

@ -110,8 +110,16 @@
/*****************************************************************************/
// General configuration
// Configuration for STM32F0 series
#if defined(STM32F0)
#define MP_HAL_UNIQUE_ID_ADDRESS (0x1ffff7ac)
#define PYB_EXTI_NUM_VECTORS (23)
#define MICROPY_HW_MAX_TIMER (17)
#define MICROPY_HW_MAX_UART (8)
// Configuration for STM32F4 series
#if defined(STM32F4)
#elif defined(STM32F4)
#define MP_HAL_UNIQUE_ID_ADDRESS (0x1fff7a10)
#define PYB_EXTI_NUM_VECTORS (23)

View File

@ -111,7 +111,10 @@ 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(STM32F4) || defined(STM32F7)
#if defined(STM32F0)
#define AHBxENR AHBENR
#define AHBxENR_GPIOAEN_Pos RCC_AHBENR_GPIOAEN_Pos
#elif defined(STM32F4) || defined(STM32F7)
#define AHBxENR AHB1ENR
#define AHBxENR_GPIOAEN_Pos RCC_AHB1ENR_GPIOAEN_Pos
#elif defined(STM32H7)

View File

@ -539,6 +539,10 @@ 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)
#define RTC_WKUP_IRQn RTC_IRQn
#endif
// wakeup(None)
// wakeup(ms, callback=None)
// wakeup(wucksel, wut, callback)

View File

@ -203,6 +203,9 @@ STATIC void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baud
if (prescale == 0xffffffff) {
// prescaler not given, so select one that yields at most the requested baudrate
mp_uint_t spi_clock;
#if defined(STM32F0)
spi_clock = HAL_RCC_GetPCLK1Freq();
#else
if (spi->Instance == SPI2 || spi->Instance == SPI3) {
// SPI2 and SPI3 are on APB1
spi_clock = HAL_RCC_GetPCLK1Freq();
@ -210,6 +213,7 @@ STATIC void spi_set_params(const spi_t *spi_obj, uint32_t prescale, int32_t baud
// SPI1, SPI4, SPI5 and SPI6 are on APB2
spi_clock = HAL_RCC_GetPCLK2Freq();
}
#endif
prescale = spi_clock / baudrate;
}
if (prescale <= 2) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; }
@ -500,7 +504,9 @@ STATIC void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy
uint spi_num = 1; // default to SPI1
if (spi->Instance == SPI2) { spi_num = 2; }
#if defined(SPI3)
else if (spi->Instance == SPI3) { spi_num = 3; }
#endif
#if defined(SPI4)
else if (spi->Instance == SPI4) { spi_num = 4; }
#endif
@ -516,6 +522,9 @@ STATIC void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy
if (spi->Init.Mode == SPI_MODE_MASTER) {
// compute baudrate
uint spi_clock;
#if defined(STM32F0)
spi_clock = HAL_RCC_GetPCLK1Freq();
#else
if (spi->Instance == SPI2 || spi->Instance == SPI3) {
// SPI2 and SPI3 are on APB1
spi_clock = HAL_RCC_GetPCLK1Freq();
@ -523,6 +532,7 @@ STATIC void spi_print(const mp_print_t *print, const spi_t *spi_obj, bool legacy
// SPI1, SPI4, SPI5 and SPI6 are on APB2
spi_clock = HAL_RCC_GetPCLK2Freq();
}
#endif
uint log_prescaler = (spi->Init.BaudRatePrescaler >> 3) + 1;
uint baudrate = spi_clock >> log_prescaler;
if (legacy) {

View File

@ -579,6 +579,39 @@ void RTC_WKUP_IRQHandler(void) {
IRQ_EXIT(RTC_WKUP_IRQn);
}
#if defined(STM32F0)
void RTC_IRQHandler(void) {
IRQ_ENTER(RTC_IRQn);
RTC->ISR &= ~(1 << 10); // clear wakeup interrupt flag
Handle_EXTI_Irq(EXTI_RTC_WAKEUP); // clear EXTI flag and execute optional callback
IRQ_EXIT(RTC_IRQn);
}
void EXTI0_1_IRQHandler(void) {
IRQ_ENTER(EXTI0_1_IRQn);
Handle_EXTI_Irq(0);
Handle_EXTI_Irq(1);
IRQ_EXIT(EXTI0_1_IRQn);
}
void EXTI2_3_IRQHandler(void) {
IRQ_ENTER(EXTI2_3_IRQn);
Handle_EXTI_Irq(2);
Handle_EXTI_Irq(3);
IRQ_EXIT(EXTI2_3_IRQn);
}
void EXTI4_15_IRQHandler(void) {
IRQ_ENTER(EXTI4_15_IRQn);
for (int i = 4; i <= 15; ++i) {
Handle_EXTI_Irq(i);
}
IRQ_EXIT(EXTI4_15_IRQn);
}
#endif
void TIM1_BRK_TIM9_IRQHandler(void) {
IRQ_ENTER(TIM1_BRK_TIM9_IRQn);
timer_irq_handler(9);
@ -718,6 +751,21 @@ void USART2_IRQHandler(void) {
IRQ_EXIT(USART2_IRQn);
}
#if defined(STM32F0)
void USART3_8_IRQHandler(void) {
IRQ_ENTER(USART3_8_IRQn);
uart_irq_handler(3);
uart_irq_handler(4);
uart_irq_handler(5);
uart_irq_handler(6);
uart_irq_handler(7);
uart_irq_handler(8);
IRQ_EXIT(USART3_8_IRQn);
}
#else
void USART3_IRQHandler(void) {
IRQ_ENTER(USART3_IRQn);
uart_irq_handler(3);
@ -758,6 +806,8 @@ void UART8_IRQHandler(void) {
}
#endif
#endif
#if defined(MICROPY_HW_CAN1_TX)
void CAN1_RX0_IRQHandler(void) {
IRQ_ENTER(CAN1_RX0_IRQn);

View File

@ -0,0 +1,203 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* Taken from ST Cube library and modified. See below for original header.
*/
/**
******************************************************************************
* @file system_stm32f0xx.c
* @author MCD Application Team
* @brief CMSIS Cortex-M0 Device Peripheral Access Layer System Source File.
*
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
#include STM32_HAL_H
#ifndef HSE_VALUE
#define HSE_VALUE (8000000)
#endif
#ifndef HSI_VALUE
#define HSI_VALUE (8000000)
#endif
#ifndef HSI48_VALUE
#define HSI48_VALUE (48000000)
#endif
/* This variable is updated in three ways:
1) by calling CMSIS function SystemCoreClockUpdate()
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
Note: If you use this function to configure the system clock there is no need to
call the 2 first functions listed above, since SystemCoreClock variable is
updated automatically.
*/
uint32_t SystemCoreClock = 8000000;
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
void SystemInit(void) {
// Set HSION bit
RCC->CR |= (uint32_t)0x00000001U;
#if defined(STM32F051x8) || defined(STM32F058x8)
// Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits
RCC->CFGR &= (uint32_t)0xF8FFB80CU;
#else
// Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits
RCC->CFGR &= (uint32_t)0x08FFB80CU;
#endif
// Reset HSEON, CSSON and PLLON bits
RCC->CR &= (uint32_t)0xFEF6FFFFU;
// Reset HSEBYP bit
RCC->CR &= (uint32_t)0xFFFBFFFFU;
// Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits
RCC->CFGR &= (uint32_t)0xFFC0FFFFU;
// Reset PREDIV[3:0] bits
RCC->CFGR2 &= (uint32_t)0xFFFFFFF0U;
#if defined(STM32F072xB) || defined(STM32F078xx)
// Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits
RCC->CFGR3 &= (uint32_t)0xFFFCFE2CU;
#elif defined(STM32F071xB)
// Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits
RCC->CFGR3 &= (uint32_t)0xFFFFCEACU;
#elif defined(STM32F091xC) || defined(STM32F098xx)
// Reset USART3SW[1:0], USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits
RCC->CFGR3 &= (uint32_t)0xFFF0FEACU;
#elif defined(STM32F030x6) || defined(STM32F030x8) || defined(STM32F031x6) || defined(STM32F038xx) || defined(STM32F030xC)
// Reset USART1SW[1:0], I2C1SW and ADCSW bits
RCC->CFGR3 &= (uint32_t)0xFFFFFEECU;
#elif defined(STM32F051x8) || defined(STM32F058xx)
// Reset USART1SW[1:0], I2C1SW, CECSW and ADCSW bits
RCC->CFGR3 &= (uint32_t)0xFFFFFEACU;
#elif defined(STM32F042x6) || defined(STM32F048xx)
// Reset USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits
RCC->CFGR3 &= (uint32_t)0xFFFFFE2CU;
#elif defined(STM32F070x6) || defined(STM32F070xB)
// Reset USART1SW[1:0], I2C1SW, USBSW and ADCSW bits
RCC->CFGR3 &= (uint32_t)0xFFFFFE6CU;
// Set default USB clock to PLLCLK, since there is no HSI48
RCC->CFGR3 |= (uint32_t)0x00000080U;
#else
#warning "No target selected"
#endif
// Reset HSI14 bit
RCC->CR2 &= (uint32_t)0xFFFFFFFEU;
// Disable all interrupts
RCC->CIR = 0x00000000U;
// dpgeorge: enable 8-byte stack alignment for IRQ handlers, in accord with EABI
SCB->CCR |= SCB_CCR_STKALIGN_Msk;
}
void SystemClock_Config(void) {
// Set flash latency to 1 because SYSCLK > 24MHz
FLASH->ACR = (FLASH->ACR & ~0x7) | 0x1;
// Use the 48MHz internal oscillator
RCC->CR2 |= RCC_CR2_HSI48ON;
while ((RCC->CR2 & RCC_CR2_HSI48RDY) == 0) {
}
RCC->CFGR |= 3 << RCC_CFGR_SW_Pos;
while (((RCC->CFGR >> RCC_CFGR_SWS_Pos) & 0x3) != 0x03) {
// Wait for SYSCLK source to change
}
SystemCoreClockUpdate();
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
}
void SystemCoreClockUpdate(void) {
// Get SYSCLK source
uint32_t tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp) {
case RCC_CFGR_SWS_HSI:
SystemCoreClock = HSI_VALUE;
break;
case RCC_CFGR_SWS_HSE:
SystemCoreClock = HSE_VALUE;
break;
case RCC_CFGR_SWS_PLL: {
/* Get PLL clock source and multiplication factor */
uint32_t pllmull = RCC->CFGR & RCC_CFGR_PLLMUL;
uint32_t pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
pllmull = (pllmull >> 18) + 2;
uint32_t predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1;
if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV) {
/* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */
SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull;
#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F072xB) \
|| defined(STM32F078xx) || defined(STM32F091xC) || defined(STM32F098xx)
} else if (pllsource == RCC_CFGR_PLLSRC_HSI48_PREDIV) {
/* HSI48 used as PLL clock source : SystemCoreClock = HSI48/PREDIV * PLLMUL */
SystemCoreClock = (HSI48_VALUE/predivfactor) * pllmull;
#endif
} else {
#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F070x6) \
|| defined(STM32F078xx) || defined(STM32F071xB) || defined(STM32F072xB) \
|| defined(STM32F070xB) || defined(STM32F091xC) || defined(STM32F098xx) || defined(STM32F030xC)
/* HSI used as PLL clock source : SystemCoreClock = HSI/PREDIV * PLLMUL */
SystemCoreClock = (HSI_VALUE / predivfactor) * pllmull;
#else
/* HSI used as PLL clock source : SystemCoreClock = HSI/2 * PLLMUL */
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
#endif
}
break;
}
case RCC_CFGR_SWS_HSI48:
SystemCoreClock = HSI48_VALUE;
break;
default:
SystemCoreClock = HSI_VALUE;
break;
}
// Compute HCLK clock frequency
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
SystemCoreClock >>= tmp;
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -231,16 +231,22 @@ uint32_t timer_get_source_freq(uint32_t tim_id) {
uint32_t source, clk_div;
if (tim_id == 1 || (8 <= tim_id && tim_id <= 11)) {
// TIM{1,8,9,10,11} are on APB2
#if defined(STM32F0)
source = HAL_RCC_GetPCLK1Freq();
clk_div = RCC->CFGR & RCC_CFGR_PPRE;
#elif defined(STM32H7)
source = HAL_RCC_GetPCLK2Freq();
#if defined(STM32H7)
clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE2;
#else
source = HAL_RCC_GetPCLK2Freq();
clk_div = RCC->CFGR & RCC_CFGR_PPRE2;
#endif
} else {
// TIM{2,3,4,5,6,7,12,13,14} are on APB1
source = HAL_RCC_GetPCLK1Freq();
#if defined(STM32H7)
#if defined(STM32F0)
clk_div = RCC->CFGR & RCC_CFGR_PPRE;
#elif defined(STM32H7)
clk_div = RCC->D2CFGR & RCC_D2CFGR_D2PPRE1;
#else
clk_div = RCC->CFGR & RCC_CFGR_PPRE1;
@ -694,25 +700,27 @@ STATIC const uint32_t tim_instance_table[MICROPY_HW_MAX_TIMER] = {
#if defined(TIM13)
TIM_ENTRY(13, TIM8_UP_TIM13_IRQn),
#endif
#if defined(TIM14)
#if defined(STM32F0)
TIM_ENTRY(14, TIM14_IRQn),
#elif defined(TIM14)
TIM_ENTRY(14, TIM8_TRG_COM_TIM14_IRQn),
#endif
#if defined(TIM15)
#if defined(STM32H7)
#if defined(STM32F0) || defined(STM32H7)
TIM_ENTRY(15, TIM15_IRQn),
#else
TIM_ENTRY(15, TIM1_BRK_TIM15_IRQn),
#endif
#endif
#if defined(TIM16)
#if defined(STM32H7)
#if defined(STM32F0) || defined(STM32H7)
TIM_ENTRY(16, TIM16_IRQn),
#else
TIM_ENTRY(16, TIM1_UP_TIM16_IRQn),
#endif
#endif
#if defined(TIM17)
#if defined(STM32H7)
#if defined(STM32F0) || defined(STM32H7)
TIM_ENTRY(17, TIM17_IRQn),
#else
TIM_ENTRY(17, TIM1_TRG_COM_TIM17_IRQn),

View File

@ -289,11 +289,17 @@ STATIC bool uart_init2(pyb_uart_obj_t *uart_obj) {
#if defined(MICROPY_HW_UART8_TX) && defined(MICROPY_HW_UART8_RX)
case PYB_UART_8:
uart_unit = 8;
#if defined(STM32F0)
UARTx = USART8;
irqn = USART3_8_IRQn;
__HAL_RCC_USART8_CLK_ENABLE();
#else
UARTx = UART8;
irqn = UART8_IRQn;
__HAL_RCC_UART8_CLK_ENABLE();
#endif
pins[0] = MICROPY_HW_UART8_TX;
pins[1] = MICROPY_HW_UART8_RX;
__HAL_RCC_UART8_CLK_ENABLE();
break;
#endif
@ -390,7 +396,7 @@ int uart_rx_char(pyb_uart_obj_t *self) {
return data;
} else {
// no buffering
#if defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
#if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
return self->uart.Instance->RDR & self->char_mask;
#else
return self->uart.Instance->DR & self->char_mask;
@ -508,7 +514,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(STM32F7) || defined(STM32L4) || defined(STM32H7)
#if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
int data = self->uart.Instance->RDR; // clears UART_FLAG_RXNE
#else
int data = self->uart.Instance->DR; // clears UART_FLAG_RXNE
@ -698,7 +704,9 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const
// compute actual baudrate that was configured
// (this formula assumes UART_OVERSAMPLING_16)
uint32_t actual_baudrate = 0;
#if defined(STM32F7) || defined(STM32H7)
#if defined(STM32F0)
actual_baudrate = HAL_RCC_GetPCLK1Freq();
#elif defined(STM32F7) || defined(STM32H7)
UART_ClockSourceTypeDef clocksource = UART_CLOCKSOURCE_UNDEFINED;
UART_GETCLOCKSOURCE(&self->uart, clocksource);
switch (clocksource) {
@ -854,7 +862,9 @@ STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
__HAL_RCC_USART2_CLK_DISABLE();
#if defined(USART3)
} else if (uart->Instance == USART3) {
#if !defined(STM32F0)
HAL_NVIC_DisableIRQ(USART3_IRQn);
#endif
__HAL_RCC_USART3_FORCE_RESET();
__HAL_RCC_USART3_RELEASE_RESET();
__HAL_RCC_USART3_CLK_DISABLE();
@ -949,7 +959,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 = self_in;
#if defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
#if defined(STM32F0) || defined(STM32F7) || defined(STM32L4) || defined(STM32H7)
self->uart.Instance->RQR = USART_RQR_SBKRQ; // write-only register
#else
self->uart.Instance->CR1 |= USART_CR1_SBK;