I2C slave mode on KL02Z with processor expert and Kinetis I2C2_LDD

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

I2C slave mode on KL02Z with processor expert and Kinetis I2C2_LDD

1,729 次查看
georgeaddison
Contributor I

Hi all,

I am using an MKL02Z32VFM4 micro-controller for my project, programming it through the KDS (3.2.0) and PE (3.0.2.b151214). I am using the Kinetis I2C2_LDD component for I2C communications, set to slave mode, running at 93.623kHz at address 0x2A. However, I am not entirely sure how to use the component when it comes to implementing my code. When a master tries writing data to the slave, it enters the I2C2_OnSlaveRxRequest() function in Events.c. I then try receiving the data with:

res = I2C2_SlaveReceiveBlock(&deviceData, &data, 1U);

if (res != ERR_OK) {

     return ERR_FAILED;

}

but every time I2C2_SlaveReceiveBlock() returns 0x08, which is ERR_BUSY /*!< Device is busy. */

Do I need to generate an acknowledgement of the master addressing the slave before attempting to read the data? And if so, how would I go about doing this? I feel as though I am missing some steps here, can anyone point me in the right direction?

Many thanks,

George

标签 (1)
标记 (3)
0 项奖励
回复
3 回复数

900 次查看
marek_neuzil
NXP Employee
NXP Employee

Hello George,

You must use (call) the I2C2_SlaveReceiveBlock() before the data are being received, i.e. this method sets pointer to your buffer for storing data. See the following example the is available on the Typical Usage page of the I2C_LDD component help.

Please note, that the data are received in the buffer when the I2C3_OnSlaveBlockReceived() event is invoked.

volatile bool DataReceivedFlg = FALSE;

volatile bool DataTransmittedFlg = FALSE;

uint8_t OutData[4] = {0x00U, 0x01U, 0x02U, 0x03U}; /* Initialization of output data buffer */

uint8_t InpData[4];

LDD_TError Error;

LDD_TDeviceData *MyI2CPtr;

void main(void)

{

  . . .

  MyI2CPtr = I2C2_Init(NULL); /* Initialization of I2C2 component */

  Error = I2C2_SlaveSendBlock(MyI2CPtr, OutData, 4U); /* Send OutData (4bytes) to I2C BUS */

  while (!DataTransmittedFlg) { /* Wait until OutData are transmitted */

  }

  DataTransmittedFlg = FALSE;

  Error = I2C2_SlaveReceiveBlock(MyI2CPtr, InpData, 4U); /* Receive InpData (16bytes) from I2C BUS */

  while (!DataReceivedFlg) { /* Wait until InpData are received */

  }

  DataReceivedFlg = FALSE;

  for(;;) {}

}

Content of Event.c:

extern volatile bool DataTransmittedFlg;
void I2C3_OnSlaveBlockSent(LDD_TUserData *UserDataPtr)
{
  DataTransmittedFlg = TRUE; /* Set DataTransmittedFlg flag */
}

extern volatile bool DataReceivedFlg;
void I2C3_OnSlaveBlockReceived(LDD_TUserData *UserDataPtr)
{
  DataReceivedFlg = TRUE; /* Set DataReceivedFlg flag */
}

Best Regards,

Marek Neuzil

900 次查看
georgeaddison
Contributor I

Hi Marek,

This is great, thank you very much for showing me this. I confess I was unaware of the component help feature, this will certainly make my life a lot easier!

The example given in the component help does indeed work as expected, however my only confusion now is, this example seems to rely on the slave knowing exactly when to receive the data? If the master is requesting to read or write data to the slave at arbitrary times, I would like to be able to be able to respond to an interrupt when the slave is addressed. When the master writes the slaves address, followed by the write bit, the I2C2_OnSlaveRxRequest() is called. I assumed I could then use this to trigger the beginning of the slave's receipt of the data, but as mentioned in the description of this event:

After the return from the event call the first data byte receiving starts

So presumably I cannot receive data until that function has returned. I tried setting a flag here to tell another function when to start receiving data, but then that flag must be constantly polled, which rather defeats the purpose of interrupts.

So my question boils down to, how do I know when to call I2C2_SlaveReceiveBlock() if the master is addressing the slave at an unknown time intervals?

I suspect this is due to my lack of programming knowledge, so sorry if this is a silly question. Thanks again for your help,

George

0 项奖励
回复

900 次查看
marek_neuzil
NXP Employee
NXP Employee

Hello George,

In your case you can directly use the event I2C2_SlaveReceiveBlock() to process the received data (you needn't wait for a flag in a loop). E.g. you can use this event to copy these received data into another buffer for processing, you can wakeup a task (in case of a RTOS is used) or do another action based on received data.

Therefore, in you application, you can prepare a buffer for receiving data by using the I2C2_SlaveReceiveBlock() method of the I2C component (in a main function/task). This method just prepare buffer for the data and the application can run (it is not a blocking method). When the I2C interrupt occurs the enabled events (I2C2_OnSlaveRxRequest, I2C2_SlaveReceiveBlock) are subsequently called and you can use these events to trigger or process an action.

Best Regards,

Marek Neuzil

0 项奖励
回复