altos: Provide ISR-based code paths for SPI serial-at-interrupt
authorKeith Packard <keithp@keithp.com>
Sat, 19 May 2012 03:13:05 +0000 (20:13 -0700)
committerKeith Packard <keithp@keithp.com>
Sat, 19 May 2012 03:19:18 +0000 (20:19 -0700)
This allows SPI to be entirely interrupt driven, with callbacks for
completion. It's not tested yet...

Signed-off-by: Keith Packard <keithp@keithp.com>
src/stm/ao_adc_stm.c
src/stm/ao_arch_funcs.h
src/stm/ao_dma_stm.c
src/stm/ao_i2c_stm.c
src/stm/ao_spi_stm.c

index a256990851f3bfeb5af3c2e2e79b53f7a64a3f4d..93cf6b6de8f3adfee98e2fb168e7001a8475c114 100644 (file)
@@ -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);
index 447042dd6a0ad3bda8c04d8c74d5368dc780d7d9..5ab021136842156aa1c11a080860107bbb5ffe87 100644 (file)
@@ -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);
index 8379a1a533ca0ec5e19321910b1a9975a952f744..c44e66f0e142818ed012dc809bf9c04274bc1b35 100644 (file)
@@ -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;
 }
 
index 763ae6cd5c0ec0fefa7074912c19bada14134175..73587aac4fb89319e0c12035c474b32d2fd82f11 100644 (file)
@@ -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();
index 8bb0d8e8a2be33e869e393a75598be8dac7c5329..b8ab7db69fdb16d4d861d49964b08d3a46728bc4 100644 (file)
@@ -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