- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Solved! Go to Solution.
- Labels:
-
BLE
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you can post a minimum bundle of the workspace containing the code in question, that would help us out to debug it;
Here is an example project that uses the I2C SCB Master: http://www.cypress.com/documentation/code-examples/ce95363-i2c-master-using-serial-communication-blo...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK, I updated my read code to use read/write buffer routines as in the sample.
I am getting data but not what I expect. The read is expected to return the device ID (0x5A) but it does not.
Any ideas ?
Thanks
byte buf[4];
byte addrWReadBitSet = (address << 1) | 0x01; /* slave address 0x1D with the R/W bit set to “1” for a read from the previously selected register. */
buf[0] = address;
buf[1] = reg;
//Write the address and the register. Don't generate stop
Accel_I2CMasterWriteBuf(address, buf, 2, Accel_I2C_MODE_NO_STOP);
while (0u == (Accel_I2CMasterStatus() & Accel_I2C_MSTAT_WR_CMPLT))
{
/* Waits until master completes write transfer */
}
//Generate repeat start and write the device address with the read bit set
Accel_I2CMasterWriteBuf(address, &addrWReadBitSet, 1, Accel_I2C_MODE_REPEAT_START);
while (0u == (Accel_I2CMasterStatus() & Accel_I2C_MSTAT_WR_CMPLT))
{
/* Waits until master completes write transfer */
}
// now read the data
memset(buf, 0, sizeof(buf));
Accel_I2CMasterReadBuf(address, buf, sizeof(buf),Accel_I2C_MODE_COMPLETE_XFER);
// (void) Accel_I2CMasterReadBuf(address, buf, sizeof(buf),Accel_I2C_MODE_COMPLETE_XFER);
while (0u == (Accel_I2CMasterStatus() & Accel_I2C_MSTAT_RD_CMPLT))
{
/* Waits until master complete read transfer */
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It worked! Thank you so much
On to the next problem 🙂
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok, here is the next problem
I can now do a single byte read and get the device ID but write does not seem to work.
No error is returned from SCB routines but if I write a non zero value and read it back a zero is returned.
I realize this could be a board issue but looking at my write routine, does anything seem incorrect ?
void IIC_RegWrite(byte address, byte reg,byte val)
{
Accel_I2CMasterSendStart(address,Accel_I2C_WRITE_XFER_MODE);
Accel_I2CMasterWriteByte(address); // Send IIC "Write" Address
Accel_I2CMasterWriteByte(reg); // Send Register
Accel_I2CMasterWriteByte(val);// Send Value
Accel_I2CMasterSendStop(); // Send Stop
}
To test : The line below writes a 1 to the device control register 1
IIC_RegWrite(SlaveAddressIIC, CTRL_REG1, 1);
Read it back:
n = IIC_RegRead(SlaveAddressIIC, CTRL_REG1);
n is zero.
Thanks
Andy
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Delete the line
Accel_I2CMasterWriteByte(address); // Send IIC "Write" Address
You must not send the device address, this is done automatically by the SendStart() API
Bob
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
That was it
Now I can read data !
Thank you Bob!
On to the next problem 🙂
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am trying to do a very similar thing. I have a SI7021 humidity and temp sensor and a Pioneer BLE board and cannot get anything going. Can you share your solution? I am banging my head against a wall on this. I have the adafruit si7021 sensor and can read it just fine from a teensy running the basic example from here: https://github.com/adafruit/Adafruit_Si7021. I cannot seem to get the i2c bus on the pioneer board talking, though. When I scope it I get random cycles but no i2c comms. What am I missing?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Before you can read and write you need to call I2CM_I2CMasterSendStart and I2CM_I2CMasterSendStop when you're done
Check the return result of I2CM_I2CMasterSendStart - and only proceed with a read or write if there was no error
Another thing is that your code just calls I2CM_I2CMasterReadBuf to read the data. Maybe that's how your part works
In my case the part spec defines a process that has to be followed,i.e to do a read, you first have to do a write to the "read" register to tell the part which register you want to read from , then send a restart (I2CM_I2CMasterSendRestart()) and then do the read