spi_flash.c 12 KB

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