-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathflash.c
120 lines (102 loc) · 3.2 KB
/
flash.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "hal.h"
#include "portab.h"
#include "stm32h7xx_hal_flash.h"
#include "stm32h7xx_hal_flash_ex.h"
/* flash parameters that we should not really know */
static struct {
uint32_t sector_number;
uint32_t size;
uint32_t bank;
} flash_sectors[] = {
{0x00, 128 * 1024, FLASH_BANK_1},
{0x01, 128 * 1024, FLASH_BANK_1},
{0x02, 128 * 1024, FLASH_BANK_1},
{0x03, 128 * 1024, FLASH_BANK_1},
{0x04, 128 * 1024, FLASH_BANK_1},
{0x05, 128 * 1024, FLASH_BANK_1},
{0x06, 128 * 1024, FLASH_BANK_1},
{0x07, 128 * 1024, FLASH_BANK_1},
{0x00, 128 * 1024, FLASH_BANK_2},
{0x01, 128 * 1024, FLASH_BANK_2},
{0x02, 128 * 1024, FLASH_BANK_2},
{0x03, 128 * 1024, FLASH_BANK_2},
{0x04, 128 * 1024, FLASH_BANK_2},
{0x05, 128 * 1024, FLASH_BANK_2},
{0x06, 128 * 1024, FLASH_BANK_2},
{0x07, 128 * 1024, FLASH_BANK_2},
};
uint32_t flash_func_sector_size(unsigned sector) {
if (sector < BOARD_FLASH_SECTORS) {
return flash_sectors[sector].size;
}
return 0;
}
static uint8_t erasedSectors[BOARD_FLASH_SECTORS];
static bool is_blank(uint32_t addr, uint32_t size) {
for (unsigned i = 0; i < size; i += sizeof(uint32_t)) {
if (*(uint32_t*)(addr + i) != 0xffffffff) {
// DMESG("non blank: %p i=%d/%d", addr, i, size);
return false;
}
}
return true;
}
/*
* Write flash, erase sector if necessary and not already erased.
*
* When failsafe=true don't check if the sector is empty to not fail on ECC errors.
*/
void flash_write(uint32_t dst, const uint8_t *src, int len, bool failsafe) {
uint32_t addr = 0x08000000;
uint32_t sector = 0;
uint32_t size = 0;
for (unsigned i = 0; i < BOARD_FLASH_SECTORS; i++) {
size = flash_func_sector_size(i);
if (addr + size > dst) {
sector = i;
break;
}
addr += size;
}
// sector = (dst - 0x08000000) / (128 * 1024);
if (sector == 0 || sector >= BOARD_FLASH_SECTORS) {// Bootloader sector should not be erased
return; //PANIC("invalid sector");
}
HAL_FLASH_Unlock();
if (!erasedSectors[sector]) {
if (failsafe || !is_blank(addr, size)) {
FLASH_EraseInitTypeDef eraseInit;
eraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;
eraseInit.Banks = flash_sectors[sector].bank;
eraseInit.Sector = flash_sectors[sector].sector_number;
eraseInit.NbSectors = 1;
eraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3;
uint32_t sectorError = 0;
HAL_FLASHEx_Erase(&eraseInit, §orError);
// if (!is_blank(addr, size) | (sectorError != 0xffffffff))
// PANIC("failed to erase!");
}
erasedSectors[sector] = 1; // don't erase anymore - we will continue writing here!
}
// invalidate flash buffer after it may have been erased
cacheBufferInvalidate(dst, len);
// check if flash is really empty, otherwise ECC errors might be created
if (!is_blank(dst, len)) {
// PANIC("flash to write is not empty");
// TODO: better error handling
while (true) {
usbDisconnectBus(&USBD1);
palToggleLine(PORTAB_BLINK_LED);
chThdSleepMilliseconds(30);
}
}
for (int i = 0; i < len; i += 4) {
HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, dst + i, (uint32_t)src + i);
}
// TODO: implement error checking
// ccrc = CalcCRC32((uint8_t *)(SDRAM_BANK_ADDR + 0x010), flength);
// if (memcmp((void*)dst, src, len) != 0) {
// PANIC("failed to write");
// }
HAL_FLASH_Lock();
}