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.

HAL_SPI.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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. /**
  23. * Software SPI functions originally from Arduino Sd2Card Library
  24. * Copyright (c) 2009 by William Greiman
  25. */
  26. /**
  27. * For TARGET_LPC1768
  28. */
  29. /**
  30. * Hardware SPI and Software SPI implementations are included in this file.
  31. * The hardware SPI runs faster and has higher throughput but is not compatible
  32. * with some LCD interfaces/adapters.
  33. *
  34. * Control of the slave select pin(s) is handled by the calling routines.
  35. *
  36. * Some of the LCD interfaces/adapters result in the LCD SPI and the SD card
  37. * SPI sharing pins. The SCK, MOSI & MISO pins can NOT be set/cleared with
  38. * WRITE nor digitalWrite when the hardware SPI module within the LPC17xx is
  39. * active. If any of these pins are shared then the software SPI must be used.
  40. *
  41. * A more sophisticated hardware SPI can be found at the following link.
  42. * This implementation has not been fully debugged.
  43. * https://github.com/MarlinFirmware/Marlin/tree/071c7a78f27078fd4aee9a3ef365fcf5e143531e
  44. */
  45. #ifdef TARGET_LPC1768
  46. #include "../../inc/MarlinConfig.h"
  47. #include <SPI.h>
  48. // Hardware SPI and SPIClass
  49. #include <lpc17xx_pinsel.h>
  50. #include <lpc17xx_clkpwr.h>
  51. #include "../shared/HAL_SPI.h"
  52. // ------------------------
  53. // Public functions
  54. // ------------------------
  55. #if ENABLED(LPC_SOFTWARE_SPI)
  56. // Software SPI
  57. #include <SoftwareSPI.h>
  58. #ifndef HAL_SPI_SPEED
  59. #define HAL_SPI_SPEED SPI_FULL_SPEED
  60. #endif
  61. static uint8_t SPI_speed = HAL_SPI_SPEED;
  62. static uint8_t spiTransfer(uint8_t b) {
  63. return swSpiTransfer(b, SPI_speed, SD_SCK_PIN, SD_MISO_PIN, SD_MOSI_PIN);
  64. }
  65. void spiBegin() {
  66. swSpiBegin(SD_SCK_PIN, SD_MISO_PIN, SD_MOSI_PIN);
  67. }
  68. void spiInit(uint8_t spiRate) {
  69. SPI_speed = swSpiInit(spiRate, SD_SCK_PIN, SD_MOSI_PIN);
  70. }
  71. uint8_t spiRec() { return spiTransfer(0xFF); }
  72. void spiRead(uint8_t*buf, uint16_t nbyte) {
  73. for (int i = 0; i < nbyte; i++)
  74. buf[i] = spiTransfer(0xFF);
  75. }
  76. void spiSend(uint8_t b) { (void)spiTransfer(b); }
  77. void spiSend(const uint8_t* buf, size_t nbyte) {
  78. for (uint16_t i = 0; i < nbyte; i++)
  79. (void)spiTransfer(buf[i]);
  80. }
  81. void spiSendBlock(uint8_t token, const uint8_t* buf) {
  82. (void)spiTransfer(token);
  83. for (uint16_t i = 0; i < 512; i++)
  84. (void)spiTransfer(buf[i]);
  85. }
  86. #else
  87. #ifndef HAL_SPI_SPEED
  88. #ifdef SD_SPI_SPEED
  89. #define HAL_SPI_SPEED SD_SPI_SPEED
  90. #else
  91. #define HAL_SPI_SPEED SPI_FULL_SPEED
  92. #endif
  93. #endif
  94. void spiBegin() { spiInit(HAL_SPI_SPEED); } // Set up SCK, MOSI & MISO pins for SSP0
  95. void spiInit(uint8_t spiRate) {
  96. #if SD_MISO_PIN == BOARD_SPI1_MISO_PIN
  97. SPI.setModule(1);
  98. #elif SD_MISO_PIN == BOARD_SPI2_MISO_PIN
  99. SPI.setModule(2);
  100. #endif
  101. SPI.setDataSize(DATA_SIZE_8BIT);
  102. SPI.setDataMode(SPI_MODE0);
  103. SPI.setClock(SPISettings::spiRate2Clock(spiRate));
  104. SPI.begin();
  105. }
  106. static uint8_t doio(uint8_t b) {
  107. return SPI.transfer(b & 0x00FF) & 0x00FF;
  108. }
  109. void spiSend(uint8_t b) { doio(b); }
  110. void spiSend(const uint8_t* buf, size_t nbyte) {
  111. for (uint16_t i = 0; i < nbyte; i++) doio(buf[i]);
  112. }
  113. void spiSend(uint32_t chan, byte b) {}
  114. void spiSend(uint32_t chan, const uint8_t* buf, size_t nbyte) {}
  115. // Read single byte from SPI
  116. uint8_t spiRec() { return doio(0xFF); }
  117. uint8_t spiRec(uint32_t chan) { return 0; }
  118. // Read from SPI into buffer
  119. void spiRead(uint8_t *buf, uint16_t nbyte) {
  120. for (uint16_t i = 0; i < nbyte; i++) buf[i] = doio(0xFF);
  121. }
  122. uint8_t spiTransfer(uint8_t b) { return doio(b); }
  123. // Write from buffer to SPI
  124. void spiSendBlock(uint8_t token, const uint8_t* buf) {
  125. (void)spiTransfer(token);
  126. for (uint16_t i = 0; i < 512; i++)
  127. (void)spiTransfer(buf[i]);
  128. }
  129. // Begin SPI transaction, set clock, bit order, data mode
  130. void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
  131. // TODO: Implement this method
  132. }
  133. #endif // LPC_SOFTWARE_SPI
  134. /**
  135. * @brief Wait until TXE (tx empty) flag is set and BSY (busy) flag unset.
  136. */
  137. static inline void waitSpiTxEnd(LPC_SSP_TypeDef *spi_d) {
  138. while (SSP_GetStatus(spi_d, SSP_STAT_TXFIFO_EMPTY) == RESET) { /* nada */ } // wait until TXE=1
  139. while (SSP_GetStatus(spi_d, SSP_STAT_BUSY) == SET) { /* nada */ } // wait until BSY=0
  140. }
  141. // Retain the pin init state of the SPI, to avoid init more than once,
  142. // even if more instances of SPIClass exist
  143. static bool spiInitialised[BOARD_NR_SPI] = { false };
  144. SPIClass::SPIClass(uint8_t device) {
  145. // Init things specific to each SPI device
  146. // clock divider setup is a bit of hack, and needs to be improved at a later date.
  147. #if BOARD_NR_SPI >= 1
  148. _settings[0].spi_d = LPC_SSP0;
  149. _settings[0].dataMode = SPI_MODE0;
  150. _settings[0].dataSize = DATA_SIZE_8BIT;
  151. _settings[0].clock = SPI_CLOCK_MAX;
  152. //_settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock);
  153. #endif
  154. #if BOARD_NR_SPI >= 2
  155. _settings[1].spi_d = LPC_SSP1;
  156. _settings[1].dataMode = SPI_MODE0;
  157. _settings[1].dataSize = DATA_SIZE_8BIT;
  158. _settings[1].clock = SPI_CLOCK_MAX;
  159. //_settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock);
  160. #endif
  161. setModule(device);
  162. // Init the GPDMA controller
  163. // TODO: call once in the constructor? or each time?
  164. GPDMA_Init();
  165. }
  166. SPIClass::SPIClass(pin_t mosi, pin_t miso, pin_t sclk, pin_t ssel) {
  167. #if BOARD_NR_SPI >= 1
  168. if (mosi == BOARD_SPI1_MOSI_PIN) SPIClass(1);
  169. #endif
  170. #if BOARD_NR_SPI >= 2
  171. if (mosi == BOARD_SPI2_MOSI_PIN) SPIClass(2);
  172. #endif
  173. }
  174. void SPIClass::begin() {
  175. // Init the SPI pins in the first begin call
  176. if ((_currentSetting->spi_d == LPC_SSP0 && spiInitialised[0] == false) ||
  177. (_currentSetting->spi_d == LPC_SSP1 && spiInitialised[1] == false)) {
  178. pin_t sck, miso, mosi;
  179. if (_currentSetting->spi_d == LPC_SSP0) {
  180. sck = BOARD_SPI1_SCK_PIN;
  181. miso = BOARD_SPI1_MISO_PIN;
  182. mosi = BOARD_SPI1_MOSI_PIN;
  183. spiInitialised[0] = true;
  184. }
  185. else if (_currentSetting->spi_d == LPC_SSP1) {
  186. sck = BOARD_SPI2_SCK_PIN;
  187. miso = BOARD_SPI2_MISO_PIN;
  188. mosi = BOARD_SPI2_MOSI_PIN;
  189. spiInitialised[1] = true;
  190. }
  191. PINSEL_CFG_Type PinCfg; // data structure to hold init values
  192. PinCfg.Funcnum = 2;
  193. PinCfg.OpenDrain = 0;
  194. PinCfg.Pinmode = 0;
  195. PinCfg.Pinnum = LPC176x::pin_bit(sck);
  196. PinCfg.Portnum = LPC176x::pin_port(sck);
  197. PINSEL_ConfigPin(&PinCfg);
  198. SET_OUTPUT(sck);
  199. PinCfg.Pinnum = LPC176x::pin_bit(miso);
  200. PinCfg.Portnum = LPC176x::pin_port(miso);
  201. PINSEL_ConfigPin(&PinCfg);
  202. SET_INPUT(miso);
  203. PinCfg.Pinnum = LPC176x::pin_bit(mosi);
  204. PinCfg.Portnum = LPC176x::pin_port(mosi);
  205. PINSEL_ConfigPin(&PinCfg);
  206. SET_OUTPUT(mosi);
  207. }
  208. updateSettings();
  209. SSP_Cmd(_currentSetting->spi_d, ENABLE); // start SSP running
  210. }
  211. void SPIClass::beginTransaction(const SPISettings &cfg) {
  212. setBitOrder(cfg.bitOrder);
  213. setDataMode(cfg.dataMode);
  214. setDataSize(cfg.dataSize);
  215. //setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock));
  216. begin();
  217. }
  218. uint8_t SPIClass::transfer(const uint16_t b) {
  219. // Send and receive a single byte
  220. SSP_ReceiveData(_currentSetting->spi_d); // read any previous data
  221. SSP_SendData(_currentSetting->spi_d, b);
  222. waitSpiTxEnd(_currentSetting->spi_d); // wait for it to finish
  223. return SSP_ReceiveData(_currentSetting->spi_d);
  224. }
  225. uint16_t SPIClass::transfer16(const uint16_t data) {
  226. return (transfer((data >> 8) & 0xFF) << 8) | (transfer(data & 0xFF) & 0xFF);
  227. }
  228. void SPIClass::end() {
  229. // Neither is needed for Marlin
  230. //SSP_Cmd(_currentSetting->spi_d, DISABLE);
  231. //SSP_DeInit(_currentSetting->spi_d);
  232. }
  233. void SPIClass::send(uint8_t data) {
  234. SSP_SendData(_currentSetting->spi_d, data);
  235. }
  236. void SPIClass::dmaSend(void *buf, uint16_t length, bool minc) {
  237. //TODO: LPC dma can only write 0xFFF bytes at once.
  238. GPDMA_Channel_CFG_Type GPDMACfg;
  239. /* Configure GPDMA channel 0 -------------------------------------------------------------*/
  240. /* DMA Channel 0 */
  241. GPDMACfg.ChannelNum = 0;
  242. // Source memory
  243. GPDMACfg.SrcMemAddr = (uint32_t)buf;
  244. // Destination memory - Not used
  245. GPDMACfg.DstMemAddr = 0;
  246. // Transfer size
  247. GPDMACfg.TransferSize = length;
  248. // Transfer width
  249. GPDMACfg.TransferWidth = (_currentSetting->dataSize == DATA_SIZE_16BIT) ? GPDMA_WIDTH_HALFWORD : GPDMA_WIDTH_BYTE;
  250. // Transfer type
  251. GPDMACfg.TransferType = GPDMA_TRANSFERTYPE_M2P;
  252. // Source connection - unused
  253. GPDMACfg.SrcConn = 0;
  254. // Destination connection
  255. GPDMACfg.DstConn = (_currentSetting->spi_d == LPC_SSP0) ? GPDMA_CONN_SSP0_Tx : GPDMA_CONN_SSP1_Tx;
  256. GPDMACfg.DMALLI = 0;
  257. // Enable dma on SPI
  258. SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, ENABLE);
  259. // Only increase memory if minc is true
  260. GPDMACfg.MemoryIncrease = (minc ? GPDMA_DMACCxControl_SI : 0);
  261. // Setup channel with given parameter
  262. GPDMA_Setup(&GPDMACfg);
  263. // Enable DMA
  264. GPDMA_ChannelCmd(0, ENABLE);
  265. // Wait for data transfer
  266. while (!GPDMA_IntGetStatus(GPDMA_STAT_RAWINTTC, 0) && !GPDMA_IntGetStatus(GPDMA_STAT_RAWINTERR, 0)) { }
  267. // Clear err and int
  268. GPDMA_ClearIntPending (GPDMA_STATCLR_INTTC, 0);
  269. GPDMA_ClearIntPending (GPDMA_STATCLR_INTERR, 0);
  270. // Disable DMA
  271. GPDMA_ChannelCmd(0, DISABLE);
  272. waitSpiTxEnd(_currentSetting->spi_d);
  273. SSP_DMACmd(_currentSetting->spi_d, SSP_DMA_TX, DISABLE);
  274. }
  275. uint16_t SPIClass::read() {
  276. return SSP_ReceiveData(_currentSetting->spi_d);
  277. }
  278. void SPIClass::read(uint8_t *buf, uint32_t len) {
  279. for (uint16_t i = 0; i < len; i++) buf[i] = transfer(0xFF);
  280. }
  281. void SPIClass::setClock(uint32_t clock) { _currentSetting->clock = clock; }
  282. void SPIClass::setModule(uint8_t device) { _currentSetting = &_settings[device - 1]; } // SPI channels are called 1, 2, and 3 but the array is zero-indexed
  283. void SPIClass::setBitOrder(uint8_t bitOrder) { _currentSetting->bitOrder = bitOrder; }
  284. void SPIClass::setDataMode(uint8_t dataMode) { _currentSetting->dataMode = dataMode; }
  285. void SPIClass::setDataSize(uint32_t dataSize) { _currentSetting->dataSize = dataSize; }
  286. /**
  287. * Set up/tear down
  288. */
  289. void SPIClass::updateSettings() {
  290. //SSP_DeInit(_currentSetting->spi_d); //todo: need force de init?!
  291. // Divide PCLK by 2 for SSP0
  292. //CLKPWR_SetPCLKDiv(_currentSetting->spi_d == LPC_SSP0 ? CLKPWR_PCLKSEL_SSP0 : CLKPWR_PCLKSEL_SSP1, CLKPWR_PCLKSEL_CCLK_DIV_2);
  293. SSP_CFG_Type HW_SPI_init; // data structure to hold init values
  294. SSP_ConfigStructInit(&HW_SPI_init); // set values for SPI mode
  295. HW_SPI_init.ClockRate = _currentSetting->clock;
  296. HW_SPI_init.Databit = _currentSetting->dataSize;
  297. /**
  298. * SPI Mode CPOL CPHA Shift SCK-edge Capture SCK-edge
  299. * 0 0 0 Falling Rising
  300. * 1 0 1 Rising Falling
  301. * 2 1 0 Rising Falling
  302. * 3 1 1 Falling Rising
  303. */
  304. switch (_currentSetting->dataMode) {
  305. case SPI_MODE0:
  306. HW_SPI_init.CPHA = SSP_CPHA_FIRST;
  307. HW_SPI_init.CPOL = SSP_CPOL_HI;
  308. break;
  309. case SPI_MODE1:
  310. HW_SPI_init.CPHA = SSP_CPHA_SECOND;
  311. HW_SPI_init.CPOL = SSP_CPOL_HI;
  312. break;
  313. case SPI_MODE2:
  314. HW_SPI_init.CPHA = SSP_CPHA_FIRST;
  315. HW_SPI_init.CPOL = SSP_CPOL_LO;
  316. break;
  317. case SPI_MODE3:
  318. HW_SPI_init.CPHA = SSP_CPHA_SECOND;
  319. HW_SPI_init.CPOL = SSP_CPOL_LO;
  320. break;
  321. default:
  322. break;
  323. }
  324. // TODO: handle bitOrder
  325. SSP_Init(_currentSetting->spi_d, &HW_SPI_init); // puts the values into the proper bits in the SSP0 registers
  326. }
  327. #if SD_MISO_PIN == BOARD_SPI1_MISO_PIN
  328. SPIClass SPI(1);
  329. #elif SD_MISO_PIN == BOARD_SPI2_MISO_PIN
  330. SPIClass SPI(2);
  331. #endif
  332. #endif // TARGET_LPC1768