dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_flash_internal.c
Go to the documentation of this file.
1 
14 /*
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23  * for more details.
24  *
25  * You should have received a copy of the GNU General Public License along
26  * with this program; if not, see <http://www.gnu.org/licenses/>
27  */
28 
29 #include "pios.h"
30 
31 #if defined(PIOS_INCLUDE_FLASH_INTERNAL)
32 
33 #include "stm32f4xx_flash.h"
35 #include "pios_wdg.h"
36 #include "pios_semaphore.h"
37 #include <stdbool.h>
38 
39 /* TODO: Build an armed infrastructure for PiOS as a whole-- figure out
40  * a good header to put it in, and use accessor functions from outside
41  * PiOS. */
42 bool __attribute__((weak)) vehicle_is_armed = false;
43 
44 static const uint16_t sector_to_st_sector_map[] = {
45  [0] = FLASH_Sector_0,
46  [1] = FLASH_Sector_1,
47  [2] = FLASH_Sector_2,
48  [3] = FLASH_Sector_3,
49  [4] = FLASH_Sector_4,
50  [5] = FLASH_Sector_5,
51  [6] = FLASH_Sector_6,
52  [7] = FLASH_Sector_7,
53  [8] = FLASH_Sector_8,
54  [9] = FLASH_Sector_9,
55  [10] = FLASH_Sector_10,
56  [11] = FLASH_Sector_11,
57 };
58 
59 enum pios_internal_flash_dev_magic {
60  PIOS_INTERNAL_FLASH_DEV_MAGIC = 0x33445902,
61 };
62 
63 struct pios_internal_flash_dev {
64  enum pios_internal_flash_dev_magic magic;
65 
66  const struct pios_flash_internal_cfg *cfg;
67 
68  struct pios_semaphore *transaction_lock;
69 };
70 
71 static bool PIOS_Flash_Internal_Validate(struct pios_internal_flash_dev *flash_dev) {
72  return (flash_dev && (flash_dev->magic == PIOS_INTERNAL_FLASH_DEV_MAGIC));
73 }
74 
75 static struct pios_internal_flash_dev *PIOS_Flash_Internal_alloc(void)
76 {
77  struct pios_internal_flash_dev *flash_dev;
78 
79  flash_dev = (struct pios_internal_flash_dev *)PIOS_malloc(sizeof(*flash_dev));
80  if (!flash_dev) return (NULL);
81 
82  flash_dev->magic = PIOS_INTERNAL_FLASH_DEV_MAGIC;
83 
84  return(flash_dev);
85 }
86 
87 void FLASH_IRQHandler() {
88  PIOS_Assert(0);
89 }
90 
91 int32_t PIOS_Flash_Internal_Init(uintptr_t *chip_id, const struct pios_flash_internal_cfg *cfg)
92 {
93  struct pios_internal_flash_dev *flash_dev;
94 
95  flash_dev = PIOS_Flash_Internal_alloc();
96  if (flash_dev == NULL)
97  return -1;
98 
99  flash_dev->transaction_lock = PIOS_Semaphore_Create();
100 
101  flash_dev->cfg = cfg;
102 
103  /* Catch ERRIE interrupt indicating a flash error.
104  * These are usually null-pointer dereferences inadvertently
105  * accessing flash memory.
106  */
107  NVIC_InitTypeDef intr = {
108  .NVIC_IRQChannel = FLASH_IRQn,
109  .NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST,
110  .NVIC_IRQChannelSubPriority = 0,
111  .NVIC_IRQChannelCmd = ENABLE,
112  };
113 
114  NVIC_Init(&intr);
115  FLASH_ITConfig(FLASH_IT_ERR, ENABLE);
116 
117  *chip_id = (uintptr_t) flash_dev;
118 
119  return 0;
120 }
121 
122 /**********************************
123  *
124  * Provide a PIOS flash driver API
125  *
126  *********************************/
127 #include "pios_flash_priv.h"
128 
129 static int32_t PIOS_Flash_Internal_StartTransaction(uintptr_t chip_id)
130 {
131  struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)chip_id;
132 
133  if (!PIOS_Flash_Internal_Validate(flash_dev))
134  return -1;
135 
136  if (PIOS_Semaphore_Take(flash_dev->transaction_lock, PIOS_SEMAPHORE_TIMEOUT_MAX) != true)
137  return -2;
138 
139  /* Unlock the internal flash so we can write to it */
140  FLASH_Unlock();
141  return 0;
142 }
143 
144 static int32_t PIOS_Flash_Internal_EndTransaction(uintptr_t chip_id)
145 {
146  struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)chip_id;
147 
148  if (!PIOS_Flash_Internal_Validate(flash_dev))
149  return -1;
150 
151  if (PIOS_Semaphore_Give(flash_dev->transaction_lock) != true)
152  return -2;
153 
154  /* Lock the internal flash again so we can no longer write to it */
155  FLASH_Lock();
156 
157  return 0;
158 }
159 
160 int32_t PIOS_Flash_Internal_EraseSector_FromRam(uint16_t st_sector)
161  __attribute__ ((section (".ramtext"),long_call));
162 
163 static int32_t PIOS_Flash_Internal_EraseSector(uintptr_t chip_id, uint32_t chip_sector, uint32_t chip_offset)
164 {
165  struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)chip_id;
166 
167  if (!PIOS_Flash_Internal_Validate(flash_dev))
168  return -1;
169 
170 #if defined(PIOS_INCLUDE_WDG)
171  PIOS_WDG_Clear();
172 #endif
173 
174  /* Is the requested sector within this chip? */
175  if (chip_sector >= NELEMENTS(sector_to_st_sector_map))
176  return -2;
177 
178  uint32_t st_sector = sector_to_st_sector_map[chip_sector];
179 
181 
182  int32_t ret = PIOS_Flash_Internal_EraseSector_FromRam(st_sector);
183 
184  PIOS_IRQ_Enable();
185 
186  if (ret) {
187  return ret;
188  }
189 
190  if (FLASH_GetStatus() != FLASH_COMPLETE) {
191  return -1;
192  }
193 
194  return 0;
195 }
196 
197 int32_t PIOS_Flash_Internal_EraseSector_FromRam(uint16_t st_sector)
198 {
199  if (vehicle_is_armed) {
200  return -1;
201  }
202 
203 #define KR_KEY_RELOAD ((uint16_t)0xAAAA)
204 
205  /* Wait for last operation to be completed */
206  while ((FLASH->SR & FLASH_FLAG_BSY) == FLASH_FLAG_BSY) {
207  IWDG->KR = KR_KEY_RELOAD;
208  }
209 
210  uint32_t cr = FLASH->CR;
211 
212  cr &= CR_PSIZE_MASK;
213  cr |= FLASH_PSIZE_WORD;
214 
215 #define SECTOR_MASK ((uint32_t)0xFFFFFF07)
216 
217  cr &= SECTOR_MASK;
218  cr |= FLASH_CR_SER | st_sector;
219 
220  FLASH->CR = cr;
221 
222  /* Start operation */
223  FLASH->CR = cr | FLASH_CR_STRT;
224 
225  while ((FLASH->SR & FLASH_FLAG_BSY) == FLASH_FLAG_BSY) {
226  IWDG->KR = KR_KEY_RELOAD;
227  }
228 
229  FLASH->CR &= (~FLASH_CR_SER) & SECTOR_MASK;
230 
231  return 0;
232 }
233 
234 static int32_t PIOS_Flash_Internal_WriteData(uintptr_t chip_id, uint32_t chip_offset, const uint8_t *data, uint16_t len)
235 {
236  PIOS_Assert(data);
237 
238  struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)chip_id;
239 
240  if (!PIOS_Flash_Internal_Validate(flash_dev))
241  return -1;
242 
243  /* Write the data */
244  for (uint16_t i = 0; i < len; i++) {
245  FLASH_Status status;
246  /*
247  * This is inefficient. Should try to do word writes.
248  * Not sure if word writes need to be aligned though.
249  */
250  status = FLASH_ProgramByte(FLASH_BASE + chip_offset + i, data[i]);
251  PIOS_Assert(status == FLASH_COMPLETE);
252  }
253 
254  return 0;
255 }
256 
257 static int32_t PIOS_Flash_Internal_ReadData(uintptr_t chip_id, uint32_t chip_offset, uint8_t *data, uint16_t len)
258 {
259  PIOS_Assert(data);
260 
261  struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)chip_id;
262 
263  if (!PIOS_Flash_Internal_Validate(flash_dev))
264  return -1;
265 
266  /* Read the data into the buffer directly */
267  memcpy(data, (void *)(FLASH_BASE + chip_offset), len);
268 
269  return 0;
270 }
271 
272 static void * PIOS_Flash_Internal_GetPointer(uintptr_t chip_id, uint32_t chip_offset)
273 {
274  struct pios_internal_flash_dev *flash_dev = (struct pios_internal_flash_dev *)chip_id;
275 
276  PIOS_Assert(PIOS_Flash_Internal_Validate(flash_dev));
277 
278  return (void *)(FLASH_BASE + chip_offset);
279 }
280 
281 /* Provide a flash driver to external drivers */
283  .start_transaction = PIOS_Flash_Internal_StartTransaction,
284  .end_transaction = PIOS_Flash_Internal_EndTransaction,
285  .erase_sector = PIOS_Flash_Internal_EraseSector,
286  .write_data = PIOS_Flash_Internal_WriteData,
287  .read_data = PIOS_Flash_Internal_ReadData,
288  .get_pointer = PIOS_Flash_Internal_GetPointer,
289 };
290 
291 #endif /* defined(PIOS_INCLUDE_FLASH_INTERNAL) */
292 
int32_t PIOS_Flash_Internal_Init(uintptr_t *flash_id, const struct pios_flash_internal_cfg *cfg)
int32_t PIOS_IRQ_Enable(void)
Definition: pios_irq.c:53
#define PIOS_SEMAPHORE_TIMEOUT_MAX
void weak
Definition: pios_heap.c:124
Main PiOS header to include all the compiled in PiOS options.
#define NELEMENTS(x)
Definition: pios.h:192
bool vehicle_is_armed
Definition: manualcontrol.c:71
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
#define PIOS_IRQ_PRIO_HIGHEST
Definition: pios_board.h:172
#define FLASH_IRQHandler
uint8_t data[XFER_BYTES_PER_PACKET]
Definition: bl_messages.h:129
void PIOS_WDG_Clear(void)
Clear the watchdog timer.
Definition: pios_wdg.c:147
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
int16_t status
Definition: main.c:61
struct pios_semaphore * PIOS_Semaphore_Create(void)
Creates a binary semaphore.
SPI functions header.
uint8_t i
Definition: msp_messages.h:97
bool PIOS_Semaphore_Give(struct pios_semaphore *sema)
Gives binary semaphore.
uint32_t magic
int32_t PIOS_IRQ_Disable(void)
Definition: pios_irq.c:40
bool PIOS_Semaphore_Take(struct pios_semaphore *sema, uint32_t timeout_ms)
Takes binary semaphore.
#define PIOS_Assert(test)
Definition: pios_debug.h:52
int32_t(* start_transaction)(uintptr_t chip_id)
const struct pios_flash_driver pios_internal_flash_driver
typedef __attribute__
Definition: serial_4way.h:43