Skip to content

Commit c4e58ea

Browse files
committed
stmhal/i2c: Add option to I2C to enable/disable use of DMA transfers.
New keyword option in constructor and init() method is "dma=<bool>". DMA is now disabled by default for I2C transfers because it currently does not handle I2C bus errors very well (eg if slave device doesn't ACK or NACK correctly during a transfer).
1 parent e6da6a7 commit c4e58ea

File tree

3 files changed

+40
-21
lines changed

3 files changed

+40
-21
lines changed

docs/library/pyb.I2C.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,17 @@ Methods
9292

9393
.. only:: port_pyboard
9494

95-
.. method:: I2C.init(mode, \*, addr=0x12, baudrate=400000, gencall=False)
95+
.. method:: I2C.init(mode, \*, addr=0x12, baudrate=400000, gencall=False, dma=False)
9696

9797
Initialise the I2C bus with the given parameters:
9898

9999
- ``mode`` must be either ``I2C.MASTER`` or ``I2C.SLAVE``
100100
- ``addr`` is the 7-bit address (only sensible for a slave)
101101
- ``baudrate`` is the SCL clock rate (only sensible for a master)
102102
- ``gencall`` is whether to support general call mode
103+
- ``dma`` is whether to allow the use of DMA for the I2C transfers (note
104+
that DMA transfers have more precise timing but currently do not handle bus
105+
errors properly)
103106

104107
.. method:: I2C.is_ready(addr)
105108

stmhal/i2c.c

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ typedef struct _pyb_i2c_obj_t {
109109
I2C_HandleTypeDef *i2c;
110110
const dma_descr_t *tx_dma_descr;
111111
const dma_descr_t *rx_dma_descr;
112+
bool *use_dma;
112113
} pyb_i2c_obj_t;
113114

114115
#if defined(MICROPY_HW_I2C1_SCL)
@@ -121,21 +122,23 @@ I2C_HandleTypeDef I2CHandle2 = {.Instance = NULL};
121122
I2C_HandleTypeDef I2CHandle3 = {.Instance = NULL};
122123
#endif
123124

125+
STATIC bool pyb_i2c_use_dma[3];
126+
124127
STATIC const pyb_i2c_obj_t pyb_i2c_obj[] = {
125128
#if defined(MICROPY_HW_I2C1_SCL)
126-
{{&pyb_i2c_type}, &I2CHandle1, &dma_I2C_1_TX, &dma_I2C_1_RX},
129+
{{&pyb_i2c_type}, &I2CHandle1, &dma_I2C_1_TX, &dma_I2C_1_RX, &pyb_i2c_use_dma[0]},
127130
#else
128-
{{&pyb_i2c_type}, NULL, NULL, NULL},
131+
{{&pyb_i2c_type}, NULL, NULL, NULL, NULL},
129132
#endif
130133
#if defined(MICROPY_HW_I2C2_SCL)
131-
{{&pyb_i2c_type}, &I2CHandle2, &dma_I2C_2_TX, &dma_I2C_2_RX},
134+
{{&pyb_i2c_type}, &I2CHandle2, &dma_I2C_2_TX, &dma_I2C_2_RX, &pyb_i2c_use_dma[1]},
132135
#else
133-
{{&pyb_i2c_type}, NULL, NULL, NULL},
136+
{{&pyb_i2c_type}, NULL, NULL, NULL, NULL},
134137
#endif
135138
#if defined(MICROPY_HW_I2C3_SCL)
136-
{{&pyb_i2c_type}, &I2CHandle3, &dma_I2C_3_TX, &dma_I2C_3_RX},
139+
{{&pyb_i2c_type}, &I2CHandle3, &dma_I2C_3_TX, &dma_I2C_3_RX, &pyb_i2c_use_dma[2]},
137140
#else
138-
{{&pyb_i2c_type}, NULL, NULL, NULL},
141+
{{&pyb_i2c_type}, NULL, NULL, NULL, NULL},
139142
#endif
140143
};
141144

@@ -338,6 +341,7 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, mp_uint_t n_args,
338341
{ MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x12} },
339342
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROPY_HW_I2C_BAUDRATE_DEFAULT} },
340343
{ MP_QSTR_gencall, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
344+
{ MP_QSTR_dma, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
341345
};
342346

343347
// parse args
@@ -362,6 +366,8 @@ STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, mp_uint_t n_args,
362366
init->OwnAddress2 = 0; // unused
363367
init->NoStretchMode = I2C_NOSTRETCH_DISABLE;
364368

369+
*self->use_dma = args[4].u_bool;
370+
365371
// init the I2C bus
366372
i2c_init(self->i2c);
367373

@@ -514,9 +520,11 @@ STATIC mp_obj_t pyb_i2c_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
514520
uint8_t data[1];
515521
pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data);
516522

