Communicating to a part via I2C

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

My board design uses a MMA8653FC Accelerometer 
I defined an I2C SCB to communicate with it 
Set up the SCL and SDA pins per my board schematic. The part SendStart routine returns no error so I assume the SCB is configured properly 
The part spec describes the single byte register read as follows 

5.8.1 Single-byte read 
1. The transmission of an 8-bit command begins on the falling edge of SCL. After the eight clock cycles are used to send the command, note that the data returned is sent with the MSB first after the data is received. Figure 10 shows the timing diagram for the accelerometer 8-bit I2C read operation. 
2. The Master (or MCU) transmits a start condition (ST) to the MMA8653FC [slave address (0x1D), with the R/W bit set to “0” for a write], and the MMA8653FC sends an acknowledgement. 
3. Next the Master (or MCU) transmits the address of the register to read, and the MMA8653FC sends an acknowledgement. 
4. The Master (or MCU) transmits a repeated start condition (SR) and then addresses the MMA8653FC (0x1D), with the R/W bit set to “1” for a read from the previously selected register. 
5. The Slave then acknowledges and transmits the data from the requested register. The Master does not acknowledge(NAK) the transmitted data, but transmits a stop condition to end the data transfer. 

I'm having trouble translating steps 4 and 5 into code that uses the I2C SCB 
#5 implies that the register must be read immediately after the repeated start is sent. It's not clear how to do this in SCB I2C. 
The Accel_I2CMasterReadByte issued after Accel_I2CMasterWriteBuf returns 0xFF because the check if master is active in Accel_I2CMasterReadByte fails : 
Here is a routine I use

   


byte IIC_RegRead(byte address, byte reg) 

byte b = 0; 
byte repeatStartAddr = (address << 1) | 0x01;  /* slave address 0x1D with the R/W bit set to “1” for a read from the previously selected register. */
status = Accel_I2CMasterSendStart(address,DIR_WRITE); 

if(status == Accel_I2C_MSTR_NO_ERROR) 

Accel_I2CMasterWriteByte(address); // Send IIC "Write" Address 
Accel_I2CMasterWriteByte(reg); // Send Register 

Accel_I2CMasterWriteBuf(address,&repeatStartAddr,1,Accel_I2C_MODE_REPEAT_START); 

   

----These fail
b = Accel_I2CMasterReadByte(GENERATE_ACK); // *** Dummy read: reads "IIC_ReadAddress" value *** 
b = Accel_I2CMasterReadByte(GENERATE_ACK);  /* read the value */
status = Accel_I2CMasterSendStop(); 

return b; 

Your help is much appreciated. 

0 Likes
1 Solution
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

You use

   

byte IIC_RegRead(byte address, byte reg)
{
    byte b = 0;
    byte repeatStartAddr = (address << 1) | 0x01;  /* slave address 0x1D with the R/W bit set to “1” for a read from the previously selected register. */

   


The shifting and ORing of the RnW bit is done by the component, no need for that code.

   

Try this:

   

byte IIC_RegRead(byte address, byte reg)
{
    byte b;
    uint32 status;
    status = Accel_I2CMasterSendStart(address,Accel_I2C_WRITE_XFER_MODE);    //    Request the bus
    if(status == Accel_I2C_MSTR_NO_ERROR)                                    //    When successful
    {
        status = Accel_I2CMasterWriteByte(reg);                                //    Send register to read from
        status = Accel_I2CMasterSendRestart(address,Accel_I2C_READ_XFER_MODE); // Restart to read mode
     
           b = Accel_I2CMasterReadByte(Accel_I2C_NAK_DATA);                    //    Read single byte
        status = Accel_I2CMasterSendStop();                                    //    Relinquish bus
    }
    return b;                                                                //    Return register value
    
}

   

 

   

Bob

View solution in original post

0 Likes
10 Replies