1919 * @author Hauke Petersen <[email protected] > 2020 * @author Dylan Laduranty <[email protected] > 2121 *
22+ * As this implementation is based on the nRF5x TWIM peripheral, it can not
23+ * issue a read following a read (or a write following a write) without
24+ * creating a (repeated) start condition:
25+ * <https://devzone.nordicsemi.com/f/nordic-q-a/66615/nrf52840-twim-how-to-write-multiple-buffers-without-repeated-start-condition>,
26+ * backed also by later experiments discussed in the [Rust embedded
27+ * channel](https://matrix.to/#/!BHcierreUuwCMxVqOf:matrix.org/$JwNejRaeJx_tvqKgS88GenDG8ZNHrkTW09896dIehQ8?via=matrix.org&via=catircservices.org&via=tchncs.de).
28+ * Due to this shortcoming in the hardware, any operations with I2C_NOSTART
29+ * fail.
30+ *
31+ * Relatedly, the successful termination of a read or write can not be detected
32+ * by an interrupt (only the eventual STOPPED condition after the event
33+ * short-circuiting of LASTTX/LASTRX to STOP triggers one). There are LASTTX /
34+ * LASTRX interrupts, but while the LASTTX is sensible enough (the last byte
35+ * has been read, is being written, the caller may now repurpose the buffers),
36+ * the LASTRX interrupt fires at the start of the last byte reading, and the
37+ * user can not reliably know when the last byte was written (at least not
38+ * easily). Therefore, reads with I2C_NOSTOP are not supported.
39+ *
40+ * In combination, these still allow the typical I2C operations: A single
41+ * write, and a write (selecting a register) followed by a read, as well as
42+ * stand-alone reads. More complex patterns are not supported; in particular,
43+ * scatter-gather reads or writes are not possible.
44+ *
2245 * @}
2346 */
2447
@@ -77,13 +100,15 @@ static inline NRF_TWIM_Type *bus(i2c_t dev)
77100 * * TWIM_INTEN_STOPPED_Msk (when a stop condition is to be set and the short
78101 * circuit will pull TWIM into the stopped condition)
79102 * * TWIM_INTEN_LASTTX_Msk (when sending without a stop condition)
80- * * TWIM_INTEN_LASTRX_Msk (when reading without a stop condition)
103+ *
104+ * (TWIM_INTEN_LASTRX_Msk makes no sense here because that interrupt fires
105+ * before the data is ready).
81106 *
82107 * Any addition needs to be added to the mask in i2c_isr_handler.
83108 */
84109static int finish (i2c_t dev , int inten_success_flag )
85110{
86- DEBUG ("[i2c] waiting for success (STOPPED/LAST.X ) or ERROR event\n" );
111+ DEBUG ("[i2c] waiting for success (STOPPED/LASTTX ) or ERROR event\n" );
87112 /* Unmask interrupts */
88113 bus (dev )-> INTENSET = inten_success_flag | TWIM_INTEN_ERROR_Msk ;
89114 mutex_lock (& busy [dev ]);
@@ -251,7 +276,7 @@ int i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len,
251276{
252277 assert ((dev < I2C_NUMOF ) && data && (len > 0 ) && (len < 256 ));
253278
254- if (flags & (I2C_NOSTART | I2C_ADDR10 )) {
279+ if (flags & (I2C_NOSTART | I2C_ADDR10 | I2C_NOSTOP )) {
255280 return - EOPNOTSUPP ;
256281 }
257282 DEBUG ("[i2c] read_bytes: %i bytes from addr 0x%02x\n" , (int )len , (int )addr );
@@ -261,14 +286,8 @@ int i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len,
261286 bus (dev )-> RXD .MAXCNT = (uint8_t )len ;
262287
263288 int inten_success_flag ;
264- if (!(flags & I2C_NOSTOP )) {
265- bus (dev )-> SHORTS = TWIM_SHORTS_LASTRX_STOP_Msk ;
266- inten_success_flag = TWIM_INTEN_STOPPED_Msk ;
267- }
268- else {
269- bus (dev )-> SHORTS = 0 ;
270- inten_success_flag = TWIM_INTEN_LASTRX_Msk ;
271- }
289+ bus (dev )-> SHORTS = TWIM_SHORTS_LASTRX_STOP_Msk ;
290+ inten_success_flag = TWIM_INTEN_STOPPED_Msk ;
272291 /* Start transmission */
273292 bus (dev )-> TASKS_STARTRX = 1 ;
274293
@@ -280,7 +299,7 @@ int i2c_read_regs(i2c_t dev, uint16_t addr, uint16_t reg,
280299{
281300 assert ((dev < I2C_NUMOF ) && data && (len > 0 ) && (len < 256 ));
282301
283- if (flags & (I2C_NOSTART | I2C_ADDR10 )) {
302+ if (flags & (I2C_NOSTART | I2C_ADDR10 | I2C_NOSTOP )) {
284303 return - EOPNOTSUPP ;
285304 }
286305
@@ -301,12 +320,8 @@ int i2c_read_regs(i2c_t dev, uint16_t addr, uint16_t reg,
301320 bus (dev )-> RXD .PTR = (uint32_t )data ;
302321 bus (dev )-> RXD .MAXCNT = (uint8_t )len ;
303322
304- int inten_success_flag = TWIM_INTEN_LASTRX_Msk ;
305- bus (dev )-> SHORTS = (TWIM_SHORTS_LASTTX_STARTRX_Msk );
306- if (!(flags & I2C_NOSTOP )) {
307- bus (dev )-> SHORTS |= TWIM_SHORTS_LASTRX_STOP_Msk ;
308- inten_success_flag = TWIM_INTEN_STOPPED_Msk ;
309- }
323+ int inten_success_flag = TWIM_INTEN_STOPPED_Msk ;
324+ bus (dev )-> SHORTS = TWIM_SHORTS_LASTTX_STARTRX_Msk | TWIM_SHORTS_LASTRX_STOP_Msk ;
310325
311326 /* Start transfer */
312327 bus (dev )-> TASKS_STARTTX = 1 ;
@@ -346,7 +361,7 @@ void i2c_isr_handler(void *arg)
346361 i2c_t dev = (i2c_t )(uintptr_t )arg ;
347362
348363 /* Mask interrupts to ensure that they only trigger once */
349- bus (dev )-> INTENCLR = TWIM_INTEN_STOPPED_Msk | TWIM_INTEN_ERROR_Msk | TWIM_INTEN_LASTTX_Msk | TWIM_INTEN_LASTRX_Msk ;
364+ bus (dev )-> INTENCLR = TWIM_INTEN_STOPPED_Msk | TWIM_INTEN_ERROR_Msk | TWIM_INTEN_LASTTX_Msk ;
350365
351366 mutex_unlock (& busy [dev ]);
352367}
0 commit comments