From c1ad8f443d5a9780a9897c79deda61241c0e34c2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 May 2012 20:13:05 -0700 Subject: [PATCH] altos: Provide ISR-based code paths for SPI This allows SPI to be entirely interrupt driven, with callbacks for completion. It's not tested yet... Signed-off-by: Keith Packard --- src/stm/ao_adc_stm.c | 4 +- src/stm/ao_arch_funcs.h | 6 ++- src/stm/ao_dma_stm.c | 8 ++-- src/stm/ao_i2c_stm.c | 26 +++++++++-- src/stm/ao_spi_stm.c | 97 +++++++++++++++++++++++++++++++++++++---- 5 files changed, 123 insertions(+), 18 deletions(-) diff --git a/src/stm/ao_adc_stm.c b/src/stm/ao_adc_stm.c index a2569908..93cf6b6d 100644 --- a/src/stm/ao_adc_stm.c +++ b/src/stm/ao_adc_stm.c @@ -41,7 +41,7 @@ static uint8_t ao_adc_ready; * * Mark time in ring, shut down DMA engine */ -static void ao_adc_done(int index) +static void ao_adc_done(int arg) { ao_adc_ring[ao_adc_head].tick = ao_time(); ao_adc_head = ao_adc_ring_next(ao_adc_head); @@ -72,7 +72,7 @@ ao_adc_poll(void) (0 << STM_DMA_CCR_PINC) | (0 << STM_DMA_CCR_CIRC) | (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR)); - ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC1), ao_adc_done); + ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC1), ao_adc_done, 0); ao_dma_start(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC1)); stm_adc.cr2 = AO_ADC_CR2_VAL | (1 << STM_ADC_CR2_SWSTART); diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 447042dd..5ab02113 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -31,6 +31,10 @@ ao_spi_put(uint8_t spi_index); void ao_spi_send(void *block, uint16_t len, uint8_t spi_index); +void +ao_spi_queue_send(void *block, uint16_t len, uint8_t spi_index, + void (*callback)(int spi_index)); + void ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index); @@ -105,7 +109,7 @@ ao_dma_set_transfer(uint8_t index, uint32_t ccr); void -ao_dma_set_isr(uint8_t index, void (*isr)(int index)); +ao_dma_set_isr(uint8_t index, void (*isr)(int arg), int arg); void ao_dma_start(uint8_t index); diff --git a/src/stm/ao_dma_stm.c b/src/stm/ao_dma_stm.c index 8379a1a5..c44e66f0 100644 --- a/src/stm/ao_dma_stm.c +++ b/src/stm/ao_dma_stm.c @@ -20,7 +20,8 @@ #define NUM_DMA 7 struct ao_dma_config { - void (*isr)(int index); + void (*isr)(int arg); + int arg; }; uint8_t ao_dma_done[NUM_DMA]; @@ -39,7 +40,7 @@ ao_dma_isr(uint8_t index) { /* Ack them */ stm_dma.ifcr = isr; if (ao_dma_config[index].isr) - (*ao_dma_config[index].isr)(index); + (*ao_dma_config[index].isr)(ao_dma_config[index].arg); else { ao_dma_done[index] = 1; ao_wakeup(&ao_dma_done[index]); @@ -79,8 +80,9 @@ ao_dma_set_transfer(uint8_t index, } void -ao_dma_set_isr(uint8_t index, void (*isr)(int)) +ao_dma_set_isr(uint8_t index, void (*isr)(int), int arg) { + ao_dma_config[index].arg = arg; ao_dma_config[index].isr = isr; } diff --git a/src/stm/ao_i2c_stm.c b/src/stm/ao_i2c_stm.c index 763ae6cd..73587aac 100644 --- a/src/stm/ao_i2c_stm.c +++ b/src/stm/ao_i2c_stm.c @@ -32,6 +32,7 @@ struct ao_i2c_stm_info { static uint8_t ao_i2c_state[STM_NUM_I2C]; static uint16_t ao_i2c_addr[STM_NUM_I2C]; uint8_t ao_i2c_mutex[STM_NUM_I2C]; +static void (*ao_i2c_callback[STM_NUM_I2C])(uint8_t index); #define AO_STM_I2C_CR1 ((0 << STM_I2C_CR1_SWRST) | \ (0 << STM_I2C_CR1_ALERT) | \ @@ -182,8 +183,8 @@ static inline void out_dr(char *where, struct stm_i2c *stm_i2c, uint32_t dr) { stm_i2c->dr = dr; } -uint8_t -ao_i2c_start(uint8_t index, uint16_t addr) +void +ao_i2c_queue_start(uint8_t index, uint16_t addr) { struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; uint32_t sr1, sr2; @@ -196,9 +197,28 @@ ao_i2c_start(uint8_t index, uint16_t addr) AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_START)); out_cr2("start", stm_i2c, AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN)); +} + +void +ao_i2c_set_start_callback(uint8_t index, void (*callback)(uint8_t index)) +{ + +} + +uint8_t +ao_i2c_is_idle(uint8_t index) +{ + return ao_i2c_state[index] == I2C_IDLE; +} + +uint8_t +ao_i2c_start(uint8_t index, uint16_t addr) +{ + ao_i2c_queue_start(index, addr); + ao_alarm(1); cli(); - while (ao_i2c_state[index] == I2C_IDLE) + while (ao_i2c_is_idle(index)) if (ao_sleep(&ao_i2c_state[index])) break; sei(); diff --git a/src/stm/ao_spi_stm.c b/src/stm/ao_spi_stm.c index 8bb0d8e8..b8ab7db6 100644 --- a/src/stm/ao_spi_stm.c +++ b/src/stm/ao_spi_stm.c @@ -24,6 +24,7 @@ struct ao_spi_stm_info { }; uint8_t ao_spi_mutex[STM_NUM_SPI]; +static void (*ao_spi_callback[STM_NUM_SPI])(int spi_index); static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = { { @@ -40,8 +41,8 @@ static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = { static uint8_t spi_dev_null; -void -ao_spi_send(void *block, uint16_t len, uint8_t spi_index) +static void +ao_spi_setup_send(void *block, uint16_t len, uint8_t spi_index) { struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi; uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index; @@ -86,14 +87,61 @@ ao_spi_send(void *block, uint16_t len, uint8_t spi_index) (0 << STM_SPI_CR2_SSOE) | (1 << STM_SPI_CR2_TXDMAEN) | (1 << STM_SPI_CR2_RXDMAEN)); +} + +static void +ao_spi_start_send(uint8_t spi_index) +{ + uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index; + ao_dma_start(miso_dma_index); ao_dma_start(mosi_dma_index); +} + +static void +ao_spi_finish_send(uint8_t spi_index) +{ + uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index; + + ao_dma_done_transfer(mosi_dma_index); + ao_dma_done_transfer(miso_dma_index); +} + +void +ao_spi_dma_isr(int spi_index) +{ + ao_spi_callback[spi_index](spi_index); + ao_spi_finish_send(spi_index); +} + +void +ao_spi_queue_send(void *block, uint16_t len, uint8_t spi_index, + void (*callback)(int spi_index)) +{ + uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index; + + ao_spi_setup_send(block, len, spi_index); + ao_spi_callback[spi_index] = callback; + ao_dma_set_isr(miso_dma_index, ao_spi_dma_isr, spi_index); + ao_spi_start_send(spi_index); +} + +void +ao_spi_send(void *block, uint16_t len, uint8_t spi_index) +{ + uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index; + + ao_spi_setup_send(block, len, spi_index); + ao_spi_start_send(spi_index); ao_arch_critical( while (!ao_dma_done[miso_dma_index]) ao_sleep(&ao_dma_done[miso_dma_index]); ); - ao_dma_done_transfer(mosi_dma_index); - ao_dma_done_transfer(miso_dma_index); + + ao_spi_finish_send(spi_index); } void @@ -152,8 +200,8 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index) ao_dma_done_transfer(miso_dma_index); } -void -ao_spi_recv(void *block, uint16_t len, uint8_t spi_index) +static void +ao_spi_setup_recv(void *block, uint16_t len, uint8_t spi_index) { struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi; uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index; @@ -196,17 +244,48 @@ ao_spi_recv(void *block, uint16_t len, uint8_t spi_index) (0 << STM_SPI_CR2_SSOE) | (1 << STM_SPI_CR2_TXDMAEN) | (1 << STM_SPI_CR2_RXDMAEN)); +} + +static void +ao_spi_start_recv(uint8_t spi_index) +{ + uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index; ao_dma_start(miso_dma_index); ao_dma_start(mosi_dma_index); +} + +static void +ao_spi_done_recv(uint8_t spi_index) +{ + uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index; + ao_dma_done_transfer(mosi_dma_index); + ao_dma_done_transfer(miso_dma_index); +} +void +ao_spi_queue_recv(void *block, uint16_t len, uint8_t spi_index, void (*callback)(int spi_index)) +{ + uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index; + ao_spi_setup_recv(block, len, spi_index); + ao_spi_callback[spi_index] = callback; + ao_dma_set_isr(miso_dma_index, ao_spi_dma_isr, spi_index); + ao_spi_start_recv(spi_index); +} + +void +ao_spi_recv(void *block, uint16_t len, uint8_t spi_index) +{ + uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index; + ao_spi_setup_recv(block, len, spi_index); + ao_spi_start_recv(spi_index); /* Wait until the SPI unit is done */ ao_arch_critical( while (!ao_dma_done[miso_dma_index]) ao_sleep(&ao_dma_done[miso_dma_index]); ); - - ao_dma_done_transfer(mosi_dma_index); - ao_dma_done_transfer(miso_dma_index); + ao_spi_done_recv(spi_index); } void -- 2.30.2