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.

lpc17xx_spi.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. /**********************************************************************
  2. * $Id$ lpc17xx_spi.c 2010-05-21
  3. *//**
  4. * @file lpc17xx_spi.c
  5. * @brief Contains all functions support for SPI firmware library on LPC17xx
  6. * @version 2.0
  7. * @date 21. May. 2010
  8. * @author NXP MCU SW Application Team
  9. *
  10. * Copyright(C) 2010, NXP Semiconductor
  11. * All rights reserved.
  12. *
  13. ***********************************************************************
  14. * Software that is described herein is for illustrative purposes only
  15. * which provides customers with programming information regarding the
  16. * products. This software is supplied "AS IS" without any warranties.
  17. * NXP Semiconductors assumes no responsibility or liability for the
  18. * use of the software, conveys no license or title under any patent,
  19. * copyright, or mask work right to the product. NXP Semiconductors
  20. * reserves the right to make changes in the software without
  21. * notification. NXP Semiconductors also make no representation or
  22. * warranty that such application will be suitable for the specified
  23. * use without further testing or modification.
  24. * Permission to use, copy, modify, and distribute this software and its
  25. * documentation is hereby granted, under NXP Semiconductors'
  26. * relevant copyright in the software, without fee, provided that it
  27. * is used in conjunction with NXP Semiconductors microcontrollers. This
  28. * copyright, permission, and disclaimer notice must appear in all copies of
  29. * this code.
  30. **********************************************************************/
  31. /* Peripheral group ----------------------------------------------------------- */
  32. /** @addtogroup SPI
  33. * @{
  34. */
  35. /* Includes ------------------------------------------------------------------- */
  36. #include "lpc17xx_spi.h"
  37. #include "lpc17xx_clkpwr.h"
  38. /* If this source file built with example, the LPC17xx FW library configuration
  39. * file in each example directory ("lpc17xx_libcfg.h") must be included,
  40. * otherwise the default FW library configuration file must be included instead
  41. */
  42. #ifdef __BUILD_WITH_EXAMPLE__
  43. #include "lpc17xx_libcfg.h"
  44. #else
  45. #include "lpc17xx_libcfg_default.h"
  46. #endif /* __BUILD_WITH_EXAMPLE__ */
  47. #ifdef _SPI
  48. /* Public Functions ----------------------------------------------------------- */
  49. /** @addtogroup SPI_Public_Functions
  50. * @{
  51. */
  52. /*********************************************************************//**
  53. * @brief Setup clock rate for SPI device
  54. * @param[in] SPIx SPI peripheral definition, should be LPC_SPI
  55. * @param[in] target_clock : clock of SPI (Hz)
  56. * @return None
  57. ***********************************************************************/
  58. void SPI_SetClock (LPC_SPI_TypeDef *SPIx, uint32_t target_clock)
  59. {
  60. uint32_t spi_pclk;
  61. uint32_t prescale, temp;
  62. CHECK_PARAM(PARAM_SPIx(SPIx));
  63. if (SPIx == LPC_SPI){
  64. spi_pclk = CLKPWR_GetPCLK (CLKPWR_PCLKSEL_SPI);
  65. } else {
  66. return;
  67. }
  68. prescale = 8;
  69. // Find closest clock to target clock
  70. while (1){
  71. temp = target_clock * prescale;
  72. if (temp >= spi_pclk){
  73. break;
  74. }
  75. prescale += 2;
  76. if(prescale >= 254){
  77. break;
  78. }
  79. }
  80. // Write to register
  81. SPIx->SPCCR = SPI_SPCCR_COUNTER(prescale);
  82. }
  83. /*********************************************************************//**
  84. * @brief De-initializes the SPIx peripheral registers to their
  85. * default reset values.
  86. * @param[in] SPIx SPI peripheral selected, should be LPC_SPI
  87. * @return None
  88. **********************************************************************/
  89. void SPI_DeInit(LPC_SPI_TypeDef *SPIx)
  90. {
  91. CHECK_PARAM(PARAM_SPIx(SPIx));
  92. if (SPIx == LPC_SPI){
  93. /* Set up clock and power for SPI module */
  94. CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, DISABLE);
  95. }
  96. }
  97. /*********************************************************************//**
  98. * @brief Get data bit size per transfer
  99. * @param[in] SPIx SPI peripheral selected, should be LPC_SPI
  100. * @return number of bit per transfer, could be 8-16
  101. **********************************************************************/
  102. uint8_t SPI_GetDataSize (LPC_SPI_TypeDef *SPIx)
  103. {
  104. CHECK_PARAM(PARAM_SPIx(SPIx));
  105. return ((SPIx->SPCR)>>8 & 0xF);
  106. }
  107. /********************************************************************//**
  108. * @brief Initializes the SPIx peripheral according to the specified
  109. * parameters in the UART_ConfigStruct.
  110. * @param[in] SPIx SPI peripheral selected, should be LPC_SPI
  111. * @param[in] SPI_ConfigStruct Pointer to a SPI_CFG_Type structure
  112. * that contains the configuration information for the
  113. * specified SPI peripheral.
  114. * @return None
  115. *********************************************************************/
  116. void SPI_Init(LPC_SPI_TypeDef *SPIx, SPI_CFG_Type *SPI_ConfigStruct)
  117. {
  118. uint32_t tmp;
  119. CHECK_PARAM(PARAM_SPIx(SPIx));
  120. if(SPIx == LPC_SPI){
  121. /* Set up clock and power for UART module */
  122. CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCSPI, ENABLE);
  123. } else {
  124. return;
  125. }
  126. // Configure SPI, interrupt is disable as default
  127. tmp = ((SPI_ConfigStruct->CPHA) | (SPI_ConfigStruct->CPOL) \
  128. | (SPI_ConfigStruct->DataOrder) | (SPI_ConfigStruct->Databit) \
  129. | (SPI_ConfigStruct->Mode) | SPI_SPCR_BIT_EN) & SPI_SPCR_BITMASK;
  130. // write back to SPI control register
  131. SPIx->SPCR = tmp;
  132. // Set clock rate for SPI peripheral
  133. SPI_SetClock(SPIx, SPI_ConfigStruct->ClockRate);
  134. // If interrupt flag is set, Write '1' to Clear interrupt flag
  135. if (SPIx->SPINT & SPI_SPINT_INTFLAG){
  136. SPIx->SPINT = SPI_SPINT_INTFLAG;
  137. }
  138. }
  139. /*****************************************************************************//**
  140. * @brief Fills each SPI_InitStruct member with its default value:
  141. * - CPHA = SPI_CPHA_FIRST
  142. * - CPOL = SPI_CPOL_HI
  143. * - ClockRate = 1000000
  144. * - DataOrder = SPI_DATA_MSB_FIRST
  145. * - Databit = SPI_DATABIT_8
  146. * - Mode = SPI_MASTER_MODE
  147. * @param[in] SPI_InitStruct Pointer to a SPI_CFG_Type structure
  148. * which will be initialized.
  149. * @return None
  150. *******************************************************************************/
  151. void SPI_ConfigStructInit(SPI_CFG_Type *SPI_InitStruct)
  152. {
  153. SPI_InitStruct->CPHA = SPI_CPHA_FIRST;
  154. SPI_InitStruct->CPOL = SPI_CPOL_HI;
  155. SPI_InitStruct->ClockRate = 1000000;
  156. SPI_InitStruct->DataOrder = SPI_DATA_MSB_FIRST;
  157. SPI_InitStruct->Databit = SPI_DATABIT_8;
  158. SPI_InitStruct->Mode = SPI_MASTER_MODE;
  159. }
  160. /*********************************************************************//**
  161. * @brief Transmit a single data through SPIx peripheral
  162. * @param[in] SPIx SPI peripheral selected, should be LPC_SPI
  163. * @param[in] Data Data to transmit (must be 16 or 8-bit long,
  164. * this depend on SPI data bit number configured)
  165. * @return none
  166. **********************************************************************/
  167. void SPI_SendData(LPC_SPI_TypeDef* SPIx, uint16_t Data)
  168. {
  169. CHECK_PARAM(PARAM_SPIx(SPIx));
  170. SPIx->SPDR = Data & SPI_SPDR_BITMASK;
  171. }
  172. /*********************************************************************//**
  173. * @brief Receive a single data from SPIx peripheral
  174. * @param[in] SPIx SPI peripheral selected, should be LPC_SPI
  175. * @return Data received (16-bit long)
  176. **********************************************************************/
  177. uint16_t SPI_ReceiveData(LPC_SPI_TypeDef* SPIx)
  178. {
  179. CHECK_PARAM(PARAM_SPIx(SPIx));
  180. return ((uint16_t) (SPIx->SPDR & SPI_SPDR_BITMASK));
  181. }
  182. /*********************************************************************//**
  183. * @brief SPI Read write data function
  184. * @param[in] SPIx Pointer to SPI peripheral, should be LPC_SPI
  185. * @param[in] dataCfg Pointer to a SPI_DATA_SETUP_Type structure that
  186. * contains specified information about transmit
  187. * data configuration.
  188. * @param[in] xfType Transfer type, should be:
  189. * - SPI_TRANSFER_POLLING: Polling mode
  190. * - SPI_TRANSFER_INTERRUPT: Interrupt mode
  191. * @return Actual Data length has been transferred in polling mode.
  192. * In interrupt mode, always return (0)
  193. * Return (-1) if error.
  194. * Note: This function can be used in both master and slave mode.
  195. ***********************************************************************/
  196. int32_t SPI_ReadWrite (LPC_SPI_TypeDef *SPIx, SPI_DATA_SETUP_Type *dataCfg, \
  197. SPI_TRANSFER_Type xfType)
  198. {
  199. uint8_t *rdata8;
  200. uint8_t *wdata8;
  201. uint16_t *rdata16;
  202. uint16_t *wdata16;
  203. uint32_t stat;
  204. uint32_t temp;
  205. uint8_t dataword;
  206. //read for empty buffer
  207. temp = SPIx->SPDR;
  208. //dummy to clear status
  209. temp = SPIx->SPSR;
  210. dataCfg->counter = 0;
  211. dataCfg->status = 0;
  212. if(SPI_GetDataSize (SPIx) == 8)
  213. dataword = 0;
  214. else dataword = 1;
  215. if (xfType == SPI_TRANSFER_POLLING){
  216. if (dataword == 0){
  217. rdata8 = (uint8_t *)dataCfg->rx_data;
  218. wdata8 = (uint8_t *)dataCfg->tx_data;
  219. } else {
  220. rdata16 = (uint16_t *)dataCfg->rx_data;
  221. wdata16 = (uint16_t *)dataCfg->tx_data;
  222. }
  223. while(dataCfg->counter < dataCfg->length)
  224. {
  225. // Write data to buffer
  226. if(dataCfg->tx_data == NULL){
  227. if (dataword == 0){
  228. SPI_SendData(SPIx, 0xFF);
  229. } else {
  230. SPI_SendData(SPIx, 0xFFFF);
  231. }
  232. } else {
  233. if (dataword == 0){
  234. SPI_SendData(SPIx, *wdata8);
  235. wdata8++;
  236. } else {
  237. SPI_SendData(SPIx, *wdata16);
  238. wdata16++;
  239. }
  240. }
  241. // Wait for transfer complete
  242. while (!((stat = SPIx->SPSR) & SPI_SPSR_SPIF));
  243. // Check for error
  244. if (stat & (SPI_SPSR_ABRT | SPI_SPSR_MODF | SPI_SPSR_ROVR | SPI_SPSR_WCOL)){
  245. // save status
  246. dataCfg->status = stat | SPI_STAT_ERROR;
  247. return (dataCfg->counter);
  248. }
  249. // Read data from SPI dat
  250. temp = (uint32_t) SPI_ReceiveData(SPIx);
  251. // Store data to destination
  252. if (dataCfg->rx_data != NULL)
  253. {
  254. if (dataword == 0){
  255. *(rdata8) = (uint8_t) temp;
  256. rdata8++;
  257. } else {
  258. *(rdata16) = (uint16_t) temp;
  259. rdata16++;
  260. }
  261. }
  262. // Increase counter
  263. if (dataword == 0){
  264. dataCfg->counter++;
  265. } else {
  266. dataCfg->counter += 2;
  267. }
  268. }
  269. // Return length of actual data transferred
  270. // save status
  271. dataCfg->status = stat | SPI_STAT_DONE;
  272. return (dataCfg->counter);
  273. }
  274. // Interrupt mode
  275. else {
  276. // Check if interrupt flag is already set
  277. if(SPIx->SPINT & SPI_SPINT_INTFLAG){
  278. SPIx->SPINT = SPI_SPINT_INTFLAG;
  279. }
  280. if (dataCfg->counter < dataCfg->length){
  281. // Write data to buffer
  282. if(dataCfg->tx_data == NULL){
  283. if (dataword == 0){
  284. SPI_SendData(SPIx, 0xFF);
  285. } else {
  286. SPI_SendData(SPIx, 0xFFFF);
  287. }
  288. } else {
  289. if (dataword == 0){
  290. SPI_SendData(SPIx, (*(uint8_t *)dataCfg->tx_data));
  291. } else {
  292. SPI_SendData(SPIx, (*(uint16_t *)dataCfg->tx_data));
  293. }
  294. }
  295. SPI_IntCmd(SPIx, ENABLE);
  296. } else {
  297. // Save status
  298. dataCfg->status = SPI_STAT_DONE;
  299. }
  300. return (0);
  301. }
  302. }
  303. /********************************************************************//**
  304. * @brief Enable or disable SPIx interrupt.
  305. * @param[in] SPIx SPI peripheral selected, should be LPC_SPI
  306. * @param[in] NewState New state of specified UART interrupt type,
  307. * should be:
  308. * - ENALBE: Enable this SPI interrupt.
  309. * - DISALBE: Disable this SPI interrupt.
  310. * @return None
  311. *********************************************************************/
  312. void SPI_IntCmd(LPC_SPI_TypeDef *SPIx, FunctionalState NewState)
  313. {
  314. CHECK_PARAM(PARAM_SPIx(SPIx));
  315. CHECK_PARAM(PARAM_FUNCTIONALSTATE(NewState));
  316. if (NewState == ENABLE)
  317. {
  318. SPIx->SPCR |= SPI_SPCR_SPIE;
  319. }
  320. else
  321. {
  322. SPIx->SPCR &= (~SPI_SPCR_SPIE) & SPI_SPCR_BITMASK;
  323. }
  324. }
  325. /********************************************************************//**
  326. * @brief Checks whether the SPI interrupt flag is set or not.
  327. * @param[in] SPIx SPI peripheral selected, should be LPC_SPI
  328. * @return The new state of SPI Interrupt Flag (SET or RESET)
  329. *********************************************************************/
  330. IntStatus SPI_GetIntStatus (LPC_SPI_TypeDef *SPIx)
  331. {
  332. CHECK_PARAM(PARAM_SPIx(SPIx));
  333. return ((SPIx->SPINT & SPI_SPINT_INTFLAG) ? SET : RESET);
  334. }
  335. /********************************************************************//**
  336. * @brief Clear SPI interrupt flag.
  337. * @param[in] SPIx SPI peripheral selected, should be LPC_SPI
  338. * @return None
  339. *********************************************************************/
  340. void SPI_ClearIntPending(LPC_SPI_TypeDef *SPIx)
  341. {
  342. CHECK_PARAM(PARAM_SPIx(SPIx));
  343. SPIx->SPINT = SPI_SPINT_INTFLAG;
  344. }
  345. /********************************************************************//**
  346. * @brief Get current value of SPI Status register in SPIx peripheral.
  347. * @param[in] SPIx SPI peripheral selected, should be LPC_SPI
  348. * @return Current value of SPI Status register in SPI peripheral.
  349. * Note: The return value of this function must be used with
  350. * SPI_CheckStatus() to determine current flag status
  351. * corresponding to each SPI status type. Because some flags in
  352. * SPI Status register will be cleared after reading, the next reading
  353. * SPI Status register could not be correct. So this function used to
  354. * read SPI status register in one time only, then the return value
  355. * used to check all flags.
  356. *********************************************************************/
  357. uint32_t SPI_GetStatus(LPC_SPI_TypeDef* SPIx)
  358. {
  359. CHECK_PARAM(PARAM_SPIx(SPIx));
  360. return (SPIx->SPSR & SPI_SPSR_BITMASK);
  361. }
  362. /********************************************************************//**
  363. * @brief Checks whether the specified SPI Status flag is set or not
  364. * via inputSPIStatus parameter.
  365. * @param[in] inputSPIStatus Value to check status of each flag type.
  366. * This value is the return value from SPI_GetStatus().
  367. * @param[in] SPIStatus Specifies the SPI status flag to check,
  368. * should be one of the following:
  369. - SPI_STAT_ABRT: Slave abort.
  370. - SPI_STAT_MODF: Mode fault.
  371. - SPI_STAT_ROVR: Read overrun.
  372. - SPI_STAT_WCOL: Write collision.
  373. - SPI_STAT_SPIF: SPI transfer complete.
  374. * @return The new state of SPIStatus (SET or RESET)
  375. *********************************************************************/
  376. FlagStatus SPI_CheckStatus (uint32_t inputSPIStatus, uint8_t SPIStatus)
  377. {
  378. CHECK_PARAM(PARAM_SPI_STAT(SPIStatus));
  379. return ((inputSPIStatus & SPIStatus) ? SET : RESET);
  380. }
  381. /**
  382. * @}
  383. */
  384. #endif /* _SPI */
  385. /**
  386. * @}
  387. */
  388. /* --------------------------------- End Of File ------------------------------ */