Skip to content

Commit

Permalink
cpu/nrf5x i2c: Set up correct interrupts after NOSTOP transmissions
Browse files Browse the repository at this point in the history
  • Loading branch information
chrysn committed Jan 22, 2024
1 parent 504c169 commit b91161d
Showing 1 changed file with 28 additions and 7 deletions.
35 changes: 28 additions & 7 deletions cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,23 @@ static inline NRF_TWIM_Type *bus(i2c_t dev)
return i2c_config[dev].dev;
}

static int finish(i2c_t dev)
/**
* Block until the interrupt described by inten_success_flag or
* TWIM_INTEN_ERROR_Msk fires.
*
* Allowed values for inten_success_flag are
* * TWIM_INTEN_STOPPED_Msk (when a stop condition is to be set and the short
* circuit will pull TWIM into the stopped condition)
* * TWIM_INTEN_LASTTX_Msk (when sending without a stop condition)
* * TWIM_INTEN_LASTRX_Msk (when reading without a stop condition)
*
* Any addition needs to be added to the mask in i2c_isr_handler.
*/
static int finish(i2c_t dev, int inten_success_flag)
{
DEBUG("[i2c] waiting for STOPPED or ERROR event\n");
DEBUG("[i2c] waiting for success (STOPPED/LAST.X) or ERROR event\n");
/* Unmask interrupts */
bus(dev)->INTENSET = TWIM_INTEN_STOPPED_Msk | TWIM_INTEN_ERROR_Msk;
bus(dev)->INTENSET = inten_success_flag | TWIM_INTEN_ERROR_Msk;
mutex_lock(&busy[dev]);

if ((bus(dev)->EVENTS_STOPPED)) {
Expand Down Expand Up @@ -248,16 +260,19 @@ int i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len,
bus(dev)->RXD.PTR = (uint32_t)data;
bus(dev)->RXD.MAXCNT = (uint8_t)len;

int inten_success_flag;
if (!(flags & I2C_NOSTOP)) {
bus(dev)->SHORTS = TWIM_SHORTS_LASTRX_STOP_Msk;
inten_success_flag = TWIM_INTEN_STOPPED_Msk;
}
else {
bus(dev)->SHORTS = 0;
inten_success_flag = TWIM_INTEN_LASTRX_Msk;
}
/* Start transmission */
bus(dev)->TASKS_STARTRX = 1;

return finish(dev);
return finish(dev, inten_success_flag);
}

int i2c_read_regs(i2c_t dev, uint16_t addr, uint16_t reg,
Expand Down Expand Up @@ -285,15 +300,18 @@ int i2c_read_regs(i2c_t dev, uint16_t addr, uint16_t reg,
bus(dev)->TXD.PTR = (uint32_t)®
bus(dev)->RXD.PTR = (uint32_t)data;
bus(dev)->RXD.MAXCNT = (uint8_t)len;

int inten_success_flag = TWIM_INTEN_LASTRX_Msk;
bus(dev)->SHORTS = (TWIM_SHORTS_LASTTX_STARTRX_Msk);
if (!(flags & I2C_NOSTOP)) {
bus(dev)->SHORTS |= TWIM_SHORTS_LASTRX_STOP_Msk;
inten_success_flag = TWIM_INTEN_STOPPED_Msk;
}

/* Start transfer */
bus(dev)->TASKS_STARTTX = 1;

return finish(dev);
return finish(dev, inten_success_flag);
}

int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len,
Expand All @@ -309,23 +327,26 @@ int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len,
bus(dev)->ADDRESS = addr;
bus(dev)->TXD.PTR = (uint32_t)data;
bus(dev)->TXD.MAXCNT = (uint8_t)len;
int inten_success_flag;
if (!(flags & I2C_NOSTOP)) {
bus(dev)->SHORTS = TWIM_SHORTS_LASTTX_STOP_Msk;
inten_success_flag = TWIM_INTEN_STOPPED_Msk;
}
else {
bus(dev)->SHORTS = 0;
inten_success_flag = TWIM_INTEN_LASTTX_Msk;
}
bus(dev)->TASKS_STARTTX = 1;

return finish(dev);
return finish(dev, inten_success_flag);
}

void i2c_isr_handler(void *arg)
{
i2c_t dev = (i2c_t)(uintptr_t)arg;

/* Mask interrupts to ensure that they only trigger once */
bus(dev)->INTENCLR = TWIM_INTEN_STOPPED_Msk | TWIM_INTEN_ERROR_Msk;
bus(dev)->INTENCLR = TWIM_INTEN_STOPPED_Msk | TWIM_INTEN_ERROR_Msk | TWIM_INTEN_LASTTX_Msk | TWIM_INTEN_LASTRX_Msk;

mutex_unlock(&busy[dev]);
}

0 comments on commit b91161d

Please sign in to comment.