MAX32655 - I2C driver hangs forever
Hi, I am working with a MAX32655 custom board with 2 I2C devices on the same bus (I2C1). The devices are ADXL343 and MAX31328. After experimenting with the I2C example, I noticed that sometimes the driver would just hang after running for a while.
When trying using the sync function MXC_I2C_MasterTransaction, it would not return. When trying to use the async function MXC_I2C_MasterTransactionAsync or MXC_I2C_MasterTransactionDMA, the interrupt would never come.
Using a logic analyzer, it seems to be a state machine issue with the I2C driver, as sometimes the STOP condition would never happen or the MAX32655 would not send an ACK.
As my board is based on the MAX32655FTHR, I tried to reproduce the issue with the 2 I2C components on the board (the Audio Codec and the PMIC). The main code below, when compiled for the Feather board, hangs. However, if you uncomment lines 124 and 149 (thus printing to the console), then it works.
I could not find a similar issue here with the I2C driver. Have you seen this problem before?
Thank you!
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "mxc_device.h"
#include "mxc_delay.h"
#include "nvic_table.h"
#include "i2c.h"
#include "dma.h"
#include "rtc.h"
#include "wut.h"
#define I2C_FREQ 400000
#define I2C_TCXO_ADDR 0x68
#define I2C_ACCEL_ADDR 0x53
#define I2C_BYTES 8
#define I2C_PMIC_ADDR 0b0101000
#define I2C_CODEC_ADDR 0b0011000
static uint8_t txdata[I2C_BYTES];
static uint8_t rxdata[I2C_BYTES];
volatile int I2C_FLAG;
void I2C_Callback(mxc_i2c_req_t *req, int error)
{
I2C_FLAG = error;
if (error) {
printf("Callback: Error code: %d\n", error);
while(1);
}
}
void I2C1_IRQHandler(void)
{
MXC_I2C_AsyncHandler(MXC_I2C1);
}
int main(void)
{
mxc_i2c_req_t reqMaster;
printf("\n******** I2C MAX31328 Test ********\n");
MXC_Delay(MXC_DELAY_SEC(1));
NVIC_EnableIRQ(I2C1_IRQn);
int error = 0;
if (MXC_I2C_Init(MXC_I2C1, 1, 0) != E_NO_ERROR) {
printf("[ERROR] Could not configure I2C master\n");
return 1;
}
MXC_I2C_SetFrequency(MXC_I2C1, I2C_FREQ);
for (int i = 0; i < 100; i++) {
memset(txdata, 0, I2C_BYTES);
memset(rxdata, 0, I2C_BYTES);
txdata[0] = 0x00;
reqMaster.i2c = MXC_I2C1;
reqMaster.addr = I2C_PMIC_ADDR;
reqMaster.tx_buf = txdata;
reqMaster.tx_len = 1;
reqMaster.rx_buf = rxdata;
reqMaster.rx_len = 1;
reqMaster.restart = 0;
reqMaster.callback = I2C_Callback;
I2C_FLAG = 1;
if ((error = MXC_I2C_MasterTransactionAsync(&reqMaster)) != 0) {
printf("Error writing: %d\n", error);
return error;
}
while(I2C_FLAG);
printf("[%02i] HardwareID: %02x\n", i, rxdata[0]);
// ================================================================ //
memset(txdata, 0, I2C_BYTES);
memset(rxdata, 0, I2C_BYTES);
txdata[0] = 0x01;
reqMaster.i2c = MXC_I2C1;
reqMaster.addr = I2C_PMIC_ADDR;
reqMaster.tx_buf = txdata;
reqMaster.tx_len = 1;
reqMaster.rx_buf = rxdata;
reqMaster.rx_len = 1;
reqMaster.restart = 0;
reqMaster.callback = I2C_Callback;
I2C_FLAG = 1;
if ((error = MXC_I2C_MasterTransactionAsync(&reqMaster)) != 0) {
printf("Error writing: %d\n", error);
return error;
}
while(I2C_FLAG);
printf("[%02i] FirmwareID: %02x\n", i, rxdata[0]);
// ================================================================ //
memset(txdata, 0, I2C_BYTES);
memset(rxdata, 0, I2C_BYTES);
txdata[0] = 0x0F;
reqMaster.i2c = MXC_I2C1;
reqMaster.addr = I2C_PMIC_ADDR;
reqMaster.tx_buf = txdata;
reqMaster.tx_len = 1;
reqMaster.rx_buf = rxdata;
reqMaster.rx_len = 4;
reqMaster.restart = 0;
reqMaster.callback = I2C_Callback;
I2C_FLAG = 1;
if ((error = MXC_I2C_MasterTransactionAsync(&reqMaster)) != 0) {
printf("Error writing: %d\n", error);
return error;
}
while(I2C_FLAG);
// printf("[%02i]\n", i); // UNCOMMENT THIS LINE
// ================================================================ //
memset(txdata, 0, I2C_BYTES);
memset(rxdata, 0, I2C_BYTES);
txdata[0] = 0x17;
txdata[1] = 0x80;
reqMaster.i2c = MXC_I2C1;
reqMaster.addr = I2C_CODEC_ADDR;
reqMaster.tx_buf = txdata;
reqMaster.tx_len = 2;
reqMaster.rx_buf = rxdata;
reqMaster.rx_len = 0;
reqMaster.restart = 0;
reqMaster.callback = I2C_Callback;
I2C_FLAG = 1;
if ((error = MXC_I2C_MasterTransactionAsync(&reqMaster)) != 0) {
printf("Error writing: %d\n", error);
return error;
}
while(I2C_FLAG);
// printf("[%02i]\n", i); // UNCOMMENT THIS LINE
// ================================================================ //
memset(txdata, 0, I2C_BYTES);
memset(rxdata, 0, I2C_BYTES);
txdata[0] = 0x00;
reqMaster.i2c = MXC_I2C1;
reqMaster.addr = I2C_CODEC_ADDR;
reqMaster.tx_buf = txdata;
reqMaster.tx_len = 1;
reqMaster.rx_buf = rxdata;
reqMaster.rx_len = 1;
reqMaster.restart = 0;
reqMaster.callback = I2C_Callback;
I2C_FLAG = 1;
if ((error = MXC_I2C_MasterTransactionAsync(&reqMaster)) != 0) {
printf("Error writing: %d\n", error);
return error;
}
while(I2C_FLAG);
printf("[%02i] Status: %02x\n", i, rxdata[0]);
}
MXC_I2C_Shutdown(MXC_I2C1);
return E_NO_ERROR;
}
This sounds similar to the recently closed #1261
I am not sure that the fix merged in pull request #1263 fixed the issue. I have been meaning to reopen the issue, but I haven't had time to set up a reproducible test case.
I am still/also seeing infinite loops when calling MXC_I2C_RevA_MasterTransaction(), but it moved to a different while loop.
Before the fix in pull request #1263 I saw it hang here: https://github.com/analogdevicesinc/msdk/blob/d2480e18f148a307b1e70ce16b07a4d674ff82b9/Libraries/PeriphDrivers/Source/I2C/i2c_reva.c#L997
After 1263 I now see it hang here: https://github.com/analogdevicesinc/msdk/blob/d2480e18f148a307b1e70ce16b07a4d674ff82b9/Libraries/PeriphDrivers/Source/I2C/i2c_reva.c#L1001
The temporary hack my team has been doing is to replace line 997 in i2c_reva.c with this line:
while (!(i2c->intfl0 & MXC_F_I2C_REVA_INTFL0_STOP)) {}
This brings the behavior back to pre-commit 79c0d9a.
I am not sure if we're doing the perfect thing, but I just thought I'd mention that there is a closed issue describing the same thing, and I don't think the fix committed actually fixed it.
Thank you for the detailed response.
Yes, I saw the issue and the pull request, I thought this was going to solve it, but as you said, this moved to a different loop, so I don't think it solved the problem.
I will try the temporary hack on my side.
Hi, we are trying to squash this bug with a new PR. Any chance one of you could test this out? Seems this issue is related. https://github.com/analogdevicesinc/msdk/pull/1359
Sorry about the delay, I had a chance to test the temporary hack, and it works.