spi_flash.c 11 KB

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