From a7c7e10b3bbfbdf9667d071634cdd6fdf12a1f85 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Mar 2016 10:17:24 -0700 Subject: altos: Expose fast timer API from kernel/ This allows multiple SoCs to provide the same driver interface Signed-off-by: Keith Packard --- src/stm/ao_fast_timer.h | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 src/stm/ao_fast_timer.h (limited to 'src/stm') diff --git a/src/stm/ao_fast_timer.h b/src/stm/ao_fast_timer.h deleted file mode 100644 index 90fb3930..00000000 --- a/src/stm/ao_fast_timer.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright © 2013 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#ifndef _AO_FAST_TIMER_H_ -#define _AO_FAST_TIMER_H_ - -void -ao_fast_timer_init(void); - -#ifndef AO_FAST_TIMER_MAX -#define AO_FAST_TIMER_MAX 2 -#endif - -void -ao_fast_timer_on(void (*callback)(void)); - -void -ao_fast_timer_off(void (*callback)(void)); - -#endif /* _AO_FAST_TIMER_H_ */ -- cgit v1.2.3 From 6a9546413d6a236c010e806b50506d870961d074 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 26 Mar 2016 15:49:59 -0700 Subject: altos/stm: Run scheduler code on interrupt stack This provides a bit more room for tasks on their stack Signed-off-by: Keith Packard --- src/stm/ao_arch_funcs.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src/stm') diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 42f1a2e5..02b344b1 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -335,6 +335,13 @@ static inline void ao_arch_save_stack(void) { static inline void ao_arch_restore_stack(void) { uint32_t sp; + uint32_t control; + + asm("mrs %0,control" : "=&r" (control)); + control |= (1 << 1); + asm("msr control,%0" : : "r" (control)); + asm("isb"); + sp = (uint32_t) ao_cur_task->sp; /* Switch stacks */ @@ -375,7 +382,14 @@ static inline void ao_arch_start_scheduler(void) { } #endif -#define ao_arch_isr_stack() +static inline void ao_arch_isr_stack(void) { + uint32_t control; + + asm("mrs %0,control" : "=&r" (control)); + control &= ~(1 << 1); + asm("msr control,%0" : : "r" (control)); + asm("isb"); +} #endif -- cgit v1.2.3 From 4fa71ecf168e275b24534a5a20e3dd4e178c7bbd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 26 Mar 2016 15:54:24 -0700 Subject: altos/stm: Validate current task SP in interrupt by looking at PSP We use a separate stack pointer for task code, which means we can verify that it is in range in any interrupt handler. This adds checks for the task stack (under #ifdef DEBUG) that run in ao_wakeup as well as at every timer interrupt. Signed-off-by: Keith Packard --- src/kernel/ao_task.c | 2 +- src/kernel/ao_task.h | 4 ++++ src/stm/ao_arch_funcs.h | 16 ++++++++++++++++ src/stm/ao_timer.c | 1 + 4 files changed, 22 insertions(+), 1 deletion(-) (limited to 'src/stm') diff --git a/src/kernel/ao_task.c b/src/kernel/ao_task.c index 55e423bb..104d1074 100644 --- a/src/kernel/ao_task.c +++ b/src/kernel/ao_task.c @@ -355,7 +355,6 @@ ao_yield(void) ao_arch_naked_define */ if (ao_cur_task->wchan == NULL) ao_task_to_run_queue(ao_cur_task); - ao_cur_task = NULL; for (;;) { ao_arch_memory_barrier(); if (!ao_list_is_empty(&run_queue)) @@ -425,6 +424,7 @@ ao_sleep(__xdata void *wchan) void ao_wakeup(__xdata void *wchan) __reentrant { + ao_validate_cur_stack(); #if HAS_TASK_QUEUE struct ao_task *sleep, *next; struct ao_list *sleep_queue; diff --git a/src/kernel/ao_task.h b/src/kernel/ao_task.h index c6bec0e3..0e353fe8 100644 --- a/src/kernel/ao_task.h +++ b/src/kernel/ao_task.h @@ -56,6 +56,10 @@ extern __data uint8_t ao_num_tasks; extern __xdata struct ao_task *__data ao_cur_task; extern __data uint8_t ao_task_minimize_latency; /* Reduce IRQ latency */ +#ifndef HAS_ARCH_VALIDATE_CUR_STACK +#define ao_validate_cur_stack() +#endif + /* ao_task.c */ diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 02b344b1..6b38032c 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -366,6 +366,22 @@ static inline void ao_arch_restore_stack(void) { #define HAS_SAMPLE_PROFILE 0 #endif +#if DEBUG +#define HAS_ARCH_VALIDATE_CUR_STACK 1 + +static inline void +ao_validate_cur_stack(void) +{ + uint8_t *psp; + + asm("mrs %0,psp" : "=&r" (psp)); + if (ao_cur_task && + psp <= ao_cur_task->stack && + psp >= ao_cur_task->stack - 256) + ao_panic(AO_PANIC_STACK); +} +#endif + #if !HAS_SAMPLE_PROFILE #define HAS_ARCH_START_SCHEDULER 1 diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index 8db62e76..91ede84b 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -41,6 +41,7 @@ volatile __data uint8_t ao_data_count; void stm_systick_isr(void) { + ao_validate_cur_stack(); if (stm_systick.csr & (1 << STM_SYSTICK_CSR_COUNTFLAG)) { ++ao_tick_count; #if HAS_TASK_QUEUE -- cgit v1.2.3 From a86d98b708d84c6e0b85cb950e3f1ee16cfc56f5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 26 Mar 2016 15:59:26 -0700 Subject: altos/stm: Allow apps to define different stack size While 512 bytes is a reasonable size, sometimes apps don't have that much stack space. Signed-off-by: Keith Packard --- src/stm/ao_arch.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/stm') diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index a6276c5a..f9508b8f 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -25,7 +25,9 @@ * STM32L definitions and code fragments for AltOS */ +#ifndef AO_STACK_SIZE #define AO_STACK_SIZE 512 +#endif #define AO_LED_TYPE uint16_t -- cgit v1.2.3 From 7348cc4736c9a94f9ad299edd78199b544d0e95a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 24 Mar 2016 19:25:33 -0600 Subject: altos: Add one-byte SPI output routine for LPC and STM cores This allows for SPI output at interrupt time, one byte at a time. Signed-off-by: Keith Packard --- src/lpc/ao_arch_funcs.h | 22 ++++++++++++++++++++++ src/stm/ao_arch_funcs.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) (limited to 'src/stm') diff --git a/src/lpc/ao_arch_funcs.h b/src/lpc/ao_arch_funcs.h index fbe641d8..dbb41538 100644 --- a/src/lpc/ao_arch_funcs.h +++ b/src/lpc/ao_arch_funcs.h @@ -227,6 +227,28 @@ ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index); void ao_spi_init(void); +static inline void +ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index) +{ + ao_spi_send(block, len, spi_index); +} + +static inline void ao_spi_send_byte(uint8_t byte, uint8_t spi_index) +{ + struct lpc_ssp *lpc_ssp; + switch (spi_index) { + case 0: + lpc_ssp = &lpc_ssp0; + break; + case 1: + lpc_ssp = &lpc_ssp1; + break; + } + lpc_ssp->dr = byte; + while ((lpc_ssp->sr & (1 << LPC_SSP_SR_RNE)) == 0); + (void) lpc_ssp->dr; +} + #define ao_spi_init_cs(port, mask) do { \ uint8_t __bit__; \ for (__bit__ = 0; __bit__ < 32; __bit__++) { \ diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 6b38032c..087e00d9 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -82,6 +82,34 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index); void ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index); +static inline void +ao_spi_send_byte(uint8_t byte, uint8_t spi_index) +{ + struct stm_spi *stm_spi; + + switch (AO_SPI_INDEX(spi_index)) { + case 0: + stm_spi = &stm_spi1; + break; + case 1: + stm_spi = &stm_spi2; + break; + } + + stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) | + (0 << STM_SPI_CR2_RXNEIE) | + (0 << STM_SPI_CR2_ERRIE) | + (0 << STM_SPI_CR2_SSOE) | + (0 << STM_SPI_CR2_TXDMAEN) | + (0 << STM_SPI_CR2_RXDMAEN)); + + /* Clear RXNE */ + (void) stm_spi->dr; + + while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE))); + stm_spi->dr = byte; +} + void ao_spi_recv(void *block, uint16_t len, uint8_t spi_index); -- cgit v1.2.3 From e3f0c5eb8e5d57cbd8882587477d1381e2a83226 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 17 Dec 2015 19:27:42 -0800 Subject: altos: Add ao_gpi_set/clr_bits functions These set or clear a group of bits in a single GPIO register all together. Signed-off-by: Keith Packard --- src/cc1111/ao_arch_funcs.h | 4 +++- src/stm/ao_arch_funcs.h | 5 +++++ src/stm/stm32l.h | 10 ++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) (limited to 'src/stm') diff --git a/src/cc1111/ao_arch_funcs.h b/src/cc1111/ao_arch_funcs.h index ea340dfd..1eb506cd 100644 --- a/src/cc1111/ao_arch_funcs.h +++ b/src/cc1111/ao_arch_funcs.h @@ -146,4 +146,6 @@ ao_spi_init(void); #define ao_enable_output(port,bit,pin,v) cc1111_enable_output(port,token_evaluator(port,DIR), token_evaluator(port,SEL), pin, bit, v) #define ao_gpio_set(port, bit, pin, v) ((pin) = (v)) #define ao_gpio_get(port, bit, pin) (pin) - +#define ao_gpio_get_bits(port) (port) +#define ao_gpio_set_bits(port, bits) ((port) |= bits) +#define ao_gpio_clr_bits(port, bits) ((port) &= ~bits) diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 087e00d9..f1d17ed1 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -177,6 +177,11 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s #define ao_gpio_get(port, bit, pin) stm_gpio_get(port, bit) +#define ao_gpio_set_bits(port, bits) stm_gpio_set_bits(port, bits) + +#define ao_gpio_clr_bits(port, bits) stm_gpio_clr_bits(port, bits); + + #define ao_enable_output(port,bit,pin,v) do { \ ao_enable_port(port); \ ao_gpio_set(port, bit, pin, v); \ diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index 01afedc6..0b6b2798 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -166,6 +166,16 @@ stm_gpio_set(struct stm_gpio *gpio, int pin, uint8_t value) { gpio->bsrr = ((uint32_t) (value ^ 1) << (pin + 16)) | ((uint32_t) value << pin); } +static inline void +stm_gpio_set_bits(struct stm_gpio *gpio, uint16_t bits) { + gpio->bsrr = bits; +} + +static inline void +stm_gpio_clr_bits(struct stm_gpio *gpio, uint16_t bits) { + gpio->bsrr = ((uint32_t) bits) << 16; +} + static inline uint8_t stm_gpio_get(struct stm_gpio *gpio, int pin) { return (gpio->idr >> pin) & 1; -- cgit v1.2.3 From eee2ca7fa7fd77be8ca5806cad7e250053465048 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Apr 2016 11:47:45 -0400 Subject: Debug bits for telebt --- src/stm/ao_serial_stm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/stm') diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index 88f2d029..9959e460 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -70,6 +70,7 @@ _ao_usart_pollchar(struct ao_stm_usart *usart) uint8_t u; ao_fifo_remove(usart->rx_fifo,u); c = u; + ao_usb_putchar(c); ao_usb_flush(); } return c; } @@ -82,6 +83,7 @@ ao_usart_getchar(struct ao_stm_usart *usart) while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN) ao_sleep(&usart->rx_fifo); ao_arch_release_interrupts(); + ao_usb_putchar(c); ao_usb_flush(); return (char) c; } @@ -94,6 +96,7 @@ _ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout) void ao_usart_putchar(struct ao_stm_usart *usart, char c) { + ao_usb_putchar(c); ao_usb_flush(); ao_arch_block_interrupts(); while (ao_fifo_full(usart->tx_fifo)) ao_sleep(&usart->tx_fifo); -- cgit v1.2.3 From 7c9a111ac1c88467ce28e03b4a9d3eabc9d7015b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 19 Jan 2016 23:53:27 -0800 Subject: altos: Use TXE instead of TC for serial on STM32l Using TXE allows for full-speed communication, rather than waiting for each byte to be transmitted before inserting the next into the queue. Signed-off-by: Keith Packard --- src/stm/ao_arch_funcs.h | 2 ++ src/stm/ao_serial_stm.c | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 7 deletions(-) (limited to 'src/stm') diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index f1d17ed1..6fcfd5f8 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -284,6 +284,8 @@ struct ao_stm_usart { struct ao_fifo tx_fifo; struct stm_usart *reg; uint8_t tx_started; + uint8_t tx_running; + uint8_t draining; }; #if HAS_SERIAL_1 diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index 9959e460..e7b6ab78 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -26,14 +26,19 @@ ao_debug_out(char c) stm_usart1.dr = c; } -static void +static int _ao_usart_tx_start(struct ao_stm_usart *usart) { if (!ao_fifo_empty(usart->tx_fifo) && !usart->tx_started) { usart->tx_started = 1; + usart->tx_running = 1; + usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE); ao_fifo_remove(usart->tx_fifo, usart->reg->dr); + ao_wakeup(&usart->tx_fifo); + return 1; } + return 0; } static void @@ -52,10 +57,18 @@ ao_usart_isr(struct ao_stm_usart *usart, int stdin) if (stdin) ao_wakeup(&ao_stdin_ready); } - if (sr & (1 << STM_USART_SR_TC)) { + if (sr & (1 << STM_USART_SR_TXE)) { usart->tx_started = 0; - _ao_usart_tx_start(usart); - ao_wakeup(&usart->tx_fifo); + if (!_ao_usart_tx_start(usart)) + usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE); + } + if (sr & (1 << STM_USART_SR_TC)) { + usart->tx_running = 0; + usart->reg->cr1 &= ~(1 << STM_USART_CR1_TCIE); + if (usart->draining) { + usart->draining = 0; + ao_wakeup(&usart->tx_fifo); + } } } @@ -105,12 +118,14 @@ ao_usart_putchar(struct ao_stm_usart *usart, char c) ao_arch_release_interrupts(); } -void +static void ao_usart_drain(struct ao_stm_usart *usart) { ao_arch_block_interrupts(); - while (!ao_fifo_empty(usart->tx_fifo)) + while (!ao_fifo_empty(usart->tx_fifo) || usart->tx_running) { + usart->draining = 1; ao_sleep(&usart->tx_fifo); + } ao_arch_release_interrupts(); } @@ -153,7 +168,7 @@ ao_usart_init(struct ao_stm_usart *usart) (0 << STM_USART_CR1_PS) | (0 << STM_USART_CR1_PEIE) | (0 << STM_USART_CR1_TXEIE) | - (1 << STM_USART_CR1_TCIE) | + (0 << STM_USART_CR1_TCIE) | (1 << STM_USART_CR1_RXNEIE) | (0 << STM_USART_CR1_IDLEIE) | (1 << STM_USART_CR1_TE) | @@ -234,6 +249,7 @@ ao_serial1_drain(void) void ao_serial1_set_speed(uint8_t speed) { + ao_usart_drain(&ao_stm_usart1); ao_usart_set_speed(&ao_stm_usart1, speed); } #endif /* HAS_SERIAL_1 */ @@ -277,6 +293,7 @@ ao_serial2_drain(void) void ao_serial2_set_speed(uint8_t speed) { + ao_usart_drain(&ao_stm_usart2); ao_usart_set_speed(&ao_stm_usart2, speed); } #endif /* HAS_SERIAL_2 */ @@ -314,8 +331,15 @@ _ao_serial3_sleep_for(uint16_t timeout) void ao_serial3_set_speed(uint8_t speed) { + ao_usart_drain(&ao_stm_usart3); ao_usart_set_speed(&ao_stm_usart3, speed); } + +void +ao_serial3_drain(void) +{ + ao_usart_drain(&ao_stm_usart3); +} #endif /* HAS_SERIAL_3 */ void -- cgit v1.2.3 From 27319e4edbc503f193475b437fa5fe2937d47cbe Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 25 Apr 2016 18:48:47 -0400 Subject: altos/stm32l: Add support for software-driven HW flow control This allows applications to request that the flow control bits be driven from software rather than hardware, permitting more flexible pin configuration. Signed-off-by: Keith Packard --- src/kernel/ao.h | 2 + src/stm/ao_arch_funcs.h | 23 +++++++- src/stm/ao_serial_stm.c | 154 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 140 insertions(+), 39 deletions(-) (limited to 'src/stm') diff --git a/src/kernel/ao.h b/src/kernel/ao.h index a794ba71..6ed0299e 100644 --- a/src/kernel/ao.h +++ b/src/kernel/ao.h @@ -820,6 +820,8 @@ struct ao_fifo { } while(0) #define ao_fifo_full(f) ((((f).insert + 1) & (AO_FIFO_SIZE-1)) == (f).remove) +#define ao_fifo_mostly(f) ((((f).insert - (f).remove) & (AO_FIFO_SIZE-1)) >= (AO_FIFO_SIZE * 3 / 4)) +#define ao_fifo_barely(f) ((((f).insert - (f).remove) & (AO_FIFO_SIZE-1)) >= (AO_FIFO_SIZE * 1 / 4)) #define ao_fifo_empty(f) ((f).insert == (f).remove) #if PACKET_HAS_MASTER || PACKET_HAS_SLAVE diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 6fcfd5f8..5a7782de 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -278,14 +278,35 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop); void ao_i2c_init(void); +#if USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_SW_FLOW +#define HAS_SERIAL_SW_FLOW 1 +#else +#define HAS_SERIAL_SW_FLOW 0 +#endif + +#if USE_SERIAL_1_FLOW && !USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_FLOW && !USE_SERIAL_3_SW_FLOW +#define HAS_SERIAL_HW_FLOW 1 +#else +#define HAS_SERIAL_HW_FLOW 0 +#endif + /* ao_serial_stm.c */ struct ao_stm_usart { struct ao_fifo rx_fifo; struct ao_fifo tx_fifo; struct stm_usart *reg; - uint8_t tx_started; uint8_t tx_running; uint8_t draining; +#if HAS_SERIAL_SW_FLOW + /* RTS - 0 if we have FIFO space, 1 if not + * CTS - 0 if we can send, 0 if not + */ + struct stm_gpio *gpio_rts; + struct stm_gpio *gpio_cts; + uint8_t pin_rts; + uint8_t pin_cts; + uint8_t rts; +#endif }; #if HAS_SERIAL_1 diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index e7b6ab78..bf079060 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -16,6 +16,7 @@ */ #include +#include void ao_debug_out(char c) @@ -29,40 +30,67 @@ ao_debug_out(char c) static int _ao_usart_tx_start(struct ao_stm_usart *usart) { - if (!ao_fifo_empty(usart->tx_fifo) && !usart->tx_started) - { - usart->tx_started = 1; - usart->tx_running = 1; - usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE); - ao_fifo_remove(usart->tx_fifo, usart->reg->dr); - ao_wakeup(&usart->tx_fifo); - return 1; + if (!ao_fifo_empty(usart->tx_fifo)) { +#if HAS_SERIAL_SW_FLOW + if (usart->gpio_cts && ao_gpio_get(usart->gpio_cts, usart->pin_cts, foo) == 1) { + ao_exti_enable(usart->gpio_cts, usart->pin_cts); + return 0; + } +#endif + if (usart->reg->sr & (1 << STM_USART_SR_TXE)) + { + usart->tx_running = 1; + usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE); + ao_fifo_remove(usart->tx_fifo, usart->reg->dr); + ao_wakeup(&usart->tx_fifo); + return 1; + } } return 0; } +#if HAS_SERIAL_SW_FLOW +static void +_ao_usart_cts(struct ao_stm_usart *usart) +{ + if (_ao_usart_tx_start(usart)) + ao_exti_disable(usart->gpio_cts, usart->pin_cts); +} +#endif + +static void +_ao_usart_rx(struct ao_stm_usart *usart, int stdin) +{ + if (usart->reg->sr & (1 << STM_USART_SR_RXNE)) { + if (!ao_fifo_full(usart->rx_fifo)) { + ao_fifo_insert(usart->rx_fifo, usart->reg->dr); + ao_wakeup(&usart->rx_fifo); + if (stdin) + ao_wakeup(&ao_stdin_ready); +#if HAS_SERIAL_SW_FLOW + /* If the fifo is nearly full, turn off RTS and wait + * for it to drain a bunch + */ + if (usart->gpio_rts && ao_fifo_mostly(usart->rx_fifo)) { + ao_gpio_set(usart->gpio_rts, usart->pin_rts, usart->pin_rts, 1); + usart->rts = 0; + } +#endif + } else { + usart->reg->cr1 &= ~(1 << STM_USART_CR1_RXNEIE); + } + } +} + static void ao_usart_isr(struct ao_stm_usart *usart, int stdin) { - uint32_t sr; + _ao_usart_rx(usart, stdin); - sr = usart->reg->sr; - usart->reg->sr = 0; + if (!_ao_usart_tx_start(usart)) + usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE); - if (sr & (1 << STM_USART_SR_RXNE)) { - char c = usart->reg->dr; - if (!ao_fifo_full(usart->rx_fifo)) - ao_fifo_insert(usart->rx_fifo, c); - ao_wakeup(&usart->rx_fifo); - if (stdin) - ao_wakeup(&ao_stdin_ready); - } - if (sr & (1 << STM_USART_SR_TXE)) { - usart->tx_started = 0; - if (!_ao_usart_tx_start(usart)) - usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE); - } - if (sr & (1 << STM_USART_SR_TC)) { + if (usart->reg->sr & (1 << STM_USART_SR_TC)) { usart->tx_running = 0; usart->reg->cr1 &= ~(1 << STM_USART_CR1_TCIE); if (usart->draining) { @@ -72,7 +100,7 @@ ao_usart_isr(struct ao_stm_usart *usart, int stdin) } } -int +static int _ao_usart_pollchar(struct ao_stm_usart *usart) { int c; @@ -82,13 +110,23 @@ _ao_usart_pollchar(struct ao_stm_usart *usart) else { uint8_t u; ao_fifo_remove(usart->rx_fifo,u); + if ((usart->reg->cr1 & (1 << STM_USART_CR1_RXNEIE)) == 0) { + if (ao_fifo_barely(usart->rx_fifo)) + usart->reg->cr1 |= (1 << STM_USART_CR1_RXNEIE); + } +#if HAS_SERIAL_SW_FLOW + /* If we've cleared RTS, check if there's space now and turn it back on */ + if (usart->gpio_rts && usart->rts == 0 && ao_fifo_barely(usart->rx_fifo)) { + ao_gpio_set(usart->gpio_rts, usart->pin_rts, foo, 0); + usart->rts = 1; + } +#endif c = u; - ao_usb_putchar(c); ao_usb_flush(); } return c; } -char +static char ao_usart_getchar(struct ao_stm_usart *usart) { int c; @@ -96,7 +134,6 @@ ao_usart_getchar(struct ao_stm_usart *usart) while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN) ao_sleep(&usart->rx_fifo); ao_arch_release_interrupts(); - ao_usb_putchar(c); ao_usb_flush(); return (char) c; } @@ -106,10 +143,9 @@ _ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout) return ao_sleep_for(&usart->rx_fifo, timeout); } -void +static void ao_usart_putchar(struct ao_stm_usart *usart, char c) { - ao_usb_putchar(c); ao_usb_flush(); ao_arch_block_interrupts(); while (ao_fifo_full(usart->tx_fifo)) ao_sleep(&usart->tx_fifo); @@ -149,7 +185,7 @@ static const struct { }, }; -void +static void ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed) { if (speed > AO_SERIAL_SPEED_115200) @@ -157,7 +193,7 @@ ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed) usart->reg->brr = ao_usart_speeds[speed].brr; } -void +static void ao_usart_init(struct ao_stm_usart *usart) { usart->reg->cr1 = ((0 << STM_USART_CR1_OVER8) | @@ -203,12 +239,14 @@ ao_usart_init(struct ao_stm_usart *usart) ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600); } -void +#if HAS_SERIAL_HW_FLOW +static void ao_usart_set_flow(struct ao_stm_usart *usart) { usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) | (1 << STM_USART_CR3_RTSE)); } +#endif #if HAS_SERIAL_1 @@ -296,13 +334,22 @@ ao_serial2_set_speed(uint8_t speed) ao_usart_drain(&ao_stm_usart2); ao_usart_set_speed(&ao_stm_usart2, speed); } + +#if HAS_SERIAL_SW_FLOW +void +ao_serial2_cts(void) +{ + _ao_usart_cts(&ao_stm_usart2); +} +#endif + #endif /* HAS_SERIAL_2 */ #if HAS_SERIAL_3 struct ao_stm_usart ao_stm_usart3; -void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_2_STDIN); } +void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_3_STDIN); } char ao_serial3_getchar(void) @@ -342,6 +389,28 @@ ao_serial3_drain(void) } #endif /* HAS_SERIAL_3 */ +#if HAS_SERIAL_SW_FLOW +static void +ao_serial_set_sw_rts_cts(struct ao_stm_usart *usart, + void (*isr)(void), + struct stm_gpio *port_rts, + int pin_rts, + struct stm_gpio *port_cts, + int pin_cts) +{ + /* Pull RTS low to note that there's space in the FIFO + */ + ao_enable_output(port_rts, pin_rts, foo, 0); + usart->gpio_rts = port_rts; + usart->pin_rts = pin_rts; + usart->rts = 1; + + ao_exti_setup(port_cts, pin_cts, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, isr); + usart->gpio_cts = port_cts; + usart->pin_cts = pin_cts; +} +#endif + void ao_serial_init(void) { @@ -394,10 +463,19 @@ ao_serial_init(void) stm_afr_set(&stm_gpioa, 2, STM_AFR_AF7); stm_afr_set(&stm_gpioa, 3, STM_AFR_AF7); -#if USE_SERIAL_2_FLOW +# if USE_SERIAL_2_FLOW +# if USE_SERIAL_2_SW_FLOW + ao_serial_set_sw_rts_cts(&ao_stm_usart2, + ao_serial2_cts, + SERIAL_2_PORT_RTS, + SERIAL_2_PIN_RTS, + SERIAL_2_PORT_CTS, + SERIAL_2_PIN_CTS); +# else stm_afr_set(&stm_gpioa, 0, STM_AFR_AF7); stm_afr_set(&stm_gpioa, 1, STM_AFR_AF7); -#endif +# endif +# endif #else #if SERIAL_2_PD5_PD6 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN); @@ -416,7 +494,7 @@ ao_serial_init(void) ao_stm_usart2.reg = &stm_usart2; ao_usart_init(&ao_stm_usart2); -#if USE_SERIAL_2_FLOW +#if USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW ao_usart_set_flow(&ao_stm_usart2); #endif -- cgit v1.2.3 From 7695da327ff8861a858b6695f4849fa1399548d8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 30 Apr 2016 08:46:52 -0700 Subject: Revert "altos/stm: Run scheduler code on interrupt stack" This reverts commit 6a9546413d6a236c010e806b50506d870961d074. This causes the device to stop reliably handling interrupts. --- src/stm/ao_arch_funcs.h | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'src/stm') diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 5a7782de..2c017c79 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -391,13 +391,6 @@ static inline void ao_arch_save_stack(void) { static inline void ao_arch_restore_stack(void) { uint32_t sp; - uint32_t control; - - asm("mrs %0,control" : "=&r" (control)); - control |= (1 << 1); - asm("msr control,%0" : : "r" (control)); - asm("isb"); - sp = (uint32_t) ao_cur_task->sp; /* Switch stacks */ @@ -454,14 +447,7 @@ static inline void ao_arch_start_scheduler(void) { } #endif -static inline void ao_arch_isr_stack(void) { - uint32_t control; - - asm("mrs %0,control" : "=&r" (control)); - control &= ~(1 << 1); - asm("msr control,%0" : : "r" (control)); - asm("isb"); -} +#define ao_arch_isr_stack() #endif -- cgit v1.2.3