Skip to content

Commit a017cfc

Browse files
committed
altos/stm32f1: Grab both TX/RX DMA mutexes while doing I2C
The I2C engine appears to trigger an extra RX DMA transaction which scrambles anything sharing the same DMA units. Signed-off-by: Keith Packard <[email protected]>
1 parent d9140ea commit a017cfc

File tree

3 files changed

+36
-3
lines changed

3 files changed

+36
-3
lines changed

src/stm32f1/ao_arch_funcs.h

+6
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,12 @@ ao_dma_set_transfer(uint8_t index,
350350
uint16_t count,
351351
uint32_t ccr);
352352

353+
void
354+
ao_dma_mutex_get(uint8_t index);
355+
356+
void
357+
ao_dma_mutex_put(uint8_t index);
358+
353359
void
354360
ao_dma_set_isr(uint8_t index, void (*isr)(int index));
355361

src/stm32f1/ao_dma_stm.c

+21
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,27 @@ void stm_dma1_channel7_isr(void) { ao_dma_isr(STM_DMA_INDEX(7)); }
6666
static uint8_t ao_dma_active;
6767
#endif
6868

69+
void
70+
ao_dma_mutex_get(uint8_t index)
71+
{
72+
if (ao_dma_allocated[index]) {
73+
if (ao_dma_mutex[index])
74+
ao_panic(AO_PANIC_DMA);
75+
ao_dma_mutex[index] = 0xff;
76+
} else
77+
ao_mutex_get(&ao_dma_mutex[index]);
78+
}
79+
80+
void
81+
ao_dma_mutex_put(uint8_t index)
82+
{
83+
if (ao_dma_allocated[index])
84+
ao_dma_mutex[index] = 0;
85+
else
86+
ao_mutex_put(&ao_dma_mutex[index]);
87+
}
88+
89+
6990
void
7091
ao_dma_set_transfer(uint8_t index,
7192
volatile void *peripheral,

src/stm32f1/ao_i2c_stm.c

+9-3
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,11 @@ ao_i2c_send(void *block, uint16_t len, uint8_t index, uint8_t stop)
224224
{
225225
struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c;
226226
uint8_t tx_dma_index = ao_i2c_stm_info[index].tx_dma_index;
227+
uint8_t rx_dma_index = ao_i2c_stm_info[index].rx_dma_index;
227228

228229
/* Clear any pending ADDR bit */
229230
(void) stm_i2c->sr2;
230231
ao_i2c_wait_addr(index);
231-
stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_DMAEN);
232232
ao_dma_set_transfer(tx_dma_index,
233233
&stm_i2c->dr,
234234
block,
@@ -241,13 +241,14 @@ ao_i2c_send(void *block, uint16_t len, uint8_t index, uint8_t stop)
241241
(0 << STM_DMA_CCR_PINC) |
242242
(0 << STM_DMA_CCR_CIRC) |
243243
(STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
244+
ao_dma_mutex_get(rx_dma_index);
245+
stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_DMAEN);
244246

245247
ao_dma_start(tx_dma_index);
246248
ao_arch_block_interrupts();
247249
while (!ao_dma_done[tx_dma_index])
248250
if (ao_sleep_for(&ao_dma_done[tx_dma_index], 1 + len))
249251
break;
250-
ao_dma_done_transfer(tx_dma_index);
251252
stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN);
252253
while ((stm_i2c->sr1 & (1 << STM_I2C_SR1_BTF)) == 0)
253254
if (ao_sleep_for(&ao_i2c_state[index], 1 + len))
@@ -258,6 +259,8 @@ ao_i2c_send(void *block, uint16_t len, uint8_t index, uint8_t stop)
258259
stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP);
259260
ao_i2c_wait_stop(index);
260261
}
262+
ao_dma_mutex_put(rx_dma_index);
263+
ao_dma_done_transfer(tx_dma_index);
261264
return true;
262265
}
263266

@@ -311,7 +314,9 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t index, uint8_t stop)
311314
ao_arch_release_interrupts();
312315
ret = ao_i2c_recv_len[index] == 0;
313316
} else {
317+
uint8_t tx_dma_index = ao_i2c_stm_info[index].tx_dma_index;
314318
uint8_t rx_dma_index = ao_i2c_stm_info[index].rx_dma_index;
319+
ao_dma_mutex_get(tx_dma_index);
315320
ao_dma_set_transfer(rx_dma_index,
316321
&stm_i2c->dr,
317322
block,
@@ -349,8 +354,9 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t index, uint8_t stop)
349354
break;
350355
ao_arch_release_interrupts();
351356
ret = ao_dma_done[rx_dma_index];
352-
ao_dma_done_transfer(rx_dma_index);
353357
stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP);
358+
ao_dma_done_transfer(rx_dma_index);
359+
ao_dma_mutex_put(tx_dma_index);
354360
}
355361
if (stop)
356362
ao_i2c_wait_stop(index);

0 commit comments

Comments
 (0)