i2c_controller.c 15 KB

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