Summary: I recently began firmware programming and am working on a new design that uses the KL27 Kinetis MCU. There are two other chips on this board that the MCU needs to communicate with via I2C: one is located at 0x80 and the other at 0x30.
The Problem: Whenever we write to the address 0x80 or 0x30, our oscilloscope reads everything perfectly, and this is proven by our design working. But only when we use I2C_WriteRegister. I2C_ReadRegister however has NACK (No Acknowledge) around the data that is supposed to be returned. I've been trying to solve this for the past week and cannot find this issue anywhere with the KL27.
IC2.c
//#include "derivative.h"
#include "system_MKL27Z4.h"
#include "I2C.h"
void I2C_init(void)
{
SIM->SCGC5 |= SIM_SCGC5_PORTB_MASK; /* PORTB Clocks */
SIM->SCGC4 |= SIM_SCGC4_I2C0_MASK; /* I2C0 Clocks */
// configure GPIO for I2C function
PORTB->PCR[0] = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;
PORTB->PCR[1] = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;
// I2C0->C2 |= I2C_C2_HDRS_MASK;
I2C0->F = 0x14; // baudrate (page 589)
I2C0->C1 |= 0x80; // enable IIC
}
void I2C_WriteRegister(unsigned char u8SlaveAddress, unsigned char u8RegisterAddress, /*unsigned*/ char u8Data)
{
I2C_Start();
I2C0_D = u8SlaveAddress; /* Send I2C device address with W/R bit = 0 */
I2C_Wait();
I2C0_D = u8RegisterAddress; /* Send register address */
I2C_Wait();
I2C0_D = u8Data; /* Send the data */
I2C_Wait();
I2C_Stop();
Pause(50);
}
unsigned char I2C_ReadRegister(unsigned char u8SlaveAddress, unsigned char u8RegisterAddress)
{
unsigned char result;
I2C_Start();
I2C0_D = u8SlaveAddress; /* Send I2C device address with W/R bit = 0 */
I2C_Wait();
I2C0_D = u8RegisterAddress; /* Send register address */
I2C_Wait();
I2C_RepeatedStart();
// while((I2C0_S2 & I2C_S2_EMPTY_MASK) == 0);
// I2C0_D = (u8SlaveAddress ) | 0x01; /* Send I2C device address this time with W/R bit = 1 */
I2C0_D = (u8RegisterAddress ) | 0x01;
I2C_Wait();
I2C_EnterRxMode();
I2C_DisableAck();
result = I2C0_D;
I2C_Wait();
I2C_Stop();
result = I2C0_D;
Pause(50);
return result;
}
void I2C_ReadMultiRegisters(unsigned char u8SlaveAddress, unsigned char u8RegisterAddress, unsigned char n, unsigned char *r)
{
char i;
I2C_Start();
I2C0_D = u8SlaveAddress ; /* Send I2C device address with W/R bit = 0 */
I2C_Wait();
I2C0_D = u8RegisterAddress; /* Send register address */
I2C_Wait();
I2C_RepeatedStart();
I2C0_D = (u8SlaveAddress) | 0x01; /* Send I2C device address this time with W/R bit = 1 */
I2C_Wait();
I2C_EnterRxMode();
I2C_EnableAck();
i = I2C0_D;
I2C_Wait();
for(i=0; i<n-2; i++)
{
*r = I2C0_D;
r++;
I2C_Wait();
}
I2C_DisableAck();
*r = I2C0_D;
r++;
I2C_Wait();
I2C_Stop();
*r = I2C0_D;
Pause(50);
}
void Pause(int number)
{
int cnt;
for(cnt=0; cnt<number; cnt++)
{
__nop();//asm("nop");
};
}
I2C.h
#include "system_MKL27Z4.h"
#include "MKL27Z4.h"
#ifndef I2C_H_
#define I2C_H_
#define I2C_DisableAck() I2C0_C1 |= I2C_C1_TXAK_MASK // 0000 0000 | 0000 1000
#define I2C_EnableAck() I2C0_C1 &= ~I2C_C1_TXAK_MASK // 0000 1000 & 1111 0111
#define I2C_RepeatedStart() I2C0_C1 |= I2C_C1_RSTA_MASK // 0000 0000 | 0000 0100
#define I2C_EnterRxMode() I2C0_C1 &= ~I2C_C1_TX_MASK // 0000 0000 | 0001 0000
#define I2C_write_byte(data) I2C0_D = data
#define I2C_Start() I2C0_C1 |= I2C_C1_TX_MASK;\
I2C0_C1 |= I2C_C1_MST_MASK
#define I2C_Stop() I2C0_C1 &= ~I2C_C1_MST_MASK;\
I2C0_C1 &= ~I2C_C1_TX_MASK
#define I2C_Wait() while((I2C0_S & I2C_S_IICIF_MASK)==0) {} \
I2C0_S |= I2C_S_IICIF_MASK; \
while((I2C0_S2 & I2C_S2_EMPTY_MASK) == 0)
void I2C_init(void);
void I2C_WriteRegister(unsigned char u8SlaveAddress, unsigned char u8RegisterAddress, /*unsigned*/ char u8Data);
unsigned char I2C_ReadRegister(unsigned char u8SlaveAddress, unsigned char u8RegisterAddress);
void I2C_ReadMultiRegisters(unsigned char u8SlaveAddress, unsigned char u8RegisterAddress, unsigned char n, unsigned char *r);
void Pause(int number);
#endif /* I2C_H_*/
Hi Max,
I would recommend customer to check the similar issue from below link:
I2C write register stuck at i2c_Wait() K60N512
And customer could find FRDM-KL26Z board demo (hal_dev_mma8451_read_reg function at <hal_dev_mma8451.c>), which also provides KL26 read MMA8451 sensor value via I2C.
Wish it helps.
Have a great day,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------