20
20
* SOFTWARE.
21
21
*/
22
22
23
+ #include < stdio.h>
23
24
#include < string.h>
25
+ #include < algorithm>
24
26
#include " FlashIAP.h"
25
27
#include " mbed_assert.h"
26
28
@@ -57,6 +59,9 @@ int FlashIAP::init()
57
59
if (flash_init (&_flash)) {
58
60
ret = -1 ;
59
61
}
62
+ uint32_t page_size = get_page_size ();
63
+ _page_buf = new uint8_t [page_size];
64
+
60
65
_mutex->unlock ();
61
66
return ret;
62
67
}
@@ -68,6 +73,7 @@ int FlashIAP::deinit()
68
73
if (flash_free (&_flash)) {
69
74
ret = -1 ;
70
75
}
76
+ delete[] _page_buf;
71
77
_mutex->unlock ();
72
78
return ret;
73
79
}
@@ -85,22 +91,43 @@ int FlashIAP::read(void *buffer, uint32_t addr, uint32_t size)
85
91
int FlashIAP::program (const void *buffer, uint32_t addr, uint32_t size)
86
92
{
87
93
uint32_t page_size = get_page_size ();
88
- uint32_t current_sector_size = flash_get_sector_size (&_flash, addr);
89
- // addr and size should be aligned to page size, and multiple of page size
90
- // page program should not cross sector boundaries
91
- if (!is_aligned (addr, page_size) ||
92
- !is_aligned (size, page_size) ||
93
- (size < page_size) ||
94
- (((addr % current_sector_size) + size) > current_sector_size)) {
94
+ uint32_t flash_size = flash_get_size (&_flash);
95
+ uint32_t flash_start_addr = flash_get_start_address (&_flash);
96
+ uint32_t chunk, prog_size;
97
+ const uint8_t *buf = (uint8_t *) buffer;
98
+ const uint8_t *prog_buf;
99
+
100
+ // addr should be aligned to page size
101
+ if (!is_aligned (addr, page_size) || (!buffer) ||
102
+ ((addr + size) > (flash_start_addr + flash_size))) {
95
103
return -1 ;
96
104
}
97
105
98
106
int ret = 0 ;
99
107
_mutex->lock ();
100
- if (flash_program_page (&_flash, addr, (const uint8_t *)buffer, size)) {
101
- ret = -1 ;
108
+ while (size) {
109
+ uint32_t current_sector_size = flash_get_sector_size (&_flash, addr);
110
+ chunk = std::min (current_sector_size - (addr % current_sector_size), size);
111
+ if (chunk < page_size) {
112
+ memcpy (_page_buf, buf, chunk);
113
+ memset (_page_buf + chunk, 0xFF , page_size - chunk);
114
+ prog_buf = _page_buf;
115
+ prog_size = page_size;
116
+ } else {
117
+ chunk = chunk / page_size * page_size;
118
+ prog_buf = buf;
119
+ prog_size = chunk;
120
+ }
121
+ if (flash_program_page (&_flash, addr, prog_buf, prog_size)) {
122
+ ret = -1 ;
123
+ break ;
124
+ }
125
+ size -= chunk;
126
+ addr += chunk;
127
+ buf += chunk;
102
128
}
103
129
_mutex->unlock ();
130
+
104
131
return ret;
105
132
}
106
133
@@ -117,10 +144,19 @@ bool FlashIAP::is_aligned_to_sector(uint32_t addr, uint32_t size)
117
144
118
145
int FlashIAP::erase (uint32_t addr, uint32_t size)
119
146
{
120
- uint32_t current_sector_size = 0UL ;
147
+ uint32_t current_sector_size;
148
+ uint32_t flash_size = flash_get_size (&_flash);
149
+ uint32_t flash_start_addr = flash_get_start_address (&_flash);
150
+ uint32_t flash_end_addr = flash_start_addr + flash_size;
151
+ uint32_t erase_end_addr = addr + size;
121
152
122
- if (! is_aligned_to_sector (addr, size) ) {
153
+ if (erase_end_addr > flash_end_addr ) {
123
154
return -1 ;
155
+ } else if (erase_end_addr < flash_end_addr){
156
+ uint32_t following_sector_size = flash_get_sector_size (&_flash, erase_end_addr);
157
+ if (!is_aligned (erase_end_addr, following_sector_size)) {
158
+ return -1 ;
159
+ }
124
160
}
125
161
126
162
int32_t ret = 0 ;
@@ -132,10 +168,6 @@ int FlashIAP::erase(uint32_t addr, uint32_t size)
132
168
break ;
133
169
}
134
170
current_sector_size = flash_get_sector_size (&_flash, addr);
135
- if (!is_aligned_to_sector (addr, size)) {
136
- ret = -1 ;
137
- break ;
138
- }
139
171
size -= current_sector_size;
140
172
addr += current_sector_size;
141
173
}
0 commit comments