X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=src%2Fstm%2Fao_serial_stm.c;h=7a552e5d86a5884d0e5653081b11c3921a3b8999;hp=88f2d0299ecf65f1b350dde44e0ede1d744c7c1f;hb=6aeb000899ad7f22e92b487b5891664554bc4d33;hpb=f4c812bef76a2cd95f675cb27ea89059561ceec7 diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index 88f2d029..7a552e5d 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -3,7 +3,8 @@ * * 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. + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,6 +17,7 @@ */ #include +#include void ao_debug_out(char c) @@ -26,40 +28,80 @@ 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; - ao_fifo_remove(usart->tx_fifo, usart->reg->dr); + 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) == 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_isr(struct ao_stm_usart *usart, int stdin) +_ao_usart_cts(struct ao_stm_usart *usart) { - uint32_t sr; - - sr = usart->reg->sr; - usart->reg->sr = 0; + if (_ao_usart_tx_start(usart)) + ao_exti_disable(usart->gpio_cts, usart->pin_cts); +} +#endif - 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); +static void +_ao_usart_rx(struct ao_stm_usart *usart, int is_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 (is_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, 1); + usart->rts = 0; + } +#endif + } else { + usart->reg->cr1 &= ~(1 << STM_USART_CR1_RXNEIE); + } } - if (sr & (1 << STM_USART_SR_TC)) { - usart->tx_started = 0; - _ao_usart_tx_start(usart); - ao_wakeup(&usart->tx_fifo); +} + +static void +ao_usart_isr(struct ao_stm_usart *usart, int is_stdin) +{ + _ao_usart_rx(usart, is_stdin); + + if (!_ao_usart_tx_start(usart)) + usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE); + + if (usart->reg->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); + } } } -int +static int _ao_usart_pollchar(struct ao_stm_usart *usart) { int c; @@ -69,12 +111,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, 0); + usart->rts = 1; + } +#endif c = u; } return c; } -char +static char ao_usart_getchar(struct ao_stm_usart *usart) { int c; @@ -91,7 +144,7 @@ _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_arch_block_interrupts(); @@ -102,12 +155,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(); } @@ -131,7 +186,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) @@ -139,8 +194,8 @@ ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed) usart->reg->brr = ao_usart_speeds[speed].brr; } -void -ao_usart_init(struct ao_stm_usart *usart) +static void +ao_usart_init(struct ao_stm_usart *usart, int hw_flow) { usart->reg->cr1 = ((0 << STM_USART_CR1_OVER8) | (1 << STM_USART_CR1_UE) | @@ -150,7 +205,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) | @@ -181,16 +236,20 @@ ao_usart_init(struct ao_stm_usart *usart) (0 << STM_USART_CR3_IREN) | (0 << STM_USART_CR3_EIE)); + if (hw_flow) + usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) | + (1 << STM_USART_CR3_RTSE)); + /* Pick a 9600 baud rate */ 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 @@ -231,6 +290,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 */ @@ -274,15 +334,25 @@ 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); } + +#if HAS_SERIAL_SW_FLOW +static 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) @@ -311,10 +381,39 @@ _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 */ +#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, 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) { @@ -344,10 +443,10 @@ ao_serial_init(void) stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN); ao_stm_usart1.reg = &stm_usart1; - ao_usart_init(&ao_stm_usart1); + ao_usart_init(&ao_stm_usart1, 0); stm_nvic_set_enable(STM_ISR_USART1_POS); - stm_nvic_set_priority(STM_ISR_USART1_POS, 4); + stm_nvic_set_priority(STM_ISR_USART1_POS, AO_STM_NVIC_MED_PRIORITY); #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN ao_add_stdio(_ao_serial1_pollchar, ao_serial1_putchar, @@ -367,10 +466,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); @@ -388,13 +496,10 @@ ao_serial_init(void) stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN); ao_stm_usart2.reg = &stm_usart2; - ao_usart_init(&ao_stm_usart2); -#if USE_SERIAL_2_FLOW - ao_usart_set_flow(&ao_stm_usart2); -#endif + ao_usart_init(&ao_stm_usart2, USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW); stm_nvic_set_enable(STM_ISR_USART2_POS); - stm_nvic_set_priority(STM_ISR_USART2_POS, 4); + stm_nvic_set_priority(STM_ISR_USART2_POS, AO_STM_NVIC_MED_PRIORITY); #if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN ao_add_stdio(_ao_serial2_pollchar, ao_serial2_putchar, @@ -435,10 +540,10 @@ ao_serial_init(void) stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART3EN); ao_stm_usart3.reg = &stm_usart3; - ao_usart_init(&ao_stm_usart3); + ao_usart_init(&ao_stm_usart3, 0); stm_nvic_set_enable(STM_ISR_USART3_POS); - stm_nvic_set_priority(STM_ISR_USART3_POS, 4); + stm_nvic_set_priority(STM_ISR_USART3_POS, AO_STM_NVIC_MED_PRIORITY); #if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN ao_add_stdio(_ao_serial3_pollchar, ao_serial3_putchar,