altos/lpc: Give up on interrupt-driven SPI driver
authorKeith Packard <keithp@keithp.com>
Sat, 7 Feb 2015 09:05:57 +0000 (01:05 -0800)
committerKeith Packard <keithp@keithp.com>
Sat, 7 Feb 2015 09:05:57 +0000 (01:05 -0800)
There are just too many limitations in when interrupts are delivered
to make them useful. Instead, just drive the SPI directly with the
CPU. At higher spi speeds (6Mhz or more), it's probably faster to do
it this way anyways.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/lpc/ao_spi_lpc.c

index 5a358919937c7027e5af06b71fd97dac95168cdb..f091c89c570963542f602c0e7f6d8957116895d4 100644 (file)
 
 static uint8_t         ao_spi_mutex[LPC_NUM_SPI];
 
-struct ao_lpc_ssp_state {
-       int             tx_count;
-       const uint8_t   *tx;
-       int             tx_inc;
-       int             rx_count;
-       uint8_t         *rx;
-       int             rx_inc;
-};
-
-static struct ao_lpc_ssp_state ao_lpc_ssp_state[LPC_NUM_SPI];
-
 static struct lpc_ssp * const ao_lpc_ssp[LPC_NUM_SPI] = { &lpc_ssp0, &lpc_ssp1 };
 
-static inline void
-ao_lpc_ssp_recv(struct lpc_ssp *lpc_ssp, struct ao_lpc_ssp_state *state)
-{
-       while ((lpc_ssp->sr & (1 << LPC_SSP_SR_RNE)) &&
-              state->rx_count)
-       {
-               /* RX ready, read a byte */
-               *state->rx = lpc_ssp->dr;
-               state->rx += state->rx_inc;
-               state->rx_count--;
-       }
-}
-
-static void
-ao_lpc_ssp_isr(struct lpc_ssp *lpc_ssp, struct ao_lpc_ssp_state *state)
-{
-       ao_lpc_ssp_recv(lpc_ssp, state);
-       while ((lpc_ssp->sr & (1 << LPC_SSP_SR_TNF)) &&
-              state->tx_count)
-       {
-               /* TX ready, write a byte */
-               lpc_ssp->dr = *state->tx;
-               state->tx += state->tx_inc;
-               state->tx_count--;
-               ao_lpc_ssp_recv(lpc_ssp, state);
-       }
-       if (!state->rx_count) {
-               lpc_ssp->imsc &= ~(1 << LPC_SSP_IMSC_TXIM);
-               ao_wakeup(state);
-       }
-}
-
-void
-lpc_ssp0_isr(void)
-{
-       ao_lpc_ssp_isr(&lpc_ssp0, &ao_lpc_ssp_state[0]);
-}
-
-void
-lpc_ssp1_isr(void)
-{
-       ao_lpc_ssp_isr(&lpc_ssp1, &ao_lpc_ssp_state[1]);
-}
-
-static void
-ao_spi_run(struct lpc_ssp *lpc_ssp, struct ao_lpc_ssp_state *state)
-{
-       ao_arch_block_interrupts();
-       lpc_ssp->imsc = (1 << LPC_SSP_IMSC_TXIM);
-       while (state->rx_count)
-               ao_sleep(state);
-       ao_arch_release_interrupts();
-}
-
-static uint8_t ao_spi_tx_dummy = 0xff;
-static uint8_t ao_spi_rx_dummy;
+#define spi_loop(len, put, get) do {                                   \
+               while (len--) {                                         \
+                       /* send a byte */                               \
+                       lpc_ssp->dr = put;                              \
+                       /* wait for the received byte to appear */      \
+                       while ((lpc_ssp->sr & (1 << LPC_SSP_SR_RNE)) == 0) \
+                               ;                                       \
+                       /* receive a byte */                            \
+                       get lpc_ssp->dr;                                \
+               }                                                       \
+               /* Wait for the SSP to go idle (it already should be) */ \
+               while (lpc_ssp->sr & (1 << LPC_SSP_SR_BSY));            \
+       } while (0)
 
 void
 ao_spi_send(const void *block, uint16_t len, uint8_t id)
 {
        struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
-       struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
-
-       state->tx_count = state->rx_count = len;
-       state->tx = block;
-       state->tx_inc = 1;
-       state->rx = &ao_spi_rx_dummy;
-       state->rx_inc = 0;
-       ao_spi_run(lpc_ssp, state);
+       const uint8_t   *o = block;
+
+       spi_loop(len, *o++, (void));
 }
 
 void
 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t id)
 {
        struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
-       struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
-
-       state->tx_count = state->rx_count = len;
-       state->tx = &value;
-       state->tx_inc = 0;
-       state->rx = &ao_spi_rx_dummy;
-       state->rx_inc = 0;
-       ao_spi_run(lpc_ssp, state);
+
+       spi_loop(len, value, (void));
 }
 
 void
 ao_spi_recv(void *block, uint16_t len, uint8_t id)
 {
        struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
-       struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
-
-       state->tx_count = state->rx_count = len;
-       state->tx = &ao_spi_tx_dummy;
-       state->tx_inc = 0;
-       state->rx = block;
-       state->rx_inc = 1;
-       ao_spi_run(lpc_ssp, state);
+       uint8_t *i = block;
+
+       spi_loop(len, 0xff, *i++ =);
 }
 
 void
 ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t id)
 {
        struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
-       struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
-
-       state->tx_count = state->rx_count = len;
-       state->tx = out;
-       state->tx_inc = 1;
-       state->rx = in;
-       state->rx_inc = 1;
-       ao_spi_run(lpc_ssp, state);
+       const uint8_t *o = out;
+       uint8_t *i = in;
+
+       spi_loop(len, *o++, *i++ =);
 }
 
 void
@@ -223,10 +149,6 @@ ao_spi_init(void)
        lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
        lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
        ao_spi_channel_init(0);
-
-       /* Configure NVIC */
-       lpc_nvic_set_enable(LPC_ISR_SSP0_POS);
-       lpc_nvic_set_priority(LPC_ISR_SSP0_POS, 0);
 #endif
 
 #if HAS_SPI_1
@@ -277,10 +199,5 @@ ao_spi_init(void)
        lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
        lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
        ao_spi_channel_init(1);
-
-       /* Configure NVIC */
-       lpc_nvic_set_enable(LPC_ISR_SSP1_POS);
-       lpc_nvic_set_priority(LPC_ISR_SSP1_POS, 0);
-
 #endif /* HAS_SPI_1 */
 }