Hi everybody,
I'm a beginner in the NXP world and I can't understand a problem that I have with I2C. I'm using the FRDM KL25Z with the NXP gyroscope FXAS21002C. I found a library on the internet and everything it's ok, but I would like to develop my library to enable me to use the OHIBOARD library on gitHub GitHub - ohilab/libohiboard: OHIBoard library . The problem is that I'm not able to send a repeated start as you can see in the picture below. I have checked everything and the only difference I found is that on the internet library I have this line to send a repeated start:
I2C1_C1 |= I2C_C1_RSTA_MASK;
while in the OHILAB there is this one:
I2C_C1_REG(dev->regMap) |= I2C_C1_RSTA_MASK;
I attach the main.c and the library I wrote.
Can anybody help me?
Gianluca.
Original Attachment has been moved to: FXAS21002C.c.zip
Original Attachment has been moved to: FXAS21002C.h.zip
Solved! Go to Solution.
Hello!
Finnaly we have found the solutions!! After a lot of tests we found this post form BlackNight!!! There is an issue in the silicon of KL25!! We have changed the prescaler to 0, and now it works fine!!!
Thanks all for your help!
Just a note: this issue has been known since 2012, why no one solve the problem in the silicon mask?? The freedom that we have bought is recent!!
Thanks again,
Marco
Thank you for your answers,
As you can see in the picture ( Image_2 ) the register is correct, and in pictures Image_3 and Image_4 you can see the all steps I made to read a register which are the same that Hui_Ma suggested.
Have a nice day.
Gianluca
Hi
I checked you using below code at FXAS21002C_getRegister() function in <FXAS21002C.c> file:
Iic_writeByte(dev->device, reg); |
And I checked the Iic_writeByte() function without any delay (wait for I2Cx_S [IICIF] flag was set).
I would recommend customer to add i2c_wait() function after each Iic_writeByte() function called:
If you using I2C interrupt mode, you also need to pending after each Iic_writeByte() function called.
void i2c_wait(I2C_MemMapPtr p)
{
// wait flag
while((p->S & I2C_S_IICIF_MASK)==0)
;
// clear flag
p->S |= I2C_S_IICIF_MASK;
}
After that, you could set the repeated start as expected.
Wish it helps.
Have a great day,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Hui_Ma,
according to your suggestions I copied all I2C function in OHIBOARD library but the result it's the same.
Below you can see the two libraries:
void FXAS21002C_getRegister(FXAS21002C_Device *dev, uint8_t reg, uint8_t *data)
{
uint8_t read = 0;
unsigned char result;
Iic_start(dev->device);
Iic_writeByte(dev->device, dev->addressWrite);
Iic_wait(dev->device);
Iic_writeByte(dev->device, reg);
Iic_wait(dev->device);
Iic_repeatedStart(dev->device);
Iic_writeByte(dev->device, dev->addressRead);
Iic_wait(dev->device);
Iic_enterRXMode(dev->device);
Iic_sendNack(dev->device);
Iic_readByte(dev->device, &read, 0);
Iic_wait(dev->device);
Iic_stop(dev->device);
Iic_readByte(dev->device, &read, 0);
for(uint8_t i=0; i<100; i++)
{
__asm("nop");
}
*data = read;
}
void Iic_start (Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) |= I2C_C1_TX_MASK;
I2C_C1_REG(dev->regMap) |= I2C_C1_MST_MASK;
}
void Iic_repeatedStart (Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) |= I2C_C1_RSTA_MASK;
}
void Iic_stop (Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) &= ~I2C_C1_MST_MASK;
I2C_C1_REG(dev->regMap) &= ~I2C_C1_TX_MASK;
}
void Iic_sendNack (Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) |= I2C_C1_TXAK_MASK;
}
void Iic_sendAck (Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) &= ~I2C_C1_TXAK_MASK;
}
System_Errors Iic_writeByte (Iic_DeviceHandle dev, uint8_t data)
{
I2C_D_REG(dev->regMap) = data;
}
System_Errors Iic_enterRXMode(Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) &= ~I2C_C1_TX_MASK;
}
System_Errors Iic_enterRXMode(Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) &= ~I2C_C1_TX_MASK;
}
System_Errors Iic_readByte (Iic_DeviceHandle dev, uint8_t *data,
Iic_LastByteMode lastByte)
{
*data = (I2C_D_REG(dev->regMap) & 0xFF);
}
System_Errors Iic_wait(Iic_DeviceHandle dev)
{
while((I2C1_S & I2C_S_IICIF_MASK)==0) {} \
I2C1_S |= I2C_S_IICIF_MASK;
}
I really don't understand what is wrong.
Have a great day.
Gianluca.
Hi
I did a test using FRDM-KL25Z board with FRDM-STBC-AGM01 board to read FXAS21002C CTRL_REG0 register value.
Below is my test environment:
The I2C communication signal is below:
There with correct re-start signal.
I also attached my test code for your reference.
Wish it helps.
Have a great day,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi,
I work with Gianluca in this project. We did the same test with libohiboard where we change the I2C function like you but the result is the same!
Below our setup and the result of logic analyzer:
Our code is:
void Iic_start (Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) |= I2C_C1_TX_MASK;
I2C_C1_REG(dev->regMap) |= I2C_C1_MST_MASK;
}
void Iic_repeatedStart (Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) |= I2C_C1_RSTA_MASK;
}
void Iic_stop (Iic_DeviceHandle dev)
{
uint8_t i;
I2C_C1_REG(dev->regMap) &= ~I2C_C1_MST_MASK;
I2C_C1_REG(dev->regMap) &= ~I2C_C1_TX_MASK;
for (i = 0; i < 100; ++i ) __asm ("nop");
}
void Iic_sendNack (Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) |= I2C_C1_TXAK_MASK;
}
void Iic_sendAck (Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) &= ~I2C_C1_TXAK_MASK;
}
void Iic_setReceiveMode (Iic_DeviceHandle dev)
{
I2C_C1_REG(dev->regMap) &= ~I2C_C1_TX_MASK;
}
void Iic_writeByte (Iic_DeviceHandle dev, uint8_t data)
{
/* Set TX mode */
I2C_C1_REG(dev->regMap) |= I2C_C1_TX_MASK;
/* Write the data in the register */
I2C_D_REG(dev->regMap) = data;
}
void Iic_readByte (Iic_DeviceHandle dev, uint8_t *data)
{
/* Read the data in the register */
*data = I2C_D_REG(dev->regMap);
}
void Iic_waitTransfer (Iic_DeviceHandle dev)
{
while((I2C_S_REG(dev->regMap) & I2C_S_IICIF_MASK)==0) {}
I2C_S_REG(dev->regMap) |= I2C_S_IICIF_MASK;
}
bool Iic_getAck (Iic_DeviceHandle dev)
{
if((I2C_S_REG(dev->regMap) & I2C_S_RXAK_MASK) == 0)
return TRUE;
else
return FALSE;
}
and the read register function is:
void FXAS21002C_getRegister(FXAS21002C_Device *dev, uint8_t reg, uint8_t *data)
{
uint8_t read = 0;
Iic_start(OB_IIC0);
Iic_writeByte(OB_IIC0, 0x40);
Iic_waitTransfer(OB_IIC0);
Iic_getAck(OB_IIC0);
Iic_writeByte(OB_IIC0, reg);
Iic_waitTransfer(OB_IIC0);
Iic_getAck(OB_IIC0);
Iic_repeatedStart(OB_IIC0);
Iic_writeByte(OB_IIC0, 0x41);
Iic_waitTransfer(OB_IIC0);
Iic_getAck(OB_IIC0);
Iic_setReceiveMode(OB_IIC0);
Iic_sendNack(OB_IIC0);
Iic_readByte(OB_IIC0, &read);
Iic_waitTransfer(OB_IIC0);
Iic_stop(OB_IIC0);
Iic_readByte(OB_IIC0, &read);
for(uint8_t i=0; i<40; i++)
{
__asm("nop");
}
*data = read;
}
We don't know where is the problem...
Regards
Marco
Hi
In general, the FRDM-KL25Z board PTC8 & PTC9 without external pull up resistors.
Do you have add the external pull up resistor with KL25 PTC8/PTC9 pins?
During my test, I use two 10K pull up resistors connecting with PTC8 and PTC9 pins.
Wish it helps.
Have a great day,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hello!
Finnaly we have found the solutions!! After a lot of tests we found this post form BlackNight!!! There is an issue in the silicon of KL25!! We have changed the prescaler to 0, and now it works fine!!!
Thanks all for your help!
Just a note: this issue has been known since 2012, why no one solve the problem in the silicon mask?? The freedom that we have bought is recent!!
Thanks again,
Marco
Hi
Thank you for the info.
I checked the KL25 errata file of mask set 2N97F with below errata record:
e6070: I2C: Repeat start cannot be generated if the I2Cx_F[MULT] field is set to a nonzero value
Errata type: Errata
Description: If the I2Cx_F[MULT] field is written with a non-zero value, then a repeat start cannot be
generated
Workaround: There are two possible workarounds:
1) Configure I2Cx_F[MULT] to zero if a repeat start has to be generated.
2) Temporarily set I2Cx_F [MULT] to zero immediately before setting the Repeat START bit in the I2C C1 register (I2Cx_C1[RSTA]=1) and restore
Have a great day,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi
That's really strange.
I will check this issue on my site and will let you know when there with any updated info.
Thank you for the patience.
Wish it helps.
Have a great day,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Gianluca,
if this I2C1_C1 |= I2C_C1_RSTA_MASK approach is functional then it should only be problem in access to memory using your approach.
Could you please share your I2C_C1_REG(x) macro definition?
Also please, try look at disassembly if I2C_C1_RSTA_MASK value (should by 8-bit value) is really stored at the correct 0x40067002 address as 8-bit value. Consider that the I2C registers are only 8-bit registers and CM0+ core does not allow unligned access to memory too.
regards
R.
Hi Rastislav,
the macro that I use is:
/** I2C - Register Layout Typedef */
typedef struct {
__IO uint8_t A1; /**< I2C Address Register 1, offset: 0x0 */
__IO uint8_t F; /**< I2C Frequency Divider register, offset: 0x1 */
__IO uint8_t C1; /**< I2C Control Register 1, offset: 0x2 */
__IO uint8_t S; /**< I2C Status register, offset: 0x3 */
__IO uint8_t D; /**< I2C Data I/O register, offset: 0x4 */
__IO uint8_t C2; /**< I2C Control Register 2, offset: 0x5 */
__IO uint8_t FLT; /**< I2C Programmable Input Glitch Filter register, offset: 0x6 */
__IO uint8_t RA; /**< I2C Range Address register, offset: 0x7 */
__IO uint8_t SMB; /**< I2C SMBus Control and Status register, offset: 0x8 */
__IO uint8_t A2; /**< I2C Address Register 2, offset: 0x9 */
__IO uint8_t SLTH; /**< I2C SCL Low Timeout Register High, offset: 0xA */
__IO uint8_t SLTL; /**< I2C SCL Low Timeout Register Low, offset: 0xB */
} I2C_Type, *I2C_MemMapPtr;
#define I2C_C1_REG(base) ((base)->C1)
that is included inside MKL25Z4.h file of KDS.
The disassembly is the following, but I don't understand where I can find the address...
Iic_repeatedStart:
00005694: push {r7, lr}
00005696: sub sp, #8
00005698: add r7, sp, #0
0000569a: str r0, [r7, #4]
346 I2C_C1_REG(dev->regMap) |= I2C_C1_RSTA_MASK;
0000569c: ldr r3, [r7, #4]
0000569e: ldr r2, [r3, #0]
000056a0: ldr r3, [r7, #4]
000056a2: ldr r3, [r3, #0]
000056a4: ldrb r3, [r3, #2]
000056a6: uxtb r3, r3
000056a8: movs r1, #4
000056aa: orrs r3, r1
000056ac: uxtb r3, r3
000056ae: strb r3, [r2, #2]
349 }
000056b0: mov sp, r7
000056b2: add sp, #8
000056b4: pop {r7, pc}
000056b6: nop ; (mov r8, r8)
352 {
Thanks
Gianluca
Hi Gianluca,
I would only recommend to check whether this line access to the correct I2C module based address.
I2C_C1_REG(dev->regMap) |= I2C_C1_RSTA_MASK;
You want to write into the I2C1 module, check whether I2C_C1_REG(dev->regMap) represents the same address as I2C1_C1. I expect that likely you are writting into the I2C0 module instead of I2C1.
regards
R.
Hi
I would recommend customer to refer KL25 bare metal example software [twr-kl25Demo] about I2C application:
There with below code about read sensor value at <hal_dev_mma8451.c> file:
uint8 hal_dev_mma8451_read_reg(uint8 addr)
{
uint8 result;
i2c_start(I2C0_B);
i2c_write_byte(I2C0_B, MMA8451_I2C_ADDRESS | I2C_WRITE);
i2c_wait(I2C0_B);
i2c_get_ack(I2C0_B);
i2c_write_byte(I2C0_B, addr);
i2c_wait(I2C0_B);
i2c_get_ack(I2C0_B);
i2c_repeated_start(I2C0_B);
i2c_write_byte(I2C0_B, MMA8451_I2C_ADDRESS | I2C_READ);
i2c_wait(I2C0_B);
i2c_get_ack(I2C0_B);
i2c_set_rx_mode(I2C0_B);
i2c_give_nack(I2C0_B);
result = i2c_read_byte(I2C0_B);
i2c_wait(I2C0_B);
i2c_stop(I2C0_B);
result = i2c_read_byte(I2C0_B);
pause();
return result;
}
The related I2C driver code located at <hal_i2c.c> file.
Wish it helps.
Have a great day,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------