Skip to content

Commit 5230513

Browse files
Riscadanielinux
authored andcommitted
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 <[email protected]>
1 parent b9a3958 commit 5230513

File tree

3 files changed

+401
-0
lines changed

3 files changed

+401
-0
lines changed

arch.mk

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ ifeq ($(ARCH),ARM)
139139
ARCH_FLASH_OFFSET=0x08000000
140140
endif
141141

142+
ifeq ($(TARGET),stm32f1)
143+
CORTEX_M3=1
144+
NO_ARM_ASM=1
145+
ARCH_FLASH_OFFSET=0x08000000
146+
endif
147+
142148
ifeq ($(TARGET),stm32f4)
143149
ARCH_FLASH_OFFSET=0x08000000
144150
SPI_TARGET=stm32

hal/stm32f1.c

Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
/* stm32f1.c
2+
*
3+
* Copyright (C) 2025 wolfSSL Inc.
4+
*
5+
* This file is part of wolfBoot.
6+
*
7+
* wolfBoot is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfBoot is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
22+
#include <stdint.h>
23+
#include <string.h>
24+
25+
#include "image.h"
26+
27+
#ifndef ARCH_FLASH_OFFSET
28+
#define ARCH_FLASH_OFFSET 0x08000000U
29+
#endif
30+
31+
/* STM32 F103 register Assembly helpers */
32+
#define DMB() asm volatile ("dmb")
33+
34+
/*** RCC ***/
35+
#define RCC_BASE (0x40021000U)
36+
#define RCC_CR (*(volatile uint32_t *)(RCC_BASE + 0x00U))
37+
#define RCC_CFGR (*(volatile uint32_t *)(RCC_BASE + 0x04U))
38+
39+
#define RCC_CR_PLLRDY (1 << 25)
40+
#define RCC_CR_PLLON (1 << 24)
41+
#define RCC_CR_HSERDY (1 << 17)
42+
#define RCC_CR_HSEON (1 << 16)
43+
#define RCC_CR_HSIRDY (1 << 1)
44+
#define RCC_CR_HSION (1 << 0)
45+
46+
#define RCC_CFGR_SW_MASK 0x0003
47+
#define RCC_CFGR_SW_HSI 0x0
48+
#define RCC_CFGR_SW_HSE 0x1
49+
#define RCC_CFGR_SW_PLL 0x2
50+
51+
#define RCC_CFGR_SWS_MASK 0x000C
52+
#define RCC_CFGR_SWS_HSI (0 << 2)
53+
#define RCC_CFGR_SWS_HSE (1 << 2)
54+
#define RCC_CFGR_SWS_PLL (2 << 2)
55+
56+
#define RCC_CFGR_HPRE_MASK 0x00F0
57+
#define RCC_CFGR_HPRE_DIV_NONE (0 << 4)
58+
#define RCC_CFGR_HPRE_DIV_2 (8 << 4)
59+
#define RCC_CFGR_HPRE_DIV_4 (9 << 4)
60+
61+
#define RCC_CFGR_PPRE1_MASK 0x0700
62+
#define RCC_CFGR_PPRE1_DIV_NONE (0 << 8)
63+
#define RCC_CFGR_PPRE1_DIV_2 (4 << 8)
64+
#define RCC_CFGR_PPRE1_DIV_4 (5 << 8)
65+
66+
#define RCC_CFGR_PPRE2_MASK 0x3800
67+
#define RCC_CFGR_PPRE2_DIV_NONE (0 << 11)
68+
#define RCC_CFGR_PPRE2_DIV_2 (4 << 11)
69+
#define RCC_CFGR_PPRE2_DIV_4 (5 << 11)
70+
71+
#define PLL_FULL_MASK (0x003F0000)
72+
#define RCC_CFGR_PLLSRC (1 << 22)
73+
#define RCC_CFGR_PLLMUL_MUL_9 (7 << 18)
74+
75+
/*** FLASH ***/
76+
#define RCC_APB1ENR (*(volatile uint32_t *)(RCC_BASE + 0x1C))
77+
#define RCC_APB1ENR_PWREN (1 << 28)
78+
79+
#define FLASH_BASE (0x40022000U)
80+
#define FLASH_ACR (*(volatile uint32_t *)(FLASH_BASE + 0x00U))
81+
#define FLASH_KEYR (*(volatile uint32_t *)(FLASH_BASE + 0x04U))
82+
#define FLASH_SR (*(volatile uint32_t *)(FLASH_BASE + 0x0CU))
83+
#define FLASH_CR (*(volatile uint32_t *)(FLASH_BASE + 0x10U))
84+
#define FLASH_AR (*(volatile uint32_t *)(FLASH_BASE + 0x14U))
85+
86+
#define FLASH_MAX_SZ (128*1024) /* only low- and medium-density devices supported */
87+
#define FLASH_PAGE_SZ (1024)
88+
89+
/* Register values */
90+
#define FLASH_ACR_ENABLE_PRFT (1 << 4)
91+
92+
#define FLASH_SR_BSY (1 << 0)
93+
94+
#define FLASH_CR_LOCK (1 << 7)
95+
#define FLASH_CR_STRT (1 << 6)
96+
#define FLASH_CR_PER (1 << 1)
97+
#define FLASH_CR_PG (1 << 0)
98+
99+
#define FLASH_KEY1 (0x45670123U)
100+
#define FLASH_KEY2 (0xCDEF89ABU)
101+
102+
static void RAMFUNCTION flash_set_waitstates(int waitstates)
103+
{
104+
FLASH_ACR |= waitstates | FLASH_ACR_ENABLE_PRFT;
105+
}
106+
107+
static int RAMFUNCTION valid_flash_area(uint32_t address, int len)
108+
{
109+
if (len <= 0 || len > FLASH_MAX_SZ)
110+
return -1;
111+
if (address < ARCH_FLASH_OFFSET || address >= (ARCH_FLASH_OFFSET + FLASH_MAX_SZ))
112+
return -1;
113+
if ((address + len) > (ARCH_FLASH_OFFSET + FLASH_MAX_SZ))
114+
return -1;
115+
116+
return 0;
117+
}
118+
119+
static inline void RAMFUNCTION flash_wait_complete(void)
120+
{
121+
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY)
122+
;
123+
}
124+
125+
static int RAMFUNCTION flash_erase_page(uint32_t address)
126+
{
127+
const uint32_t end = address + FLASH_PAGE_SZ;
128+
129+
flash_wait_complete();
130+
131+
FLASH_CR |= FLASH_CR_PER;
132+
FLASH_AR = address;
133+
FLASH_CR |= FLASH_CR_STRT;
134+
flash_wait_complete();
135+
FLASH_CR &= ~FLASH_CR_PER;
136+
137+
/* verify erase */
138+
while (address < end) {
139+
if (*(uint32_t*)address != (uint32_t)~0)
140+
return -1;
141+
142+
address += 4;
143+
}
144+
145+
return 0;
146+
}
147+
148+
static int RAMFUNCTION flash_w16(volatile uint16_t *dst, const uint16_t value)
149+
{
150+
/* do the write */
151+
*dst = value;
152+
DMB();
153+
flash_wait_complete();
154+
155+
/* verify */
156+
return (*dst == value) ? 0 : -1;
157+
}
158+
159+
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
160+
{
161+
uint16_t tmp;
162+
const uint8_t *src = data;
163+
const uint8_t * const end = src + len;
164+
/* make sure dst is aligned to 16 bits */
165+
volatile uint16_t *dst = (volatile uint16_t*)(address & ~1);
166+
167+
if (valid_flash_area(address, len) != 0)
168+
return -1;
169+
170+
flash_wait_complete();
171+
FLASH_CR |= FLASH_CR_PG;
172+
/* writes are 16 bits. Check for unaligned initial write */
173+
if (address & 1) {
174+
/* read-modify-write */
175+
tmp = (*dst & 0x00FF) | (data[0] << 8);
176+
if (flash_w16(dst, tmp) != 0) {
177+
FLASH_CR &= ~FLASH_CR_PG;
178+
return -1;
179+
}
180+
/* advance dst 2 bytes, src 1 byte */
181+
dst++;
182+
src++;
183+
}
184+
/* main write loop */
185+
while (src < end) {
186+
/* check for unaligned last write */
187+
if (src + 1 == end) {
188+
/* read-modify-write */
189+
tmp = (*dst & 0xFF00) | *src;
190+
if (flash_w16(dst, tmp) != 0) {
191+
FLASH_CR &= ~FLASH_CR_PG;
192+
return -1;
193+
}
194+
break;
195+
}
196+
/* all systems go for a regular write */
197+
tmp = *(const uint16_t*)src;
198+
if (flash_w16(dst, tmp) != 0) {
199+
FLASH_CR &= ~FLASH_CR_PG;
200+
return -1;
201+
}
202+
/* advance 2 bytes */
203+
src += 2;
204+
dst++;
205+
}
206+
FLASH_CR &= ~FLASH_CR_PG;
207+
return 0;
208+
}
209+
210+
void RAMFUNCTION hal_flash_unlock(void)
211+
{
212+
FLASH_KEYR = FLASH_KEY1;
213+
FLASH_KEYR = FLASH_KEY2;
214+
}
215+
216+
void RAMFUNCTION hal_flash_lock(void)
217+
{
218+
FLASH_CR |= FLASH_CR_LOCK;
219+
}
220+
221+
int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
222+
{
223+
const uint32_t end_address = address + len;
224+
225+
if (valid_flash_area(address, len) != 0)
226+
return -1;
227+
if (len % FLASH_PAGE_SZ)
228+
return -1;
229+
230+
while (address < end_address) {
231+
if (flash_erase_page(address))
232+
return -1;
233+
234+
address += FLASH_PAGE_SZ;
235+
}
236+
237+
return 0;
238+
}
239+
240+
static void clock_pll_off(void)
241+
{
242+
uint32_t reg32;
243+
244+
/* Enable internal high-speed oscillator. */
245+
RCC_CR |= RCC_CR_HSION;
246+
DMB();
247+
while ((RCC_CR & RCC_CR_HSIRDY) == 0) {};
248+
249+
/* Select HSI as SYSCLK source. */
250+
reg32 = RCC_CFGR;
251+
reg32 &= ~(RCC_CFGR_SW_MASK);
252+
RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI);
253+
DMB();
254+
255+
/* Turn off PLL */
256+
RCC_CR &= ~RCC_CR_PLLON;
257+
DMB();
258+
}
259+
260+
static void clock_pll_on(int powersave)
261+
{
262+
uint32_t reg32;
263+
264+
/* Enable Power controller */
265+
RCC_APB1ENR |= RCC_APB1ENR_PWREN;
266+
267+
/* 2 wait states, if 48 MHz < SYSCLK <= 72 MHz */
268+
flash_set_waitstates(2);
269+
270+
/* Enable internal high-speed oscillator. */
271+
RCC_CR |= RCC_CR_HSION;
272+
DMB();
273+
while ((RCC_CR & RCC_CR_HSIRDY) == 0) {};
274+
275+
/* Select HSI as SYSCLK source. */
276+
reg32 = RCC_CFGR;
277+
reg32 &= ~(RCC_CFGR_SW_MASK);
278+
RCC_CFGR = (reg32 | RCC_CFGR_SW_HSI);
279+
DMB();
280+
281+
/* Enable external high-speed oscillator 8MHz. */
282+
RCC_CR |= RCC_CR_HSEON;
283+
DMB();
284+
while ((RCC_CR & RCC_CR_HSERDY) == 0) {};
285+
286+
/*
287+
* Set prescalers for AHB, ABP1, ABP2.
288+
*/
289+
reg32 = RCC_CFGR;
290+
reg32 &= ~(RCC_CFGR_HPRE_MASK);
291+
RCC_CFGR = reg32 | RCC_CFGR_HPRE_DIV_NONE;
292+
DMB();
293+
reg32 = RCC_CFGR;
294+
reg32 &= ~(RCC_CFGR_PPRE1_MASK);
295+
RCC_CFGR = reg32 | RCC_CFGR_PPRE1_DIV_2;
296+
DMB();
297+
reg32 = RCC_CFGR;
298+
reg32 &= ~(RCC_CFGR_PPRE2_MASK);
299+
RCC_CFGR = reg32 | RCC_CFGR_PPRE1_DIV_NONE;
300+
DMB();
301+
302+
/* Set PLL config */
303+
reg32 = RCC_CFGR;
304+
reg32 &= ~(PLL_FULL_MASK);
305+
/* PLL clock: 8 MHz (HSE) * 9 = 72 MHz */
306+
RCC_CFGR = reg32 | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL_MUL_9;
307+
DMB();
308+
/* Enable PLL oscillator and wait for it to stabilize. */
309+
RCC_CR |= RCC_CR_PLLON;
310+
DMB();
311+
while ((RCC_CR & RCC_CR_PLLRDY) == 0) {};
312+
313+
/* Select PLL as SYSCLK source. */
314+
reg32 = RCC_CFGR;
315+
reg32 &= ~(RCC_CFGR_SW_MASK);
316+
RCC_CFGR = (reg32 | RCC_CFGR_SW_PLL);
317+
DMB();
318+
319+
/* Wait for PLL clock to be selected. */
320+
while ((RCC_CFGR & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_PLL) {};
321+
322+
/* Disable internal high-speed oscillator. */
323+
RCC_CR &= ~RCC_CR_HSION;
324+
}
325+
326+
void hal_init(void)
327+
{
328+
clock_pll_on(0);
329+
}
330+
331+
void hal_prepare_boot(void)
332+
{
333+
clock_pll_off();
334+
}

0 commit comments

Comments
 (0)