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

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