stm32/mboot: Add support for H7 MCUs, with H743 flash layout.

This commit is contained in:
Damien George 2019-04-08 14:33:57 +10:00
parent ae1e18a346
commit fd13ce5e60
3 changed files with 202 additions and 11 deletions

View File

@ -48,6 +48,7 @@ CFLAGS_CORTEX_M = -mthumb
# Options for particular MCU series
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_h7 = $(CFLAGS_CORTEX_M) -mtune=cortex-m7 -mcpu=cortex-m7
CFLAGS_MCU_l4 = $(CFLAGS_CORTEX_M) -mtune=cortex-m4 -mcpu=cortex-m4
CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_EXTRA)

View File

@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2017-2018 Damien P. George
* Copyright (c) 2017-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
@ -38,7 +38,7 @@
// This DFU code with polling runs in about 70% of the time of the ST bootloader
#define USE_USB_POLLING (1)
// Using cache probably won't make it faster because we run at 48MHz, and best
// Using cache probably won't make it faster because we run at a low frequency, and best
// to keep the MCU config as minimal as possible.
#define USE_CACHE (0)
@ -46,18 +46,25 @@
#define IRQ_PRI_SYSTICK (NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 0, 0))
#define IRQ_PRI_I2C (NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 1, 0))
// Configure PLL to give a 48MHz CPU freq
// Configure PLL to give the desired CPU freq
#undef MICROPY_HW_FLASH_LATENCY
#if defined(STM32H7)
#define CORE_PLL_FREQ (96000000)
#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_2
#else
#define CORE_PLL_FREQ (48000000)
#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_1
#endif
#undef MICROPY_HW_CLK_PLLM
#undef MICROPY_HW_CLK_PLLN
#undef MICROPY_HW_CLK_PLLP
#undef MICROPY_HW_CLK_PLLQ
#undef MICROPY_HW_FLASH_LATENCY
#undef MICROPY_HW_CLK_PLLR
#define MICROPY_HW_CLK_PLLM (HSE_VALUE / 1000000)
#define MICROPY_HW_CLK_PLLN (192)
#define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV4)
#define MICROPY_HW_CLK_PLLP (MICROPY_HW_CLK_PLLN / (CORE_PLL_FREQ / 1000000))
#define MICROPY_HW_CLK_PLLQ (4)
#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_1
#define MICROPY_HW_CLK_PLLR (2)
// Work out which USB device to use for the USB DFU interface
#if !defined(MICROPY_HW_USB_MAIN_DEV)
@ -137,11 +144,25 @@ static void __fatal_error(const char *msg) {
#define CONFIG_RCC_CR_2ND (RCC_CR_HSEON || RCC_CR_CSSON || RCC_CR_PLLON)
#define CONFIG_RCC_PLLCFGR (0x24003010)
#elif defined(STM32H7)
#define CONFIG_RCC_CR_1ST (RCC_CR_HSION)
#define CONFIG_RCC_CR_2ND (RCC_CR_PLL3ON | RCC_CR_PLL2ON | RCC_CR_PLL1ON | RCC_CR_CSSHSEON \
| RCC_CR_HSEON | RCC_CR_HSI48ON | RCC_CR_CSIKERON | RCC_CR_CSION)
#define CONFIG_RCC_PLLCFGR (0x00000000)
#else
#error Unknown processor
#endif
void SystemInit(void) {
#if defined(STM32H7)
// Configure write-once power options, and wait for voltage levels to be ready
PWR->CR3 = PWR_CR3_LDOEN;
while (!(PWR->CSR1 & PWR_CSR1_ACTVOSRDY)) {
}
#endif
// Set HSION bit
RCC->CR |= CONFIG_RCC_CR_1ST;
@ -154,11 +175,27 @@ void SystemInit(void) {
// Reset PLLCFGR register
RCC->PLLCFGR = CONFIG_RCC_PLLCFGR;
#if defined(STM32H7)
// Reset PLL and clock configuration registers
RCC->D1CFGR = 0x00000000;
RCC->D2CFGR = 0x00000000;
RCC->D3CFGR = 0x00000000;
RCC->PLLCKSELR = 0x00000000;
RCC->D1CCIPR = 0x00000000;
RCC->D2CCIP1R = 0x00000000;
RCC->D2CCIP2R = 0x00000000;
RCC->D3CCIPR = 0x00000000;
#endif
// Reset HSEBYP bit
RCC->CR &= (uint32_t)0xFFFBFFFF;
// Disable all interrupts
#if defined(STM32F4) || defined(STM32F7)
RCC->CIR = 0x00000000;
#elif defined(STM32H7)
RCC->CIER = 0x00000000;
#endif
// Set location of vector table
SCB->VTOR = FLASH_BASE;
@ -173,6 +210,8 @@ void systick_init(void) {
NVIC_SetPriority(SysTick_IRQn, IRQ_PRI_SYSTICK);
}
#if defined(STM32F4) || defined(STM32F7)
void SystemClock_Config(void) {
// This function assumes that HSI is used as the system clock (see RCC->CFGR, SWS bits)
@ -243,6 +282,87 @@ void SystemClock_Config(void) {
#endif
}
#elif defined(STM32H7)
void SystemClock_Config(void) {
// This function assumes that HSI is used as the system clock (see RCC->CFGR, SWS bits)
// Select VOS level as high voltage to give reliable operation
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while (__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY) == RESET) {
}
// Turn HSE on
__HAL_RCC_HSE_CONFIG(RCC_HSE_ON);
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET) {
}
// Disable PLL1
__HAL_RCC_PLL_DISABLE();
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET) {
}
// Configure PLL1 factors and source
RCC->PLLCKSELR =
MICROPY_HW_CLK_PLLM << RCC_PLLCKSELR_DIVM1_Pos
| 2 << RCC_PLLCKSELR_PLLSRC_Pos; // HSE selected as PLL source
RCC->PLL1DIVR =
(MICROPY_HW_CLK_PLLN - 1) << RCC_PLL1DIVR_N1_Pos
| (MICROPY_HW_CLK_PLLP - 1) << RCC_PLL1DIVR_P1_Pos // only even P allowed
| (MICROPY_HW_CLK_PLLQ - 1) << RCC_PLL1DIVR_Q1_Pos
| (MICROPY_HW_CLK_PLLR - 1) << RCC_PLL1DIVR_R1_Pos;
// Enable PLL1 outputs for SYSCLK and USB
RCC->PLLCFGR = RCC_PLLCFGR_DIVP1EN | RCC_PLLCFGR_DIVQ1EN;
// Select PLL1-Q for USB clock source
RCC->D2CCIP2R |= 1 << RCC_D2CCIP2R_USBSEL_Pos;
// Enable PLL1
__HAL_RCC_PLL_ENABLE();
while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET) {
}
// Increase latency before changing SYSCLK
if (MICROPY_HW_FLASH_LATENCY > (FLASH->ACR & FLASH_ACR_LATENCY)) {
__HAL_FLASH_SET_LATENCY(MICROPY_HW_FLASH_LATENCY);
}
// Configure AHB divider
RCC->D1CFGR =
0 << RCC_D1CFGR_D1CPRE_Pos // SYSCLK prescaler of 1
| 8 << RCC_D1CFGR_HPRE_Pos // AHB prescaler of 2
;
// Configure SYSCLK source from PLL
__HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_PLLCLK);
while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL1) {
}
// Decrease latency after changing clock
if (MICROPY_HW_FLASH_LATENCY < (FLASH->ACR & FLASH_ACR_LATENCY)) {
__HAL_FLASH_SET_LATENCY(MICROPY_HW_FLASH_LATENCY);
}
// Set APB clock dividers
RCC->D1CFGR |=
4 << RCC_D1CFGR_D1PPRE_Pos // APB3 prescaler of 2
;
RCC->D2CFGR =
4 << RCC_D2CFGR_D2PPRE2_Pos // APB2 prescaler of 2
| 4 << RCC_D2CFGR_D2PPRE1_Pos // APB1 prescaler of 2
;
RCC->D3CFGR =
4 << RCC_D3CFGR_D3PPRE_Pos // APB4 prescaler of 2
;
// Update clock value and reconfigure systick now that the frequency changed
SystemCoreClock = CORE_PLL_FREQ;
systick_init();
}
#endif
// Needed by HAL_PCD_IRQHandler
uint32_t HAL_RCC_GetHCLKFreq(void) {
return SystemCoreClock;
@ -251,13 +371,21 @@ uint32_t HAL_RCC_GetHCLKFreq(void) {
/******************************************************************************/
// GPIO
#if defined(STM32F4) || defined(STM32F7)
#define AHBxENR AHB1ENR
#define AHBxENR_GPIOAEN_Pos RCC_AHB1ENR_GPIOAEN_Pos
#elif defined(STM32H7)
#define AHBxENR AHB4ENR
#define AHBxENR_GPIOAEN_Pos RCC_AHB4ENR_GPIOAEN_Pos
#endif
void mp_hal_pin_config(mp_hal_pin_obj_t port_pin, uint32_t mode, uint32_t pull, uint32_t alt) {
GPIO_TypeDef *gpio = (GPIO_TypeDef*)(port_pin & ~0xf);
// Enable the GPIO peripheral clock
uint32_t en_bit = RCC_AHB1ENR_GPIOAEN_Pos + ((uintptr_t)gpio - GPIOA_BASE) / (GPIOB_BASE - GPIOA_BASE);
RCC->AHB1ENR |= 1 << en_bit;
volatile uint32_t tmp = RCC->AHB1ENR; // Delay after enabling clock
uint32_t gpio_idx = ((uintptr_t)gpio - GPIOA_BASE) / (GPIOB_BASE - GPIOA_BASE);
RCC->AHBxENR |= 1 << (AHBxENR_GPIOAEN_Pos + gpio_idx);
volatile uint32_t tmp = RCC->AHBxENR; // Delay after enabling clock
(void)tmp;
// Configure the pin
@ -381,6 +509,14 @@ static const flash_layout_t flash_layout[] = {
{ 0x08040000, 0x40000, 7 },
};
#elif defined(STM32H743xx)
#define FLASH_LAYOUT_STR "@Internal Flash /0x08000000/16*128Kg" MBOOT_SPIFLASH_LAYOUT MBOOT_SPIFLASH2_LAYOUT
static const flash_layout_t flash_layout[] = {
{ 0x08000000, 0x20000, 16 },
};
#endif
static uint32_t flash_get_sector_index(uint32_t addr, uint32_t *sector_size) {
@ -401,6 +537,27 @@ static uint32_t flash_get_sector_index(uint32_t addr, uint32_t *sector_size) {
return 0;
}
#if defined(STM32H7)
// get the bank of a given flash address
static uint32_t get_bank(uint32_t addr) {
if (READ_BIT(FLASH->OPTCR, FLASH_OPTCR_SWAP_BANK) == 0) {
// no bank swap
if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
return FLASH_BANK_1;
} else {
return FLASH_BANK_2;
}
} else {
// bank swap
if (addr < (FLASH_BASE + FLASH_BANK_SIZE)) {
return FLASH_BANK_2;
} else {
return FLASH_BANK_1;
}
}
}
#endif
static int flash_mass_erase(void) {
// TODO
return -1;
@ -419,13 +576,20 @@ static int flash_page_erase(uint32_t addr, uint32_t *next_addr) {
HAL_FLASH_Unlock();
// Clear pending flags (if any)
#if defined(STM32H7)
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS_BANK1 | FLASH_FLAG_ALL_ERRORS_BANK2);
#else
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
#endif
// erase the sector(s)
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; // voltage range needs to be 2.7V to 3.6V
#if defined(STM32H7)
EraseInitStruct.Banks = get_bank(addr);
#endif
EraseInitStruct.Sector = sector;
EraseInitStruct.NbSectors = 1;
@ -454,6 +618,20 @@ static int flash_write(uint32_t addr, const uint8_t *src8, size_t len) {
const uint32_t *src = (const uint32_t*)src8;
size_t num_word32 = (len + 3) / 4;
HAL_FLASH_Unlock();
#if defined(STM32H7)
// program the flash 256 bits at a time
for (int i = 0; i < num_word32 / 8; ++i) {
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, addr, (uint64_t)(uint32_t)src) != HAL_OK) {
return - 1;
}
addr += 32;
src += 8;
}
#else
// program the flash word by word
for (size_t i = 0; i < num_word32; i++) {
if (HAL_FLASH_Program(TYPEPROGRAM_WORD, addr, *src) != HAL_OK) {
@ -463,6 +641,8 @@ static int flash_write(uint32_t addr, const uint8_t *src8, size_t len) {
src += 1;
}
#endif
// TODO verify data
return 0;
@ -1130,6 +1310,11 @@ static void pyb_usbdd_init(pyb_usbdd_obj_t *self, int phy_id) {
static void pyb_usbdd_start(pyb_usbdd_obj_t *self) {
if (!self->started) {
#if defined(STM32H7)
PWR->CR3 |= PWR_CR3_USB33DEN;
while (!(PWR->CR3 & PWR_CR3_USB33RDY)) {
}
#endif
USBD_LL_Init(&self->hUSBDDevice, 0);
USBD_LL_Start(&self->hUSBDDevice);
self->started = true;
@ -1249,8 +1434,8 @@ void stm32_main(int initial_r0) {
goto enter_bootloader;
}
// MCU starts up with 16MHz HSI
SystemCoreClock = 16000000;
// MCU starts up with HSI
SystemCoreClock = HSI_VALUE;
int reset_mode = get_reset_mode();
uint32_t msp = *(volatile uint32_t*)APPLICATION_ADDR;

View File

@ -48,8 +48,13 @@
#define mp_hal_pin_input(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_INPUT, MP_HAL_PIN_PULL_NONE, 0)
#define mp_hal_pin_output(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OUTPUT, MP_HAL_PIN_PULL_NONE, 0)
#define mp_hal_pin_open_drain(p) mp_hal_pin_config((p), MP_HAL_PIN_MODE_OPEN_DRAIN, MP_HAL_PIN_PULL_NONE, 0)
#if defined(STM32H7)
#define mp_hal_pin_low(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRRH = 1 << ((p) & 0xf))
#define mp_hal_pin_high(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRRL = 1 << ((p) & 0xf))
#else
#define mp_hal_pin_low(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRR = 0x10000 << ((p) & 0xf))
#define mp_hal_pin_high(p) (((GPIO_TypeDef*)((p) & ~0xf))->BSRR = 1 << ((p) & 0xf))
#endif
#define mp_hal_pin_od_low(p) mp_hal_pin_low(p)
#define mp_hal_pin_od_high(p) mp_hal_pin_high(p)
#define mp_hal_pin_read(p) ((((GPIO_TypeDef*)((p) & ~0xf))->IDR >> ((p) & 0xf)) & 1)