spi_flash.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. #include "at32f403a_407.h"
  2. #include "spi_flash.h"
  3. #include "spi_common.h"
  4. #include "FreeRTOS.h"
  5. #include "task.h"
  6. #include "common_config.h"
  7. #include <string.h>
  8. #include <stdio.h>
  9. #define SPI_FLASH SPI3
  10. #define INCLUDE_SPI_TEST 0
  11. //SemaphoreHandle_t spi_mutex;
  12. static uint8_t spi_tx_rx(uint8_t byte) {
  13. return common_spi_tx_rx(SPI_FLASH, byte);
  14. }
  15. #define CMD_WREN 0x06 // +
  16. #define CMD_WRDI 0x04 // +
  17. #define CMD_WRSR 0x01 // +
  18. #define CMD_RDSR 0x05 // +
  19. #if defined (FLASH_TYPE_AT25SF161)
  20. #define CMD_READ 0x03 //0x0B // +
  21. #elif defined (FLASH_TYPE_MX25L1606E)
  22. #define CMD_READ 0x03 // +
  23. #endif
  24. #define CMD_SE 0x20 // + Block Erse 4 Kbytes
  25. #define CMD_BE 0x52 // Block Erase 32 Kbytes
  26. #define CMD_CE 0x60 // + Chip Erase
  27. #define CMD_PP 0x02 // + Byte/Page Program (1 to 256 Bytes)
  28. #define CMD_RDSFDP 0x5A // - not used for FLASH_TYPE_AT25SF161
  29. #define SR_WIP (1 << 0)
  30. #define SR_WEL (1 << 1)
  31. #define SR_SRWD (1 << 7)
  32. static spi_flash_desc_t spi_flash_desc;
  33. static inline void wait_write_enable(void) {
  34. uint8_t status;
  35. SPI_FLASH_CS_L();
  36. spi_tx_rx(CMD_RDSR);
  37. do {
  38. status = spi_tx_rx(0);
  39. } while (!(status & SR_WEL));
  40. SPI_FLASH_CS_H();
  41. }
  42. static inline void wait_write_end(void) {
  43. uint8_t status;
  44. SPI_FLASH_CS_L();
  45. spi_tx_rx(CMD_RDSR);
  46. do {
  47. status = spi_tx_rx(0);
  48. } while (status & SR_WIP);
  49. SPI_FLASH_CS_H();
  50. }
  51. static inline void send_addr(int addr) {
  52. spi_tx_rx((addr >> 16) & 0xFF);
  53. spi_tx_rx((addr >> 8) & 0xFF);
  54. spi_tx_rx(addr & 0xFF);
  55. }
  56. static int spi_flash_read_sfdp(int addr, void *buf, size_t len) {
  57. uint8_t *ptr = (uint8_t*)buf;
  58. //xSemaphoreTake(spi_mutex, portMAX_DELAY);
  59. SPI_FLASH_CS_L();
  60. spi_tx_rx(CMD_RDSFDP);
  61. send_addr(addr);
  62. spi_tx_rx(0);
  63. while (len--)
  64. *ptr++ = spi_tx_rx(0);
  65. SPI_FLASH_CS_H();
  66. //xSemaphoreGive(spi_mutex);
  67. return 0;
  68. }
  69. ssize_t spi_flash_read(int addr, void *buf, size_t len, uint32_t timeout) {
  70. uint8_t *ptr = (uint8_t*)buf;
  71. (void)timeout;
  72. //xSemaphoreTake(spi_mutex, portMAX_DELAY);
  73. SPI_FLASH_CS_L();
  74. spi_tx_rx(CMD_READ);
  75. send_addr(addr);
  76. while (len--)
  77. *ptr++ = spi_tx_rx(0);
  78. SPI_FLASH_CS_H();
  79. //xSemaphoreGive(spi_mutex);
  80. return len;
  81. }
  82. #define TIMEOUT 10000
  83. uint16_t spi_flash_pp(int addr, const void *buf, size_t len, uint32_t timeout) {
  84. uint8_t *ptr = (uint8_t*)buf;
  85. (void)timeout;
  86. ssize_t ret = 0;
  87. if ((addr & 0xFF) + len > 0xFF)
  88. len = 0x100 - (addr & 0xFF);
  89. ret = len;
  90. //xSemaphoreTake(spi_mutex, portMAX_DELAY);
  91. SPI_FLASH_CS_L();
  92. spi_tx_rx(CMD_WREN);
  93. SPI_FLASH_CS_H();
  94. wait_write_enable();
  95. SPI_FLASH_CS_L();
  96. spi_tx_rx(CMD_PP);
  97. send_addr(addr);
  98. while (len--)
  99. spi_tx_rx(*ptr++);
  100. SPI_FLASH_CS_H();
  101. wait_write_end();
  102. //xSemaphoreGive(spi_mutex);
  103. return ret;
  104. }
  105. ssize_t spi_flash_write(int addr, const void *buf, size_t len, uint32_t timeout) {
  106. (void)timeout;
  107. int ret = 0, offset = 0;
  108. do {
  109. ret = spi_flash_pp(addr + offset, (uint8_t*)buf + offset, len - offset, 0);
  110. offset += ret;
  111. } while (len - offset);
  112. return 0;
  113. }
  114. int spi_flash_chip_erase(uint32_t timeout) {
  115. (void)timeout;
  116. //xSemaphoreTake(spi_mutex, portMAX_DELAY);
  117. SPI_FLASH_CS_L();
  118. spi_tx_rx(CMD_WREN);
  119. SPI_FLASH_CS_H();
  120. wait_write_enable();
  121. SPI_FLASH_CS_L();
  122. spi_tx_rx(CMD_CE);
  123. SPI_FLASH_CS_H();
  124. wait_write_end();
  125. //xSemaphoreGive(spi_mutex);
  126. return 0;
  127. }
  128. int spi_flash_erase_sector(int addr, uint32_t timeout) {
  129. (void)timeout;
  130. //xSemaphoreTake(spi_mutex, portMAX_DELAY);
  131. SPI_FLASH_CS_L();
  132. spi_tx_rx(CMD_WREN);
  133. SPI_FLASH_CS_H();
  134. wait_write_enable();
  135. SPI_FLASH_CS_L();
  136. spi_tx_rx(CMD_SE);
  137. send_addr(addr);
  138. SPI_FLASH_CS_H();
  139. wait_write_end();
  140. //xSemaphoreGive(spi_mutex);
  141. return 0;
  142. }
  143. unsigned int spi_flash_get_sector_size(void) {
  144. return spi_flash_desc.sector_size;
  145. }
  146. unsigned int spi_flash_get_sector_count(void) {
  147. return spi_flash_desc.sector_count;
  148. }
  149. unsigned int spi_flash_get_total_size(void) {
  150. return spi_flash_desc.sector_count * spi_flash_desc.sector_size;
  151. }
  152. bool spi_flash_is_init(void) {
  153. return spi_flash_desc.present;
  154. }
  155. bool spi_flash_init(void)
  156. {
  157. bool ret = false;
  158. uint8_t tmp[4] = {0};
  159. SPI_FLASH_CS_H();
  160. spi_flash_get_id(tmp);
  161. if (!(tmp[0] == 0x1F && tmp[1] == 0x86 && tmp[2] == 0x01))
  162. {
  163. ret = false;
  164. spi_flash_read_sfdp(0, tmp, 4);
  165. if (!(tmp[0] == 0x53 && tmp[1] == 0x46 && tmp[2] == 0x44 && tmp[3] == 0x50))
  166. ret = false;
  167. else
  168. ret = true;
  169. }
  170. else
  171. ret = true;
  172. if (ret)
  173. {
  174. spi_flash_desc.sector_size = SPI_FLASH_SECTOR_SIZE;
  175. spi_flash_desc.sector_erase_op = 32;
  176. spi_flash_desc.sector_count = 512;
  177. spi_flash_desc.present = true;
  178. return true;
  179. }
  180. else
  181. return false;
  182. #if 0
  183. #if defined (FLASH_TYPE_AT25SF161)
  184. uint8_t tmp[4] = {0};
  185. SPI_FLASH_CS_H();
  186. spi_flash_get_id(tmp);
  187. if (!(tmp[0] == 0x1F && tmp[1] == 0x86 && tmp[2] == 0x01))
  188. return 0;
  189. spi_flash_desc.sector_size = SPI_FLASH_SECTOR_SIZE;
  190. spi_flash_desc.sector_erase_op = 32;
  191. spi_flash_desc.sector_count = 512;
  192. spi_flash_desc.present = true;
  193. return 1;
  194. #elif defined (FLASH_TYPE_MX25L1606E)
  195. uint32_t i, ptable, bitsize = 0;
  196. uint8_t tmp[4];
  197. spi_flash_desc.present = false;
  198. // check SFDP magic
  199. SPI_FLASH_CS_H();
  200. spi_flash_read_sfdp(0, tmp, 4);
  201. if (!(tmp[0] == 0x53 && tmp[1] == 0x46 &&
  202. tmp[2] == 0x44 && tmp[3] == 0x50))
  203. return 0;
  204. // get parameter headers count
  205. spi_flash_read_sfdp(0x06, tmp, 1);
  206. // find first jedec pheader (with ID == 0)
  207. for (ptable = 0x08, i = 0; i <= tmp[0]; i++, ptable += 8) {
  208. spi_flash_read_sfdp(ptable, tmp, 1);
  209. if (tmp[0] == 0)
  210. break;
  211. }
  212. // read ptable pointer from pheader
  213. spi_flash_read_sfdp(ptable + 4, &ptable, 3);
  214. // get flash density (size in bits)
  215. if (spi_flash_read_sfdp(ptable + 4, &bitsize, 4) < 0 || !bitsize)
  216. return 0;
  217. // find smallest available sector
  218. for (i = 0; i < 4; i++) {
  219. tmp[0] = 0;
  220. if (spi_flash_read_sfdp(ptable + 0x1C + i*2, &tmp, 2) >= 0 &&
  221. tmp[0]) {
  222. spi_flash_desc.sector_size = 1 << tmp[0];
  223. spi_flash_desc.sector_erase_op = tmp[1];
  224. spi_flash_desc.sector_count = (bitsize + 1) >> (3 + tmp[0]);
  225. break;
  226. }
  227. }
  228. if (!spi_flash_desc.sector_size)
  229. return 0;
  230. spi_flash_desc.present = true;
  231. return 1;
  232. #endif
  233. return 0;
  234. #endif
  235. }
  236. /*
  237. bool spi_flash_init(void){
  238. //spi_init_();
  239. spi_flash_desc.sector_size = SPI_FLASH_SECTOR_SIZE;
  240. spi_flash_desc.sector_erase_op = 32;
  241. spi_flash_desc.sector_count = 512;
  242. spi_flash_desc.present = true;
  243. return 1;
  244. }
  245. */
  246. /*
  247. void init_spi_mutex(void)
  248. {
  249. spi_mutex = xSemaphoreCreateMutex();
  250. }
  251. */
  252. // -------------------------------------------------------------------------- //
  253. void spi_flash_get_id(uint8_t *buf)
  254. {
  255. //xSemaphoreTake(spi_mutex, portMAX_DELAY);
  256. SPI_FLASH_CS_L();
  257. spi_tx_rx(0x9F);
  258. *buf++ = spi_tx_rx(0);
  259. *buf++ = spi_tx_rx(0);
  260. *buf++ = spi_tx_rx(0);
  261. SPI_FLASH_CS_H();
  262. //xSemaphoreGive(spi_mutex);
  263. }
  264. // -------------------------------------------------------------------------- //
  265. #if INCLUDE_SPI_TEST
  266. const uint8_t txbuf1[] = "This film came out on DVD yesterday and I rushed to buy it. \
  267. This version is the first to render all the detail and perfection \
  268. of Jack Cardiff's amazing compositions and brilliant, varied photography. \
  269. As a collection of memorable images, this film is better than any comparable \
  270. historical epic of the period and even gives GWTW a run for its money. \
  271. King Vidor's direction is a series of 'tableaux vivants' where the \
  272. characters are not posing but acting in a very natural, period-specific way. \
  273. I have never had a problem with this adaptation of Tolstoy's novel. \
  274. I think it is a wonderful introduction to the period and the novel and that \
  275. it is a very poetic, very original work in its own right. Henry Fonda's \
  276. characterization is especially moving, including great memorable interactions \
  277. with/reations to Mel Ferrer, Audrey Hepburn, Helmut Dantine and John Mills, but \
  278. all members of the cast are actually perfect. The harrowing last 45 minutes of \
  279. the film manage to convey a sense of history, a sense of grandeur as well as to \
  280. communicate very clearly Tolstoy's ideas about the meaning of life, by relying \
  281. mostly on the power of memorable images. The most conspicuous handicap of this movie, \
  282. in my opinion, is its soundtrack (in glorious mono). The barely hi-fi recording of \
  283. dialogues and music sounds pinched, hollow and tinny and it always has in very version \
  284. I have ever seen: in the theatres, on TV and on video. Even the soundtrack album is \
  285. an atrocity. In some scenes, before the necessary adjustments of bass and treble, \
  286. Audrey Hepburn's and Mel Ferrer's voices actually hurt your ear. Nino Rota's very \
  287. Russian-sounding score is serviceable and melodic, although rather sparse in its \
  288. orchestration and in the number of players. One can only wonder what 'War and Peace' \
  289. could have sounded like with a cohort of Hollywood arrangers, decent recording facilities \
  290. and lavish, varied orchestrations in true high fidelity and stereophonic sound. \
  291. According to Lukas Kendall of 'Film Score Monthly', the original recording elements \
  292. of the soundtrack have long ago disappeared, which is the common lot of international, \
  293. independent co-productions of the era. Someone somewhere is certainly guilty of \
  294. skimping on quality or embezzlement for this 1956 movie to sound so much worse \
  295. than a 1939, pre-hi-fi epic like GWTW. Like all VistaVision films, this one was \
  296. meant to be shown in Perspecta Stereophonic Sound where the mono dialog track was \
  297. meant to be channelled to three different directions, making it directional, while \
  298. the separate mono music + sound effects track was generally directed to all three \
  299. speakers at the same time. The results fooled the viewers into thinking everything \
  300. was in true stereo and the reproduction of the music was usually in very high fidelity. \
  301. Maybe the soundtrack used on the DVD is a mono reduction of those two separate tracks \
  302. that has squandered that fidelity and maybe the DVD can be issued again with better \
  303. results in some kind of 4.0 presentation. When they do, very little electronic \
  304. restoration work will be needed to make the image absolutely perfect. \
  305. But let's concentrate on the positive: This film is a summit of visual \
  306. splendour and its sets, costumes, colour photography, composition and lighting \
  307. achieve, in every single scene, wonders of artistry, creativity and delicacy \
  308. But let's concentrate on the positive: This film is a summit of visual \
  309. splendour and its sets, costumes, colour photography, composition and lighting \
  310. achieve, in every single scene, wonders of artistry, creativity and delicacy \
  311. that will probably never be equalled. Suffice it to say that it has, \
  312. among many other treasures, a sunrise duel scene in the snow that still has viewers \
  313. wondering whether it was shot outdoors or in a studio and that will have them wondering foreverhsgkhgkshgu.\r\n";
  314. #define countof(a) (sizeof(a) / sizeof(*(a)))
  315. #define bufsize1 (countof(txbuf1)-1)
  316. uint8_t rxbuf1[bufsize1] = {0};
  317. bool spi_flash_test(void) {
  318. if (!spi_flash_is_init()) {
  319. return false;
  320. }
  321. const unsigned int sector_count = spi_flash_get_sector_count();
  322. const unsigned int sector_size = spi_flash_get_sector_size();
  323. const unsigned int total_size = spi_flash_get_total_size();
  324. printf("Present: %u sectors, %u bytes per sector (%u bytes total)\r\n",
  325. sector_count, sector_size, total_size);
  326. for (uint16_t i = 0; i < sector_count; i++) {
  327. printf("sector: %u/%u ", i, sector_count);
  328. spi_flash_erase_sector(i * sector_size, 0);
  329. spi_flash_write(i * sector_size, txbuf1, bufsize1, 0);
  330. memset(rxbuf1, 0, bufsize1);
  331. spi_flash_read(i * sector_size, rxbuf1, bufsize1, 0);
  332. if (memcmp(txbuf1, rxbuf1, bufsize1) != 0) {
  333. printf("fail\r\n");
  334. return false;
  335. }
  336. printf("ok\r\n");
  337. }
  338. printf("\r\nDone\r\n");
  339. return true;
  340. }
  341. #endif