imxrt master non-blocking transfer issue

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

imxrt master non-blocking transfer issue

Jump to solution
4,950 Views
o00batman00o
Contributor II

Hello,

I use I2C drivers from SDK 2.5 and I have an issue with non-blocking transfer as a master. The callback is called before the end of the transfer and return the wrong status.

To write 34 bytes to an I2C EEPROM memory (microchip 24AA02), I make 5 I2C transfers. 4 times 8 bytes + 2 bytes. After each transfer the memory replies with a NAK until write cycle is done.

Step1: At first transfer of 8 bytes, the callback is called after the stop bit detection with status =  kStatus_Success.

Step2: At second transfer, the callback is called on NAK detection (before stop bit detection) with status =  kStatus_LPI2C_Nak.

Step3: After several retry with NAK response, the callback is called 4 bytes before the stop bit with status =  kStatus_Success.

Step 4: Step2 and Step3 are repeated for others 8 bytes transfers.

Step 5: Last transfer of 2 bytes, the callback is called without sending any data with status =  kStatus_Success instead of kStatus_LPI2C_Nak.

In step5, commands are written to the FIFO then the state machine wait for the stop bit detection. But because the stop bit of the previous transfer is detected after that this transfer has been initiated, the callback retuns the wrong status and the data are never transmitted.

I attached some capture of this issue. The blue trace is a GPIO that is set when the transfer is initiated and cleared when the callback is called.

4th_tranfer.png

Note: In LPI2C_RTOS_Transfer(), handle->async_status should be saved in status variable before unlocking the resource mutex. A task with higher priority may overwrite handle->async_status.

BR

Anthony

0 Kudos
Reply
1 Solution
4,662 Views
jorge_a_vazquez
NXP Employee
NXP Employee

Hi Anthony SIEGRIST

SDK drivers are not implemented to work with Nak, so every time it received a NAK, the driver will identify this as an error and it will return. So, If your memory will answer with a specific protocol (sending NAK) I would recommend to implement your own state machine driver, you could use Interrupt example (without transfer drivers) ad handle the different events.

Best regards

Jorge Alcala

View solution in original post

0 Kudos
Reply
3 Replies
4,663 Views
jorge_a_vazquez
NXP Employee
NXP Employee

Hi Anthony SIEGRIST

SDK drivers are not implemented to work with Nak, so every time it received a NAK, the driver will identify this as an error and it will return. So, If your memory will answer with a specific protocol (sending NAK) I would recommend to implement your own state machine driver, you could use Interrupt example (without transfer drivers) ad handle the different events.

Best regards

Jorge Alcala

0 Kudos
Reply
4,662 Views
o00batman00o
Contributor II

Hi Jorge,

OK. From the comments in LPI2C_MasterCheckAndClearError(), I understood that a stop is automatically sent when an error is detected. In fact, I see that the clock stays low until a new transfer is initiated.

I finally found the solution below. I ask for a stop when the transfer does not success. This way it works as expected (The right status is returned when the transfer on the bus is done ).

BR

wStatus = LPI2C_MasterTransferNonBlocking(apDrvHandle->mpBase, &apDrvHandle->mFslDrvHandle, apMasterTransfer);

if (wStatus == kStatus_Success)

{

     /* Wait for transfer to finish */

     xSemaphoreTake(apDrvHandle->mSemaphore, portMAX_DELAY);

     /* Return status captured by callback function */

     wStatus = apDrvHandle->mAsyncStatus;

}

/* If an error occured, send the stop command */

if(kStatus_Success != wStatus)

{

     LPI2C_MasterStop(apDrvHandle->mpBase); // Take about 4us @400kHz

}

0 Kudos
Reply
4,662 Views
o00batman00o
Contributor II

Hello,

My previous workaround works only if LPI2C_MasterStop() is called quickly after that error show up. If not, the bus stalls and you will get FIFO error when calling LPI2C_MasterStop().

I finally found and solved my issue.

LPI2C_MasterTransferNonBlocking() and LPI2C_MasterTransferBlocking() clear the AUTOSTOP bit.
Then in case of error, LPI2C_MasterCheckAndClearError() reset the FIFOs.
According to comments in LPI2C_MasterCheckAndClearError(), a stop is automatically sent in case of error. It is WRONG because the AUTOSTOP has been cleared. The bus will stall after few controller clock as explained in the reference manual in chapter 37.3.3.2. 


The only solution to avoid or escape the bus stall is to set the AUTOSTOP bit again. A stop bit will be generated and you can wait on it to get the real transfer end.

BR

0 Kudos
Reply