I'm working on a project using the Pico and a Microchip MCP23017 i2c GPIO expander and I'm running into a problem when I try to read any register on the MCP23017. This manifests as the Pico eventually hanging when the i2c_read_blocking() function executes and the only option to recover is to reboot the Pico. The hang doesn't occur immediately and can take anywhere up to 10 minutes to manifest.
Having dug in to the C/C++ SDK and the i2c_read_blocking_internal() function, there's nothing obvious to suggest what the cause may be. The only thing that I can think of is that the serial clock timing is slightly out of kilter and the slave device is holding the SDA line low and therefore the portion of the read blocking code is where the hang appears to occur. Unfortunately, I don't have an analyser with which to check this theory
So, I guess my question is:-
Has anyone encountered/experienced this issue and if you managed to resolve it, what was the resolution?
The code I'm running whilst trying to troubleshoot this problem is fairly simplistic and is shown below (compiled against SDK 1.5.1):-
Having dug in to the C/C++ SDK and the i2c_read_blocking_internal() function, there's nothing obvious to suggest what the cause may be. The only thing that I can think of is that the serial clock timing is slightly out of kilter and the slave device is holding the SDA line low and therefore the portion of the read blocking code
Code:
*dst++ = (uint8_t) i2c->hw->data_cmd;
So, I guess my question is:-
Has anyone encountered/experienced this issue and if you managed to resolve it, what was the resolution?
The code I'm running whilst trying to troubleshoot this problem is fairly simplistic and is shown below (compiled against SDK 1.5.1):-
Code:
#define MCP23017_ADDR 0x20int I2C_WriteReg8(i2c_inst_t * _block, int _addr, uint8_t _reg, uint8_t _value){int result; uint8_t reg = _reg;uint8_t command[] = {reg, _value };result = i2c_write_blocking(_block, _addr, (uint8_t *)&command, 2, false);if (result < 0){return (PICO_ERROR_GENERIC);}return PICO_ERROR_NONE;}int I2C_WriteReg16(i2c_inst_t * _block, int _addr, uint8_t _reg, int _value){int result;uint8_t reg = _reg;uint8_t command[] = { reg, (uint8_t)(_value & 0xff), (uint8_t)((_value >> 8) & 0xff) };result = i2c_write_blocking(_block, _addr, (uint8_t *) &command, 3, false);if (result == PICO_ERROR_GENERIC){return (result);}return PICO_ERROR_NONE;}int I2C_ReadReg8(i2c_inst_t * _block, int _addr, uint8_t _reg){uint8_t buffer = 0;uint8_t reg = _reg;int result, ctr, bytes;uint8_t command[] = { _addr, reg };result = i2c_write_blocking(_block, _addr, &_reg, 1, true);if (result == PICO_ERROR_GENERIC){return (result);}result = i2c_read_blocking(_block, _addr, (uint8_t *)&buffer, 1, false);if (result < 0){return result;}return buffer;}int I2C_ReadReg16(i2c_inst_t * _block, int _addr, uint8_t _reg){uint8_t buffer[2] = { 0, 0 };int result;result = i2c_write_blocking(_block, _addr, &_reg, 1, true);if (result == PICO_ERROR_GENERIC){return result;}result = i2c_read_blocking(_block, _addr, (uint8_t *)&buffer, 2, false);if (result < 0){return result;}return (buffer[1] << 8) + buffer[0];bool StartMCP23017(int _addr){int retVal;retVal = I2C_WriteReg8(i2c0, _addr, IOCON, MCP_SEQOP_DISABLE);if (retVal < 0)return (false);retVal = I2C_WriteReg16(i2c0, _addr, INTCONA, 0x0000);// disable the interrupt line for nowif (retVal < 0)return (false);retVal = I2C_WriteReg8(i2c0, _addr, IODIRA, 0xff);// set all pins to i/pif (retVal < 0)return (false);retVal = I2C_WriteReg8(i2c0, _addr, IODIRB, 0xff);// set all pins to i/pif (retVal < 0)return (false);retVal = I2C_WriteReg8(i2c0, _addr, GPPUA, 0xff);// enable the pullupsif (retVal < 0)return (false);retVal = I2C_WriteReg8(i2c0, _addr, GPPUB, 0xff);// enable the pullupsif (retVal < 0)return (false);/* NOTE - disabled the interrupts */retVal = I2C_WriteReg8(i2c0, _addr, GPINTENA, 0x00);if (retVal < 0)return (false);retVal = I2C_WriteReg8(i2c0, _addr, INTCONB, 0x00);// interrupt on change/compare against previous stateif (retVal < 0)return (false);retVal = I2C_WriteReg8(i2c0, _addr, DEFVALB, 0x00);// clear the default values registerif (retVal < 0)return (false);/* NOTE - disabled the interrupts for now*/retVal = I2C_WriteReg8(i2c0, _addr, GPINTENB, 0x00);if (retVal < 0)return (false);return (true);}int main(){bool errCode = false;int regVal;// register read return valuei2c_init(i2c0, 400000);// set the i2c baudrategpio_set_function(12, GPIO_FUNC_I2C);gpio_set_function(13, GPIO_FUNC_I2C);gpio_pull_up(12);gpio_pull_up(13);if (!StartMCP23017(MCP23017_ADDR))errCode = true;while (!errCode){registerValA = I2C_ReadReg8(i2c0, MCP23017_ADDR, GPIOA);sleep_ms(500);}}
Statistics: Posted by swgrainger1960 — Tue Mar 05, 2024 10:11 pm — Replies 2 — Views 47