My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

W25Qxx.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * Based on Sprinter and grbl.
  6. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #include "../inc/MarlinConfig.h"
  23. #if HAS_SPI_FLASH
  24. #include "W25Qxx.h"
  25. #include <SPI.h>
  26. W25QXXFlash W25QXX;
  27. #ifndef SPI_FLASH_MISO_PIN
  28. #define SPI_FLASH_MISO_PIN W25QXX_MISO_PIN
  29. #endif
  30. #ifndef SPI_FLASH_MOSI_PIN
  31. #define SPI_FLASH_MOSI_PIN W25QXX_MOSI_PIN
  32. #endif
  33. #ifndef SPI_FLASH_SCK_PIN
  34. #define SPI_FLASH_SCK_PIN W25QXX_SCK_PIN
  35. #endif
  36. #ifndef SPI_FLASH_CS_PIN
  37. #define SPI_FLASH_CS_PIN W25QXX_CS_PIN
  38. #endif
  39. #define W25QXX_CS_H OUT_WRITE(SPI_FLASH_CS_PIN, HIGH)
  40. #define W25QXX_CS_L OUT_WRITE(SPI_FLASH_CS_PIN, LOW)
  41. void W25QXXFlash::init(uint8_t spiRate) {
  42. OUT_WRITE(SPI_FLASH_CS_PIN, HIGH);
  43. /**
  44. * STM32F1 APB2 = 72MHz, APB1 = 36MHz, max SPI speed of this MCU if 18Mhz
  45. * STM32F1 has 3 SPI ports, SPI1 in APB2, SPI2/SPI3 in APB1
  46. * so the minimum prescale of SPI1 is DIV4, SPI2/SPI3 is DIV2
  47. */
  48. #if SPI_DEVICE == 1
  49. #define SPI_CLOCK_MAX SPI_CLOCK_DIV4
  50. #else
  51. #define SPI_CLOCK_MAX SPI_CLOCK_DIV2
  52. #endif
  53. uint8_t clock;
  54. switch (spiRate) {
  55. case SPI_FULL_SPEED: clock = SPI_CLOCK_MAX; break;
  56. case SPI_HALF_SPEED: clock = SPI_CLOCK_DIV4; break;
  57. case SPI_QUARTER_SPEED: clock = SPI_CLOCK_DIV8; break;
  58. case SPI_EIGHTH_SPEED: clock = SPI_CLOCK_DIV16; break;
  59. case SPI_SPEED_5: clock = SPI_CLOCK_DIV32; break;
  60. case SPI_SPEED_6: clock = SPI_CLOCK_DIV64; break;
  61. default: clock = SPI_CLOCK_DIV2;// Default from the SPI library
  62. }
  63. SPI.setModule(SPI_DEVICE);
  64. SPI.begin();
  65. SPI.setClockDivider(clock);
  66. SPI.setBitOrder(MSBFIRST);
  67. SPI.setDataMode(SPI_MODE0);
  68. }
  69. /**
  70. * @brief Receive a single byte from the SPI port.
  71. *
  72. * @return Byte received
  73. *
  74. * @details
  75. */
  76. uint8_t W25QXXFlash::spi_flash_Rec() {
  77. uint8_t returnByte = SPI.transfer(ff);
  78. return returnByte;
  79. }
  80. uint8_t W25QXXFlash::spi_flash_read_write_byte(uint8_t data) {
  81. uint8_t returnByte = SPI.transfer(data);
  82. return returnByte;
  83. }
  84. /**
  85. * @brief Receive a number of bytes from the SPI port to a buffer
  86. *
  87. * @param buf Pointer to starting address of buffer to write to.
  88. * @param nbyte Number of bytes to receive.
  89. * @return Nothing
  90. *
  91. * @details Uses DMA
  92. */
  93. void W25QXXFlash::spi_flash_Read(uint8_t* buf, uint16_t nbyte) { SPI.dmaTransfer(0, const_cast<uint8_t*>(buf), nbyte); }
  94. /**
  95. * @brief Send a single byte on SPI port
  96. *
  97. * @param b Byte to send
  98. *
  99. * @details
  100. */
  101. void W25QXXFlash::spi_flash_Send(uint8_t b) { SPI.send(b); }
  102. /**
  103. * @brief Write token and then write from 512 byte buffer to SPI (for SD card)
  104. *
  105. * @param buf Pointer with buffer start address
  106. * @return Nothing
  107. *
  108. * @details Use DMA
  109. */
  110. void W25QXXFlash::spi_flash_SendBlock(uint8_t token, const uint8_t* buf) {
  111. SPI.send(token);
  112. SPI.dmaSend(const_cast<uint8_t*>(buf), 512);
  113. }
  114. uint16_t W25QXXFlash::W25QXX_ReadID(void) {
  115. uint16_t Temp = 0;
  116. W25QXX_CS_L;
  117. spi_flash_Send(0x90);
  118. spi_flash_Send(0x00);
  119. spi_flash_Send(0x00);
  120. spi_flash_Send(0x00);
  121. Temp |= spi_flash_Rec() << 8;
  122. Temp |= spi_flash_Rec();
  123. W25QXX_CS_H;
  124. return Temp;
  125. }
  126. void W25QXXFlash::SPI_FLASH_WriteEnable(void) {
  127. /* Select the FLASH: Chip Select low */
  128. W25QXX_CS_L;
  129. /* Send "Write Enable" instruction */
  130. spi_flash_Send(W25X_WriteEnable);
  131. /* Deselect the FLASH: Chip Select high */
  132. W25QXX_CS_H;
  133. }
  134. /*******************************************************************************
  135. * Function Name : SPI_FLASH_WaitForWriteEnd
  136. * Description : Polls the status of the Write In Progress (WIP) flag in the
  137. * FLASH's status register and loop until write opertaion
  138. * has completed.
  139. * Input : None
  140. * Output : None
  141. * Return : None
  142. *******************************************************************************/
  143. void W25QXXFlash::SPI_FLASH_WaitForWriteEnd(void) {
  144. uint8_t FLASH_Status = 0;
  145. /* Select the FLASH: Chip Select low */
  146. W25QXX_CS_L;
  147. /* Send "Read Status Register" instruction */
  148. spi_flash_Send(W25X_ReadStatusReg);
  149. /* Loop as long as the memory is busy with a write cycle */
  150. do
  151. /* Send a dummy byte to generate the clock needed by the FLASH
  152. and put the value of the status register in FLASH_Status variable */
  153. FLASH_Status = spi_flash_Rec();
  154. while ((FLASH_Status & WIP_Flag) == 0x01); /* Write in progress */
  155. /* Deselect the FLASH: Chip Select high */
  156. W25QXX_CS_H;
  157. }
  158. void W25QXXFlash::SPI_FLASH_SectorErase(uint32_t SectorAddr) {
  159. /* Send write enable instruction */
  160. SPI_FLASH_WriteEnable();
  161. /* Sector Erase */
  162. /* Select the FLASH: Chip Select low */
  163. W25QXX_CS_L;
  164. /* Send Sector Erase instruction */
  165. spi_flash_Send(W25X_SectorErase);
  166. /* Send SectorAddr high nibble address byte */
  167. spi_flash_Send((SectorAddr & 0xFF0000) >> 16);
  168. /* Send SectorAddr medium nibble address byte */
  169. spi_flash_Send((SectorAddr & 0xFF00) >> 8);
  170. /* Send SectorAddr low nibble address byte */
  171. spi_flash_Send(SectorAddr & 0xFF);
  172. /* Deselect the FLASH: Chip Select high */
  173. W25QXX_CS_H;
  174. /* Wait the end of Flash writing */
  175. SPI_FLASH_WaitForWriteEnd();
  176. }
  177. void W25QXXFlash::SPI_FLASH_BlockErase(uint32_t BlockAddr) {
  178. SPI_FLASH_WriteEnable();
  179. W25QXX_CS_L;
  180. /* Send Sector Erase instruction */
  181. spi_flash_Send(W25X_BlockErase);
  182. /* Send SectorAddr high nibble address byte */
  183. spi_flash_Send((BlockAddr & 0xFF0000) >> 16);
  184. /* Send SectorAddr medium nibble address byte */
  185. spi_flash_Send((BlockAddr & 0xFF00) >> 8);
  186. /* Send SectorAddr low nibble address byte */
  187. spi_flash_Send(BlockAddr & 0xFF);
  188. W25QXX_CS_H;
  189. SPI_FLASH_WaitForWriteEnd();
  190. }
  191. /*******************************************************************************
  192. * Function Name : SPI_FLASH_BulkErase
  193. * Description : Erases the entire FLASH.
  194. * Input : None
  195. * Output : None
  196. * Return : None
  197. *******************************************************************************/
  198. void W25QXXFlash::SPI_FLASH_BulkErase(void) {
  199. /* Send write enable instruction */
  200. SPI_FLASH_WriteEnable();
  201. /* Bulk Erase */
  202. /* Select the FLASH: Chip Select low */
  203. W25QXX_CS_L;
  204. /* Send Bulk Erase instruction */
  205. spi_flash_Send(W25X_ChipErase);
  206. /* Deselect the FLASH: Chip Select high */
  207. W25QXX_CS_H;
  208. /* Wait the end of Flash writing */
  209. SPI_FLASH_WaitForWriteEnd();
  210. }
  211. /*******************************************************************************
  212. * Function Name : SPI_FLASH_PageWrite
  213. * Description : Writes more than one byte to the FLASH with a single WRITE
  214. * cycle(Page WRITE sequence). The number of byte can't exceed
  215. * the FLASH page size.
  216. * Input : - pBuffer : pointer to the buffer containing the data to be
  217. * written to the FLASH.
  218. * - WriteAddr : FLASH's internal address to write to.
  219. * - NumByteToWrite : number of bytes to write to the FLASH,
  220. * must be equal or less than "SPI_FLASH_PageSize" value.
  221. * Output : None
  222. * Return : None
  223. *******************************************************************************/
  224. void W25QXXFlash::SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {
  225. /* Enable the write access to the FLASH */
  226. SPI_FLASH_WriteEnable();
  227. /* Select the FLASH: Chip Select low */
  228. W25QXX_CS_L;
  229. /* Send "Write to Memory " instruction */
  230. spi_flash_Send(W25X_PageProgram);
  231. /* Send WriteAddr high nibble address byte to write to */
  232. spi_flash_Send((WriteAddr & 0xFF0000) >> 16);
  233. /* Send WriteAddr medium nibble address byte to write to */
  234. spi_flash_Send((WriteAddr & 0xFF00) >> 8);
  235. /* Send WriteAddr low nibble address byte to write to */
  236. spi_flash_Send(WriteAddr & 0xFF);
  237. NOMORE(NumByteToWrite, SPI_FLASH_PerWritePageSize);
  238. /* while there is data to be written on the FLASH */
  239. while (NumByteToWrite--) {
  240. /* Send the current byte */
  241. spi_flash_Send(*pBuffer);
  242. /* Point on the next byte to be written */
  243. pBuffer++;
  244. }
  245. /* Deselect the FLASH: Chip Select high */
  246. W25QXX_CS_H;
  247. /* Wait the end of Flash writing */
  248. SPI_FLASH_WaitForWriteEnd();
  249. }
  250. /*******************************************************************************
  251. * Function Name : SPI_FLASH_BufferWrite
  252. * Description : Writes block of data to the FLASH. In this function, the
  253. * number of WRITE cycles are reduced, using Page WRITE sequence.
  254. * Input : - pBuffer : pointer to the buffer containing the data to be
  255. * written to the FLASH.
  256. * - WriteAddr : FLASH's internal address to write to.
  257. * - NumByteToWrite : number of bytes to write to the FLASH.
  258. * Output : None
  259. * Return : None
  260. *******************************************************************************/
  261. void W25QXXFlash::SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {
  262. uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
  263. Addr = WriteAddr % SPI_FLASH_PageSize;
  264. count = SPI_FLASH_PageSize - Addr;
  265. NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
  266. NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
  267. if (Addr == 0) { /* WriteAddr is SPI_FLASH_PageSize aligned */
  268. if (NumOfPage == 0) { /* NumByteToWrite < SPI_FLASH_PageSize */
  269. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
  270. }
  271. else { /* NumByteToWrite > SPI_FLASH_PageSize */
  272. while (NumOfPage--) {
  273. SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
  274. WriteAddr += SPI_FLASH_PageSize;
  275. pBuffer += SPI_FLASH_PageSize;
  276. }
  277. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
  278. }
  279. }
  280. else { /* WriteAddr is not SPI_FLASH_PageSize aligned */
  281. if (NumOfPage == 0) { /* NumByteToWrite < SPI_FLASH_PageSize */
  282. if (NumOfSingle > count) { /* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */
  283. temp = NumOfSingle - count;
  284. SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
  285. WriteAddr += count;
  286. pBuffer += count;
  287. SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
  288. }
  289. else {
  290. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
  291. }
  292. }
  293. else { /* NumByteToWrite > SPI_FLASH_PageSize */
  294. NumByteToWrite -= count;
  295. NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
  296. NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
  297. SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
  298. WriteAddr += count;
  299. pBuffer += count;
  300. while (NumOfPage--) {
  301. SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
  302. WriteAddr += SPI_FLASH_PageSize;
  303. pBuffer += SPI_FLASH_PageSize;
  304. }
  305. if (NumOfSingle != 0)
  306. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
  307. }
  308. }
  309. }
  310. /*******************************************************************************
  311. * Function Name : SPI_FLASH_BufferRead
  312. * Description : Reads a block of data from the FLASH.
  313. * Input : - pBuffer : pointer to the buffer that receives the data read
  314. * from the FLASH.
  315. * - ReadAddr : FLASH's internal address to read from.
  316. * - NumByteToRead : number of bytes to read from the FLASH.
  317. * Output : None
  318. * Return : None
  319. *******************************************************************************/
  320. void W25QXXFlash::SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead) {
  321. /* Select the FLASH: Chip Select low */
  322. W25QXX_CS_L;
  323. /* Send "Read from Memory " instruction */
  324. spi_flash_Send(W25X_ReadData);
  325. /* Send ReadAddr high nibble address byte to read from */
  326. spi_flash_Send((ReadAddr & 0xFF0000) >> 16);
  327. /* Send ReadAddr medium nibble address byte to read from */
  328. spi_flash_Send((ReadAddr & 0xFF00) >> 8);
  329. /* Send ReadAddr low nibble address byte to read from */
  330. spi_flash_Send(ReadAddr & 0xFF);
  331. if (NumByteToRead < 33) {
  332. while (NumByteToRead--) { /* while there is data to be read */
  333. /* Read a byte from the FLASH */
  334. *pBuffer = spi_flash_Rec();
  335. /* Point to the next location where the byte read will be saved */
  336. pBuffer++;
  337. }
  338. }
  339. else {
  340. spi_flash_Read(pBuffer, NumByteToRead);
  341. }
  342. W25QXX_CS_H;
  343. }
  344. #endif // HAS_SPI_FLASH