spi_flash.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  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. uint8_t* foo = (uint8_t *)buf;
  117. SPI_FLASH_CS_L();
  118. spi_tx_rx(CMD_RDSFDP);
  119. send_addr(addr);
  120. spi_tx_rx(0);
  121. while (len--)
  122. //*((uint8_t *)buf++) = spi_tx_rx(0);
  123. *(foo++) = spi_tx_rx(0);
  124. SPI_FLASH_CS_H();
  125. return 0;
  126. }
  127. ssize_t spi_flash_read(int addr, void *buf, size_t len, uint32_t timeout) {
  128. uint8_t* foo = (uint8_t *)buf;
  129. ssize_t ret = 0;
  130. // ret = tn_mutex_lock(&spi_mutex, timeout);
  131. // if (ret != TERR_NO_ERR)
  132. // return ret;
  133. SPI_FLASH_CS_L();
  134. spi_tx_rx(CMD_READ);
  135. send_addr(addr);
  136. while (len--)
  137. //*((uint8_t *)buf++) = spi_tx_rx(0);
  138. *(foo++) = spi_tx_rx(0);
  139. SPI_FLASH_CS_H();
  140. // tn_mutex_unlock(&spi_mutex);
  141. return len;
  142. }
  143. #define TIMEOUT 10000
  144. uint16_t spi_flash_pp(int addr, const void *buf, size_t len, uint32_t timeout) {
  145. uint8_t* foo = (uint8_t *)buf;
  146. // ret = tn_mutex_lock(&spi_mutex, timeout);
  147. // if (ret != TERR_NO_ERR)
  148. // return ret;
  149. // don't allow page wrapping
  150. ssize_t ret = 0;
  151. if ((addr & 0xFF) + len > 0xFF)
  152. len = 0x100 - (addr & 0xFF);
  153. ret = len;
  154. SPI_FLASH_CS_L();
  155. spi_tx_rx(CMD_WREN);
  156. SPI_FLASH_CS_H();
  157. wait_write_enable();
  158. SPI_FLASH_CS_L();
  159. spi_tx_rx(CMD_PP);
  160. send_addr(addr);
  161. while (len--)
  162. //spi_tx_rx(*((uint8_t *)buf++));
  163. spi_tx_rx(*(foo++));
  164. SPI_FLASH_CS_H();
  165. wait_write_end();
  166. // tn_mutex_unlock(&spi_mutex);
  167. return ret;
  168. }
  169. ssize_t spi_flash_write(int addr, const void *buf, size_t len, uint32_t timeout) {
  170. uint8_t* foo = (uint8_t *)buf;
  171. int ret = 0, offset = 0;
  172. do {
  173. //ret = spi_flash_pp(addr + offset, buf + offset, len - offset, 0);
  174. ret = spi_flash_pp(addr + offset, foo + offset, len - offset, 0);
  175. offset += ret;
  176. } while (len - offset);
  177. return 0;
  178. }
  179. int spi_flash_chip_erase(uint32_t timeout) {
  180. SPI_FLASH_CS_L();
  181. spi_tx_rx(CMD_WREN);
  182. SPI_FLASH_CS_H();
  183. wait_write_enable();
  184. SPI_FLASH_CS_L();
  185. spi_tx_rx(CMD_CE);
  186. SPI_FLASH_CS_H();
  187. wait_write_end();
  188. return 0;
  189. }
  190. int spi_flash_erase_sector(int addr, uint32_t timeout) {
  191. int ret = 0;
  192. // ret = tn_mutex_lock(&spi_mutex, timeout);
  193. // if (ret != TERR_NO_ERR)
  194. // return ret;
  195. SPI_FLASH_CS_L();
  196. spi_tx_rx(CMD_WREN);
  197. SPI_FLASH_CS_H();
  198. wait_write_enable();
  199. SPI_FLASH_CS_L();
  200. spi_tx_rx(CMD_SE);
  201. send_addr(addr);
  202. SPI_FLASH_CS_H();
  203. wait_write_end();
  204. // tn_mutex_unlock(&spi_mutex);
  205. return 0;
  206. }
  207. /*
  208. bool spi_flash_init(void) {
  209. uint32_t i, ptable, bitsize = 0;
  210. uint8_t tmp[4];
  211. spi_flash_desc.present = false;
  212. spi_init_();
  213. // check SFDP magic
  214. spi_flash_read_sfdp(0, tmp, 4);
  215. if (!(tmp[0] == 0x53 && tmp[1] == 0x46 &&
  216. tmp[2] == 0x44 && tmp[3] == 0x50))
  217. return 0;
  218. // get parameter headers count
  219. spi_flash_read_sfdp(0x06, tmp, 1);
  220. // find first jedec pheader (with ID == 0)
  221. for (ptable = 0x08, i = 0; i <= tmp[0]; i++, ptable += 8) {
  222. spi_flash_read_sfdp(ptable, tmp, 1);
  223. if (tmp[0] == 0)
  224. break;
  225. }
  226. // read ptable pointer from pheader
  227. spi_flash_read_sfdp(ptable + 4, &ptable, 3);
  228. // get flash density (size in bits)
  229. if (spi_flash_read_sfdp(ptable + 4, &bitsize, 4) < 0 || !bitsize)
  230. return 0;
  231. // find smallest available sector
  232. for (i = 0; i < 4; i++) {
  233. tmp[0] = 0;
  234. if (spi_flash_read_sfdp(ptable + 0x1C + i*2, &tmp, 2) >= 0 &&
  235. tmp[0]) {
  236. spi_flash_desc.sector_size = 1 << tmp[0];
  237. spi_flash_desc.sector_erase_op = tmp[1];
  238. spi_flash_desc.sector_count = (bitsize + 1) >> (3 + tmp[0]);
  239. break;
  240. }
  241. }
  242. if (!spi_flash_desc.sector_size)
  243. return 0;
  244. spi_flash_desc.present = true;
  245. return 1;
  246. }*/
  247. bool spi_flash_init(void){
  248. spi_init_();
  249. spi_flash_desc.sector_size = SPI_FLASH_SECTOR_SIZE;
  250. spi_flash_desc.sector_erase_op = 32;
  251. spi_flash_desc.sector_count = 512;
  252. spi_flash_desc.present = true;
  253. return 1;
  254. }
  255. uint8_t txbuf1[] = "This film came out on DVD yesterday and I rushed to buy it. \
  256. This version is the first to render all the detail and perfection \
  257. of Jack Cardiff's amazing compositions and brilliant, varied photography. \
  258. As a collection of memorable images, this film is better than any comparable \
  259. historical epic of the period and even gives GWTW a run for its money. \
  260. King Vidor's direction is a series of 'tableaux vivants' where the \
  261. characters are not posing but acting in a very natural, period-specific way. \
  262. I have never had a problem with this adaptation of Tolstoy's novel. \
  263. I think it is a wonderful introduction to the period and the novel and that \
  264. it is a very poetic, very original work in its own right. Henry Fonda's \
  265. characterization is especially moving, including great memorable interactions \
  266. with/reations to Mel Ferrer, Audrey Hepburn, Helmut Dantine and John Mills, but \
  267. all members of the cast are actually perfect. The harrowing last 45 minutes of \
  268. the film manage to convey a sense of history, a sense of grandeur as well as to \
  269. communicate very clearly Tolstoy's ideas about the meaning of life, by relying \
  270. mostly on the power of memorable images. The most conspicuous handicap of this movie, \
  271. in my opinion, is its soundtrack (in glorious mono). The barely hi-fi recording of \
  272. dialogues and music sounds pinched, hollow and tinny and it always has in very version \
  273. I have ever seen: in the theatres, on TV and on video. Even the soundtrack album is \
  274. an atrocity. In some scenes, before the necessary adjustments of bass and treble, \
  275. Audrey Hepburn's and Mel Ferrer's voices actually hurt your ear. Nino Rota's very \
  276. Russian-sounding score is serviceable and melodic, although rather sparse in its \
  277. orchestration and in the number of players. One can only wonder what 'War and Peace' \
  278. could have sounded like with a cohort of Hollywood arrangers, decent recording facilities \
  279. and lavish, varied orchestrations in true high fidelity and stereophonic sound. \
  280. According to Lukas Kendall of 'Film Score Monthly', the original recording elements \
  281. of the soundtrack have long ago disappeared, which is the common lot of international, \
  282. independent co-productions of the era. Someone somewhere is certainly guilty of \
  283. skimping on quality or embezzlement for this 1956 movie to sound so much worse \
  284. than a 1939, pre-hi-fi epic like GWTW. Like all VistaVision films, this one was \
  285. meant to be shown in Perspecta Stereophonic Sound where the mono dialog track was \
  286. meant to be channelled to three different directions, making it directional, while \
  287. the separate mono music + sound effects track was generally directed to all three \
  288. speakers at the same time. The results fooled the viewers into thinking everything \
  289. was in true stereo and the reproduction of the music was usually in very high fidelity. \
  290. Maybe the soundtrack used on the DVD is a mono reduction of those two separate tracks \
  291. that has squandered that fidelity and maybe the DVD can be issued again with better \
  292. results in some kind of 4.0 presentation. When they do, very little electronic \
  293. restoration work will be needed to make the image absolutely perfect. \
  294. But let's concentrate on the positive: This film is a summit of visual \
  295. splendour and its sets, costumes, colour photography, composition and lighting \
  296. achieve, in every single scene, wonders of artistry, creativity and delicacy \
  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. that will probably never be equalled. Suffice it to say that it has, \
  301. among many other treasures, a sunrise duel scene in the snow that still has viewers \
  302. wondering whether it was shot outdoors or in a studio and that will have them wondering foreverhsgkhgkshgu.\r\n";
  303. uint8_t txbuf2[] = "STM32F4xx SPI Firmware Library Example: communication with an M25P SPI FLASH\r\n";
  304. #define countof(a) (sizeof(a) / sizeof(*(a)))
  305. #define bufsize1 (countof(txbuf1)-1)
  306. #define bufsize2 (countof(txbuf2)-1)
  307. uint8_t rxbuf1[bufsize1] = {0};
  308. uint8_t rxbuf2[bufsize2] = {0};
  309. bool spi_flash_test(void) {
  310. uint16_t i;
  311. if (!spi_flash_init())
  312. return false;
  313. int ret = 0, addr = 0, offset = 0;
  314. for(i = 0; i < 1; i ++){//spi_flash_desc.sector_count
  315. //spi_flash_read(i*spi_flash_desc.sector_size, rxbuf1, bufsize1, 0);
  316. spi_flash_erase_sector(i*spi_flash_desc.sector_size,0);
  317. //spi_flash_read(0, rxbuf1, bufsize1, 0);
  318. spi_flash_write(i*spi_flash_desc.sector_size, txbuf1, bufsize1, 0);
  319. memset(rxbuf1, 0, bufsize1);
  320. spi_flash_read(i*spi_flash_desc.sector_size, rxbuf1, bufsize1, 0);
  321. if (memcmp(txbuf1, rxbuf1, bufsize1) != 0)
  322. return false;
  323. }
  324. return true;
  325. /*spi_flash_erase_sector(0,0);
  326. spi_flash_read(0, rxbuf1, bufsize1, 0);
  327. spi_flash_write(0, txbuf2, bufsize2, 0);
  328. memset(rxbuf2, 0, bufsize2);
  329. spi_flash_read(0, rxbuf2, bufsize2, 0);*/
  330. /*
  331. * TODO restore spi_flash_init();
  332. spi_flash_init();
  333. if (!spi_flash_desc.present)
  334. return -1;
  335. printf("\tPresent: %d sectors, %d bytes per sector (%d bytes total)\n",
  336. spi_flash_desc.sector_count,
  337. spi_flash_desc.sector_size,
  338. spi_flash_desc.sector_size * spi_flash_desc.sector_count);
  339. return 0;
  340. */
  341. }