Paparazzi UAS  v5.10_stable-5-g83a0da5-dirty
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
settings_arch.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011 Martin Mueller <martinmm@pfump.org>
3  *
4  * This file is part of Paparazzi.
5  *
6  * Paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * Paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Paparazzi; see the file COPYING. If not, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  */
22 
35 #include "subsystems/settings.h"
36 
37 #include <libopencm3/stm32/flash.h>
38 #include <libopencm3/stm32/crc.h>
39 #include <libopencm3/stm32/dbgmcu.h>
40 
41 struct FlashInfo {
42  uint32_t addr;
46 };
47 
48 
49 static uint32_t pflash_checksum(uint32_t ptr, uint32_t size);
50 static int32_t flash_detect(struct FlashInfo *flash);
51 static int32_t pflash_program_bytes(struct FlashInfo *flash,
52  uint32_t src,
53  uint32_t size,
54  uint32_t chksum);
55 
56 #if defined(STM32F1)
57 #define FLASH_SIZE_ MMIO16(0x1FFFF7E0)
58 #elif defined(STM32F4)
59 #define FLASH_SIZE_ MMIO16(0x1FFF7A22)
60 #endif
61 
62 #define FLASH_BEGIN 0x08000000
63 #define FSIZ 8
64 #define FCHK 4
65 
66 
68 {
69  uint32_t i;
70 
71  /* reset crc */
72  CRC_CR = CRC_CR_RESET;
73 
74  if (ptr % 4) {
75  /* calc in 8bit chunks */
76  for (i = 0; i < (size & ~3); i += 4) {
77  CRC_DR = (*(uint8_t *)(ptr + i)) |
78  (*(uint8_t *)(ptr + i + 1)) << 8 |
79  (*(uint8_t *)(ptr + i + 2)) << 16 |
80  (*(uint8_t *)(ptr + i + 3)) << 24;
81  }
82  } else {
83  /* calc in 32bit */
84  for (i = 0; i < (size & ~3); i += 4) {
85  CRC_DR = *(uint32_t *)(ptr + i);
86  }
87  }
88 
89  /* remaining bytes */
90  switch (size % 4) {
91  case 1:
92  CRC_DR = *(uint8_t *)(ptr + i);
93  break;
94  case 2:
95  CRC_DR = (*(uint8_t *)(ptr + i)) |
96  (*(uint8_t *)(ptr + i + 1)) << 8;
97  break;
98  case 3:
99  CRC_DR = (*(uint8_t *)(ptr + i)) |
100  (*(uint8_t *)(ptr + i + 1)) << 8 |
101  (*(uint8_t *)(ptr + i + 2)) << 16;
102  break;
103  default:
104  break;
105  }
106 
107  return CRC_DR;
108 }
109 
110 static int32_t flash_detect(struct FlashInfo *flash)
111 {
112 
113  flash->total_size = FLASH_SIZE_ * 0x400;
114 
115 #if defined(STM32F1)
116  /* FIXME This will not work for connectivity line (needs ID, see below), but
117  device ID is only readable when freshly loaded through JTAG?! */
118 
119  /* WARNING If you are using this for F4 this only works for memory sizes
120  * larger than 128kb. Otherwise the first few sectors are either 16kb or
121  * 64kb. To make those small devices work we would need to know what the page
122  * we want to put the settings into is. Otherwise we will might be writing
123  * into a 64kb page that is actually 16kb big.
124  */
125  switch (flash->total_size) {
126  /* low density */
127  case 0x00004000: /* 16 kBytes */
128  case 0x00008000: /* 32 kBytes */
129  /* medium density, e.g. STM32F103RBT6 (Olimex STM32-H103) */
130  case 0x00010000: /* 64 kBytes */
131  case 0x00020000: { /* 128 kBytes */
132  flash->page_size = 0x400;
133  break;
134  }
135  /* high density, e.g. STM32F103RE (Joby Lisa/M, Lisa/L) */
136  case 0x00040000: /* 256 kBytes */
137  case 0x00080000: /* 512 kBytes */
138  /* XL density */
139  case 0x000C0000: /* 768 kBytes */
140  case 0x00100000: { /* 1 MByte */
141  flash->page_size = 0x800;
142  break;
143  }
144  default: {return -1;}
145  }
146 
147 #elif defined(STM32F4) /* this is the correct way of detecting page sizes but we currently only use it for the F4 because the F1 version is broken. */
148  uint32_t device_id;
149 
150  /* read device id */
151  device_id = DBGMCU_IDCODE & DBGMCU_IDCODE_DEV_ID_MASK;
152 
153  switch (device_id) {
154  /* low density */
155  case 0x412:
156  /* medium density, e.g. STM32F103RB (Olimex STM32-H103) */
157  case 0x410: {
158  flash->page_size = 0x400;
159  break;
160  }
161  /* high density, e.g. STM32F103RE (Joby Lisa/L) */
162  case 0x414:
163  /* XL density */
164  case 0x430:
165  /* connectivity line */
166  case 0x418: {
167  flash->page_size = 0x800;
168  break;
169  }
170  case 0x0413: /* STM32F405xx/07xx and STM32F415xx/17xx) */
171  case 0x0419: /* STM32F42xxx and STM32F43xxx */
172  case 0x0423: /* STM32F401xB/C */
173  case 0x0433: /* STM32F401xD/E */
174  case 0x0431: { /* STM32F411xC/E */
175  flash->page_size = 0x20000;
176  break;
177  }
178  default: return -1;
179  }
180 
181  switch (flash->total_size) {
182  case 0x00004000: /* 16 kBytes */
183  case 0x00008000: /* 32 kBytes */
184  case 0x00010000: /* 64 kBytes */
185  case 0x00020000: /* 128 kBytes */
186  case 0x00040000: /* 256 kBytes */
187  case 0x00080000: /* 512 kBytes */
188  case 0x000C0000: /* 768 kBytes */
189  case 0x00100000: /* 1 MByte */
190  case 0x00200000: /* 2 MByte */
191  break;
192  default: return -1;
193  }
194 #else
195 #error Unknown device
196 #endif
197 
198 #if defined(STM32F1)
199  flash->page_nr = (flash->total_size / flash->page_size) - 1;
200  flash->addr = FLASH_BEGIN + flash->page_nr * flash->page_size;
201 #elif defined(STM32F4)
202  /* We are assuming all pages are 128kb so we have to compensate for the first
203  * few pages that are smaller which means we have to skip the first 4.
204  */
205  flash->page_nr = (flash->total_size / flash->page_size) - 1 + 4;
206  flash->addr = FLASH_BEGIN + (flash->page_nr - 4) * flash->page_size;
207 #endif
208 
209  return 0;
210 }
211 
212 
213 static int32_t pflash_erase(struct FlashInfo *flash)
214 {
215  uint32_t i;
216 
217  /* erase */
218  flash_unlock();
219 #if defined(STM32F1)
220  flash_erase_page(flash->addr);
221 #elif defined(STM32F4)
222  flash_erase_sector(flash->page_nr, FLASH_CR_PROGRAM_X32);
223 #endif
224  flash_lock();
225 
226  /* verify erase */
227  for (i = 0; i < flash->page_size; i += 4) {
228  if ((*(uint32_t *)(flash->addr + i)) != 0xFFFFFFFF) { return -1; }
229  }
230  return 0;
231 }
232 
233 // (gdb) p *flash
234 // $1 = {addr = 134739968, total_size = 524288, page_nr = 255, page_size = 2048}
235 // 0x807F800 0x80000
237  uint32_t src,
238  uint32_t size,
239  uint32_t chksum)
240 {
241  uint32_t i;
242 
243  /* erase, return with error if not successful */
244  if (pflash_erase(flash)) { return -1; }
245 
246  flash_unlock();
247  /* write full 16 bit words */
248  for (i = 0; i < (size & ~1); i += 2) {
249  flash_program_half_word(flash->addr + i,
250  (uint16_t)(*(uint8_t *)(src + i) | (*(uint8_t *)(src + i + 1)) << 8));
251  }
252  /* fill bytes with a zero */
253  if (size & 1) {
254  flash_program_half_word(flash->addr + i, (uint16_t)(*(uint8_t *)(src + i)));
255  }
256  /* write size */
257  flash_program_half_word(flash->addr + flash->page_size - FSIZ,
258  (uint16_t)(size & 0xFFFF));
259  flash_program_half_word(flash->addr + flash->page_size - FSIZ + 2,
260  (uint16_t)((size >> 16) & 0xFFFF));
261  /* write checksum */
262  flash_program_half_word(flash->addr + flash->page_size - FCHK,
263  (uint16_t)(chksum & 0xFFFF));
264  flash_program_half_word(flash->addr + flash->page_size - FCHK + 2,
265  (uint16_t)((chksum >> 16) & 0xFFFF));
266  flash_lock();
267 
268  /* verify data */
269  for (i = 0; i < size; i++) {
270  if ((*(uint8_t *)(flash->addr + i)) != (*(uint8_t *)(src + i))) { return -2; }
271  }
272  if (*(uint32_t *)(flash->addr + flash->page_size - FSIZ) != size) { return -3; }
273  if (*(uint32_t *)(flash->addr + flash->page_size - FCHK) != chksum) { return -4; }
274 
275  return 0;
276 }
277 
279 {
280  struct FlashInfo flash_info;
281  if (flash_detect(&flash_info)) { return -1; }
282  if ((size > flash_info.page_size - FSIZ) || (size == 0)) { return -2; }
283 
284  return pflash_program_bytes(&flash_info,
285  (uint32_t)ptr,
286  size,
287  pflash_checksum((uint32_t)ptr, size));
288 }
289 
291 {
292  struct FlashInfo flash;
293  uint32_t i;
294 
295  /* check parameters */
296  if (flash_detect(&flash)) { return -1; }
297  if ((size > flash.page_size - FSIZ) || (size == 0)) { return -2; }
298 
299  /* check consistency */
300  if (size != *(uint32_t *)(flash.addr + flash.page_size - FSIZ)) { return -3; }
301  if (pflash_checksum(flash.addr, size) !=
302  *(uint32_t *)(flash.addr + flash.page_size - FCHK)) {
303  return -4;
304  }
305 
306  /* copy data */
307  for (i = 0; i < size; i++) {
308  *(uint8_t *)((uint32_t)ptr + i) = *(uint8_t *)(flash.addr + i);
309  }
310 
311  return 0;
312 }
313 
315 {
316  struct FlashInfo flash_info;
317  if (flash_detect(&flash_info)) { return -1; }
318 
319  return pflash_erase(&flash_info);
320 }
unsigned short uint16_t
Definition: types.h:16
int32_t persistent_write(void *ptr, uint32_t size)
Definition: settings_arch.c:33
#define FSIZ
Definition: settings_arch.c:63
uint32_t addr
Definition: settings_arch.c:66
int32_t persistent_read(void *ptr, uint32_t size)
Definition: settings_arch.c:38
uint32_t page_size
Definition: settings_arch.c:69
uint32_t total_size
Definition: settings_arch.c:67
#define FCHK
Definition: settings_arch.c:64
#define FLASH_BEGIN
Definition: settings_arch.c:62
unsigned long uint32_t
Definition: types.h:18
signed long int32_t
Definition: types.h:19
static int32_t flash_detect(struct FlashInfo *flash)
static int32_t pflash_program_bytes(struct FlashInfo *flash, uint32_t src, uint32_t size, uint32_t chksum)
static uint32_t pflash_checksum(uint32_t ptr, uint32_t size)
Definition: settings_arch.c:67
unsigned char uint8_t
Definition: types.h:14
Persistent settings interface.
static int32_t pflash_erase(struct FlashInfo *flash)
uint32_t page_nr
Definition: settings_arch.c:68
int32_t persistent_clear(void)
Definition: settings_arch.c:74