From a017cfce31429ef25a53a724e99b53c8267ec4ef Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 2 Mar 2024 16:23:57 -0700 Subject: [PATCH] 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 --- src/stm32f1/ao_arch_funcs.h | 6 ++++++ src/stm32f1/ao_dma_stm.c | 21 +++++++++++++++++++++ src/stm32f1/ao_i2c_stm.c | 12 +++++++++--- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/stm32f1/ao_arch_funcs.h b/src/stm32f1/ao_arch_funcs.h index 3a83f382..7004eb46 100644 --- a/src/stm32f1/ao_arch_funcs.h +++ b/src/stm32f1/ao_arch_funcs.h @@ -350,6 +350,12 @@ ao_dma_set_transfer(uint8_t index, uint16_t count, uint32_t ccr); +void +ao_dma_mutex_get(uint8_t index); + +void +ao_dma_mutex_put(uint8_t index); + void ao_dma_set_isr(uint8_t index, void (*isr)(int index)); diff --git a/src/stm32f1/ao_dma_stm.c b/src/stm32f1/ao_dma_stm.c index d3162d5b..45bb88f3 100644 --- a/src/stm32f1/ao_dma_stm.c +++ b/src/stm32f1/ao_dma_stm.c @@ -66,6 +66,27 @@ void stm_dma1_channel7_isr(void) { ao_dma_isr(STM_DMA_INDEX(7)); } static uint8_t ao_dma_active; #endif +void +ao_dma_mutex_get(uint8_t index) +{ + if (ao_dma_allocated[index]) { + if (ao_dma_mutex[index]) + ao_panic(AO_PANIC_DMA); + ao_dma_mutex[index] = 0xff; + } else + ao_mutex_get(&ao_dma_mutex[index]); +} + +void +ao_dma_mutex_put(uint8_t index) +{ + if (ao_dma_allocated[index]) + ao_dma_mutex[index] = 0; + else + ao_mutex_put(&ao_dma_mutex[index]); +} + + void ao_dma_set_transfer(uint8_t index, volatile void *peripheral, diff --git a/src/stm32f1/ao_i2c_stm.c b/src/stm32f1/ao_i2c_stm.c index e84f594b..a61d3eb5 100644 --- a/src/stm32f1/ao_i2c_stm.c +++ b/src/stm32f1/ao_i2c_stm.c @@ -224,11 +224,11 @@ ao_i2c_send(void *block, uint16_t len, uint8_t index, uint8_t stop) { struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; uint8_t tx_dma_index = ao_i2c_stm_info[index].tx_dma_index; + uint8_t rx_dma_index = ao_i2c_stm_info[index].rx_dma_index; /* Clear any pending ADDR bit */ (void) stm_i2c->sr2; ao_i2c_wait_addr(index); - stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_DMAEN); ao_dma_set_transfer(tx_dma_index, &stm_i2c->dr, block, @@ -241,13 +241,14 @@ ao_i2c_send(void *block, uint16_t len, uint8_t index, uint8_t stop) (0 << STM_DMA_CCR_PINC) | (0 << STM_DMA_CCR_CIRC) | (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR)); + ao_dma_mutex_get(rx_dma_index); + stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_DMAEN); ao_dma_start(tx_dma_index); ao_arch_block_interrupts(); while (!ao_dma_done[tx_dma_index]) if (ao_sleep_for(&ao_dma_done[tx_dma_index], 1 + len)) break; - ao_dma_done_transfer(tx_dma_index); stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN); while ((stm_i2c->sr1 & (1 << STM_I2C_SR1_BTF)) == 0) 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) stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP); ao_i2c_wait_stop(index); } + ao_dma_mutex_put(rx_dma_index); + ao_dma_done_transfer(tx_dma_index); return true; } @@ -311,7 +314,9 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t index, uint8_t stop) ao_arch_release_interrupts(); ret = ao_i2c_recv_len[index] == 0; } else { + uint8_t tx_dma_index = ao_i2c_stm_info[index].tx_dma_index; uint8_t rx_dma_index = ao_i2c_stm_info[index].rx_dma_index; + ao_dma_mutex_get(tx_dma_index); ao_dma_set_transfer(rx_dma_index, &stm_i2c->dr, block, @@ -349,8 +354,9 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t index, uint8_t stop) break; ao_arch_release_interrupts(); ret = ao_dma_done[rx_dma_index]; - ao_dma_done_transfer(rx_dma_index); stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP); + ao_dma_done_transfer(rx_dma_index); + ao_dma_mutex_put(tx_dma_index); } if (stop) ao_i2c_wait_stop(index); -- 2.30.2