Learn MoreFAQsTutorials

4 posts / 0 new
Last post
ahiggs
Offline
Last seen:4 months 6 days ago
Joined:2019-12-17 07:10
Multiple I2C busses

Hello,

I have a question regarding using multiple I2C busses on the DA14585. I am working with MCP9600 thermocouple amplifiers which have 8 possible addresses each. I need to connect 64 of these sensors to a DA14585 and read them at ~1Hz.

我计划设置8个独立的公交车,每个与their own data line and one shared clock (using a total of 9 pins on the DA14585). The DA14585 will setup the I2C controller based on which bus it wants to talk to and when it's done with this bus, to let the data line stay high. From an I2C perspective, the chips on the inactive bus would be seeing constant 1's when their bus is not active, this is preferable to the other configuration where each has its own clock and the chip sees constant stop/start commands.

The only thing I am not sure of is how to accomplish this in the code. I would like to set it up like this so that way I can switch through the busses. Is the RESERVE_GPIO() command necessary, or would that confuse things? Otherwise I assume this would work

void init_MCP(void){ RESERVE_GPIO(,ALL_SCL_PORT, ALL_SCL_PIN, PID_I2C_SCL); RESERVE_GPIO(,BUS1_SDA_PORT, BUS1_SDA_PIN, PID_I2C_SDA);//???? RESERVE_GPIO(,BUS2_SDA_PORT, BUS2_SDA_PIN, PID_I2C_SDA);//???? remaining pins... GPIO_ConfigurePin(ALL_SCL_PORT, ALL_SCL_PIN, INPUT, PID_I2C_SCL, false); } void select_MCP_BUS(uint8_t BUS_NUMBER){ switch BUS_NUMBER: case 1: GPIO_ConfigurePin(BUS1_SDA_PORT, BUS1_SDA_PIN, INPUT, PID_I2C_SDA, false); for(all other busses) GPIO_ConfigurePin(BUS1_SDA_PORT, BUS1_SDA_PIN, INPUT, PID_GPIO, false); break; case 2: GPIO_ConfigurePin(BUS2_SDA_PORT, BUS2_SDA_PIN, INPUT, PID_I2C_SDA, false); for(all other busses) GPIO_ConfigurePin(BUS1_SDA_PORT, BUS1_SDA_PIN, INPUT, PID_GPIO, false); break; case 3: remaining busses... } void send_temperature(){ for(all 8 busses){ select_MCP_BUS(bus#) for(all 8 MCPs){ sample_send_temp(MCP#) } } }

I know I could use an I2C mux to accomplish this, but we are limited in space and it is just an extra component that could fail

Device:
PM_Dialog
Offline
Last seen:12 hours 52 min ago
Staff
Joined:2018-02-08 11:03
Hi ahiggs,

Hi ahiggs,

谢谢你的问题在线和德泰led description. We haven’t such an example demonstrating the described functionality, but this might be a possible approach. Every time that you would like to change the “BUS_NUMBER”, you should re-configure the appropriate GPIO as I2C pin. Did you test this on your HW setup?

Thanks, PM_Dialog

ahiggs
Offline
Last seen:4 months 6 days ago
Joined:2019-12-17 07:10
Hello,

Hello,

Thanks for your prompt reply. I have only tested the hardware setup with MCP9600s on one of the buses but it worked. I have not yet designed the boards to test the full system. If anyone is interested, here's a snippet of code for this setup

空白sensor_init () {adc_calibrate ();ADC_timer [0]= app_easy_timer(ADC_timer_delay[0],readADC0); //check if timers are all available for(int a=0;a<1;a++){ if(ADC_timer[a]==EASY_TIMER_INVALID_TIMER){ while(1);//BADBADBAD } } //for MCP amplifiers: bool init_error=false; read_ADC[0]=1; init_I2C(); for(uint8_t i=0;i<1;i++){//initialize 1 bus (8 max) set_I2C_BUS(i+1);//1 indexed for(uint8_t a=0;a<2;a++){//initialize 2 sensors ((8 max) if(!init_MCP(a))//0 indexed init_error=true; } } } void init_I2C(void){//Initialize the I2C bus for the MCP chips GPIO_ConfigurePin(I2C_SCL_PORT, I2C_SCL_PIN, INPUT_PULLUP, PID_I2C_SCL, false); //Dont configure the SDA pin yet } void set_I2C_BUS(uint8_t bus){//Select which data line is used for the I2C //release the other pins from PID_I2C_SDA //I suppose this could be cleaner if the last pin used was tracked... GPIO_ConfigurePin(I2C_SDA1_PORT, I2C_SDA1_PIN, INPUT, PID_GPIO, false); GPIO_ConfigurePin(I2C_SDA2_PORT, I2C_SDA2_PIN, INPUT, PID_GPIO, false); GPIO_ConfigurePin(I2C_SDA3_PORT, I2C_SDA3_PIN, INPUT, PID_GPIO, false); GPIO_ConfigurePin(I2C_SDA4_PORT, I2C_SDA4_PIN, INPUT, PID_GPIO, false); GPIO_ConfigurePin(I2C_SDA5_PORT, I2C_SDA5_PIN, INPUT, PID_GPIO, false); GPIO_ConfigurePin(I2C_SDA6_PORT, I2C_SDA6_PIN, INPUT, PID_GPIO, false); GPIO_ConfigurePin(I2C_SDA7_PORT, I2C_SDA7_PIN, INPUT, PID_GPIO, false); GPIO_ConfigurePin(I2C_SDA8_PORT, I2C_SDA8_PIN, INPUT, PID_GPIO, false); //set the new bus pin to PID_I2C_SDA switch(bus){ case 1: GPIO_ConfigurePin(I2C_SDA1_PORT, I2C_SDA1_PIN, INPUT, PID_I2C_SDA, false); break; case 2: GPIO_ConfigurePin(I2C_SDA2_PORT, I2C_SDA2_PIN, INPUT, PID_I2C_SDA, false); break; case 3: GPIO_ConfigurePin(I2C_SDA3_PORT, I2C_SDA3_PIN, INPUT, PID_I2C_SDA, false); break; case 4: GPIO_ConfigurePin(I2C_SDA4_PORT, I2C_SDA4_PIN, INPUT, PID_I2C_SDA, false); break; case 5: GPIO_ConfigurePin(I2C_SDA5_PORT, I2C_SDA5_PIN, INPUT, PID_I2C_SDA, false); break; case 6: GPIO_ConfigurePin(I2C_SDA6_PORT, I2C_SDA6_PIN, INPUT, PID_I2C_SDA, false); break; case 7: GPIO_ConfigurePin(I2C_SDA7_PORT, I2C_SDA7_PIN, INPUT, PID_I2C_SDA, false); break; case 8: GPIO_ConfigurePin(I2C_SDA8_PORT, I2C_SDA8_PIN, INPUT, PID_I2C_SDA, false); break; } } bool init_MCP(uint8_t addr){ user_i2c_init(0x60+addr, I2C_7BIT_ADDR, I2C_STANDARD, I2C_1BYTE_REGISTER, I2C_1BYTE_ADDR); //device config register, 0.0625°C ambient accuracy, 18-bit, 1 sample, shutdown mode: 0b00000001 (highest accuracy settings) if(i2c_write_2byte_MCP(0x06, 0x02)!=I2C_NO_ERROR) return 0; //initialize next sample: device status register 0x04, clear bit7 to start sample, other bits can be cleared too if(i2c_write_2byte_MCP(0x04, 0x00)!=I2C_NO_ERROR) return 0; SetWord16(I2C_ENABLE_REG, 0x0); // Disable the I2C controller SetBits16(CLK_PER_REG, I2C_ENABLE, 0); // Disable clock for I2C return 1; } uint16_t read_MCP(uint8_t addr){//read the MCP, assuming the temperature is ready user_i2c_init(0x60+addr, I2C_7BIT_ADDR, I2C_STANDARD, I2C_1BYTE_REGISTER, I2C_1BYTE_ADDR); uint16_t value=0; //device config register, 0.0625°C ambient accuracy, 18-bit, 1 sample, shutdown mode: 0b00000001 (highest accuracy settings) if(i2c_write_2byte_MCP(0x06, 0x02)!=I2C_NO_ERROR) return 0; //select register to read by first writing to select it: 0x00 for hot, 0x02 for cold(chip) temperature if(i2c_write_byte_MCP(0x00)!=I2C_NO_ERROR) value=0xFFFF; //read the two bytes from the register if(i2c_read_2byte_MCP(&value)!=I2C_NO_ERROR) value=0xFFFF; //initialize next sample: device status register, clear bit7 to start sample, other bits can be cleared too if(i2c_write_2byte_MCP(0x04, 0x00)!=I2C_NO_ERROR) value=0xFFFF; SetWord16(I2C_ENABLE_REG, 0x0); // Disable the I2C controller SetBits16(CLK_PER_REG, I2C_ENABLE, 0); // Disable clock for I2C return value;//right shift by 4 to get integer temperature (or do temp °C = MSB*16+LSB/16 if greater than 0) } #define I2C_SCL_PORT GPIO_PORT_0//pin 1 on QFN40 chip #define I2C_SCL_PIN GPIO_PIN_0 #define I2C_SDA1_PORT GPIO_PORT_0//pin 2 on QFN40 chip #define I2C_SDA1_PIN GPIO_PIN_1 #define I2C_SDA2_PORT GPIO_PORT_0//pin 3 on QFN40 chip #define I2C_SDA2_PIN GPIO_PIN_2 #define I2C_SDA3_PORT GPIO_PORT_0 #define I2C_SDA3_PIN GPIO_PIN_3 #define I2C_SDA4_PORT GPIO_PORT_2//would use P0_4, but used by UART #define I2C_SDA4_PIN GPIO_PIN_0 #define I2C_SDA5_PORT GPIO_PORT_3 #define I2C_SDA5_PIN GPIO_PIN_0 #define I2C_SDA6_PORT GPIO_PORT_2//would use P0_5 but used by UART #define I2C_SDA6_PIN GPIO_PIN_9 #define I2C_SDA7_PORT GPIO_PORT_2 #define I2C_SDA7_PIN GPIO_PIN_1 #define I2C_SDA8_PORT GPIO_PORT_1//would use P0_6 but used by UART #define I2C_SDA8_PIN GPIO_PIN_2

PM_Dialog
Offline
Last seen:12 hours 52 min ago
Staff
Joined:2018-02-08 11:03
Hi ahiggs,

Hi ahiggs,

Thanks for your inputs. If you have any other question, please raise a new forum thread.

Thanks, PM_Dialog