This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I'm trying to read out a hall effect sensor via I2C. I've based my code on the driverlib example i2c_ex5_master_slave_interrupt.c, example 2.
I can see on my Saleae logic analyzer that the writes are correct. However, when I try to read, the sensor address is put on the bus correctly, but the register address is not. It is left high, while the clock is pulsed.
The following code generates this sequence:
#include "driverlib.h" #include "device.h" #include "board.h" #include "i2cLib_FIFO_master_slave_interrupt.h" // // Defines // #define I2CA_SENSORADDRESS 0x35 #define I2CA_ADDRESS 0x30 #define I2CB_ADDRESS 0x40 // // Globals // uint16_t status = 0; struct I2CHandle I2CA; struct I2CHandle I2CB; // // Function Prototypes // __interrupt void i2cAISR(void); __interrupt void i2cAFIFOISR(void); __interrupt void i2cBISR(void); __interrupt void i2cBFIFOISR(void); uint16_t AvailableI2C_slaves[MAX_I2C_IN_NETWORK]; uint16_t I2CA_TXdata[MAX_BUFFER_SIZE]; uint16_t I2CB_TXdata[MAX_BUFFER_SIZE]; uint16_t I2CA_RXdata[MAX_BUFFER_SIZE]; uint16_t I2CB_RXdata[MAX_BUFFER_SIZE]; uint32_t I2CA_ControlAddr; uint32_t I2CB_ControlAddr; uint16_t status; // // Main // void i2c_test(void) { // // Board initialization // I2C_GPIO_init(); // // Initialize PIE and clear PIE registers. Disables CPU interrupts. // Interrupt_initModule(); // // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). // Interrupt_initVectorTable(); I2Cinit(); // Board_init(); I2C_setOwnSlaveAddress(I2CA_BASE, I2CA_ADDRESS); I2C_setOwnSlaveAddress(I2CB_BASE, I2CB_ADDRESS); //I2Cs connected to I2CA will be found in AvailableI2C_slaves buffer //after you run I2CBusScan function. //When you run I2C BusScan you need to disable I2C interrupts and clear //the flag set during I2CBusScan // uint16_t i; // // for(i=0;i<MAX_I2C_IN_NETWORK;i++) // { // AvailableI2C_slaves[i] = 0; // } // // I2C_disableInterrupt(I2CA_BASE, (I2C_INT_ADDR_SLAVE|I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST | I2C_INT_NO_ACK)); // I2C_disableInterrupt(I2CB_BASE, (I2C_INT_ADDR_SLAVE|I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST | I2C_INT_NO_ACK)); // // uint16_t *pAvailableI2C_slaves = AvailableI2C_slaves; // status = I2CBusScan(I2CA_BASE, pAvailableI2C_slaves); // // I2C_clearStatus(I2CA_BASE,I2C_STS_NO_ACK|I2C_STS_ARB_LOST|I2C_STS_REG_ACCESS_RDY|I2C_STS_STOP_CONDITION); // I2C_clearStatus(I2CB_BASE,I2C_STS_NO_ACK|I2C_STS_ARB_LOST|I2C_STS_REG_ACCESS_RDY|I2C_STS_STOP_CONDITION); // // ESTOP0; // I2C_disableInterrupt(I2CA_BASE, (I2C_INT_ADDR_SLAVE|I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST | I2C_INT_NO_ACK)); // I2C_disableInterrupt(I2CB_BASE, (I2C_INT_ADDR_SLAVE|I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST | I2C_INT_NO_ACK)); // // status = I2CBusScan(I2CB_BASE, pAvailableI2C_slaves); // // I2C_clearStatus(I2CA_BASE,I2C_STS_NO_ACK|I2C_STS_ARB_LOST|I2C_STS_REG_ACCESS_RDY|I2C_STS_STOP_CONDITION); // I2C_clearStatus(I2CB_BASE,I2C_STS_NO_ACK|I2C_STS_ARB_LOST|I2C_STS_REG_ACCESS_RDY|I2C_STS_STOP_CONDITION); I2C_clearStatus(I2CA_BASE,I2C_STS_NO_ACK|I2C_STS_ARB_LOST|I2C_STS_REG_ACCESS_RDY|I2C_STS_STOP_CONDITION); I2C_clearStatus(I2CB_BASE,I2C_STS_NO_ACK|I2C_STS_ARB_LOST|I2C_STS_REG_ACCESS_RDY|I2C_STS_STOP_CONDITION); I2C_enableInterrupt(I2CA_BASE, (I2C_INT_ADDR_SLAVE|I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST | I2C_INT_NO_ACK)); I2C_enableInterrupt(I2CB_BASE, (I2C_INT_ADDR_SLAVE|I2C_INT_STOP_CONDITION | I2C_INT_ARB_LOST | I2C_INT_NO_ACK)); // // Set I2C use, initializing it for FIFO mode // Interrupt_register(INT_I2CA, &i2cAISR); Interrupt_enable(INT_I2CA); Interrupt_register(INT_I2CB, &i2cBISR); Interrupt_enable(INT_I2CB); Interrupt_register(INT_I2CA_FIFO, &i2cAFIFOISR); Interrupt_enable(INT_I2CA_FIFO); Interrupt_register(INT_I2CB_FIFO, &i2cBFIFOISR); Interrupt_enable(INT_I2CB_FIFO); // // Enable Global Interrupt (INTM) and realtime interrupt (DBGM) // EINT; ERTM; uint16_t i; for(i=0;i<MAX_BUFFER_SIZE;i++) { I2CA_TXdata[i] = 0; I2CA_RXdata[i] = 0; I2CB_TXdata[i] = 0; I2CB_RXdata[i] = 0; } I2CA.currentHandlePtr = &I2CA; I2CA.base = I2CA_BASE; I2CA.SlaveAddr = I2CA_SENSORADDRESS; I2CA.pControlAddr = &I2CA_ControlAddr; I2CA.NumOfAddrBytes = 1; I2CA.pTX_MsgBuffer = I2CA_TXdata; I2CA.pRX_MsgBuffer = I2CA_RXdata; I2CA.NumOfDataBytes = 64; I2CB.currentHandlePtr = &I2CB; I2CB.base = I2CB_BASE; I2CB.SlaveAddr = I2CB_ADDRESS; I2CB.NumOfAddrBytes = 4; I2CB.pControlAddr = (uint32_t *)0; I2CB.pTX_MsgBuffer = (uint16_t *)0; I2CB.pRX_MsgBuffer = (uint16_t *)0; I2CA.pTX_MsgBuffer[0] = 0x00; I2CA.SlaveAddr = 0x00; I2CA.NumOfDataBytes = 1; I2CA_ControlAddr = 0x10; status = I2C_MasterTransmitter(&I2CA); // Wait for I2CA to be complete transmission of data while(I2C_getStatus(I2CA.base) & I2C_STS_BUS_BUSY); I2CA.SlaveAddr = I2CA_SENSORADDRESS; // I2CA.pTX_MsgBuffer[0] = 0x10; // register address I2CA.pTX_MsgBuffer[0] = 0b00000000; // set config register - all channels, full range, odd CP parity = 0x I2CA.pTX_MsgBuffer[1] = 0b10001001; // MOD1 register: master controlled mode, one byte read command, enabled interrupt, no collision avoidance, odd FP parity I2CA.NumOfDataBytes = 2; status = I2C_MasterTransmitter(&I2CA); // Wait for I2CA to be complete transmission of data while(I2C_getStatus(I2CA.base) & I2C_STS_BUS_BUSY); I2CA_ControlAddr = 0x00 | 0b00100000; // I2CA.pTX_MsgBuffer[0] = 0b00100000; // trigger after I2c write frame is finished I2CA.NumOfDataBytes = 0; status = I2C_MasterTransmitter(&I2CA); // Wait for I2CA to be complete transmission of data while(I2C_getStatus(I2CA.base) & I2C_STS_BUS_BUSY); SysCtl_delay(5000); //Adding delay for sensor conversion I2CA.NumOfDataBytes = 0; I2CA.pTX_MsgBuffer[0] = 0b00000000; // reset tx data I2CA_ControlAddr = 0b00000000; status = I2C_MasterReceiver(&I2CA); // Wait for I2CA to be complete transmission of data while(I2C_getStatus(I2CA.base) & I2C_STS_BUS_BUSY); ESTOP0; }
I did have to change the I2C_MasterReceiver() Code (creating and calling a I2C_TransmitSlaveAddress_ControlBytes_MasterReadBit() Method which sets I2C_MASTER_RECEIVE_MODE instead of I2C_MASTER_SEND_MODE) to send the read bit high, as the write bit was hardcoded, which did work.
I'm expecting 0x0 + ACK on the bus, but I get OxFF + NACK. The readout should look like this:
Hi,
When I2C is in Read mode, I2C master doesn't transmit any more bytes. It just expects data from I2C slave. The reason why you read 0xFF is because sensor didn't transmit anything and the pull-up resistor pull the pins high.
I did have to change the I2C_MasterReceiver() Code (creating and calling a I2C_TransmitSlaveAddress_ControlBytes_MasterReadBit() Method which sets I2C_MASTER_RECEIVE_MODE instead of I2C_MASTER_SEND_MODE) to send the read bit high, as the write bit was hardcoded, which did work.
Revert back to original I2C_MasterReceiver code and try the below method.
I2CA.NumOfDataBytes = 1; //Number of bytes to be received
I2CA_ControlAddr = 0; //Trigger bits + Register address
status = I2C_MasterReceiver(&I2CA);
Below is how the waveform would look like:
1) START condition + SLAVE address + Write bit + Wait for ACK from I2C slave
2) Transmit 1 byte (Trigger bits + Register address) + Wait for ACK from I2C slave
3) Repeated START condition + SLAVE address + Read bit+ Wait for ACK from I2C slave.
4) Receive data byte from slave + Send ACK from master to slave.
5) Generate STOP condition
Regards,
Manoj
Hi Manoj,
thanks for your reply. I've tried reverting back to the original code. However, only the sensor address in write mode and 0x00 is sent (and acknowledged). No repeated START or anything after step 2 is visible on the bus (and the clock is not pulsed after the 0x00 write). Should all of the waveform steps 1-5 above be generated by the single call to I2C_MasterReceiver()?
Alke,
Should all of the waveform steps 1-5 above be generated by the single call to I2C_MasterReceiver()?
Yes, that right!
In example i2c_ex6_eeprom_interrupt.c, it shows the example of I2C_MasterReceiver function. Here I have 2 address bytes both 0s before I send repeated START to read a byte.
In your case, you need to have EEPROM.NumOfAddrBytes = 1 and set ControlAddr = Trigger bit + Register address and run I2C_MasterReceiver(&EEPROM).
EEPROM.currentHandlePtr = &EEPROM;
EEPROM.SlaveAddr = EEPROM_SLAVE_ADDRESS;
EEPROM.WriteCycleTime_in_us = 10000; //6ms for EEPROM this code was tested
EEPROM.base = I2CA_BASE;
EEPROM.pControlAddr = &ControlAddr;
EEPROM.NumOfAddrBytes = 2;
//Example 2: EEPROM Byte Read
//Make sure 11 is written to EEPROM address 0x0
ControlAddr = 0;
EEPROM.pControlAddr = &ControlAddr;
EEPROM.pRX_MsgBuffer = RX_MsgBuffer;
EEPROM.NumOfDataBytes = 1;
status = I2C_MasterReceiver(&EEPROM);
Regards,
Manoj