mirror of https://github.com/wolfSSL/wolfBoot.git
Add STM32F103 (Blue Pill) support
The Blue Pill board is typically fitted with a STM32F103C8T6, but reports online seem to indicate that it sometimes can come with its bigger sibling the STM32F103C8TB as is the case with my board. This patch adds support for all low- to medium-density STM32F103 devices. All of these devices have their flash divided in 1 KB pages, up to 128 KB. The high-density and connectivity line of devices, sometimes called XL devices, use 2 KB pages and are not supported. Similar to the STM32F4 support, the code will spin up the PLL for maximum speed during init and turn it off just before booting the application. the maxium speed is 72 MHz. Signed-off-by: Patrik Dahlström <risca@dalakolonin.se>pull/555/head
parent
b9a39580d4
commit
523051331e
6
arch.mk
6
arch.mk
|
@ -139,6 +139,12 @@ ifeq ($(ARCH),ARM)
|
|||
ARCH_FLASH_OFFSET=0x08000000
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),stm32f1)
|
||||
CORTEX_M3=1
|
||||
NO_ARM_ASM=1
|
||||
ARCH_FLASH_OFFSET=0x08000000
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),stm32f4)
|
||||
ARCH_FLASH_OFFSET=0x08000000
|
||||
SPI_TARGET=stm32
|
||||
|
|
|
@ -0,0 +1,334 @@
|
|||
/* stm32f1.c
|
||||
*
|
||||
* Copyright (C) 2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "image.h"
|
||||
|
||||
#ifndef ARCH_FLASH_OFFSET
|
||||
#define ARCH_FLASH_OFFSET 0x08000000U
|
||||
#endif
|
||||
|
||||
/* STM32 F103 register Assembly helpers */
|
||||
#define DMB() asm volatile ("dmb")
|
||||
|
||||
/*** RCC ***/
|
||||
#define RCC_BASE (0x40021000U)
|
||||
#define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00U))
|
||||
#define RCC_CFGR (*(volatile uint32_t *)(RCC_BASE + 0x04U))
|
||||
|
||||
#define RCC_CR_PLLRDY (1 << 25)
|
||||
#define RCC_CR_PLLON (1 << 24)
|
||||
#define RCC_CR_HSERDY (1 << 17)
|
||||
#define RCC_CR_HSEON (1 << 16)
|
||||
#define RCC_CR_HSIRDY (1 << 1)
|
||||
#define RCC_CR_HSION (1 << 0)
|
||||
|
||||
#define RCC_CFGR_SW_MASK 0x0003
|
||||
#define RCC_CFGR_SW_HSI 0x0
|
||||
#define RCC_CFGR_SW_HSE 0x1
|
||||
#define RCC_CFGR_SW_PLL 0x2
|
||||
|
||||
#define RCC_CFGR_SWS_MASK 0x000C
|
||||
#define RCC_CFGR_SWS_HSI (0 << 2)
|
||||
#define RCC_CFGR_SWS_HSE (1 << 2)
|
||||
#define RCC_CFGR_SWS_PLL (2 << 2)
|
||||
|
||||
#define RCC_CFGR_HPRE_MASK 0x00F0
|
||||
#define RCC_CFGR_HPRE_DIV_NONE (0 << 4)
|
||||
#define RCC_CFGR_HPRE_DIV_2 (8 << 4)
|
||||
#define RCC_CFGR_HPRE_DIV_4 (9 << 4)
|
||||
|
||||
#define RCC_CFGR_PPRE1_MASK 0x0700
|
||||
#define RCC_CFGR_PPRE1_DIV_NONE (0 << 8)
|
||||
#define RCC_CFGR_PPRE1_DIV_2 (4 << 8)
|
||||
#define RCC_CFGR_PPRE1_DIV_4 (5 << 8)
|
||||
|
||||
#define RCC_CFGR_PPRE2_MASK 0x3800
|
||||
#define RCC_CFGR_PPRE2_DIV_NONE (0 << 11)
|
||||
#define RCC_CFGR_PPRE2_DIV_2 (4 << 11)
|
||||
#define RCC_CFGR_PPRE2_DIV_4 (5 << 11)
|
||||
|
||||
#define PLL_FULL_MASK (0x003F0000)
|
||||
#define RCC_CFGR_PLLSRC (1 << 22)
|
||||
#define RCC_CFGR_PLLMUL_MUL_9 (7 << 18)
|
||||
|
||||
/*** FLASH ***/
|
||||
#define RCC_APB1ENR (*(volatile uint32_t *)(RCC_BASE + 0x1C))
|
||||
#define RCC_APB1ENR_PWREN (1 << 28)
|
||||
|
||||
#define FLASH_BASE (0x40022000U)
|
||||
#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00U))
|
||||
#define FLASH_KEYR (*(volatile uint32_t *)(FLASH_BASE + 0x04U))
|
||||
#define FLASH_SR (*(volatile uint32_t *)(FLASH_BASE + 0x0CU))
|
||||
#define FLASH_CR (*(volatile uint32_t *)(FLASH_BASE + 0x10U))
|
||||
#define FLASH_AR (*(volatile uint32_t *)(FLASH_BASE + 0x14U))
|
||||
|
||||
#define FLASH_MAX_SZ (128*1024) /* only low- and medium-density devices supported */
|
||||
#define FLASH_PAGE_SZ (1024)
|
||||
|
||||
/* Register values */
|
||||
#define FLASH_ACR_ENABLE_PRFT (1 << 4)
|
||||
|
||||
#define FLASH_SR_BSY (1 << 0)
|
||||
|
||||
#define FLASH_CR_LOCK (1 << 7)
|
||||
#define FLASH_CR_STRT (1 << 6)
|
||||
#define FLASH_CR_PER (1 << 1)
|
||||
#define FLASH_CR_PG (1 << 0)
|
||||
|
||||
#define FLASH_KEY1 (0x45670123U)
|
||||
#define FLASH_KEY2 (0xCDEF89ABU)
|
||||
|
||||
static void RAMFUNCTION flash_set_waitstates(int waitstates)
|
||||
{
|
||||
FLASH_ACR |= waitstates | FLASH_ACR_ENABLE_PRFT;
|
||||
}
|
||||
|
||||
static int RAMFUNCTION valid_flash_area(uint32_t address, int len)
|
||||
{
|
||||
if (len <= 0 || len > FLASH_MAX_SZ)
|
||||
return -1;
|
||||
if (address < ARCH_FLASH_OFFSET || address >= (ARCH_FLASH_OFFSET + FLASH_MAX_SZ))
|
||||
return -1;
|
||||
if ((address + len) > (ARCH_FLASH_OFFSET + FLASH_MAX_SZ))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void RAMFUNCTION flash_wait_complete(void)
|
||||
{
|
||||
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY)
|
||||
;
|
||||
}
|
||||
|
||||
static int RAMFUNCTION flash_erase_page(uint32_t address)
|
||||
{
|
||||
const uint32_t end = address + FLASH_PAGE_SZ;
|
||||
|
||||
flash_wait_complete();
|
||||
|
||||
FLASH_CR |= FLASH_CR_PER;
|
||||
FLASH_AR = address;
|
||||
FLASH_CR |= FLASH_CR_STRT;
|
||||
flash_wait_complete();
|
||||
FLASH_CR &= ~FLASH_CR_PER;
|
||||
|
||||
/* verify erase */
|
||||
while (address < end) {
|
||||
if (*(uint32_t*)address != (uint32_t)~0)
|
||||
return -1;
|
||||
|
||||
address += 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int RAMFUNCTION flash_w16(volatile uint16_t *dst, const uint16_t value)
|
||||
{
|
||||
/* do the write */
|
||||
*dst = value;
|
||||
DMB();
|
||||
flash_wait_complete();
|
||||
|
||||
/* verify */
|
||||
return (*dst == value) ? 0 : -1;
|
||||
}
|
||||
|
||||
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
|
||||
{
|
||||
uint16_t tmp;
|
||||
const uint8_t *src = data;
|
||||
const uint8_t * const end = src + len;
|
||||
/* make sure dst is aligned to 16 bits */
|
||||
volatile uint16_t *dst = (volatile uint16_t*)(address & ~1);
|
||||
|
||||
if (valid_flash_area(address, len) != 0)
|
||||
return -1;
|
||||
|
||||
flash_wait_complete();
|
||||
FLASH_CR |= FLASH_CR_PG;
|
||||
/* writes are 16 bits. Check for unaligned initial write */
|
||||
if (address & 1) {
|
||||
/* read-modify-write */
|
||||
tmp = (*dst & 0x00FF) | (data[0] << 8);
|
||||
if (flash_w16(dst, tmp) != 0) {
|
||||
FLASH_CR &= ~FLASH_CR_PG;
|
||||
return -1;
|
||||
}
|
||||
/* advance dst 2 bytes, src 1 byte */
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
/* main write loop */
|
||||
while (src < end) {
|
||||
/* check for unaligned last write */
|
||||
if (src + 1 == end) {
|
||||
/* read-modify-write */
|
||||
tmp = (*dst & 0xFF00) | *src;
|
||||
if (flash_w16(dst, tmp) != 0) {
|
||||
FLASH_CR &= ~FLASH_CR_PG;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* all systems go for a regular write */
|
||||
tmp = *(const uint16_t*)src;
|
||||
if (flash_w16(dst, tmp) != 0) {
|
||||
FLASH_CR &= ~FLASH_CR_PG;
|
||||
return -1;
|
||||
}
|
||||
/* advance 2 bytes */
|
||||
src += 2;
|
||||
dst++;
|
||||
}
|
||||
FLASH_CR &= ~FLASH_CR_PG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RAMFUNCTION hal_flash_unlock(void)
|
||||
{
|
||||
FLASH_KEYR = FLASH_KEY1;
|
||||
FLASH_KEYR = FLASH_KEY2;
|
||||
}
|
||||
|
||||
void RAMFUNCTION hal_flash_lock(void)
|
||||
{
|
||||
FLASH_CR |= FLASH_CR_LOCK;
|
||||
}
|
||||
|
||||
int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
|
||||
{
|
||||
const uint32_t end_address = address + len;
|
||||
|
||||
if (valid_flash_area(address, len) != 0)
|
||||
return -1;
|
||||
if (len % FLASH_PAGE_SZ)
|
||||
return -1;
|
||||
|
||||
while (address < end_address) {
|
||||
if (flash_erase_page(address))
|
||||
return -1;
|
||||
|
||||
address += FLASH_PAGE_SZ;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clock_pll_off(void)
|
||||
{
|
||||
uint32_t reg32;
|
||||
|
||||
/* Enable internal high-speed oscillator. */
|
||||
RCC_CR |= RCC_CR_HSION;
|
||||
DMB();
|
||||
while ((RCC_CR & RCC_CR_HSIRDY) == 0) {};
|
||||
|
||||
/* Select HSI as SYSCLK source. */
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~(RCC_CFGR_SW_MASK);
|
||||
RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI);
|
||||
DMB();
|
||||
|
||||
/* Turn off PLL */
|
||||
RCC_CR &= ~RCC_CR_PLLON;
|
||||
DMB();
|
||||
}
|
||||
|
||||
static void clock_pll_on(int powersave)
|
||||
{
|
||||
uint32_t reg32;
|
||||
|
||||
/* Enable Power controller */
|
||||
RCC_APB1ENR |= RCC_APB1ENR_PWREN;
|
||||
|
||||
/* 2 wait states, if 48 MHz < SYSCLK <= 72 MHz */
|
||||
flash_set_waitstates(2);
|
||||
|
||||
/* Enable internal high-speed oscillator. */
|
||||
RCC_CR |= RCC_CR_HSION;
|
||||
DMB();
|
||||
while ((RCC_CR & RCC_CR_HSIRDY) == 0) {};
|
||||
|
||||
/* Select HSI as SYSCLK source. */
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~(RCC_CFGR_SW_MASK);
|
||||
RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI);
|
||||
DMB();
|
||||
|
||||
/* Enable external high-speed oscillator 8MHz. */
|
||||
RCC_CR |= RCC_CR_HSEON;
|
||||
DMB();
|
||||
while ((RCC_CR & RCC_CR_HSERDY) == 0) {};
|
||||
|
||||
/*
|
||||
* Set prescalers for AHB, ABP1, ABP2.
|
||||
*/
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~(RCC_CFGR_HPRE_MASK);
|
||||
RCC_CFGR = reg32 | RCC_CFGR_HPRE_DIV_NONE;
|
||||
DMB();
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~(RCC_CFGR_PPRE1_MASK);
|
||||
RCC_CFGR = reg32 | RCC_CFGR_PPRE1_DIV_2;
|
||||
DMB();
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~(RCC_CFGR_PPRE2_MASK);
|
||||
RCC_CFGR = reg32 | RCC_CFGR_PPRE1_DIV_NONE;
|
||||
DMB();
|
||||
|
||||
/* Set PLL config */
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~(PLL_FULL_MASK);
|
||||
/* PLL clock: 8 MHz (HSE) * 9 = 72 MHz */
|
||||
RCC_CFGR = reg32 | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL_MUL_9;
|
||||
DMB();
|
||||
/* Enable PLL oscillator and wait for it to stabilize. */
|
||||
RCC_CR |= RCC_CR_PLLON;
|
||||
DMB();
|
||||
while ((RCC_CR & RCC_CR_PLLRDY) == 0) {};
|
||||
|
||||
/* Select PLL as SYSCLK source. */
|
||||
reg32 = RCC_CFGR;
|
||||
reg32 &= ~(RCC_CFGR_SW_MASK);
|
||||
RCC_CFGR = (reg32 | RCC_CFGR_SW_PLL);
|
||||
DMB();
|
||||
|
||||
/* Wait for PLL clock to be selected. */
|
||||
while ((RCC_CFGR & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_PLL) {};
|
||||
|
||||
/* Disable internal high-speed oscillator. */
|
||||
RCC_CR &= ~RCC_CR_HSION;
|
||||
}
|
||||
|
||||
void hal_init(void)
|
||||
{
|
||||
clock_pll_on(0);
|
||||
}
|
||||
|
||||
void hal_prepare_boot(void)
|
||||
{
|
||||
clock_pll_off();
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = @BOOTLOADER_PARTITION_SIZE@
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
_start_text = .;
|
||||
KEEP(*(.isr_vector))
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
. = ALIGN(4);
|
||||
_end_text = .;
|
||||
} > FLASH
|
||||
.edidx :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.ARM.exidx*)
|
||||
} > FLASH
|
||||
|
||||
.edidx :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.ARM.exidx*)
|
||||
} > FLASH
|
||||
|
||||
|
||||
_stored_data = .;
|
||||
.data : AT (_stored_data)
|
||||
{
|
||||
_start_data = .;
|
||||
KEEP(*(.data*))
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.ramcode))
|
||||
. = ALIGN(4);
|
||||
_end_data = .;
|
||||
} > RAM
|
||||
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
_start_bss = .;
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_end_bss = .;
|
||||
__bss_end__ = .;
|
||||
_end = .;
|
||||
} > RAM
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
_wolfboot_partition_boot_address = @WOLFBOOT_PARTITION_BOOT_ADDRESS@;
|
||||
_wolfboot_partition_size = @WOLFBOOT_PARTITION_SIZE@;
|
||||
_wolfboot_partition_update_address = @WOLFBOOT_PARTITION_UPDATE_ADDRESS@;
|
||||
_wolfboot_partition_swap_address = @WOLFBOOT_PARTITION_SWAP_ADDRESS@;
|
||||
|
||||
END_STACK = ORIGIN(RAM) + LENGTH(RAM);
|
Loading…
Reference in New Issue