i2c_controller.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*
  2. * Copyright (c) 2024, Texas Instruments Incorporated
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  12. * * Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * * Neither the name of Texas Instruments Incorporated nor the names of
  17. * its contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  21. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  22. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  27. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  28. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  29. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  30. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #include "ti/driverlib/dl_gpio.h"
  33. #include "ti/driverlib/dl_i2c.h"
  34. #include "ti_msp_dl_config.h"
  35. #include "ti/comm_modules/i2c/controller/i2c_comm_controller.h"
  36. #include<stdint.h>
  37. #include<stdio.h>
  38. I2C_Instance gI2C;
  39. /*Multiplexer Address*/
  40. #define MULTIPLEXER_I2C_ADDR (0x70)
  41. /*Multiplexer channel*/
  42. #define ADC_I2C_CHANNEL (0x01)
  43. volatile I2C_CommandInfo gCommand;
  44. I2C_ResponseInfo gResponse;
  45. volatile bool gSendCommand = true;
  46. /*Buffers to store ADC Data*/
  47. /* Data to send to target */
  48. uint8_t gTxData[MAX_DATA_SIZE] = {0xAA,0xBB,0xCC,0xDD,0xEE,0xFF, \
  49. 0x00,0x11,0x22,0x33,0x44,0x55, \
  50. 0x66,0x77,0x88,0x99,0x12,0x23, \
  51. 0x34,0x45,0x56,0x67,0x78,0x89};
  52. /*
  53. Multiplexer TCA9548A:
  54. Address:0x70
  55. The TCA9548A is example of a single-register device, which is controlled via I2C commands. Since it has 1 bit to enable or disable a channel, there is only 1 register
  56. needed, and the controller merely writes the register data after the target address, skipping the register number.
  57. ADC connected to channel 0
  58. Both SDA and SL lines of the multiplexer is connected to VIN through pull-up resistors
  59. The following is the general procedure for a controller to access a target device:
  60. 1. If a controller wants to send data to a target:
  61. • Controller-transmitter sends a START condition and addresses the target-receiver.
  62. • Controller-transmitter sends data to target-receiver.
  63. • Controller-transmitter terminates the transfer with a STOP condition.
  64. 2. If a controller wants to receive or read data from a target:
  65. • Controller-receiver sends a START condition and addresses the target-transmitter.
  66. • Controller-receiver sends the requested register to read to target-transmitter.
  67. • Controller-receiver receives data from the target-transmitter.
  68. • Controller-receiver terminates the transfer with a STOP condition.
  69. The TCA9548A is example of a single-register device, which is controlled via I2C commands. Since it has 1 bit to enable or disable a channel,
  70. there is only 1 register needed, and the controller merely writes the register data after the target address, skipping the register number.
  71. */
  72. /*Function for Multiplexer*/
  73. void Multiplexer_SelectChannel(uint8_t channel)
  74. {
  75. uint8_t data = channel;
  76. printf("Scanning I2C Bus...\n");
  77. // Ensure bus is idle before starting communication
  78. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  79. // Attempt to send START and the device address
  80. DL_I2C_startControllerTransfer(I2C_controller_INST, MULTIPLEXER_I2C_ADDR, DL_I2C_CONTROLLER_DIRECTION_TX, 1);
  81. // Wait for a response from the multiplexer
  82. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  83. // Send the channel selection byte
  84. DL_I2C_fillControllerTXFIFO(I2C_controller_INST, &data, 1);
  85. // **CHECK FOR ADDRESS ACKNOWLEDGMENT**
  86. if (!(DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_ERROR)) {
  87. printf("Multiplexer detected at 0x70.\n");
  88. return;
  89. } else{
  90. printf("ERROR: Multiplexer (0x70) detected.\n");
  91. }
  92. // Wait for transaction completion
  93. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  94. // Verify if the multiplexer accepted the command
  95. printf("Checking the Multiplexer Configuration.\n");
  96. uint8_t response;
  97. DL_I2C_startControllerTransfer(I2C_controller_INST, MULTIPLEXER_I2C_ADDR, DL_I2C_CONTROLLER_DIRECTION_RX, 1);
  98. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  99. response = DL_I2C_receiveControllerData(I2C_controller_INST);
  100. if(response != channel){
  101. printf("ERROR: Multiplexer did not set the correct channel!\n");
  102. } else {
  103. printf("Multiplexer Active Channel: 0x%X\n", channel);
  104. }
  105. }
  106. int main(void)
  107. {
  108. SYSCFG_DL_init();
  109. printf("............System Configuration Enabled...............\n");
  110. /* Multiplexer Section */
  111. printf("Selecting Multiplexer Channel...\n");
  112. Multiplexer_SelectChannel(ADC_I2C_CHANNEL);
  113. NVIC_EnableIRQ(I2C_controller_INST_INT_IRQN);
  114. I2C_init(&gI2C);
  115. /* Default CommandInfo Object */
  116. I2C_CommandInfo CommandInfo_Obj;
  117. CommandInfo_Obj.targetAddr = DEF_TARGET_ADDR;
  118. CommandInfo_Obj.commandType = READ_COMMAND;
  119. CommandInfo_Obj.addr = 0x20207C00;
  120. CommandInfo_Obj.dataArray = &gTxData[0];
  121. CommandInfo_Obj.dataSize = 8;
  122. CommandInfo_Obj.crcEnable = false;
  123. gCommand = CommandInfo_Obj;
  124. while(1)
  125. {
  126. if(gSendCommand == true)
  127. {
  128. //Add a delay to allow conversion time (~1ms)
  129. delay_cycles(50000); // Adjust if needed
  130. //Frames a command packet and sends it to Target through I2C Write Command
  131. I2C_sendCommand(&gI2C, (I2C_CommandInfo *) &gCommand);
  132. printf("Requesting ADC Data from I2C address: 0x%X\n", gCommand.targetAddr);
  133. gI2C.status = I2C_STATUS_RX_STARTED;
  134. gI2C.rxMsg.ptr = 0;
  135. gI2C.dataLen = gCommand.dataSize;
  136. // Issues I2C Read Command to get the response from Target
  137. I2C_getResponse(&gI2C,gCommand.targetAddr);
  138. gSendCommand = false;
  139. }
  140. }
  141. }
  142. /*Interrupt for MCU -> ADC*/
  143. void I2C_controller_INST_IRQHandler(void)
  144. { printf("I2C Interrupt Triggered to ADC!\n");
  145. switch (DL_I2C_getPendingInterrupt(I2C_controller_INST))
  146. {
  147. case DL_I2C_IIDX_CONTROLLER_RX_DONE:
  148. gI2C.rxMsg.len = gI2C.rxMsg.ptr;
  149. I2C_decodeResponse(&gI2C,&gResponse);
  150. gI2C.status = I2C_STATUS_RX_COMPLETE;
  151. printf("I2C RX COMPLETE!\n");
  152. break;
  153. case DL_I2C_IIDX_CONTROLLER_TX_DONE:
  154. DL_I2C_disableInterrupt(
  155. I2C_controller_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
  156. gI2C.status = I2C_STATUS_TX_COMPLETE;
  157. printf("I2C TX COMPLETE!\n");
  158. break;
  159. case DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER:
  160. gI2C.status = I2C_STATUS_RX_INPROGRESS;
  161. /* Store bytes received from target in Rx Msg Buffer */
  162. while (DL_I2C_isControllerRXFIFOEmpty(I2C_controller_INST) != true) {
  163. if (gI2C.rxMsg.ptr < MAX_BUFFER_SIZE) {
  164. gI2C.rxMsg.buffer[gI2C.rxMsg.ptr++] =
  165. DL_I2C_receiveControllerData(I2C_controller_INST);
  166. if(gI2C.rxMsg.ptr>0){
  167. printf("Received Byte[%d]: 0x%02X\n", gI2C.rxMsg.ptr, gI2C.rxMsg.buffer[gI2C.rxMsg.ptr - 1]);
  168. }
  169. } else {
  170. printf("ERROR: RX Buffer Overflow! ptr=%d MAX_BUFFER_SIZE=%d\n", gI2C.rxMsg.ptr, MAX_BUFFER_SIZE);
  171. /* Ignore and remove from FIFO if the buffer is full */
  172. DL_I2C_receiveControllerData(I2C_controller_INST);
  173. }
  174. }
  175. break;
  176. case DL_I2C_IIDX_CONTROLLER_TXFIFO_TRIGGER:
  177. printf("TX FIFO with data!\n");
  178. gI2C.status = I2C_STATUS_TX_INPROGRESS;
  179. /* Fill TX FIFO with bytes to send */
  180. if (gI2C.txMsg.ptr < gI2C.txMsg.len) {
  181. gI2C.txMsg.ptr += DL_I2C_fillControllerTXFIFO(
  182. I2C_controller_INST, &gI2C.txMsg.buffer[gI2C.txMsg.ptr], gI2C.txMsg.len - gI2C.txMsg.ptr);
  183. }
  184. break;
  185. case DL_I2C_IIDX_CONTROLLER_ARBITRATION_LOST:
  186. printf("Interrupt index for I2C controller Arbitration Lost!\n");
  187. case DL_I2C_IIDX_CONTROLLER_NACK:
  188. printf("Interrupt index for Address/Data NACK!\n");
  189. gI2C.status = I2C_STATUS_ERROR;
  190. break;
  191. default:
  192. break;
  193. }
  194. }