aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Kühling <mail@simonkuehling.de>2021-09-03 20:58:22 +0200
committerKevinOConnor <kevin@koconnor.net>2021-10-06 21:27:51 -0400
commitd90da37433634b93ac0bc6efebee9cf39c928880 (patch)
treeb650f485e3b14ab236a5dffcf0559314f4d68cf5 /src
parent2822680eb453656673931eff5c5f3a8bd37df63a (diff)
downloadkutter-d90da37433634b93ac0bc6efebee9cf39c928880.tar.gz
kutter-d90da37433634b93ac0bc6efebee9cf39c928880.tar.xz
kutter-d90da37433634b93ac0bc6efebee9cf39c928880.zip
atsamd: Add i2c_read() implementation
Signed-off-by: Simon Kühling <mail@simonkuehling.de>
Diffstat (limited to 'src')
-rw-r--r--src/atsamd/i2c.c44
1 files changed, 43 insertions, 1 deletions
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;
+ }
}