i2c_target.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. References:
  3. https://stackoverflow.com/questions/246127/why-is-volatile-needed-in-c
  4. */
  5. #include "i2c_target.h"
  6. #include "src/battery_data/battery.h"
  7. #include "ti/driverlib/dl_i2c.h"
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include "src/peripherals/dac/dac.h"
  11. #include <inttypes.h>
  12. #include "src/config.h"
  13. #include "ti_msp_dl_config.h"
  14. #include "src/peripherals/temp/tmp1075.h"
  15. /**
  16. * Dynamic addressing function
  17. * 1. set resistor to pullup
  18. * 2. measure gpio:
  19. * is it up, set the address +0, else set it +1
  20. * 3. disable the pullup again, so there is no current wasted
  21. */
  22. void initialize_target_address() {
  23. uint8_t add = 0;
  24. if (DL_GPIO_readPins(GPIOS_PORT, GPIOS_ADDR_PIN)) {
  25. add = 1;
  26. addr_offset = 4;
  27. }
  28. DL_I2C_setTargetOwnAddress(I2C_target_INST, I2C_TARGET_BASE_ADDRESS+add);
  29. DL_I2C_enableTargetOwnAddress(I2C_target_INST);
  30. }
  31. /*Function to Rx and Tx data from Target to Controller*/
  32. // The code has multiple i2c instances (multiple MCUs connected) from which we
  33. // need to select the right one, passing a pointer as an argument
  34. int8_t mcu_i2c_handle(I2C_Regs *i2c) {
  35. if (DL_I2C_isTargetRXFIFOEmpty(i2c)) {
  36. return -1;
  37. }
  38. uint8_t receivedByte = DL_I2C_receiveTargetData(i2c);
  39. uint8_t receivedCommand = (receivedByte & 0x0F);
  40. uint8_t slot = ((receivedByte & 0xF0) >> 4);
  41. if (receivedCommand == CMD_GET_MEASUREMENT) {
  42. DL_I2C_flushTargetTXFIFO(i2c);
  43. DL_I2C_fillTargetTXFIFO(i2c, (uint8_t *)&battery_slots[slot].measurement, 8);
  44. } else if (receivedCommand == CMD_SET_CURRENT) {
  45. return slot;
  46. } else if (receivedCommand == CMD_CLEAR_ERR) {
  47. if (slot > NUM_SLOTS) {
  48. DL_I2C_flushTargetTXFIFO(i2c);
  49. return -1;
  50. }
  51. *battery_slots[slot].state = SLOT_STATE_OK;
  52. }
  53. DL_I2C_flushTargetRXFIFO(i2c);
  54. return -1;
  55. }
  56. void mcu_i2c_handle_read(I2C_Regs *i2c, uint8_t slot) {
  57. // Read incoming bytes from the Controller:
  58. uint8_t rx_index = 0;
  59. uint8_t rx_buffer[2] = {0x00, 0x00};
  60. while (rx_index < 2) {
  61. // TODO: Need to have a workaround, currently the code is getting stuck on
  62. // the first trigger and provides result on the second trigger
  63. if (!DL_I2C_isTargetRXFIFOEmpty(i2c)) {
  64. rx_buffer[rx_index] = DL_I2C_receiveTargetData(i2c);
  65. rx_index++;
  66. }
  67. }
  68. if (rx_index != 2) {
  69. #ifdef DEBUG_TARGET
  70. printf("ERROR: Incomplete I2C Rx: received %d bytes\n", rx_index);
  71. #endif
  72. DL_I2C_flushTargetRXFIFO(i2c);
  73. rx_index = 0;
  74. return;
  75. }
  76. battery_slots[slot].set_current = *((int16_t*)(&rx_buffer[0]));
  77. #ifdef DEBUG_TARGET
  78. printf("Slot id: %d, Current: %d mA (Bytes 0x%02X 0x%02X)\n", slot, battery_slots[slot].set_current, rx_buffer[0], rx_buffer[1]);
  79. #endif
  80. /*
  81. // This code is for debugging:
  82. // you can shoot directly code to the DAC / PWM for debugging
  83. if (battery_slots[slot].set_current >= 0) {
  84. DAC_SingleWrite(slot, battery_slots[slot].set_current);
  85. } else if (battery_slots[slot].set_current < 0) {
  86. DL_TimerG_setCaptureCompareValue(PWM_0_INST, -1*battery_slots[slot].set_current, DL_TIMER_CC_1_INDEX);
  87. } else {
  88. // do nothing, charge or discharge
  89. #ifdef DEBUG_TARGET
  90. printf("state is idle");
  91. #else
  92. ;
  93. #endif
  94. } */
  95. }