517-
// if IRQs are enabled then we can use DMA
523+
// if option is set and IRQs are enabled then we can use DMA
524+
bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
525+
518526
DMA_HandleTypeDef tx_dma;
519-
if (query_irq() == IRQ_STATE_ENABLED) {
527+
if (use_dma) {
520528
dma_init(&tx_dma, self->tx_dma_descr, self->i2c);
521529
self->i2c->hdmatx = &tx_dma;
522530
self->i2c->hdmarx = NULL;
@@ -526,27 +534,27 @@ STATIC mp_obj_t pyb_i2c_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
526534
HAL_StatusTypeDef status;
527535
if (in_master_mode(self)) {
528536
if (args[1].u_int == PYB_I2C_MASTER_ADDRESS) {
529-
if (query_irq() == IRQ_STATE_ENABLED) {
537+
if (use_dma) {
530538
dma_deinit(self->tx_dma_descr);
531539
}
532540
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "addr argument required"));
533541
}
534542
mp_uint_t i2c_addr = args[1].u_int << 1;
535-
if (query_irq() == IRQ_STATE_DISABLED) {
543+
if (!use_dma) {
536544
status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, args[2].u_int);
537545
} else {
538546
status = HAL_I2C_Master_Transmit_DMA(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len);
539547
}
540548
} else {
541-
if (query_irq() == IRQ_STATE_DISABLED) {
549+
if (!use_dma) {
542550
status = HAL_I2C_Slave_Transmit(self->i2c, bufinfo.buf, bufinfo.len, args[2].u_int);
543551
} else {
544552
status = HAL_I2C_Slave_Transmit_DMA(self->i2c, bufinfo.buf, bufinfo.len);
545553
}
546554
}
547555

548556
// if we used DMA, wait for it to finish
549-
if (query_irq() == IRQ_STATE_ENABLED) {
557+
if (use_dma) {
550558
if (status == HAL_OK) {
551559
status = i2c_wait_dma_finished(self->i2c, args[2].u_int);
552560
}
@@ -588,9 +596,11 @@ STATIC mp_obj_t pyb_i2c_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
588596
vstr_t vstr;
589597
mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr);
590598

591-
// if IRQs are enabled then we can use DMA
599+
// if option is set and IRQs are enabled then we can use DMA
600+
bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
601+
592602
DMA_HandleTypeDef rx_dma;
593-
if (query_irq() == IRQ_STATE_ENABLED) {
603+
if (use_dma) {
594604
dma_init(&rx_dma, self->rx_dma_descr, self->i2c);
595605
self->i2c->hdmatx = NULL;
596606
self->i2c->hdmarx = &rx_dma;
@@ -603,21 +613,21 @@ STATIC mp_obj_t pyb_i2c_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
603613
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "addr argument required"));
604614
}
605615
mp_uint_t i2c_addr = args[1].u_int << 1;
606-
if (query_irq() == IRQ_STATE_DISABLED) {
616+
if (!use_dma) {
607617
status = HAL_I2C_Master_Receive(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len, args[2].u_int);
608618
} else {
609619
status = HAL_I2C_Master_Receive_DMA(self->i2c, i2c_addr, (uint8_t*)vstr.buf, vstr.len);
610620
}
611621
} else {
612-
if (query_irq() == IRQ_STATE_DISABLED) {
622+
if (!use_dma) {
613623
status = HAL_I2C_Slave_Receive(self->i2c, (uint8_t*)vstr.buf, vstr.len, args[2].u_int);
614624
} else {
615625
status = HAL_I2C_Slave_Receive_DMA(self->i2c, (uint8_t*)vstr.buf, vstr.len);
616626
}
617627
}
618628

619629
// if we used DMA, wait for it to finish
620-
if (query_irq() == IRQ_STATE_ENABLED) {
630+
if (use_dma) {
621631
if (status == HAL_OK) {
622632
status = i2c_wait_dma_finished(self->i2c, args[2].u_int);
623633
}
@@ -680,8 +690,11 @@ STATIC mp_obj_t pyb_i2c_mem_read(mp_uint_t n_args, const mp_obj_t *pos_args, mp_
680690
mem_addr_size = I2C_MEMADD_SIZE_16BIT;
681691
}
682692

693+
// if option is set and IRQs are enabled then we can use DMA
694+
bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
695+
683696
HAL_StatusTypeDef status;
684-
if (query_irq() == IRQ_STATE_DISABLED) {
697+
if (!use_dma) {
685698
status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, mem_addr_size, (uint8_t*)vstr.buf, vstr.len, args[3].u_int);
686699
} else {
687700
DMA_HandleTypeDef rx_dma;
@@ -744,8 +757,11 @@ STATIC mp_obj_t pyb_i2c_mem_write(mp_uint_t n_args, const mp_obj_t *pos_args, mp
744757
mem_addr_size = I2C_MEMADD_SIZE_16BIT;
745758
}
746759

760+
// if option is set and IRQs are enabled then we can use DMA
761+
bool use_dma = *self->use_dma && query_irq() == IRQ_STATE_ENABLED;
762+
747763
HAL_StatusTypeDef status;
748-
if (query_irq() == IRQ_STATE_DISABLED) {
764+
if (!use_dma) {
749765
status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, mem_addr_size, bufinfo.buf, bufinfo.len, args[3].u_int);
750766
} else {
751767
DMA_HandleTypeDef tx_dma;

tests/pyb/i2c_error.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
pyb.Accel()
88

99
# get I2C bus
10-
i2c = I2C(1, I2C.MASTER)
10+
i2c = I2C(1, I2C.MASTER, dma=True)
1111

1212
# test polling mem_read
1313
pyb.disable_irq()

0 commit comments

Comments
 (0)