The I2C engine appears to trigger an extra RX DMA transaction which
scrambles anything sharing the same DMA units.
Signed-off-by: Keith Packard <keithp@keithp.com>
uint16_t count,
uint32_t ccr);
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));
void
ao_dma_set_isr(uint8_t index, void (*isr)(int index));
static uint8_t ao_dma_active;
#endif
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,
void
ao_dma_set_transfer(uint8_t index,
volatile void *peripheral,
{
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;
{
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);
/* 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,
ao_dma_set_transfer(tx_dma_index,
&stm_i2c->dr,
block,
(0 << STM_DMA_CCR_PINC) |
(0 << STM_DMA_CCR_CIRC) |
(STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
(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_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))
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))
stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP);
ao_i2c_wait_stop(index);
}
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);
ao_arch_release_interrupts();
ret = ao_i2c_recv_len[index] == 0;
} else {
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;
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,
ao_dma_set_transfer(rx_dma_index,
&stm_i2c->dr,
block,
break;
ao_arch_release_interrupts();
ret = ao_dma_done[rx_dma_index];
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);
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);
}
if (stop)
ao_i2c_wait_stop(index);