i2c_controller.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /*
  2. Main Source File
  3. */
  4. #include "i2c_target.h"
  5. #include "ti/devices/msp/peripherals/hw_dac12.h"
  6. #include "ti/driverlib/dl_adc12.h"
  7. #include "ti/driverlib/dl_gpio.h"
  8. #include "ti/driverlib/dl_i2c.h"
  9. #include "ti/driverlib/m0p/dl_core.h"
  10. #include "ti_msp_dl_config.h"
  11. #include "ti/comm_modules/i2c/controller/i2c_comm_controller.h"
  12. #include <stdint.h>
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include "multiplexer.h"
  16. #include "adc.h"
  17. #include "dac.h"
  18. #include "battery.h"
  19. #include "i2c_target.h"
  20. #include "cc_cv_charging.h"
  21. #include <ti/drivers/GPIO.h>
  22. I2C_Instance gI2C;
  23. I2C_ResponseInfo gResponse;
  24. BatteryData battery_data;
  25. /*Interrupt for MCU -> ADC
  26. * CASE: DL_I2C_IIDX_CONTROLLER_RX_DONE: ADC Reception Complete
  27. - ADC has finished sending data and it's fully received.
  28. - gI2C.rxMsg.len = gI2C.rxMsg.ptr:
  29. - Stores the received data length in the response buffer.
  30. - I2C_decodeResponse():
  31. - Decodes the received response.
  32. - gI2C.status = I2C_STATUS_RX_COMPLETE:
  33. - Marks reception is complete.
  34. * CASE: DL_I2C_IIDX_CONTROLLER_TX_DONE: Data Transmit to ADC complete
  35. - DL_I2C_disableInterrupt(..): Disables the TXFIFO interrupt since data is now sent
  36. * CASE: DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER: Receive Data in FIFO
  37. - The I2C Receive FIFO has data ready to be read.
  38. - while (DL_I2C_isControllerRXFIFOEmpty(...) != true): Loops until the RX FIFOis empty (READ all available bytes)
  39. - Inside the while loop:
  40. - If buffer has SPACE, store the received byte
  41. - Prints each received byte in HEXADECIMAL format for debugging
  42. - IF BUFFER is FULL, avoids OVERFLOW by discarding extra byte.
  43. * CASE: DL_I2C_IIDX_CONTROLLER_TXFIFO_TRIGGER: Transmit Data in FIFO
  44. - If there is still data to send:
  45. gI2C.txMsg.ptr += DL_I2C_fillControllerTXFIFO(I2C_controller_INST, &gI2C.txMsg.buffer[gI2C.txMsg.ptr], gI2C.txMsg.len - gI2C.txMsg.ptr);
  46. */
  47. void I2C_controller_INST_IRQHandler(void)
  48. {
  49. //printf("I2C Interrupt Triggered to ADC!\n");
  50. switch (DL_I2C_getPendingInterrupt(I2C_controller_INST))
  51. { /*START Condition*/
  52. case DL_I2C_IIDX_CONTROLLER_START:
  53. //gTxADCcount= 0;
  54. gRxADCcount= 0;
  55. DL_I2C_flushControllerTXFIFO(I2C_controller_INST);
  56. break;
  57. case DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER:
  58. gI2C.status= I2C_STATUS_RX_INPROGRESS;
  59. /* Store bytes received from target in Rx Msg Buffer */
  60. while (DL_I2C_isControllerRXFIFOEmpty(I2C_controller_INST) != true) {
  61. if (gRxADCcount< gRxADClen) {
  62. gRxPacket[gRxADCcount] = DL_I2C_receiveControllerData(I2C_controller_INST);
  63. printf("Received Byte[%d]: 0x%02X\n", gRxADCcount, gRxPacket[gRxADCcount]); // Debug print
  64. gRxADCcount++;
  65. } else {
  66. //printf("ERROR: RX Buffer Overflow! ptr=%d MAX_BUFFER_SIZE=%d\n", gI2C.rxMsg.ptr, MAX_BUFFER_SIZE);
  67. /* Ignore and remove from FIFO if the buffer is full */
  68. DL_I2C_receiveControllerData(I2C_controller_INST);
  69. }
  70. }
  71. if (gRxADCcount >= gRxADClen){
  72. //printf("ADC Bytes Received!\n");
  73. gRxComplete = true;
  74. DL_I2C_enableInterrupt(I2C_controller_INST, DL_I2C_INTERRUPT_CONTROLLER_STOP);
  75. }
  76. break;
  77. /*TRANSMIT data to ADC*/
  78. case DL_I2C_IIDX_CONTROLLER_TXFIFO_TRIGGER:
  79. //printf("TX FIFO with data!\n");
  80. gI2C.status= I2C_STATUS_TX_INPROGRESS;
  81. if(gTxADCcount<gTxADClen){
  82. gTxADCcount+= DL_I2C_fillControllerTXFIFO(I2C_controller_INST, &gTxPacket[gTxADCcount], (gTxADClen-gTxADCcount));
  83. } else{
  84. /*Prevent overflow and just ignore data*/
  85. DL_I2C_fillTargetTXFIFO(I2C_controller_INST, (uint8_t[]){0x00}, 1);
  86. gTxComplete= true;
  87. }
  88. break;
  89. /*STOP condition*/
  90. case DL_I2C_IIDX_CONTROLLER_STOP:
  91. gTxComplete= true;
  92. gRxComplete = true;
  93. //printf("I2C Stop Detected- RX Complete");
  94. break;
  95. case DL_I2C_IIDX_CONTROLLER_ARBITRATION_LOST:
  96. //printf("Interrupt index for I2C controller Arbitration Lost!\n");
  97. break;
  98. case DL_I2C_IIDX_CONTROLLER_NACK:
  99. //printf("I2C NACK Received\n");
  100. if((gI2C.status== I2C_STATUS_RX_STARTED)|| (gI2C.status= I2C_STATUS_TX_STARTED)){
  101. gI2C.status= I2C_STATUS_ERROR;
  102. }
  103. break;
  104. default:
  105. break;
  106. }
  107. }
  108. /**** Interrupt for Pi to MCU ****/
  109. void I2C_target_INST_IRQHandler(void) {
  110. //printf("I2C Interrupt Triggered to MCU (TARGET)!\n");
  111. uint8_t receivedCommand= 0;
  112. uint32_t status = DL_I2C_getPendingInterrupt(I2C_target_INST);
  113. //ADC_PARAMS params;
  114. switch (status) {
  115. /* START condition detected */
  116. case DL_I2C_IIDX_TARGET_START:
  117. piTxCount= 0;
  118. piRxCount= 0;
  119. piTxComplete= false;
  120. DL_I2C_flushTargetTXFIFO(I2C_target_INST);
  121. break;
  122. /* STOP condition detected */
  123. case DL_I2C_IIDX_TARGET_STOP:
  124. piTxComplete= true;
  125. piRxComplete = true;
  126. DL_I2C_flushTargetTXFIFO(I2C_target_INST);
  127. break;
  128. /* TX FIFO trigger (Pi is reading data from MCU) */
  129. /* GET battery status is triggered when command is 0x01
  130. - Pi on request of 0x01 will get a response of the battery status for all the slots
  131. - Battery_StateUpdate function is called, which in turn calls the Battery_ReadState funtion to set the state of the batteries
  132. -Pi on command of [0x02, slot_id] will GET the 'Battery Data' which is voltage, current and temperature for a given slot.
  133. - MCU reads the slot_id from Pi using DL_I2C_receiveTargetData()
  134. - piTxCount is set to 0
  135. - piTxLen is the sizeof BatteryData struct which is 7 bytes
  136. - If the requested slot is correct then:
  137. - battery pointer variable points to the memory of the requested slot
  138. - the values of voltage, current and temperature are then stored in battery_data struct
  139. - Once the values are in BatteryData struct we wait for the bus to be free
  140. - Next we send the BatteryData to Pi using DL_I2C_fillTargetRXFIFO()
  141. - Reset the RX counter for the next data.
  142. */
  143. case DL_I2C_IIDX_TARGET_TXFIFO_TRIGGER:
  144. printf("Pi GET data from MCU!\n");
  145. if(!DL_I2C_isTargetRXFIFOEmpty(I2C_target_INST)){
  146. receivedCommand= DL_I2C_receiveTargetData(I2C_target_INST);
  147. printf("Received Command: 0x%02X\n", receivedCommand);
  148. if (receivedCommand == CMD_GET_BATTERY_STATUS){
  149. printf("Battery status received.\n");
  150. //Battery_StateUpdate();
  151. piTxCount= 0;
  152. piTxLen= NUM_SLOTS;
  153. piTxComplete = false;
  154. // Prepare data to be sent to Pi:
  155. for(uint8_t slot= 0; slot < NUM_SLOTS; slot++){
  156. // Read the battery status for each slot
  157. Battery_ReadState(slot);
  158. piTxPacket[slot]= batteries[slot].state;
  159. }
  160. //Filling up the FIFO
  161. if(piTxCount < piTxLen){
  162. while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY);
  163. piTxCount += DL_I2C_fillTargetTXFIFO(I2C_target_INST, &piTxPacket[piTxCount], (piTxLen-piTxCount));
  164. }
  165. else {
  166. /*
  167. * Fill FIFO with 0x00 if more data is requested than expected piTxLen
  168. */
  169. while (
  170. DL_I2C_transmitTargetDataCheck(I2C_target_INST, 0x00) != false);
  171. }
  172. piTxComplete= true;
  173. }
  174. else if (receivedCommand == CMD_GET_BATTERY_DATA){
  175. uint8_t requestedSlot= DL_I2C_receiveTargetData(I2C_target_INST);
  176. while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY);
  177. printf("Battery Data Requested for Slot %d!\n", requestedSlot);
  178. piTxCount= 0;
  179. piTxLen= sizeof(BatteryData);
  180. BatteryData battery_data;
  181. if(requestedSlot < NUM_SLOTS){
  182. Battery *battery= &batteries[requestedSlot];
  183. battery_data.slot_id = battery-> slot_id;
  184. battery_data.voltage= battery-> voltage;
  185. battery_data.current= battery-> current;
  186. battery_data.temperature= battery-> temperature;
  187. while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY);
  188. DL_I2C_fillTargetTXFIFO(I2C_target_INST, (uint8_t *)&battery_data, sizeof(BatteryData));
  189. //piTxCount += DL_I2C_fillTargetTXFIFO(I2C_target_INST, (uint8_t*)&battery_data, piTxLen);
  190. piTxComplete= true;
  191. while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY);
  192. if(piTxCount >= piTxLen){
  193. piTxComplete= true;
  194. piTxCount=0;
  195. }
  196. } else{
  197. printf("Invalid Slot ID: %d\n.", requestedSlot);
  198. }
  199. }
  200. }
  201. break;
  202. /* TARGET_Rx FIFO trigger (Pi is writing data to MCU) */
  203. /*Pi SET battery data limits for each slot, where:
  204. - RXFIFO buffer is filled if the command from Pi is 0x03
  205. - Creating a temporary buffer named ´rxbuffer´
  206. - sizeof(BatteryLimitMsg): 11 bytes (1 byte: slot_id, 2 bytes: min_voltage; max_voltage; cut_off_current; capacitance; charge_fraction)
  207. - rx_buffer stores the data from Pi.
  208. - if all the expected bytes are received from Pi then,
  209. - memcpy() to copy the block of address from the temporary buffer to the BatteryLimitMsg structure
  210. - Why?, A: It copies the specified number of bytes from one memory location to another regardless of the type of the data stored.
  211. - verify if the received slot_id is less than NUM_SLOTS, where slot_id count starts from 0 then:
  212. - create a pointer variable for 'Battery'
  213. - battery_limits.slot_id: index of the battery slot to be updated
  214. - &batteries[battery_limits.slot_id]: gets the memory address of the battery in that slot
  215. - Accessing the structure members of Battery using -> operator. This allows efficient access to the structure's members
  216. without directly using the structure variable.
  217. */
  218. case DL_I2C_IIDX_TARGET_RXFIFO_TRIGGER:
  219. printf("Pi SET Battery limit to MCU.....\n");
  220. if(!DL_I2C_isTargetRXFIFOEmpty(I2C_target_INST)){
  221. receivedCommand= DL_I2C_receiveTargetData(I2C_target_INST);
  222. printf("Received Command: 0x%02X\n", receivedCommand);
  223. if(receivedCommand == CMD_SET_BATTERY_LIMIT){
  224. uint8_t rx_buffer[sizeof(BatteryLimitMsg)];
  225. uint8_t index= 0;
  226. while (!DL_I2C_isTargetRXFIFOEmpty(I2C_target_INST)){
  227. if(index < sizeof(BatteryLimitMsg)){
  228. rx_buffer[index]= DL_I2C_receiveTargetData(I2C_target_INST);
  229. printf("Received Byte[%d]: 0x%02X\n", index, rx_buffer[index]);
  230. index++;
  231. }
  232. else{
  233. DL_I2C_receiveTargetData(I2C_target_INST);
  234. }
  235. }
  236. printf("Total Bytes Received: %d (Expected: %d)\n", index, sizeof(BatteryLimitMsg));
  237. if(index == sizeof(BatteryLimitMsg)){
  238. printf("Received Battery Limits.\n");
  239. BatteryLimitMsg battery_limits;
  240. memcpy(&battery_limits, rx_buffer, sizeof(BatteryLimitMsg));
  241. if(battery_limits.slot_id < NUM_SLOTS){
  242. Battery *battery = &batteries[battery_limits.slot_id];
  243. battery -> min_voltage = battery_limits.min_voltage;
  244. battery -> max_voltage = battery_limits.max_voltage;
  245. battery -> cut_off_current = battery_limits.cut_off_current;
  246. battery -> capacitance = battery_limits.capacitance;
  247. battery -> charge_fraction = battery_limits.charge_fraction;
  248. printf("\n Received Battery Limits for slot %d: \n", battery_limits.slot_id);
  249. printf(" Min Voltage: %d mV (0x%04X)\n", battery_limits.min_voltage, battery_limits.min_voltage);
  250. printf(" Max Voltage: %d mV (0x%04X)\n", battery_limits.max_voltage, battery_limits.max_voltage);
  251. printf(" Cutoff Current: %d mA (0x%04X)\n", battery_limits.cut_off_current, battery_limits.cut_off_current);
  252. printf(" Capacitance: %d µF (0x%04X)\n", battery_limits.capacitance, battery_limits.capacitance);
  253. printf(" Charge Fraction: %d%% (0x%02X)\n", battery_limits.charge_fraction, battery_limits.charge_fraction);
  254. }
  255. }
  256. }
  257. }
  258. break;
  259. /* Arbitration lost or NACK */
  260. case DL_I2C_IIDX_TARGET_ARBITRATION_LOST:
  261. printf("Arbitration Lost.\n");
  262. break;
  263. default:
  264. printf("Unknown Interrupt.\n");
  265. break;
  266. }
  267. }
  268. /********MAIN function*************/
  269. int main(void)
  270. {
  271. // Initialize System and I2C
  272. SYSCFG_DL_init();
  273. // Initialize battery array and default params
  274. Battery_Init();
  275. //Reset_I2C_Bus();
  276. //NVIC_EnableIRQ(I2C_target_INST_INT_IRQN);
  277. NVIC_EnableIRQ(I2C_controller_INST_INT_IRQN);
  278. printf("............System Configuration Enabled...............\n");
  279. //Multiplexer
  280. Multiplexer_SelectChannel(I2C_CHANNEL);
  281. I2C_scanBus();
  282. I2C_init(&gI2C);
  283. // *Configure ADC for voltage: Channel 1 and Channel 2*
  284. /*ADC_PARAMS adc_voltage_params={
  285. .channel= 1,
  286. .resolution= 12,
  287. .continuous= 1,
  288. .gain= 1
  289. };
  290. ADC_PARAMS adc_current_params={
  291. .channel= 2,
  292. .resolution= 12,
  293. .continuous= 1,
  294. .gain= 1
  295. };*/
  296. //ADC_SetConfigurationBytes(adc_voltage_params);
  297. //delay_cycles(50000);
  298. //ADC_SetConfigurationBytes(adc_current_params);
  299. //delay_cycles(50000);
  300. while (1)
  301. { //Looping through the ADC Channels
  302. Battery_UpdateADCReading();
  303. delay_cycles(100000);
  304. //Battery_UpdateCurrent(adc_current_params);
  305. //delay_cycles(50000);
  306. //CC-CV Cycle: maximum cycles is not yet implemented
  307. //for(uint8_t slot_id= 0; slot_id < NUM_SLOTS; slot_id++){
  308. // CC_CV_ControlCharging(slot_id);
  309. //}
  310. //DAC_fastWrite(CHANNEL_A_VALUE);
  311. }
  312. }