spi_flash.c 12 KB

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