i2c_controller.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  1. /*
  2. 20.02.2025:
  3. Flowchart of the code:
  4. 1. MCU requests ADC data over I2C
  5. 2. ADC is connected to the MULTIPLEXER.
  6. 3. Interrupt triggers when data is available.
  7. 4. Interrupt moves RECEIVED bytes into RXFIFO Buffer
  8. 5. Interrupt marks reception complete RX_DONE
  9. 6. Read ADC_Data and retrieve the final ADc value
  10. 7. Convert ADC value to Voltage
  11. 24.02.2025:
  12. Working Code for Reading Analog Signals from ADC to MCU through Multiplexer
  13. - configured the registers with Channel, Resolution, Mode(Continuous or Single-mode) and Gain: Construct_Config_Byte()
  14. - SET configuration registers to ADC: SetConfiguration()
  15. - Read the Analog Output: Read_ADC_Data()
  16. - Convert Analog output to voltage in Volts: Convert_ADC_To_Voltage()
  17. - Commented out interrupts for the time being.
  18. - Adding code for Pi to READ ADC voltages in mV.
  19. -
  20. */
  21. #include "ti/devices/msp/peripherals/hw_dac12.h"
  22. #include "ti/driverlib/dl_gpio.h"
  23. #include "ti/driverlib/dl_i2c.h"
  24. #include "ti/driverlib/m0p/dl_core.h"
  25. #include "ti_msp_dl_config.h"
  26. #include "ti/comm_modules/i2c/controller/i2c_comm_controller.h"
  27. #include<stdint.h>
  28. #include<stdio.h>
  29. I2C_Instance gI2C;
  30. /*MULTIPLEXER SECTION:*/
  31. /*Multiplexer Address*/
  32. #define MULTIPLEXER_I2C_ADDR (0x70)
  33. /*Multiplexer channel*/
  34. #define ADC_I2C_CHANNEL (0x01)
  35. /*****************DAC*********************/
  36. /*Fast write command for DAC*/
  37. #define FAST_WRITE_COMMAND 0x00
  38. #define MULTI_WRITE 0x40
  39. #define SINGLE_WRITE 0x58
  40. #define SEQ_WRITE 0x50
  41. #define VREF_CMD 0x80
  42. #define GAIN_CMD 0xC0
  43. #define PWR_DWN_CMD 0xA0
  44. //DAC Channel Selection
  45. typedef enum{
  46. DAC_A = 0,
  47. DAC_B,
  48. DAC_C,
  49. DAC_D
  50. } DAC_CH;
  51. typedef enum{
  52. VREF_VDD= 0,
  53. VREF_INTERNAL= 1
  54. }VREF_SELECTION;
  55. typedef enum{
  56. GAIN_X1= 0,
  57. GAIN_X2= 1
  58. }GAIN_SELECTION;
  59. typedef enum{
  60. PD_NORMAL=0,
  61. PD_GND_1KOHM= 1,
  62. PD_GND_100KOHM= 2,
  63. PD_GND_500KOHM= 3
  64. }PWR_DOWN_SELECTION;
  65. // Structure to Hold DAC Register Data
  66. typedef struct {
  67. VREF_SELECTION vref;
  68. PWR_DOWN_SELECTION pd;
  69. GAIN_SELECTION gain;
  70. uint16_t data;
  71. } DACRegisterData;
  72. // Create Global Storage for DAC Values
  73. DACRegisterData read_reg_[4]; // Holds Active Register Values
  74. DACRegisterData read_eep_[4]; // Holds EEPROM Stored Values
  75. /***********************/
  76. /*
  77. ADC SETTINGS:
  78. Fixed Reference Voltage is 2.048V and PGA Gain setting default: x1
  79. Mode: can be 1: Continuous or 0: for One-Shot Conversion
  80. ADC_RESOLUTION: 16 bits -> A higher resolution means better precision but slower conversion time.
  81. Calculation for V(IN)= (ADC Value/2^ (Resolution-1))* V(REF)
  82. */
  83. /*Voltage is calculated in ADC in milliVolts:
  84. - Reference voltage in milliVolts to be read from Pi
  85. - Register address where ADC result would be stored
  86. */
  87. #define VREF 2.048
  88. // address register for ADC Voltage Read:
  89. #define ADC_REGISTER 0x10
  90. /*Register for the MCU*/
  91. #define REGISTER_SIZE 256
  92. #define I2C_BUFFER_SIZE (16)
  93. //#define DAC12_REF_VOLTAGE_mV (2500)
  94. uint8_t registers[REGISTER_SIZE]= {1, 2, 3, 4, 5};
  95. /* Buffers for data exchange with Pi*/
  96. uint16_t gRxBuffer[I2C_BUFFER_SIZE]= {0};
  97. uint16_t gTxBuffer[I2C_BUFFER_SIZE]={0};
  98. /*Counter for data length and bytes*/
  99. uint32_t gTxLen, gTxCount;
  100. uint32_t gRxLen, gRxCount;
  101. volatile I2C_CommandInfo gCommand;
  102. I2C_ResponseInfo gResponse;
  103. volatile bool gSendCommand = true;
  104. volatile bool newMeasurementAvailable = false;
  105. uint8_t gTxData[MAX_DATA_SIZE] = {0} ;
  106. /*
  107. Scans all the addresses of the peripherals:
  108. */
  109. void I2C_scanBus() {
  110. printf("Scanning I2C Bus...\n");
  111. // **Step 1: Reset I2C Controller if Busy**
  112. if (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS) {
  113. printf("I2C Bus Busy! Resetting I2C Controller...\n");
  114. DL_I2C_disableController(I2C_controller_INST); // Disable I2C
  115. delay_cycles(20000);
  116. DL_I2C_enableController(I2C_controller_INST); // Re-enable I2C
  117. delay_cycles(20000);
  118. }
  119. // **Step 2: Scan I2C Bus**
  120. for (uint8_t addr = 0x08; addr < 0x78; addr++) { // Valid I2C Address Range
  121. DL_I2C_startControllerTransfer(I2C_controller_INST, addr, DL_I2C_CONTROLLER_DIRECTION_RX, 1);
  122. delay_cycles(5000);
  123. if (!(DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_ERROR)) {
  124. printf("Device found at: 0x%02X\n", addr);
  125. }
  126. }
  127. printf("I2C Scan Complete!\n");
  128. }
  129. /*
  130. Multiplexer TCA9548A:
  131. Address:0x70
  132. 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
  133. needed, and the controller merely writes the register data after the target address, skipping the register number.
  134. ADC connected to channel 0
  135. Both SDA and SL lines of the multiplexer is connected to VIN through pull-up resistors
  136. The following is the general procedure for a controller to access a target device:
  137. 1. If a controller wants to send data to a target:
  138. • Controller-transmitter sends a START condition and addresses the target-receiver.
  139. • Controller-transmitter sends data to target-receiver.
  140. • Controller-transmitter terminates the transfer with a STOP condition.
  141. 2. If a controller wants to receive or read data from a target:
  142. • Controller-receiver sends a START condition and addresses the target-transmitter.
  143. • Controller-receiver sends the requested register to read to target-transmitter.
  144. • Controller-receiver receives data from the target-transmitter.
  145. • Controller-receiver terminates the transfer with a STOP condition.
  146. 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,
  147. there is only 1 register needed, and the controller merely writes the register data after the target address, skipping the register number.
  148. */
  149. /*Function for Multiplexer*/
  150. void Multiplexer_SelectChannel(uint8_t channel)
  151. {
  152. uint8_t data = channel;
  153. printf("Selecting Multiplexer Channel: 0x%02X\n", data);
  154. // Ensure bus is idle before starting communication
  155. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  156. // SEND Command to Multiplexer
  157. DL_I2C_startControllerTransfer(I2C_controller_INST, MULTIPLEXER_I2C_ADDR, DL_I2C_CONTROLLER_DIRECTION_TX, 1);
  158. DL_I2C_fillControllerTXFIFO(I2C_controller_INST, &data, 1);
  159. // **Ensure STOP condition is sent**
  160. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  161. // **Slightly Increase Delay for Multiplexer to Process Command**
  162. delay_cycles(30000);
  163. // Verify Multiplexer Response:
  164. uint8_t response= 0x00;
  165. DL_I2C_startControllerTransfer(I2C_controller_INST, MULTIPLEXER_I2C_ADDR, DL_I2C_CONTROLLER_DIRECTION_RX, 1);
  166. // Wait for a response from the multiplexer
  167. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  168. response = DL_I2C_receiveControllerData(I2C_controller_INST);
  169. // **Debug: Print Expected vs. Received Response**
  170. printf("Multiplexer Response: 0x%02X (Expected: 0x%02X)\n", response, data);
  171. // **CHECK FOR ADDRESS ACKNOWLEDGMENT**
  172. /*if (!(DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_ERROR)) {
  173. printf("Multiplexer detected at 0x70.\n");
  174. return;
  175. } else{
  176. printf("ERROR: Multiplexer (0x70) detected.\n");
  177. }*/
  178. // Wait for transaction completion
  179. //while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  180. if(response != data){
  181. printf("ERROR: Multiplexer did not set the correct channel!\n");
  182. // **Retry Mechanism: Attempt to Set the Channel Again**
  183. delay_cycles(10000);
  184. Multiplexer_SelectChannel(channel);
  185. } else {
  186. printf("Multiplexer Active Channel: 0x%X\n", data);
  187. }
  188. }
  189. /*
  190. CONFIGURATION REGISTER:
  191. 8-bit wide configuration register to select for: input channel, conversion mode, conversion rate, and PGA gain.
  192. Device allows the user to changethe operating condition of the device:
  193. */
  194. uint8_t Construct_Config_Byte(uint8_t channel, uint8_t resolution, bool continuous, uint8_t gain) {
  195. uint8_t config = 0;
  196. config |= ((channel - 1) << 5); // Channel Selection (Bits 6-5)
  197. if (continuous) config |= (1 << 4); // Continuous Mode (Bit 4)
  198. switch (resolution) {
  199. case 12: config |= (0b00 << 2); break;
  200. case 14: config |= (0b01 << 2); break;
  201. case 16: config |= (0b10 << 2); break;
  202. case 18: config |= (0b11 << 2); break;
  203. default: printf("ERROR: Invalid Resolution!\n"); return 0;
  204. }
  205. switch (gain) {
  206. case 1: config |= (0b00); break;
  207. case 2: config |= (0b01); break;
  208. case 4: config |= (0b10); break;
  209. case 8: config |= (0b11); break;
  210. default: printf("ERROR: Invalid Gain!\n"); return 0;
  211. }
  212. return config;
  213. }
  214. /* Tansmit Data from MCU to ADC: Function to SET configuration to ADC over I2C*/
  215. void SetConfiguration(uint8_t channel, uint8_t resolution, bool mode, uint8_t gain) {
  216. // **Step 1: Construct Configuration Byte**
  217. uint8_t config_byte = Construct_Config_Byte(channel, resolution, mode, gain);
  218. printf("Writing Config: 0x%02X to ADC (0x%X)...\n", config_byte, DEF_TARGET_ADDR_ADC);
  219. // **Step 2: Wait for I2C Bus to be Free**
  220. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  221. // **Step 3: Start I2C Write Transaction**
  222. DL_I2C_startControllerTransfer(I2C_controller_INST, DEF_TARGET_ADDR_ADC, DL_I2C_CONTROLLER_DIRECTION_TX, 1);
  223. // **Step 4: Load Configuration Byte into TX FIFO**
  224. DL_I2C_fillControllerTXFIFO(I2C_controller_INST, &config_byte, 1);
  225. // **Step 5: Ensure STOP Condition is Sent**
  226. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  227. printf("Configuration Byte: 0x%02X\n", config_byte);
  228. printf("Configuration Sent Successfully!\n");
  229. }
  230. /*Function to get the RDY bit from ADC*/
  231. bool Check_ADC_Ready()
  232. {
  233. uint8_t config_byte = 0;
  234. /*
  235. READY BIT:
  236. This bit is the data ready flag. In read mode, this bit indicates if the output register has been updated
  237. with a latest conversion result. In One-Shot Conversion mode, writing this bit to “1” initiates a new
  238. conversion.
  239. 1= Output Register has not been updated
  240. 0= Output Register has been updated
  241. */
  242. DL_I2C_startControllerTransfer(I2C_controller_INST, DEF_TARGET_ADDR_ADC, DL_I2C_CONTROLLER_DIRECTION_RX, 1);
  243. config_byte = DL_I2C_receiveControllerData(I2C_controller_INST);
  244. return (config_byte & 0x80) == 0; // Check if RDY bit is cleared in bit 7
  245. }
  246. /*
  247. Function to read ADC DATA: This function simply retrieves the ADC raw digital output as 16-bit signed integer.
  248. * The value returned is not yet converted to VOLTAGE.
  249. * adc_data[2]: Buffer with an array of size 2, to store two bytes of ADC data.
  250. * Since, the ADC output consists of two 8-bit bytes:
  251. * - adc_data[0] (MSB)
  252. * - adc_data[1] (LSB)
  253. * Next, we verify if the the I2C bus is busy using the function in the driverlib: DL_I2C_get ControllerStatus
  254. * - Prevents collisions by ensuring no two I2C device is using the same bus before initializing.
  255. * BEGIN I2C READ operation to request 2 bytes from the ADC-> DL_I2C_startControllerTransfer()
  256. * Parameters:
  257. - I2C_controller_INST: Refererence to the I2C instance bring used.
  258. - DEF_TARGET_ADDR_ADC: Address of the ADC
  259. - DL_I2C_CONTROLLER_DIRECTION_RX: Indicates that we want to receive the data from ADC
  260. - 2: Specifies that we expect 2 bytes from the ADC
  261. * WAIT for the data to be received: (DL_I2C_getControllerStatus())
  262. - Waits until the ADC sends the data over I2C.
  263. - Ensures that the data transfer is complete before proceeding.
  264. * READ the two bytes of ADc Data:
  265. - adc_data[0] : MSB
  266. - adc_data[1] : LSB
  267. - adc_data[2] : config_bytes
  268. ADC sends its 16-bit value in two parts over 8-bit I2C data frames.
  269. * COMBINE the two bytes into 16-bit Integer:
  270. - Shifts the MSB(first byte) left by 8 bits to make space for LSB.
  271. - Performs a bitwise OR operation to combine MSB and LSB into a single 16-bit number.
  272. * PRINT HEXADEC and DECIMAL format for DEBUGGING.
  273. * Output code is in binary and is proportional to the Input Voltage and PGA settings.
  274. * From the datasheet: https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/22226a.pdf
  275. - Equation 4.4 is being used to convert the output codes to input voltage
  276. */
  277. int16_t Read_ADC_Data(uint8_t resolution)
  278. {
  279. uint8_t adc_data[3] = {0}; // Buffer for ADC data (MSB, LSB, Config Byte)
  280. int16_t raw_adc = 0;
  281. printf("Reading ADC Data from MCP3428...\n");
  282. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  283. // Determine bytes to read
  284. printf("Resolution for reading ADC is %d\n", resolution);
  285. delay_cycles(10000);
  286. // Request 3 Bytes from ADC**
  287. DL_I2C_startControllerTransfer(I2C_controller_INST, DEF_TARGET_ADDR_ADC, DL_I2C_CONTROLLER_DIRECTION_RX, 3);
  288. // Read Data into Buffer**
  289. int i = 0;
  290. while(i<3){
  291. while (DL_I2C_isControllerRXFIFOEmpty(I2C_controller_INST));
  292. printf("Loop no: %d\n",i);
  293. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  294. adc_data[i] = DL_I2C_receiveControllerData(I2C_controller_INST);
  295. printf("Received Byte[%d]: 0x%02X\n", i, adc_data[i]);
  296. i++;
  297. }
  298. newMeasurementAvailable = true;
  299. /*Combining MSB and LSB for ADC output*/
  300. raw_adc= adc_data[0] << 8 | adc_data[1];
  301. printf("Raw ADC Value: 0x%0X (%d)\n", raw_adc, raw_adc);
  302. //printf("Resolution: %d \n", resolution_bits );
  303. return raw_adc;
  304. }
  305. /* Function to Convert ADC Reading to Voltage */
  306. float Convert_ADC_To_Voltage(int16_t adc_value, uint8_t resolution, uint8_t gain) {
  307. if (!newMeasurementAvailable)
  308. { return -1; }
  309. float voltage= 0;
  310. float LSB= 0;
  311. uint32_t max_adc_value= 1;
  312. switch (resolution) {
  313. case 12: // 12-bit
  314. max_adc_value = 2048;
  315. break;
  316. case 14: // 14-bit
  317. max_adc_value = 8192;
  318. break;
  319. case 16: // 16-bit
  320. max_adc_value = 32768;
  321. break;
  322. case 18: // 18-bit
  323. max_adc_value = 131072;
  324. break;
  325. default:
  326. printf("Error: Unknown ADC Resolution!\n");
  327. return 0.0;
  328. }
  329. /*Considering that MSB is always 0*/
  330. printf("Max Resolution %d\n", max_adc_value);
  331. LSB= ((VREF)/max_adc_value);
  332. printf("LSB: %f\n", LSB);
  333. float inputVoltage= ((float)adc_value*(LSB/gain));
  334. /*Formula for ADC to Voltage Conversion*/
  335. /*voltage = ((float)adc_value / max_adc_value) * VREF;
  336. printf("Converted Voltage: %.2f V\n", voltage);*/
  337. printf("Input Voltage Measured: %.2f V\n", inputVoltage);
  338. /*To send the voltage to Pi in milliVolts*/
  339. uint16_t voltage_mV= inputVoltage * 1000;
  340. /*Storing ADC voltages in mVolts */
  341. registers[ADC_REGISTER] = (voltage_mV>>8) & 0xFF; //Highest Byte
  342. registers[ADC_REGISTER + 1] = (voltage_mV) & 0xFF; //Lowest Byte
  343. newMeasurementAvailable = false;
  344. printf("ADC Voltage Stored %d mV in MCU: MSB= 0x%02X, LSB= 0x%02X\n", voltage_mV, registers[ADC_REGISTER], registers[ADC_REGISTER + 1]);
  345. return voltage;
  346. }
  347. /*
  348. DAC Configuration function: Tx to DAC channel
  349. DAC expects 3 bytes from the channel:
  350. Byte 0: write command + channel_selection
  351. Byte 1: configuration + high byte of DAC
  352. Byte 2: low byte of DAC
  353. */
  354. /*bool SET_CHANNEL_VALUE(DAC_CH ch, uint16_t new_value, VREF_SELECTION new_vref, GAIN_SELECTION new_gain, PWR_DOWN_SELECTION new_pwr_dwn, bool udac){
  355. uint8_t output_buffer[8];
  356. //Build the setter header (Address) -> 01000 DAC0 DAC1 DAC2
  357. uint8_t channel_write_cmd = FAST_WRITE_COMMAND; //0x00; FAST write mode
  358. //channel_write_cmd |= (ch << 1); //SET DAC channel
  359. //channel_write_cmd|= udac; // if udac is SET to 0; VOUT is updated after the 4th byte's ACK is issued
  360. output_buffer[0]= channel_write_cmd;
  361. // Construct the 12bit DAC value with the configuration settings
  362. // For Fast write command it does not gives VREF:
  363. // PD1 PD2 Gx D11 D10 D9 D8 [Byte 1]
  364. // D7 D6 D5 D4 D3 D2 D1 D0 [Byte 2]
  365. //new_value &= 0x0FFF; //Ensure only 12 bits are set
  366. //new_value |= (new_vref << 15);
  367. new_value |= (new_pwr_dwn << 13);
  368. //new_value |= (new_gain << 12);
  369. new_value |= new_value<< 9;
  370. new_value |= new_value<< 8;
  371. output_buffer[1]= new_value >> 8; //Upper Byte
  372. output_buffer[2]= new_value & 0xFF; //Lower Byte
  373. //Send the data via I2C:
  374. if (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS){
  375. printf("I2C Bus is busy! Retry..\n");
  376. return false;
  377. }
  378. //start I2C transmission:
  379. DL_I2C_startControllerTransfer(I2C_controller_INST, DEF_TARGET_ADDR_DAC, DL_I2C_CONTROLLER_DIRECTION_TX, 3);
  380. DL_I2C_fillControllerTXFIFO(I2C_controller_INST, output_buffer, 3);
  381. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  382. if (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_ERROR) {
  383. printf("I2C Write Error: Failed to write to DAC!\n");
  384. return false; // Return failure if there was an error
  385. }
  386. return true;
  387. }*/
  388. //The device updates all DAC analog output(vout) at the same time
  389. void update_DAC_Output() {
  390. uint8_t general_call_command = 0x08; // General Call Update Command
  391. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  392. DL_I2C_fillControllerTXFIFO(I2C_controller_INST, &general_call_command, 1);
  393. // Start I2C transaction
  394. DL_I2C_startControllerTransfer(I2C_controller_INST, 0x00, DL_I2C_CONTROLLER_DIRECTION_TX, 1);
  395. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  396. printf("DAC Outputs Updated via General Call Software Update!\n");
  397. }
  398. /**Function for FAST write command, sending values over I2c to every channel of DAC**/
  399. bool fastWrite(uint16_t channel_a_value){
  400. /*DAC has a 12 bit resolution that ranges from 0 to 4095.
  401. 0x00: sets the Power Mode to NORMAL for Channel A
  402. (channel_a_value >> 8): shifts the value to 8 places right and gives upper 4 bits
  403. */
  404. uint8_t output_buffer[8];
  405. output_buffer[0]= (0x00)|(channel_a_value >> 8)&0x0F;
  406. //output_buffer[0] = channel_a_value >> 8;
  407. output_buffer[1]= channel_a_value & 0xFF;
  408. output_buffer[2]= 0x40; // Power down for the other channels
  409. output_buffer[3]= 0x00;
  410. output_buffer[4]= 0x40;
  411. output_buffer[5]= 0x00;
  412. output_buffer[6]= 0x40;
  413. output_buffer[7]= 0x00;
  414. if (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_ERROR) {
  415. printf("I2C Write Error: Failed to write to DAC channels for FAST write mode!\n");
  416. return false; // Return failure if there was an error
  417. }
  418. // **Wait for I2C Bus to be Free**
  419. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  420. // **Start I2C Write Transaction**
  421. DL_I2C_startControllerTransfer(I2C_controller_INST, DEF_TARGET_ADDR_DAC, DL_I2C_CONTROLLER_DIRECTION_TX, 8);
  422. // **Load Configuration Byte into TX FIFO**
  423. DL_I2C_fillControllerTXFIFO(I2C_controller_INST, (uint8_t*)&output_buffer, 8);
  424. // **Ensure STOP Condition is Sent**
  425. while (DL_I2C_getControllerStatus(I2C_controller_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS);
  426. printf("DAC Fast write Successful!\n");
  427. update_DAC_Output();
  428. return true;
  429. }
  430. /*void readRegisters(){
  431. uint8_t data[24];
  432. uint8_t channel;
  433. bool isEeprom;
  434. printf("Reading MCP4728 Registers...\n");
  435. // ** Request 24 Bytes from MCP4728 over I2C **
  436. DL_I2C_startControllerTransfer(I2C_controller_INST, DEF_TARGET_ADDR_DAC, DL_I2C_CONTROLLER_DIRECTION_RX, 24);
  437. for (int i = 0; i < 24; i++) {
  438. while (DL_I2C_isControllerRXFIFOEmpty(I2C_controller_INST));
  439. data[i] = DL_I2C_receiveControllerData(I2C_controller_INST);
  440. }
  441. // ** Process the Received Data (8 Iterations for 4 Channels) **
  442. for (uint8_t i = 0; i < 8; i++) {
  443. isEeprom = i % 2; // Even indices: Register, Odd indices: EEPROM
  444. //Extract channel:
  445. uint8_t ch= (data[0] & 0x30)>>4;
  446. if (isEeprom) {
  447. read_eep_[ch].vref = (VREF_SELECTION) ((data[i * 3 + 1] & 0b10000000) >> 7);
  448. read_eep_[ch].pd = (PWR_DOWN_SELECTION) ((data[i * 3 + 1] & 0b01100000) >> 5);
  449. read_eep_[ch].gain = (GAIN_SELECTION) ((data[i * 3 + 1] & 0b00010000) >> 4);
  450. read_eep_[ch].data = (uint16_t) ((data[i * 3 + 1] & 0b00001111) << 8 | data[i * 3 + 2]);
  451. } else {
  452. read_reg_[ch].vref = (VREF_SELECTION) ((data[i * 3 + 1] & 0b10000000) >> 7);
  453. read_reg_[ch].pd = (PWR_DOWN_SELECTION) ((data[i * 3 + 1] & 0b01100000) >> 5);
  454. read_reg_[ch].gain = (GAIN_SELECTION) ((data[i * 3 + 1] & 0b00010000) >> 4);
  455. read_reg_[ch].data = (uint16_t) ((data[i * 3 + 1] & 0b00001111) << 8 | data[i * 3 + 2]);
  456. }
  457. }
  458. printf("MCP4728 Registers Read Successfully!\n");
  459. }
  460. */
  461. /*
  462. DAC Function:
  463. -12 bit Voltage Output DAC with Four Buffered outputs.
  464. -Using Internal VREF (2.048V):
  465. - Output voltage range:
  466. - 0.000V to 2.048V with Gain setting= 1
  467. - 0.000V to 4.096V with Gain setting= 2
  468. - User can select internal reference or external voltage (VDD) for each channel
  469. - VOUTA: Buffered analog voltage of Channel A.
  470. - Channel Selection bits: 0x00 for Channel A
  471. */
  472. /*int16_t read_DAC_Output()
  473. {
  474. readRegisters(); //Read current register DAC values
  475. uint16_t dac_a = read_reg_[DAC_A].data;
  476. uint16_t dac_b = read_reg_[DAC_B].data;
  477. uint16_t dac_c = read_reg_[DAC_C].data;
  478. uint16_t dac_d = read_reg_[DAC_D].data;
  479. printf("DAC Output Digital Values: A=%d, B=%d, C=%d, D=%d\n",
  480. dac_a, dac_b, dac_c, dac_d);
  481. return dac_a;
  482. }
  483. float get_DAC_Output_Voltage(DAC_CH channel){
  484. if(channel< DAC_A || channel> DAC_D){
  485. printf("Error: Invalid DAC channel!\n");
  486. return -1.0;
  487. }
  488. uint16_t dac_value = read_reg_[channel].data;
  489. VREF_SELECTION vref = read_reg_[channel].vref;
  490. GAIN_SELECTION gain = read_reg_[channel].gain;
  491. //GET correct VREF value:
  492. float vref_value= (vref==VREF_INTERNAL)? 2.048: 3.3;
  493. uint8_t gain_factor= (gain==GAIN_X2)? 2: 1;
  494. // Calculate Output Voltage
  495. float vout = ((float)dac_value / 4095.0) * vref_value * gain_factor;
  496. printf("DAC Channel %d - Digital Value: %d, VOUT: %.3fV\n", channel, dac_value, vout);
  497. return vout;
  498. }*/
  499. /**Function to call DAC*/
  500. /*void get_Analog_Output(){
  501. bool success= fastWrite(2048, 0, 0, 0);
  502. if(!success){
  503. printf("Error: DAC Fast Write Failed.\n");
  504. return;
  505. }
  506. update_DAC_Output();
  507. read_DAC_Output();
  508. float vout_a= get_DAC_Output_Voltage(DAC_A);
  509. float vout_b= get_DAC_Output_Voltage(DAC_B);
  510. float vout_c= get_DAC_Output_Voltage(DAC_C);
  511. float vout_d= get_DAC_Output_Voltage(DAC_D);
  512. printf("\nMeasured DAC output Voltages:\n");
  513. printf("Channel A: %.2f V\n", vout_a);
  514. printf("Channel B: %.2f V\n", vout_b);
  515. printf("Channel C: %.2f V\n", vout_c);
  516. printf("Channel D: %.2f V\n", vout_d);
  517. }
  518. */
  519. /*
  520. Function to initialize MCU as target: Pi communicates as the Controller and MCU as the Target
  521. */
  522. void I2C_Target_Init(void) {
  523. // Set the target address
  524. DL_I2C_setTargetOwnAddress(I2C_target_INST, I2C_target_TARGET_OWN_ADDR);
  525. // Enable target mode
  526. DL_I2C_enableTarget(I2C_target_INST);
  527. /* Enable relevant I2C interrupts */
  528. DL_I2C_enableInterrupt(I2C_target_INST, DL_I2C_INTERRUPT_TARGET_START);
  529. DL_I2C_enableInterrupt(I2C_target_INST, DL_I2C_INTERRUPT_TARGET_RXFIFO_TRIGGER);
  530. DL_I2C_enableInterrupt(I2C_target_INST, DL_I2C_INTERRUPT_TARGET_TXFIFO_TRIGGER);
  531. DL_I2C_enableInterrupt(I2C_target_INST, DL_I2C_INTERRUPT_TARGET_STOP);
  532. }
  533. /*
  534. MAIN function:
  535. */
  536. int main(void)
  537. {
  538. // **Step 1: Initialize System and I2C**
  539. SYSCFG_DL_init();
  540. printf("............System Configuration Enabled...............\n");
  541. // **Step 2: Select ADC Channel via Multiplexer**
  542. printf("Selecting Multiplexer Channel...\n");
  543. Multiplexer_SelectChannel(ADC_I2C_CHANNEL);
  544. //I2C_scanBus();
  545. // **Step 3: Enable I2C Interrupts**
  546. //NVIC_EnableIRQ(I2C_controller_INST_INT_IRQN);
  547. //NVIC_EnableIRQ(I2C_target_INST_INT_IRQN);
  548. I2C_init(&gI2C);
  549. gTxCount = 0;
  550. gTxLen = REGISTER_SIZE;
  551. gRxCount = 0;
  552. gRxLen = REGISTER_SIZE;
  553. // **Step 4: Configure ADC (Example: CH1, 16-bit, Continuous Mode, Gain x1)**
  554. uint8_t channel= 4;
  555. uint8_t resolution= 16;
  556. bool continuous= 1;
  557. uint8_t gain= 1;
  558. printf("Configuring ADC...\n");
  559. //**Set Configuration Register for ADC**
  560. //SetConfiguration(channel, resolution, continuous, gain); // CH1, 16-bit, Continuous mode, Gain x1
  561. while (1)
  562. {
  563. // Read ADC Value and DAC values:
  564. //int16_t adc_value = Read_ADC_Data(resolution);
  565. //Convert_ADC_To_Voltage(adc_value, resolution, gain);
  566. //delay_cycles(10000);
  567. fastWrite(3300);
  568. //Add Delay for Next Conversion**
  569. delay_cycles(100000);
  570. }
  571. }
  572. /*Interrupt for MCU -> ADC
  573. * CASE: DL_I2C_IIDX_CONTROLLER_RX_DONE: ADC Reception Complete
  574. - ADC has finished sending data and it's fully received.
  575. - gI2C.rxMsg.len = gI2C.rxMsg.ptr:
  576. - Stores the received data length in the response buffer.
  577. - I2C_decodeResponse():
  578. - Decodes the received response.
  579. - gI2C.status = I2C_STATUS_RX_COMPLETE:
  580. - Marks reception is complete.
  581. * CASE: DL_I2C_IIDX_CONTROLLER_TX_DONE: Data Transmit to ADC complete
  582. - DL_I2C_disableInterrupt(..): Disables the TXFIFO interrupt since data is now sent
  583. * CASE: DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER: Receive Data in FIFO
  584. - The I2C Receive FIFO has data ready to be read.
  585. - while (DL_I2C_isControllerRXFIFOEmpty(...) != true): Loops until the RX FIFOis empty (READ all available bytes)
  586. - Inside the while loop:
  587. - If buffer has SPACE, store the received byte
  588. - Prints each received byte in HEXADECIMAL format for debugging
  589. - IF BUFFER is FULL, avoids OVERFLOW by discarding extra byte.
  590. * CASE: DL_I2C_IIDX_CONTROLLER_TXFIFO_TRIGGER: Transmit Data in FIFO
  591. - If there is still data to send:
  592. gI2C.txMsg.ptr += DL_I2C_fillControllerTXFIFO(I2C_controller_INST, &gI2C.txMsg.buffer[gI2C.txMsg.ptr], gI2C.txMsg.len - gI2C.txMsg.ptr);
  593. */
  594. void I2C_controller_INST_IRQHandler(void)
  595. { printf("I2C Interrupt Triggered to ADC!\n");
  596. switch (DL_I2C_getPendingInterrupt(I2C_controller_INST))
  597. {
  598. case DL_I2C_IIDX_CONTROLLER_RX_DONE:
  599. gI2C.rxMsg.len = gI2C.rxMsg.ptr;
  600. I2C_decodeResponse(&gI2C,&gResponse);
  601. gI2C.status = I2C_STATUS_RX_COMPLETE;
  602. printf("I2C RX COMPLETE!\n");
  603. break;
  604. case DL_I2C_IIDX_CONTROLLER_TX_DONE:
  605. DL_I2C_disableInterrupt(
  606. I2C_controller_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER);
  607. gI2C.status = I2C_STATUS_TX_COMPLETE;
  608. printf("I2C TX COMPLETE!\n");
  609. break;
  610. case DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER:
  611. gI2C.status = I2C_STATUS_RX_INPROGRESS;
  612. /* Store bytes received from target in Rx Msg Buffer */
  613. while (DL_I2C_isControllerRXFIFOEmpty(I2C_controller_INST) != true) {
  614. if (gI2C.rxMsg.ptr < MAX_BUFFER_SIZE) {
  615. gI2C.rxMsg.buffer[gI2C.rxMsg.ptr++] =
  616. DL_I2C_receiveControllerData(I2C_controller_INST);
  617. if(gI2C.rxMsg.ptr>0){
  618. //printf("Received Byte[%d]: 0x%02X\n", gI2C.rxMsg.ptr, gI2C.rxMsg.buffer[gI2C.rxMsg.ptr - 1]);
  619. }
  620. } else {
  621. printf("ERROR: RX Buffer Overflow! ptr=%d MAX_BUFFER_SIZE=%d\n", gI2C.rxMsg.ptr, MAX_BUFFER_SIZE);
  622. /* Ignore and remove from FIFO if the buffer is full */
  623. DL_I2C_receiveControllerData(I2C_controller_INST);
  624. }
  625. }
  626. break;
  627. case DL_I2C_IIDX_CONTROLLER_TXFIFO_TRIGGER:
  628. printf("TX FIFO with data!\n");
  629. gI2C.status = I2C_STATUS_TX_INPROGRESS;
  630. /* Fill TX FIFO with bytes to send */
  631. if (gI2C.txMsg.ptr < gI2C.txMsg.len) {
  632. gI2C.txMsg.ptr += DL_I2C_fillControllerTXFIFO(
  633. I2C_controller_INST, &gI2C.txMsg.buffer[gI2C.txMsg.ptr], gI2C.txMsg.len - gI2C.txMsg.ptr);
  634. }
  635. break;
  636. case DL_I2C_IIDX_CONTROLLER_ARBITRATION_LOST:
  637. printf("Interrupt index for I2C controller Arbitration Lost!\n");
  638. break;
  639. case DL_I2C_IIDX_CONTROLLER_NACK:
  640. printf("I2C NACK Received\n");
  641. break;
  642. default:
  643. break;
  644. }
  645. }
  646. void I2C_target_INST_IRQHandler(void) {
  647. static bool DataRx= false;
  648. static uint16_t registerAddress=0;
  649. //printf("I2C Interrupt Triggered to MCU (TARGET)!\n");
  650. uint32_t status = DL_I2C_getPendingInterrupt(I2C_target_INST);
  651. switch (status) {
  652. /* START condition detected */
  653. case DL_I2C_IIDX_TARGET_START:
  654. //printf("START condition detected.\n");
  655. gTxCount= 0;
  656. gRxCount= 0;
  657. DataRx= false;
  658. DL_I2C_flushTargetTXFIFO(I2C_target_INST);
  659. break;
  660. /* STOP condition detected */
  661. case DL_I2C_IIDX_TARGET_STOP:
  662. //printf("STOP condition detected.\n");
  663. if (DataRx == true){
  664. //printf("Data received from Pi: ");
  665. for (uint8_t i = 0; i < gRxCount; i++) {
  666. //printf("0x%02X ", gRxBuffer[i]);
  667. }
  668. //printf("\n");
  669. DataRx= false;
  670. }
  671. DL_I2C_flushTargetTXFIFO(I2C_target_INST);
  672. break;
  673. /* RX FIFO trigger (Pi is writing data to MCU) */
  674. case DL_I2C_IIDX_TARGET_RXFIFO_TRIGGER:
  675. //printf("receiving data from Pi.\n");
  676. DataRx= true;
  677. while (!DL_I2C_isTargetRXFIFOEmpty(I2C_target_INST)) {
  678. if (gRxCount == 0) {
  679. // First byte received is the register address
  680. registerAddress = DL_I2C_receiveTargetData(I2C_target_INST);
  681. DL_I2C_flushTargetTXFIFO(I2C_target_INST);
  682. //printf("Register Address Set: 0x%02X\n", registerAddress);
  683. }
  684. else if (registerAddress < REGISTER_SIZE) {
  685. //Storing the received data from the controller correctly
  686. registers[registerAddress] = DL_I2C_receiveTargetData(I2C_target_INST);
  687. printf("Stored 0x%02X in Register 0x%02X\n", registers[registerAddress], registerAddress);
  688. //gRxBuffer[gRxCount++] = DL_I2C_receiveTargetData(I2C_0_INST);
  689. }
  690. else {
  691. printf("ERROR: RX Buffer Overflow!\n");
  692. break;
  693. }
  694. gRxCount++;
  695. }
  696. break;
  697. /* TX FIFO trigger (Pi is reading data from MCU) */
  698. case DL_I2C_IIDX_TARGET_TXFIFO_TRIGGER:
  699. //printf("transmitting data to Pi...\n");
  700. if(!DL_I2C_isTargetTXFIFOFull(I2C_target_INST)) {
  701. if (registerAddress < REGISTER_SIZE) {
  702. //DL_I2C_fillTargetTXFIFO(I2C_0_INST, &gTxBuffer[gTxCount], 1);
  703. // Retrieve stored value from the correct register
  704. uint8_t value = registers[registerAddress];
  705. //uint8_t value_test[2] = { 0x01, 0x03 };
  706. DL_I2C_fillTargetTXFIFO(I2C_target_INST, &value, 1);
  707. //printf("Sending to 0x%02X: 0x%02X\n", registerAddress, value); // Debugging
  708. } else {
  709. // **Fix: Avoid infinite while loop**
  710. printf("WARNING: TX Buffer Underflow! Sending default value.\n");
  711. DL_I2C_fillTargetTXFIFO(I2C_target_INST, (uint8_t[]){0x00}, 1);
  712. break;
  713. }
  714. }
  715. break;
  716. /* Arbitration lost or NACK */
  717. case DL_I2C_IIDX_TARGET_ARBITRATION_LOST:
  718. default:
  719. printf("Unknown Interrupt.\n");
  720. break;
  721. }
  722. }