Skip to content

Commit 6865fcb

Browse files
flash: add support for STM32H7 flash
1 parent e37d11e commit 6865fcb

2 files changed

Lines changed: 301 additions & 0 deletions

File tree

modules/flash/flash.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ struct flash_write_buf_s {
99
const void* data;
1010
};
1111

12+
#if defined(STM32F4) || defined(STM32F7) || defined(STM32F3xx_MCUCONF)
13+
#define FLASH_WORD_SIZE 2U
14+
#elif defined(STM32H7)
15+
#define FLASH_WORD_SIZE 32U
16+
#endif
17+
1218
bool flash_erase_page(void* page_addr);
1319
bool flash_write(void* address, uint8_t num_bufs, struct flash_write_buf_s* bufs);
1420
int16_t flash_get_page_num(void *address);

modules/flash/flash_stm32h7.c

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
#include "flash.h"
2+
3+
#include <ch.h>
4+
#include <hal.h>
5+
6+
#if defined(STM32H7)
7+
8+
// #pragma GCC optimize("O0")
9+
10+
/*
11+
this driver has been tested with STM32F427 and STM32F412
12+
*/
13+
#define FLASH_WORD_SIZE 32U
14+
15+
#ifndef BOARD_FLASH_SIZE
16+
#error "You must define BOARD_FLASH_SIZE in kbyte"
17+
#endif
18+
19+
#define KB(x) ((x*1024))
20+
// Refer Flash memory map in the User Manual to fill the following fields per microcontroller
21+
#define STM32_FLASH_BASE 0x08000000
22+
#define STM32_FLASH_SIZE KB(BOARD_FLASH_SIZE)
23+
24+
// the 2nd bank of flash needs to be handled differently
25+
#define STM32_FLASH_BANK2_START (STM32_FLASH_BASE+0x00080000)
26+
27+
#define STM32_FLASH_NPAGES (BOARD_FLASH_SIZE / 128)
28+
#define STM32_FLASH_FIXED_PAGE_SIZE 128
29+
30+
31+
static uint32_t stm32_flash_getpagesize(uint32_t page);
32+
33+
#define FLASH_KEY1 0x45670123
34+
#define FLASH_KEY2 0xCDEF89AB
35+
36+
static void stm32_flash_wait_idle(void)
37+
{
38+
while ((FLASH->SR1 & (FLASH_SR_BSY|FLASH_SR_QW|FLASH_SR_WBNE)) ||
39+
(FLASH->SR2 & (FLASH_SR_BSY|FLASH_SR_QW|FLASH_SR_WBNE))) {
40+
__asm__("nop");
41+
// nop
42+
}
43+
}
44+
45+
static void stm32_flash_unlock(void)
46+
{
47+
stm32_flash_wait_idle();
48+
49+
if (FLASH->CR1 & FLASH_CR_LOCK) {
50+
/* Unlock sequence */
51+
FLASH->KEYR1 = FLASH_KEY1;
52+
FLASH->KEYR1 = FLASH_KEY2;
53+
}
54+
if (FLASH->CR2 & FLASH_CR_LOCK) {
55+
/* Unlock sequence */
56+
FLASH->KEYR2 = FLASH_KEY1;
57+
FLASH->KEYR2 = FLASH_KEY2;
58+
}
59+
60+
// disable the data cache - see stm32 errata 2.1.11
61+
#ifdef FLASH_ACR_DCEN
62+
FLASH->ACR &= ~FLASH_ACR_DCEN;
63+
#endif
64+
}
65+
66+
void stm32_flash_lock(void)
67+
{
68+
stm32_flash_wait_idle();
69+
if (FLASH->SR1 & FLASH_SR_QW) {
70+
FLASH->CR1 |= FLASH_CR_FW;
71+
}
72+
if (FLASH->SR2 & FLASH_SR_QW) {
73+
FLASH->CR2 |= FLASH_CR_FW;
74+
}
75+
stm32_flash_wait_idle();
76+
FLASH->CR1 |= FLASH_CR_LOCK;
77+
FLASH->CR2 |= FLASH_CR_LOCK;
78+
// reset and re-enable the data cache - see stm32 errata 2.1.11
79+
#ifdef FLASH_ACR_DCEN
80+
FLASH->ACR |= FLASH_ACR_DCRST;
81+
FLASH->ACR &= ~FLASH_ACR_DCRST;
82+
FLASH->ACR |= FLASH_ACR_DCEN;
83+
#endif
84+
}
85+
86+
/*
87+
get the memory address of a page
88+
*/
89+
void* flash_get_page_addr(uint32_t page)
90+
{
91+
if (page >= STM32_FLASH_NPAGES) {
92+
return 0;
93+
}
94+
return STM32_FLASH_BASE + page * STM32_FLASH_FIXED_PAGE_SIZE * 1024;
95+
}
96+
97+
uint32_t flash_get_page_ofs(uint32_t page)
98+
{
99+
return (uint32_t)flash_get_page_addr(page) - (uint32_t)STM32_FLASH_BASE;
100+
}
101+
102+
/*
103+
get size in bytes of a page
104+
*/
105+
uint32_t stm32_flash_getpagesize(uint32_t page)
106+
{
107+
return STM32_FLASH_FIXED_PAGE_SIZE;
108+
}
109+
110+
111+
int16_t flash_get_page_num(void* address)
112+
{
113+
uint16_t ret = 0;
114+
while((uint32_t)flash_get_page_addr(ret) <= (uint32_t)address) {
115+
ret++;
116+
if (ret >= STM32_FLASH_NPAGES) {
117+
return -1;
118+
}
119+
}
120+
return ret - 1;
121+
}
122+
123+
static bool stm32_flash_ispageerased(uint32_t page)
124+
{
125+
uint32_t addr;
126+
uint32_t count;
127+
128+
if (page >= STM32_FLASH_NPAGES) {
129+
return false;
130+
}
131+
132+
for (addr = (uint32_t)flash_get_page_addr(page), count = stm32_flash_getpagesize(page);
133+
count; count--, addr++) {
134+
if ((*(volatile uint8_t *)(addr)) != 0xff) {
135+
return false;
136+
}
137+
}
138+
139+
return true;
140+
}
141+
142+
/*
143+
erase a page
144+
*/
145+
bool flash_erase_page(void* address)
146+
{
147+
uint16_t page = flash_get_page_num(address);
148+
if (page >= STM32_FLASH_NPAGES) {
149+
return false;
150+
}
151+
152+
stm32_flash_wait_idle();
153+
stm32_flash_unlock();
154+
155+
stm32_flash_wait_idle();
156+
157+
if (page < 8) {
158+
// first bank
159+
FLASH->SR1 = 0x1FEF000E;
160+
161+
stm32_flash_wait_idle();
162+
163+
uint32_t snb = page << 8;
164+
165+
// use 32 bit operations
166+
FLASH->CR1 = FLASH_CR_PSIZE_1 | snb | FLASH_CR_SER;
167+
FLASH->CR1 |= FLASH_CR_START;
168+
while (FLASH->SR1 & FLASH_SR_QW) ;
169+
170+
if (FLASH->SR1) {
171+
// an error occurred
172+
stm32_flash_wait_idle();
173+
FLASH->SR1 = 0x1FEF000E;
174+
stm32_flash_lock();
175+
return false;
176+
}
177+
} else {
178+
// second bank
179+
FLASH->SR2 = 0x1FEF000E;
180+
181+
stm32_flash_wait_idle();
182+
183+
uint32_t snb = (page-8) << 8;
184+
185+
// use 32 bit operations
186+
FLASH->CR2 = FLASH_CR_PSIZE_1 | snb | FLASH_CR_SER;
187+
FLASH->CR2 |= FLASH_CR_START;
188+
while (FLASH->SR2 & FLASH_SR_QW);
189+
190+
if (FLASH->SR2) {
191+
// an error occurred
192+
stm32_flash_wait_idle();
193+
FLASH->SR2 = 0x1FEF000E;
194+
stm32_flash_lock();
195+
return false;
196+
}
197+
}
198+
199+
stm32_flash_wait_idle();
200+
stm32_flash_lock();
201+
return stm32_flash_ispageerased(page);
202+
}
203+
204+
bool flash_write(void* address, volatile uint8_t num_bufs, struct flash_write_buf_s* volatile bufs)
205+
{
206+
if (num_bufs == 0 || !address || (size_t)address % FLASH_WORD_SIZE != 0) {
207+
return false;
208+
}
209+
210+
if (!(RCC->CR & RCC_CR_HSION)) {
211+
return false;
212+
}
213+
volatile uint32_t *CR, *CCR, *SR;
214+
215+
stm32_flash_unlock();
216+
if (((uint32_t)address - STM32_FLASH_BASE) < (8 * STM32_FLASH_FIXED_PAGE_SIZE * 1024)) {
217+
CR = &FLASH->CR1;
218+
CCR = &FLASH->CCR1;
219+
SR = &FLASH->SR1;
220+
} else {
221+
CR = &FLASH->CR2;
222+
CCR = &FLASH->CCR2;
223+
SR = &FLASH->SR2;
224+
}
225+
226+
// clear previous errors
227+
*SR = 0x1FEF000E;
228+
229+
*CR = FLASH_CR_PSIZE_0;
230+
231+
bool success = true;
232+
uint32_t* target_word_ptr = address;
233+
uint8_t buf_idx = 0;
234+
size_t buf_data_idx = 0;
235+
236+
while (buf_data_idx >= bufs[buf_idx].len) {
237+
buf_idx++;
238+
}
239+
240+
while (buf_idx < num_bufs) {
241+
union {
242+
uint32_t word_value[FLASH_WORD_SIZE/4];
243+
uint8_t bytes_value[FLASH_WORD_SIZE];
244+
} source_value;
245+
246+
memset(&source_value,0,sizeof(source_value));
247+
248+
for (uint8_t i=0; i<FLASH_WORD_SIZE; i++) {
249+
if (buf_idx >= num_bufs) {
250+
break;
251+
}
252+
source_value.bytes_value[i] = ((uint8_t*)bufs[buf_idx].data)[buf_data_idx];
253+
buf_data_idx++;
254+
while (buf_data_idx >= bufs[buf_idx].len) {
255+
buf_idx++;
256+
buf_data_idx = 0;
257+
}
258+
}
259+
*CCR = ~0;
260+
*CR |= FLASH_CR_PG;
261+
for (uint8_t i=0; i<FLASH_WORD_SIZE/4; i++) {
262+
while (*SR & (FLASH_SR_BSY|FLASH_SR_QW));
263+
target_word_ptr[i] = source_value.word_value[i];
264+
}
265+
266+
__DSB();
267+
stm32_flash_wait_idle();
268+
*CCR = ~0;
269+
270+
if (*SR) {
271+
// we got an error
272+
*SR = 0x1FEF000E;
273+
*CR &= ~(FLASH_CR_PG);
274+
success = false;
275+
goto failed;
276+
}
277+
278+
for (uint8_t i=0; i<FLASH_WORD_SIZE/4; i++) {
279+
// confirm data is correctly written or not
280+
if (target_word_ptr[i] != source_value.word_value[i]) {
281+
*CR &= ~(FLASH_CR_PG);
282+
success = false;
283+
goto failed;
284+
}
285+
}
286+
target_word_ptr += FLASH_WORD_SIZE/4;
287+
}
288+
289+
failed:
290+
stm32_flash_lock();
291+
292+
return success;
293+
}
294+
295+
#endif // defined(STM32H7)

0 commit comments

Comments
 (0)