/drivers/stm32l1xx/flash.c

https://github.com/hikob/openlab · C · 385 lines · 204 code · 80 blank · 101 comment · 15 complexity · bca265455c9a8182c7e8671e0c4b92f8 MD5 · raw file

  1. /*
  2. * This file is part of HiKoB Openlab.
  3. *
  4. * HiKoB Openlab is free software: you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public License
  6. * as published by the Free Software Foundation, version 3.
  7. *
  8. * HiKoB Openlab is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with HiKoB Openlab. If not, see
  15. * <http://www.gnu.org/licenses/>.
  16. *
  17. * Copyright (C) 2012 HiKoB.
  18. */
  19. /*
  20. * flash.c
  21. *
  22. * Created on: Jul 8, 2011
  23. * Author: Clément Burin des Roziers <clement.burin-des-roziers.at.hikob.com>
  24. */
  25. #include <stdint.h>
  26. #include <string.h>
  27. #include <stddef.h>
  28. #include "flash.h"
  29. #include "flash_ram.h"
  30. #include "flash_registers.h"
  31. #include "pwr.h"
  32. #include "eeprom.h"
  33. #include "platform.h"
  34. #include "cm3_scb_registers.h"
  35. enum
  36. {
  37. EEPROM_ADDRESS = 0x08080000,
  38. PEKEY1 = 0x89ABCDEF,
  39. PEKEY2 = 0x02030405,
  40. PRGKEY1 = 0x8C9DAEBF,
  41. PRGKEY2 = 0x13141516,
  42. };
  43. /* Handy Functions */
  44. static void unlock_program_memory();
  45. static void lock_program_memory();
  46. /* EEPROM API implementation */
  47. uint8_t flash_eeprom_read_uint8(uint32_t offset)
  48. {
  49. // Check offset
  50. if (offset >= FLASH_SIZE_EEPROM)
  51. {
  52. return 0;
  53. }
  54. // Read byte and return
  55. return *mem_get_reg8(EEPROM_ADDRESS + offset);
  56. }
  57. uint16_t flash_eeprom_read_uint16(uint32_t offset)
  58. {
  59. // Check offset
  60. if (offset >= FLASH_SIZE_EEPROM)
  61. {
  62. return 0;
  63. }
  64. // Read half word and return
  65. return *mem_get_reg16(EEPROM_ADDRESS + offset);
  66. }
  67. uint32_t flash_eeprom_read_uint32(uint32_t offset)
  68. {
  69. // Check offset
  70. if (offset >= FLASH_SIZE_EEPROM)
  71. {
  72. return 0;
  73. }
  74. // Read word and return
  75. return *mem_get_reg32(EEPROM_ADDRESS + offset);
  76. }
  77. void flash_eeprom_erase_uint32(uint32_t offset)
  78. {
  79. // Check offset
  80. if (offset >= FLASH_SIZE_EEPROM)
  81. {
  82. return;
  83. }
  84. // Disable interrupts during write
  85. platform_enter_critical();
  86. // Unlock PECR
  87. // Write the keys to PEKEYR
  88. *flash_get_PEKEYR() = PEKEY1;
  89. *flash_get_PEKEYR() = PEKEY2;
  90. // Erase word
  91. *mem_get_reg32(EEPROM_ADDRESS + offset) = 0;
  92. // Wait end of operation
  93. while (*flash_get_SR() & FLASH_SR__BSY)
  94. {
  95. }
  96. // Lock PECR
  97. // Set PELOCK bit in PECR
  98. *flash_get_PECR() |= FLASH_PECR__PELOCK;
  99. // Enable interrupts after write
  100. platform_exit_critical();
  101. }
  102. void flash_eeprom_write_uint32(uint32_t offset, uint32_t word)
  103. {
  104. // Check offset
  105. if (offset >= FLASH_SIZE_EEPROM)
  106. {
  107. return;
  108. }
  109. // Disable interrupts during write
  110. platform_enter_critical();
  111. // Unlock PECR
  112. // Write the keys to PEKEYR
  113. *flash_get_PEKEYR() = PEKEY1;
  114. *flash_get_PEKEYR() = PEKEY2;
  115. // Set the FTDW bit in PECR to force erase
  116. *flash_get_PECR() |= FLASH_PECR__FTDW;
  117. // Write the word
  118. *mem_get_reg32(EEPROM_ADDRESS + offset) = word;
  119. // Wait for end of operation
  120. while (*flash_get_SR() & FLASH_SR__BSY)
  121. {
  122. }
  123. // Lock PECR
  124. // Set PELOCK bit in PECR
  125. *flash_get_PECR() |= FLASH_PECR__PELOCK;
  126. // Enable interrupts after write
  127. platform_exit_critical();
  128. }
  129. /* FLASH API implementation */
  130. flash_status_t flash_memory_erase_page(uint32_t address)
  131. {
  132. // Check the address is a page border
  133. if (address % FLASH_SIZE_PAGE)
  134. {
  135. return FLASH_ERR_INVALID_ADDRESS;
  136. }
  137. // Disable interrupts during write
  138. platform_enter_critical();
  139. // Unlock program memory
  140. unlock_program_memory();
  141. // Set the ERASE bit in PECR
  142. *flash_get_PECR() |= FLASH_PECR__ERASE;
  143. // Set the PROG bit in PECR
  144. *flash_get_PECR() |= FLASH_PECR__PROG;
  145. // Wait for BSY to be cleared
  146. while (*flash_get_SR() & FLASH_SR__BSY)
  147. {
  148. }
  149. // Write 0x0 to start erasing
  150. *mem_get_reg32(address) = 0x0;
  151. // Wait for end of operation
  152. while (*flash_get_SR() & FLASH_SR__BSY)
  153. {
  154. }
  155. // Lock program memory
  156. lock_program_memory();
  157. // Enable interrupts after write
  158. platform_exit_critical();
  159. return FLASH_OK;
  160. }
  161. flash_status_t flash_memory_write_word(uint32_t address, uint32_t word)
  162. {
  163. // Disable interrupts during write
  164. asm volatile("cpsid i\n");
  165. // Unlock program memory
  166. unlock_program_memory();
  167. // Write the word to the address
  168. *mem_get_reg32(address) = word;
  169. // Wait for end of operation
  170. while (*flash_get_SR() & FLASH_SR__BSY)
  171. {
  172. }
  173. // Lock program memory
  174. lock_program_memory();
  175. // Enable interrupts after write
  176. platform_exit_critical();
  177. return FLASH_OK;
  178. }
  179. flash_status_t flash_memory_write_half_pages(uint32_t address,
  180. const uint32_t *words, uint32_t words_number)
  181. {
  182. // Check the address is a half page border
  183. if (address % (FLASH_SIZE_PAGE / 2))
  184. {
  185. return FLASH_ERR_INVALID_ADDRESS;
  186. }
  187. // Check if length has a correct words number 32 words per half page
  188. if (words_number % 32)
  189. {
  190. return FLASH_ERR_INVALID_LENGTH;
  191. }
  192. // Disable interrupts during write
  193. platform_enter_critical();
  194. // Unlock program memory
  195. unlock_program_memory();
  196. // Set the FPRG bit in PECR
  197. *flash_get_PECR() |= FLASH_PECR__FPRG;
  198. // Set the PROG bit in PECR
  199. *flash_get_PECR() |= FLASH_PECR__PROG;
  200. // Wait for BSY to be cleared
  201. while (*flash_get_SR() & FLASH_SR__BSY)
  202. {
  203. }
  204. #define RAM_COPY_CODE_LENGTH ((uint32_t) flash_ram_copy_end - (uint32_t) flash_ram_copy)
  205. uint8_t ram_code[RAM_COPY_CODE_LENGTH + 3];
  206. void
  207. (*ram_func)(uint32_t * dst, const uint32_t * src, uint32_t length) =
  208. (void( *)(uint32_t * dst, const uint32_t * src,
  209. uint32_t length))(((uint32_t) ram_code + 3) & ~0x3);
  210. uint32_t func_i, copy_i;
  211. func_i = ((uint32_t) ram_func) & ~0x3;
  212. copy_i = ((uint32_t) flash_ram_copy) & ~0x3;
  213. // Copy
  214. memcpy((void *) func_i, (void *) copy_i, RAM_COPY_CODE_LENGTH);
  215. // Set pointer
  216. ram_func
  217. = (void( *)(uint32_t * dst, const uint32_t * src, uint32_t length))(func_i
  218. | 0x1);
  219. // Call
  220. ram_func((uint32_t *) address, words, words_number);
  221. // Lock the program memory
  222. lock_program_memory();
  223. // Enable interrupts after write
  224. platform_exit_critical();
  225. return FLASH_OK;
  226. }
  227. void flash_memory_copy_upper_to_lower()
  228. {
  229. // Disable interrupts during write
  230. platform_enter_critical();
  231. // Set high power mode
  232. pwr_main_mode(PWR_VRANGE_1);
  233. // Unlock program memory
  234. unlock_program_memory();
  235. // Clear PECR
  236. *flash_get_PECR() = 0;
  237. // Set the ERASE bit in PECR
  238. *flash_get_PECR() |= FLASH_PECR__ERASE;
  239. // Set the PROG bit in PECR
  240. *flash_get_PECR() |= FLASH_PECR__PROG;
  241. // Wait for BSY to be cleared
  242. while (*flash_get_SR() & FLASH_SR__BSY)
  243. {
  244. }
  245. #define RAM_CODE_LENGTH ((uint32_t) flash_ram_copy_all_end - (uint32_t) flash_ram_copy_all)
  246. uint8_t ram_code[RAM_CODE_LENGTH + 3];
  247. void (*ram_func)() = (void( *)())(((uint32_t) ram_code + 3) & ~0x3);
  248. uint32_t func_i, copy_i;
  249. func_i = ((uint32_t) ram_func) & ~0x3;
  250. copy_i = ((uint32_t) flash_ram_copy_all) & ~0x3;
  251. // Copy
  252. memcpy((void *) func_i, (void *) copy_i, RAM_CODE_LENGTH);
  253. // Set pointer
  254. ram_func = (void( *)())(func_i | 0x1);
  255. // Call
  256. ram_func();
  257. // Enable interrupts after write
  258. platform_exit_critical();
  259. }
  260. void flash_set_1ws()
  261. {
  262. // Set 1 wait state, 64bit access
  263. *flash_get_ACR() |= FLASH_ACR__ACC64;
  264. *flash_get_ACR() = FLASH_ACR__SLEEP_PD | FLASH_ACR__ACC64
  265. | FLASH_ACR__PRFTEN | FLASH_ACR__LATENCY;
  266. }
  267. void flash_set_0ws()
  268. {
  269. // Set 0 wait state, 32bit access
  270. *flash_get_ACR() |= FLASH_ACR__ACC64;
  271. *flash_get_ACR() = FLASH_ACR__SLEEP_PD | FLASH_ACR__ACC64;
  272. *flash_get_ACR() = FLASH_ACR__SLEEP_PD;
  273. }
  274. void flash_set_1ws_nosleep()
  275. {
  276. // Set 1 wait state, 64bit access
  277. *flash_get_ACR() |= FLASH_ACR__ACC64;
  278. *flash_get_ACR() = FLASH_ACR__ACC64 | FLASH_ACR__PRFTEN
  279. | FLASH_ACR__LATENCY;
  280. }
  281. void flash_set_0ws_nosleep()
  282. {
  283. // Set 0 wait state, 32bit access
  284. *flash_get_ACR() |= FLASH_ACR__ACC64;
  285. *flash_get_ACR() = FLASH_ACR__ACC64;
  286. *flash_get_ACR() = 0;
  287. }
  288. static void unlock_program_memory()
  289. {
  290. // Unlock PECR
  291. // Write the keys to PEKEYR
  292. *flash_get_PEKEYR() = PEKEY1;
  293. *flash_get_PEKEYR() = PEKEY2;
  294. // Write the keys to PRGKEYR
  295. *flash_get_PRGKEYR() = PRGKEY1;
  296. *flash_get_PRGKEYR() = PRGKEY2;
  297. }
  298. static void lock_program_memory()
  299. {
  300. // Set the PRGLOCK bit in PECR
  301. *flash_get_PECR() |= FLASH_PECR__PRGLOCK;
  302. // Lock PECR
  303. // Set PELOCK bit in PECR
  304. *flash_get_PECR() |= FLASH_PECR__PELOCK;
  305. }