hw_i2csd.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * @brief I2C slave ROM API declarations and functions
  3. *
  4. * @note
  5. * Copyright(C) NXP Semiconductors, 2014
  6. * All rights reserved.
  7. *
  8. * @par
  9. * Software that is described herein is for illustrative purposes only
  10. * which provides customers with programming information regarding the
  11. * LPC products. This software is supplied "AS IS" without any warranties of
  12. * any kind, and NXP Semiconductors and its licensor disclaim any and
  13. * all warranties, express or implied, including all implied warranties of
  14. * merchantability, fitness for a particular purpose and non-infringement of
  15. * intellectual property rights. NXP Semiconductors assumes no responsibility
  16. * or liability for the use of the software, conveys no license or rights under any
  17. * patent, copyright, mask work right, or any other intellectual property rights in
  18. * or to any products. NXP Semiconductors reserves the right to make changes
  19. * in the software without notification. NXP Semiconductors also makes no
  20. * representation or warranty that such application will be suitable for the
  21. * specified use without further testing or modification.
  22. *
  23. * @par
  24. * Permission to use, copy, modify, and distribute this software and its
  25. * documentation is hereby granted, under NXP Semiconductors' and its
  26. * licensor's relevant copyrights 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. #include <stdint.h>
  32. #include <string.h>
  33. #include "hw_i2csd.h"
  34. #define DRVVERSION 0x0100
  35. /* Private data structure used for the I2C slave driver, holds the driver and
  36. peripheral context */
  37. typedef struct {
  38. void *pUserData; /*!< Pointer to user data used by driver instance, use NULL if not used */
  39. LPC_I2C_T *base; /*!< Base address of I2C peripheral to use */
  40. i2cSlaveStartCB pXferStartCB; /*!< Transfer start callback */
  41. i2cSlaveTransmitCB pTranTranCb; /*!< Data transmit callback */
  42. i2cSlaveReceiveCB pTranRecvCb; /*!< Data Receive callback */
  43. i2cSlaveCompleteCB pXferCompCB; /*!< Transfer complete callback */
  44. ROM_I2CS_XFER_T *pXfer; /*!< Pointer to current transfer */
  45. ErrorCode_t pendingStatus; /*!< Pending transfer status */
  46. } I2CS_DATACONTEXT_T;
  47. #define _rom_i2csEnable(pI2C) (pI2C->CFG |= I2C_CFG_SLVEN);
  48. #define _rom_i2csGetSlaveAddr(pI2C, slvNum) ((pI2C->SLVADR[slvNum] >> 1) & 0x7F)
  49. #define _rom_i2csGetSlaveMatchIndex(pI2C) ((pI2C->STAT & I2C_STAT_SLVIDX) >> 12)
  50. #define _rom_i2csGetSlaveState(pI2C) (((pI2C->STAT & I2C_STAT_SLVSTATE) >> 9) & 0x3)
  51. // **********************************************************
  52. uint32_t i2cs_get_mem_size(void)
  53. {
  54. return sizeof(I2CS_DATACONTEXT_T);
  55. }
  56. ROM_I2CS_HANDLE_T i2cs_init(void *mem, const ROM_I2CS_INIT_T *pInit)
  57. {
  58. I2CS_DATACONTEXT_T *pDrv;
  59. /* Verify alignment is at least 4 bytes */
  60. if (((uint32_t) mem & 0x3) != 0) {
  61. return NULL;
  62. }
  63. pDrv = (I2CS_DATACONTEXT_T *) mem;
  64. memset(pDrv, 0, sizeof(I2CS_DATACONTEXT_T));
  65. /* Save base of peripheral and pointer to user data */
  66. pDrv->pUserData = pInit->pUserData;
  67. pDrv->base = (LPC_I2C_T *) pInit->base;
  68. /* If this needs to be changed, it should be done in the app after
  69. this call. */
  70. pDrv->base->CLKDIV = 2;
  71. /* Clear controller state */
  72. pDrv->base->STAT = (I2C_STAT_SLVSEL | I2C_STAT_SLVDESEL);
  73. /* Enable I2C slave interface */
  74. _rom_i2csEnable(pDrv->base);
  75. return pDrv;
  76. }
  77. void i2cs_setup_slave(ROM_I2CS_HANDLE_T pHandle, ROM_I2CS_SLAVE_T *pSlaveSetup)
  78. {
  79. uint32_t sa, idx;
  80. I2CS_DATACONTEXT_T *pDrv = (I2CS_DATACONTEXT_T *) pHandle;
  81. /* Limit usable slave address indexes to the maximum the controller can support */
  82. if (pSlaveSetup->SlaveIndex <= 3) {
  83. sa = (uint32_t) (pSlaveSetup->slaveAddr & 0x7F) << 1;
  84. if (pSlaveSetup->EnableSlave == 0) {
  85. sa |= I2C_SLVADR_SADISABLE; /* Disable slave address */
  86. }
  87. /* Setup slave address at index */
  88. pDrv->base->SLVADR[pSlaveSetup->SlaveIndex] = sa;
  89. }
  90. /* Check all slave indexes. If any are enabled, then enable the slave interrupts,
  91. else disable the slave interrupts. */
  92. sa = 0;
  93. for (idx = 0; ((idx <= 3) && (sa == 0)); idx++) {
  94. if ((pDrv->base->SLVADR[idx] & I2C_SLVADR_SADISABLE) == 0) {
  95. /* Slave is enabled */
  96. sa = 1;
  97. }
  98. }
  99. if (sa) {
  100. pDrv->base->INTENSET = I2C_INTENSET_SLVPENDING;
  101. }
  102. else {
  103. pDrv->base->INTENCLR = (I2C_INTENSET_SLVPENDING | I2C_INTENSET_SLVDESEL);
  104. }
  105. }
  106. void i2cs_register_callback(ROM_I2CS_HANDLE_T pHandle, uint32_t cbIndex, void *pCB)
  107. {
  108. I2CS_DATACONTEXT_T *pDrv = (I2CS_DATACONTEXT_T *) pHandle;
  109. if (cbIndex == ROM_I2CS_START_CB) {
  110. pDrv->pXferStartCB = (i2cSlaveStartCB) pCB;
  111. }
  112. else if (cbIndex == ROM_I2CS_XFERSEND_CB) {
  113. pDrv->pTranTranCb = (i2cSlaveTransmitCB) pCB;
  114. }
  115. else if (cbIndex == ROM_I2CS_XFERRECV_CB) {
  116. pDrv->pTranRecvCb = (i2cSlaveReceiveCB) pCB;
  117. }
  118. else if (cbIndex == ROM_I2CS_DONE_CB) {
  119. pDrv->pXferCompCB = (i2cSlaveCompleteCB) pCB;
  120. }
  121. }
  122. ErrorCode_t i2cs_transfer(ROM_I2CS_HANDLE_T pHandle, ROM_I2CS_XFER_T *pXfer)
  123. {
  124. I2CS_DATACONTEXT_T *pDrv = (I2CS_DATACONTEXT_T *) pHandle;
  125. /* Is transfer NULL? */
  126. if (pXfer == NULL) {
  127. return ERR_I2C_PARAM;
  128. }
  129. /* Save transfer descriptor */
  130. pDrv->pXfer = pXfer;
  131. pXfer->status = ERR_I2C_BUSY;
  132. pDrv->pendingStatus = LPC_OK;
  133. pXfer->bytesSent = 0;
  134. pXfer->bytesRecv = 0;
  135. return pXfer->status;
  136. }
  137. // Otime = "optimize for speed of code execution"
  138. // ...add this pragma 1 line above the interrupt service routine function.
  139. void i2cs_transfer_handler(ROM_I2CS_HANDLE_T pHandle)
  140. {
  141. I2CS_DATACONTEXT_T *pDrv = (I2CS_DATACONTEXT_T *) pHandle;
  142. ROM_I2CS_XFER_T *pXfer = pDrv->pXfer;
  143. uint32_t done = 0;
  144. uint16_t data = 0;
  145. uint32_t status = pDrv->base->INTSTAT;
  146. /* Transfer complete? */
  147. if ((status & I2C_INTENSET_SLVDESEL) != 0) {
  148. pDrv->base->INTENCLR = I2C_INTENSET_SLVDESEL;
  149. pDrv->base->STAT = I2C_STAT_SLVDESEL;
  150. if (pXfer) {
  151. pXfer->status = pDrv->pendingStatus;
  152. pDrv->pXfer = NULL;
  153. }
  154. if (pDrv->pXferCompCB) {
  155. pDrv->pXferCompCB(pHandle, pXfer);
  156. }
  157. return;
  158. }
  159. else if ((status & I2C_INTENSET_SLVPENDING) != 0) {
  160. /* Determine the current I2C slave state */
  161. switch (_rom_i2csGetSlaveState(pDrv->base)) {
  162. case I2C_STAT_SLVCODE_ADDR:
  163. /* Get slave address that needs servicing */
  164. data = _rom_i2csGetSlaveAddr(pDrv->base, _rom_i2csGetSlaveMatchIndex(pDrv->base));
  165. /* Call address callback */
  166. if (pDrv->pXferStartCB) {
  167. pDrv->pXferStartCB(pHandle, data);
  168. /* Update transfer descriptor */
  169. pXfer = pDrv->pXfer;
  170. }
  171. pDrv->base->INTENSET = I2C_INTENSET_SLVDESEL;
  172. break;
  173. case I2C_STAT_SLVCODE_RX:
  174. /* Receive from master */
  175. /* A byte has been received in thee receive FIFO */
  176. if ((pXfer == NULL) || (pXfer->bytesRecv >= pXfer->rxSz)) {
  177. /* No more data, call receive data callback */
  178. if (pDrv->pTranRecvCb) {
  179. done = pDrv->pTranRecvCb(pHandle, pXfer);
  180. if (pDrv->pXfer) {
  181. pXfer = pDrv->pXfer;
  182. pXfer->bytesRecv = 0;
  183. }
  184. }
  185. }
  186. /* Not using DMA */
  187. if (!(done == ROM_I2CS_DMA)) {
  188. data = (uint8_t) pDrv->base->SLVDAT;
  189. if (pXfer == NULL) {
  190. /* Toss data and NAK, no buffer space */
  191. done = ROM_I2CS_NAK;
  192. pDrv->pendingStatus = ERR_I2C_BUFFER_OVERFLOW;
  193. }
  194. else {
  195. uint8_t *p8 = pXfer->rxBuff;
  196. if ((p8 == NULL) || (pXfer->bytesRecv >= pXfer->rxSz)) {
  197. /* Toss data and NAK, no buffer space */
  198. done = ROM_I2CS_NAK;
  199. pDrv->pendingStatus = ERR_I2C_BUFFER_OVERFLOW;
  200. }
  201. else {
  202. p8[pXfer->bytesRecv] = (uint8_t) data;
  203. pDrv->pXfer->bytesRecv++;
  204. }
  205. }
  206. }
  207. break;
  208. case I2C_STAT_SLVCODE_TX:
  209. /* Send to master */
  210. /* A byte needs to be placed into the transmit FIFO */
  211. if ((pXfer == NULL) || (pXfer->bytesSent >= pXfer->txSz)) {
  212. /* Does callback exist? */
  213. if (pDrv->pTranTranCb) {
  214. done = pDrv->pTranTranCb(pHandle, pXfer);
  215. /* Can't really NAK on read, so switch to continue */
  216. if (pDrv->pXfer) {
  217. pXfer = pDrv->pXfer;
  218. pXfer->bytesSent = 0;
  219. }
  220. if (done == ROM_I2CS_NAK) {
  221. pDrv->base->SLVDAT = 0;
  222. }
  223. }
  224. }
  225. /* Continue if not DMA or NAK */
  226. if (!((done == ROM_I2CS_NAK) || (done == ROM_I2CS_DMA))) {
  227. if (pXfer == NULL) {
  228. pDrv->base->SLVDAT = 0;
  229. pDrv->pendingStatus = ERR_I2C_BUFFER_UNDERFLOW;
  230. done = 0;
  231. }
  232. else {
  233. uint8_t *p8 = (uint8_t *) pXfer->txBuff;
  234. /* Not using DMA, so this is a normal transfer */
  235. if ((p8 == NULL) || (pXfer->bytesSent >= pXfer->txSz)) {
  236. /* Have to send something, so NAK with 0 */
  237. pDrv->base->SLVDAT = 0;
  238. pDrv->pendingStatus = ERR_I2C_BUFFER_UNDERFLOW;
  239. done = 0;
  240. }
  241. else {
  242. pDrv->base->SLVDAT = (uint32_t) p8[pXfer->bytesSent];
  243. pDrv->pXfer->bytesSent++;
  244. }
  245. }
  246. }
  247. break;
  248. }
  249. if (done == ROM_I2CS_NAK) {
  250. pDrv->base->SLVCTL = I2C_SLVCTL_SLVNACK;
  251. }
  252. else if (done == ROM_I2CS_DMA) {
  253. pDrv->base->SLVCTL = I2C_SLVCTL_SLVDMA;
  254. }
  255. else {
  256. pDrv->base->SLVCTL = I2C_SLVCTL_SLVCONTINUE;
  257. }
  258. }
  259. }
  260. uint32_t i2cs_get_driver_version(void)
  261. {
  262. return DRVVERSION;
  263. }
  264. // *********************************************************