From 58db263cc835be0abb972654c2d7369718c88b37 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 6 Nov 2014 16:04:14 -0800 Subject: altos/lpc: Declare SPI send parameters as const This matches STM Signed-off-by: Keith Packard --- src/lpc/ao_spi_lpc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/lpc/ao_spi_lpc.c') diff --git a/src/lpc/ao_spi_lpc.c b/src/lpc/ao_spi_lpc.c index e72b8286..bc8f9c69 100644 --- a/src/lpc/ao_spi_lpc.c +++ b/src/lpc/ao_spi_lpc.c @@ -43,9 +43,9 @@ static struct lpc_ssp * const ao_lpc_ssp[LPC_NUM_SPI] = { &lpc_ssp0, &lpc_ssp1 } } while (0) void -ao_spi_send(void *block, uint16_t len, uint8_t id) +ao_spi_send(const void *block, uint16_t len, uint8_t id) { - uint8_t *b = block; + const uint8_t *b = block; struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id]; spi_loop(len, *b++, (void)); @@ -69,9 +69,9 @@ ao_spi_recv(void *block, uint16_t len, uint8_t id) } void -ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t id) +ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t id) { - uint8_t *o = out; + const uint8_t *o = out; uint8_t *i = in; struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id]; -- cgit v1.2.3 From 2a053d3d157e00b6a6406f4f78ddb8e298b6c4b7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 22 Dec 2014 17:27:09 -0800 Subject: altos/lpc: Switch LPC SPI driver to interrupt-driven This improves performance for SPI transfers, while allowing other tasks to get work done during longer SPI transfers. Signed-off-by: Keith Packard --- src/lpc/ao_arch.h | 3 + src/lpc/ao_arch_funcs.h | 2 - src/lpc/ao_spi_lpc.c | 143 +++++++++++++++++++++++++++++++++++++----------- 3 files changed, 115 insertions(+), 33 deletions(-) (limited to 'src/lpc/ao_spi_lpc.c') diff --git a/src/lpc/ao_arch.h b/src/lpc/ao_arch.h index 5fbb8dfa..42faf06f 100644 --- a/src/lpc/ao_arch.h +++ b/src/lpc/ao_arch.h @@ -130,12 +130,15 @@ ao_serial_init(void); /* SPI definitions */ #define AO_SPI_SPEED_12MHz 4 +#define AO_SPI_SPEED_8MHz 6 #define AO_SPI_SPEED_6MHz 8 #define AO_SPI_SPEED_4MHz 12 #define AO_SPI_SPEED_2MHz 24 #define AO_SPI_SPEED_1MHz 48 #define AO_SPI_SPEED_500kHz 96 #define AO_SPI_SPEED_250kHz 192 +#define AO_SPI_SPEED_125kHz 384 +#define AO_SPI_SPEED_62500Hz 768 #define AO_SPI_SPEED_FAST AO_SPI_SPEED_12MHz diff --git a/src/lpc/ao_arch_funcs.h b/src/lpc/ao_arch_funcs.h index 69f2cbfb..fbe641d8 100644 --- a/src/lpc/ao_arch_funcs.h +++ b/src/lpc/ao_arch_funcs.h @@ -224,8 +224,6 @@ ao_spi_recv(void *block, uint16_t len, uint8_t spi_index); void ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index); -extern uint16_t ao_spi_speed[LPC_NUM_SPI]; - void ao_spi_init(void); diff --git a/src/lpc/ao_spi_lpc.c b/src/lpc/ao_spi_lpc.c index bc8f9c69..5a358919 100644 --- a/src/lpc/ao_spi_lpc.c +++ b/src/lpc/ao_spi_lpc.c @@ -19,63 +19,130 @@ 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 }; -#define tx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_TNF))) != (1 << LPC_SSP_SR_TNF) -#define rx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_RNE))) != (1 << LPC_SSP_SR_RNE) - -#define spi_loop(len, put, get) do { \ - while (len--) { \ - /* Wait for space in the fifo */ \ - while (tx_busy(lpc_ssp)) \ - ; \ - \ - /* send a byte */ \ - lpc_ssp->dr = put; \ - \ - /* Wait for byte to appear in the fifo */ \ - while (rx_busy(lpc_ssp)) \ - ; \ - \ - /* recv a byte */ \ - get lpc_ssp->dr; \ - } \ - } while (0) +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; void ao_spi_send(const void *block, uint16_t len, uint8_t id) { - const uint8_t *b = block; struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id]; + struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id]; - spi_loop(len, *b++, (void)); + 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); } 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]; - spi_loop(len, value, (void)); + 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); } void ao_spi_recv(void *block, uint16_t len, uint8_t id) { - uint8_t *b = block; struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id]; + struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id]; - spi_loop(len, 0xff, *b++ =); + 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); } void ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t id) { - const uint8_t *o = out; - uint8_t *i = in; struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id]; + struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id]; - spi_loop(len, *o++, *i++ =); + 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); } void @@ -84,7 +151,7 @@ ao_spi_get(uint8_t id, uint32_t speed) struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id]; ao_mutex_get(&ao_spi_mutex[id]); - + /* Set the clock prescale */ lpc_ssp->cpsr = speed; } @@ -101,6 +168,11 @@ ao_spi_channel_init(uint8_t id) struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id]; uint8_t d; + /* Clear interrupt registers */ + lpc_ssp->imsc = 0; + lpc_ssp->ris = 0; + lpc_ssp->mis = 0; + lpc_ssp->cr0 = ((LPC_SSP_CR0_DSS_8 << LPC_SSP_CR0_DSS) | (LPC_SSP_CR0_FRF_SPI << LPC_SSP_CR0_FRF) | (0 << LPC_SSP_CR0_CPOL) | @@ -151,7 +223,11 @@ 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); -#endif + + /* Configure NVIC */ + lpc_nvic_set_enable(LPC_ISR_SSP0_POS); + lpc_nvic_set_priority(LPC_ISR_SSP0_POS, 0); +#endif #if HAS_SPI_1 @@ -190,7 +266,7 @@ ao_spi_init(void) #ifndef HAS_MOSI1 #error "No pin specified for MOSI1" #endif - + /* Enable the device */ lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP1); @@ -201,5 +277,10 @@ 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 */ } -- cgit v1.2.3 From f9f235bce84df3a6c0261e9d256aac544f87f70f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 7 Feb 2015 01:05:57 -0800 Subject: altos/lpc: Give up on interrupt-driven SPI driver 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 --- src/lpc/ao_spi_lpc.c | 133 ++++++++++----------------------------------------- 1 file changed, 25 insertions(+), 108 deletions(-) (limited to 'src/lpc/ao_spi_lpc.c') diff --git a/src/lpc/ao_spi_lpc.c b/src/lpc/ao_spi_lpc.c index 5a358919..f091c89c 100644 --- a/src/lpc/ao_spi_lpc.c +++ b/src/lpc/ao_spi_lpc.c @@ -19,130 +19,56 @@ 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 */ } -- cgit v1.2.3