-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathflash_f3.c
120 lines (92 loc) · 2.93 KB
/
flash_f3.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 <stdint.h>
#include <stdbool.h>
#include "flash.h"
/* Flash registers. Copied here to avoid dependencies on either libopencm3 or
* ChibiOS. */
#define MMIO32(addr) (*(volatile uint32_t *)(addr))
#define FLASH_MEM_INTERFACE_BASE 0x40022000
#define FLASH_KEYR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x04)
#define FLASH_SR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x0C)
#define FLASH_CR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x10)
#define FLASH_AR MMIO32(FLASH_MEM_INTERFACE_BASE + 0x14)
#define FLASH_CR_PG (1 << 0)
#define FLASH_CR_PER (1 << 1)
#define FLASH_CR_STRT (1 << 6)
#define FLASH_CR_LOCK (1 << 7)
#define FLASH_SR_BSY (1 << 0)
#define FLASH_SR_EOP (1 << 5)
#define FLASH_KEYR_KEY1 ((uint32_t)0x45670123)
#define FLASH_KEYR_KEY2 ((uint32_t)0xcdef89ab)
static bool write_last_byte = false;
static uint8_t last_byte;
static void flash_wait_for_last_operation(void)
{
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY) {
}
}
static void flash_write_half_word(uint16_t *flash, uint16_t half_word)
{
/* select flash programming */
FLASH_CR |= FLASH_CR_PG;
/* perform half-word write */
*flash = half_word;
flash_wait_for_last_operation();
}
void flash_lock(void)
{
FLASH_CR |= FLASH_CR_LOCK;
}
void flash_unlock(void)
{
/* Clear the unlock sequence state. */
FLASH_CR |= FLASH_CR_LOCK;
/* Authorize the FPEC access. */
FLASH_KEYR = FLASH_KEYR_KEY1;
FLASH_KEYR = FLASH_KEYR_KEY2;
}
void flash_write(void *page, const void *data, size_t len)
{
uint8_t *bytes = (uint8_t *) data;
uint16_t *flash = (uint16_t *) page;
uint16_t half_word;
flash_wait_for_last_operation();
if ((uint32_t)flash & 0x1) {
flash = (uint16_t *)(((uint32_t)flash) & 0xfffffffe);
/* preserve value of adjacent byte */
if (write_last_byte) {
half_word = last_byte;
write_last_byte = false;
} else {
half_word = (*flash & 0xff);
}
half_word |= ((uint16_t)*bytes) << 8;
flash_write_half_word(flash, half_word);
flash ++;
bytes ++;
len --;
}
size_t count;
for (count = len; count > 1; count -= 2) {
half_word = *bytes++;
half_word |= (uint16_t)*bytes++ << 8;
flash_write_half_word(flash++, half_word);
}
if (count == 1) {
// TODO: The byte write in a string of writes might be lost if the
// total number written bytes is odd.
last_byte = *bytes;
write_last_byte = true;
}
/* reset flags */
FLASH_CR &= ~FLASH_CR_PG;
FLASH_SR |= FLASH_SR_EOP;
}
void flash_sector_erase(void *page)
{
flash_wait_for_last_operation();
FLASH_CR |= FLASH_CR_PER;
FLASH_AR = (uint32_t) page;
FLASH_CR |= FLASH_CR_STRT;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_PER;
}