diff --git a/src/atsamd/i2c.c b/src/atsamd/i2c.c index a5c128cc..0a920d85 100644 --- a/src/atsamd/i2c.c +++ b/src/atsamd/i2c.c @@ -102,5 +102,47 @@ void i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg , uint8_t read_len, uint8_t *read) { - shutdown("i2c_read not supported on samd21"); + SercomI2cm *si = (SercomI2cm *)config.si; + + // start in write mode and write register if provided + if(reg_len) { + // start in write mode + si->ADDR.reg = config.addr; + while (!(si->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB)); + + // write registers + while (reg_len--){ + si->DATA.reg = *reg++; + while (!(si->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB)); + } + } + + // start with read bit enabled + si->ADDR.reg = (config.addr | 0x1); + + // read bytes from slave + while (read_len--){ + while (!(si->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)); + + if (read_len){ + // set ACK response + si->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; + while (si->SYNCBUSY.bit.SYSOP); + + // execute ACK succeded by byte read + si->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(2); + while (si->SYNCBUSY.bit.SYSOP); + } else { + // set NACK response + si->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; + while (si->SYNCBUSY.bit.SYSOP); + + // execute NACK succeded by stop condition + si->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); + while (si->SYNCBUSY.bit.SYSOP); + } + + // read received data byte + *read++ = si->DATA.reg; + } }