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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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. uint8_t W25QXXFlash::spi_flash_Rec() {
  75. const uint8_t returnByte = SPI.transfer(0xFF);
  76. return returnByte;
  77. }
  78. uint8_t W25QXXFlash::spi_flash_read_write_byte(uint8_t data) {
  79. const uint8_t returnByte = SPI.transfer(data);
  80. return returnByte;
  81. }
  82. /**
  83. * @brief Receive a number of bytes from the SPI port to a buffer
  84. *
  85. * @param buf Pointer to starting address of buffer to write to.
  86. * @param nbyte Number of bytes to receive.
  87. * @return Nothing
  88. *
  89. * @details Uses DMA
  90. */
  91. void W25QXXFlash::spi_flash_Read(uint8_t* buf, uint16_t nbyte) { SPI.dmaTransfer(0, const_cast<uint8_t*>(buf), nbyte); }
  92. /**
  93. * @brief Send a single byte on SPI port
  94. *
  95. * @param b Byte to send
  96. *
  97. * @details
  98. */
  99. void W25QXXFlash::spi_flash_Send(uint8_t b) { SPI.send(b); }
  100. /**
  101. * @brief Write token and then write from 512 byte buffer to SPI (for SD card)
  102. *
  103. * @param buf Pointer with buffer start address
  104. * @return Nothing
  105. *
  106. * @details Use DMA
  107. */
  108. void W25QXXFlash::spi_flash_SendBlock(uint8_t token, const uint8_t* buf) {
  109. SPI.send(token);
  110. SPI.dmaSend(const_cast<uint8_t*>(buf), 512);
  111. }
  112. uint16_t W25QXXFlash::W25QXX_ReadID(void) {
  113. uint16_t Temp = 0;
  114. W25QXX_CS_L;
  115. spi_flash_Send(0x90);
  116. spi_flash_Send(0x00);
  117. spi_flash_Send(0x00);
  118. spi_flash_Send(0x00);
  119. Temp |= spi_flash_Rec() << 8;
  120. Temp |= spi_flash_Rec();
  121. W25QXX_CS_H;
  122. return Temp;
  123. }
  124. void W25QXXFlash::SPI_FLASH_WriteEnable(void) {
  125. /* Select the FLASH: Chip Select low */
  126. W25QXX_CS_L;
  127. /* Send "Write Enable" instruction */
  128. spi_flash_Send(W25X_WriteEnable);
  129. /* Deselect the FLASH: Chip Select high */
  130. W25QXX_CS_H;
  131. }
  132. /*******************************************************************************
  133. * Function Name : SPI_FLASH_WaitForWriteEnd
  134. * Description : Polls the status of the Write In Progress (WIP) flag in the
  135. * FLASH's status register and loop until write opertaion
  136. * has completed.
  137. * Input : None
  138. * Output : None
  139. * Return : None
  140. *******************************************************************************/
  141. void W25QXXFlash::SPI_FLASH_WaitForWriteEnd(void) {
  142. uint8_t FLASH_Status = 0;
  143. /* Select the FLASH: Chip Select low */
  144. W25QXX_CS_L;
  145. /* Send "Read Status Register" instruction */
  146. spi_flash_Send(W25X_ReadStatusReg);
  147. /* Loop as long as the memory is busy with a write cycle */
  148. do
  149. /* Send a dummy byte to generate the clock needed by the FLASH
  150. and put the value of the status register in FLASH_Status variable */
  151. FLASH_Status = spi_flash_Rec();
  152. while ((FLASH_Status & WIP_Flag) == 0x01); /* Write in progress */
  153. /* Deselect the FLASH: Chip Select high */
  154. W25QXX_CS_H;
  155. }
  156. void W25QXXFlash::SPI_FLASH_SectorErase(uint32_t SectorAddr) {
  157. /* Send write enable instruction */
  158. SPI_FLASH_WriteEnable();
  159. /* Sector Erase */
  160. /* Select the FLASH: Chip Select low */
  161. W25QXX_CS_L;
  162. /* Send Sector Erase instruction */
  163. spi_flash_Send(W25X_SectorErase);
  164. /* Send SectorAddr high nibble address byte */
  165. spi_flash_Send((SectorAddr & 0xFF0000) >> 16);
  166. /* Send SectorAddr medium nibble address byte */
  167. spi_flash_Send((SectorAddr & 0xFF00) >> 8);
  168. /* Send SectorAddr low nibble address byte */
  169. spi_flash_Send(SectorAddr & 0xFF);
  170. /* Deselect the FLASH: Chip Select high */
  171. W25QXX_CS_H;
  172. /* Wait the end of Flash writing */
  173. SPI_FLASH_WaitForWriteEnd();
  174. }
  175. void W25QXXFlash::SPI_FLASH_BlockErase(uint32_t BlockAddr) {
  176. SPI_FLASH_WriteEnable();
  177. W25QXX_CS_L;
  178. /* Send Sector Erase instruction */
  179. spi_flash_Send(W25X_BlockErase);
  180. /* Send SectorAddr high nibble address byte */
  181. spi_flash_Send((BlockAddr & 0xFF0000) >> 16);
  182. /* Send SectorAddr medium nibble address byte */
  183. spi_flash_Send((BlockAddr & 0xFF00) >> 8);
  184. /* Send SectorAddr low nibble address byte */
  185. spi_flash_Send(BlockAddr & 0xFF);
  186. W25QXX_CS_H;
  187. SPI_FLASH_WaitForWriteEnd();
  188. }
  189. /*******************************************************************************
  190. * Function Name : SPI_FLASH_BulkErase
  191. * Description : Erases the entire FLASH.
  192. * Input : None
  193. * Output : None
  194. * Return : None
  195. *******************************************************************************/
  196. void W25QXXFlash::SPI_FLASH_BulkErase(void) {
  197. /* Send write enable instruction */
  198. SPI_FLASH_WriteEnable();
  199. /* Bulk Erase */
  200. /* Select the FLASH: Chip Select low */
  201. W25QXX_CS_L;
  202. /* Send Bulk Erase instruction */
  203. spi_flash_Send(W25X_ChipErase);
  204. /* Deselect the FLASH: Chip Select high */
  205. W25QXX_CS_H;
  206. /* Wait the end of Flash writing */
  207. SPI_FLASH_WaitForWriteEnd();
  208. }
  209. /*******************************************************************************
  210. * Function Name : SPI_FLASH_PageWrite
  211. * Description : Writes more than one byte to the FLASH with a single WRITE
  212. * cycle(Page WRITE sequence). The number of byte can't exceed
  213. * the FLASH page size.
  214. * Input : - pBuffer : pointer to the buffer containing the data to be
  215. * written to the FLASH.
  216. * - WriteAddr : FLASH's internal address to write to.
  217. * - NumByteToWrite : number of bytes to write to the FLASH,
  218. * must be equal or less than "SPI_FLASH_PageSize" value.
  219. * Output : None
  220. * Return : None
  221. *******************************************************************************/
  222. void W25QXXFlash::SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {
  223. /* Enable the write access to the FLASH */
  224. SPI_FLASH_WriteEnable();
  225. /* Select the FLASH: Chip Select low */
  226. W25QXX_CS_L;
  227. /* Send "Write to Memory " instruction */
  228. spi_flash_Send(W25X_PageProgram);
  229. /* Send WriteAddr high nibble address byte to write to */
  230. spi_flash_Send((WriteAddr & 0xFF0000) >> 16);
  231. /* Send WriteAddr medium nibble address byte to write to */
  232. spi_flash_Send((WriteAddr & 0xFF00) >> 8);
  233. /* Send WriteAddr low nibble address byte to write to */
  234. spi_flash_Send(WriteAddr & 0xFF);
  235. NOMORE(NumByteToWrite, SPI_FLASH_PerWritePageSize);
  236. /* while there is data to be written on the FLASH */
  237. while (NumByteToWrite--) {
  238. /* Send the current byte */
  239. spi_flash_Send(*pBuffer);
  240. /* Point on the next byte to be written */
  241. pBuffer++;
  242. }
  243. /* Deselect the FLASH: Chip Select high */
  244. W25QXX_CS_H;
  245. /* Wait the end of Flash writing */
  246. SPI_FLASH_WaitForWriteEnd();
  247. }
  248. /*******************************************************************************
  249. * Function Name : SPI_FLASH_BufferWrite
  250. * Description : Writes block of data to the FLASH. In this function, the
  251. * number of WRITE cycles are reduced, using Page WRITE sequence.
  252. * Input : - pBuffer : pointer to the buffer containing the data to be
  253. * written to the FLASH.
  254. * - WriteAddr : FLASH's internal address to write to.
  255. * - NumByteToWrite : number of bytes to write to the FLASH.
  256. * Output : None
  257. * Return : None
  258. *******************************************************************************/
  259. void W25QXXFlash::SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {
  260. uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
  261. Addr = WriteAddr % SPI_FLASH_PageSize;
  262. count = SPI_FLASH_PageSize - Addr;
  263. NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
  264. NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
  265. if (Addr == 0) { /* WriteAddr is SPI_FLASH_PageSize aligned */
  266. if (NumOfPage == 0) { /* NumByteToWrite < SPI_FLASH_PageSize */
  267. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
  268. }
  269. else { /* NumByteToWrite > SPI_FLASH_PageSize */
  270. while (NumOfPage--) {
  271. SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
  272. WriteAddr += SPI_FLASH_PageSize;
  273. pBuffer += SPI_FLASH_PageSize;
  274. }
  275. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
  276. }
  277. }
  278. else { /* WriteAddr is not SPI_FLASH_PageSize aligned */
  279. if (NumOfPage == 0) { /* NumByteToWrite < SPI_FLASH_PageSize */
  280. if (NumOfSingle > count) { /* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */
  281. temp = NumOfSingle - count;
  282. SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
  283. WriteAddr += count;
  284. pBuffer += count;
  285. SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
  286. }
  287. else {
  288. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
  289. }
  290. }
  291. else { /* NumByteToWrite > SPI_FLASH_PageSize */
  292. NumByteToWrite -= count;
  293. NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
  294. NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
  295. SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
  296. WriteAddr += count;
  297. pBuffer += count;
  298. while (NumOfPage--) {
  299. SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
  300. WriteAddr += SPI_FLASH_PageSize;
  301. pBuffer += SPI_FLASH_PageSize;
  302. }
  303. if (NumOfSingle != 0)
  304. SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
  305. }
  306. }
  307. }
  308. /*******************************************************************************
  309. * Function Name : SPI_FLASH_BufferRead
  310. * Description : Reads a block of data from the FLASH.
  311. * Input : - pBuffer : pointer to the buffer that receives the data read
  312. * from the FLASH.
  313. * - ReadAddr : FLASH's internal address to read from.
  314. * - NumByteToRead : number of bytes to read from the FLASH.
  315. * Output : None
  316. * Return : None
  317. *******************************************************************************/
  318. void W25QXXFlash::SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead) {
  319. /* Select the FLASH: Chip Select low */
  320. W25QXX_CS_L;
  321. /* Send "Read from Memory " instruction */
  322. spi_flash_Send(W25X_ReadData);
  323. /* Send ReadAddr high nibble address byte to read from */
  324. spi_flash_Send((ReadAddr & 0xFF0000) >> 16);
  325. /* Send ReadAddr medium nibble address byte to read from */
  326. spi_flash_Send((ReadAddr & 0xFF00) >> 8);
  327. /* Send ReadAddr low nibble address byte to read from */
  328. spi_flash_Send(ReadAddr & 0xFF);
  329. if (NumByteToRead < 33) {
  330. while (NumByteToRead--) { /* while there is data to be read */
  331. /* Read a byte from the FLASH */
  332. *pBuffer = spi_flash_Rec();
  333. /* Point to the next location where the byte read will be saved */
  334. pBuffer++;
  335. }
  336. }
  337. else {
  338. spi_flash_Read(pBuffer, NumByteToRead);
  339. }
  340. W25QXX_CS_H;
  341. }
  342. #endif // HAS_SPI_FLASH