X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=src%2Fstm%2Fao_serial_stm.c;h=bf07906016387c870213b0ae02316f0deb06b280;hp=bd3b1e61c89b8cfb1f626d99cb01040e2b4b567f;hb=27319e4edbc503f193475b437fa5fe2937d47cbe;hpb=f6e557bc2f0bd6d4272ed00dd09554d27a83be89 diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index bd3b1e61..bf079060 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -16,13 +16,7 @@ */ #include - -struct ao_stm_usart { - struct ao_fifo rx_fifo; - struct ao_fifo tx_fifo; - struct stm_usart *reg; - uint8_t tx_started; -}; +#include void ao_debug_out(char c) @@ -33,111 +27,173 @@ ao_debug_out(char c) stm_usart1.dr = c; } -static void -ao_usart_tx_start(struct ao_stm_usart *usart) +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, 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_isr(struct ao_stm_usart *usart, int stdin) +_ao_usart_cts(struct ao_stm_usart *usart) { - uint32_t sr; + if (_ao_usart_tx_start(usart)) + ao_exti_disable(usart->gpio_cts, usart->pin_cts); +} +#endif - sr = usart->reg->sr; - usart->reg->sr = 0; +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); + } + } +} - 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_isr(struct ao_stm_usart *usart, int stdin) +{ + _ao_usart_rx(usart, 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); + } } - if (sr & (1 << STM_USART_SR_TC)) { - usart->tx_started = 0; - ao_usart_tx_start(usart); - ao_wakeup(&usart->tx_fifo); +} + +static int +_ao_usart_pollchar(struct ao_stm_usart *usart) +{ + int c; + + if (ao_fifo_empty(usart->rx_fifo)) + c = AO_READ_AGAIN; + 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; } + return c; } -char +static char ao_usart_getchar(struct ao_stm_usart *usart) { - char c; - cli(); - while (ao_fifo_empty(usart->rx_fifo)) + int c; + ao_arch_block_interrupts(); + while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN) ao_sleep(&usart->rx_fifo); - ao_fifo_remove(usart->rx_fifo, c); - sei(); - return c; + ao_arch_release_interrupts(); + return (char) c; } -char -ao_usart_pollchar(struct ao_stm_usart *usart) +static inline uint8_t +_ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout) { - char c; - cli(); - if (ao_fifo_empty(usart->rx_fifo)) { - sei(); - return AO_READ_AGAIN; - } - ao_fifo_remove(usart->rx_fifo,c); - sei(); - return c; + return ao_sleep_for(&usart->rx_fifo, timeout); } -void +static void ao_usart_putchar(struct ao_stm_usart *usart, char c) { - cli(); + ao_arch_block_interrupts(); while (ao_fifo_full(usart->tx_fifo)) ao_sleep(&usart->tx_fifo); ao_fifo_insert(usart->tx_fifo, c); - ao_usart_tx_start(usart); - sei(); + _ao_usart_tx_start(usart); + ao_arch_release_interrupts(); } -void +static void ao_usart_drain(struct ao_stm_usart *usart) { - cli(); - while (!ao_fifo_empty(usart->tx_fifo)) + ao_arch_block_interrupts(); + while (!ao_fifo_empty(usart->tx_fifo) || usart->tx_running) { + usart->draining = 1; ao_sleep(&usart->tx_fifo); - sei(); + } + ao_arch_release_interrupts(); } static const struct { uint32_t brr; } ao_usart_speeds[] = { [AO_SERIAL_SPEED_4800] = { - STM_APB1 / 4800 + AO_PCLK1 / 4800 }, [AO_SERIAL_SPEED_9600] = { - STM_APB1 / 9600 + AO_PCLK1 / 9600 }, [AO_SERIAL_SPEED_19200] = { - STM_APB1 / 19200 + AO_PCLK1 / 19200 }, [AO_SERIAL_SPEED_57600] = { - STM_APB1 / 57600 + AO_PCLK1 / 57600 + }, + [AO_SERIAL_SPEED_115200] = { + AO_PCLK1 / 115200 }, }; -void +static void ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed) { - if (speed > AO_SERIAL_SPEED_57600) + if (speed > AO_SERIAL_SPEED_115200) return; - stm_usart1.brr = ao_usart_speeds[speed].brr; + 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) | @@ -148,7 +204,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) | @@ -183,47 +239,214 @@ ao_usart_init(struct ao_stm_usart *usart) ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600); } +#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 + struct ao_stm_usart ao_stm_usart1; -void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_STDIN); } -#endif + +void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_1_STDIN); } + +char +ao_serial1_getchar(void) +{ + return ao_usart_getchar(&ao_stm_usart1); +} + +void +ao_serial1_putchar(char c) +{ + ao_usart_putchar(&ao_stm_usart1, c); +} + +int +_ao_serial1_pollchar(void) +{ + return _ao_usart_pollchar(&ao_stm_usart1); +} + +uint8_t +_ao_serial1_sleep_for(uint16_t timeout) +{ + return _ao_usart_sleep_for(&ao_stm_usart1, timeout); +} + +void +ao_serial1_drain(void) +{ + ao_usart_drain(&ao_stm_usart1); +} + +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 */ + #if HAS_SERIAL_2 + struct ao_stm_usart ao_stm_usart2; -void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, 0); } + +void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, USE_SERIAL_2_STDIN); } + +char +ao_serial2_getchar(void) +{ + return ao_usart_getchar(&ao_stm_usart2); +} + +void +ao_serial2_putchar(char c) +{ + ao_usart_putchar(&ao_stm_usart2, c); +} + +int +_ao_serial2_pollchar(void) +{ + return _ao_usart_pollchar(&ao_stm_usart2); +} + +uint8_t +_ao_serial2_sleep_for(uint16_t timeout) +{ + return _ao_usart_sleep_for(&ao_stm_usart2, timeout); +} + +void +ao_serial2_drain(void) +{ + ao_usart_drain(&ao_stm_usart2); +} + +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 +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, 0); } + +void stm_usart3_isr(void) { ao_usart_isr(&ao_stm_usart3, USE_SERIAL_3_STDIN); } + +char +ao_serial3_getchar(void) +{ + return ao_usart_getchar(&ao_stm_usart3); +} + +void +ao_serial3_putchar(char c) +{ + ao_usart_putchar(&ao_stm_usart3, c); +} + +int +_ao_serial3_pollchar(void) +{ + return _ao_usart_pollchar(&ao_stm_usart3); +} + +uint8_t +_ao_serial3_sleep_for(uint16_t timeout) +{ + return _ao_usart_sleep_for(&ao_stm_usart3, 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, 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) { -#ifdef HAS_SERIAL_1 +#if HAS_SERIAL_1 /* * TX RX * PA9 PA10 * PB6 PB7 * */ +#if SERIAL_1_PA9_PA10 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); + + stm_afr_set(&stm_gpioa, 9, STM_AFR_AF7); + stm_afr_set(&stm_gpioa, 10, STM_AFR_AF7); +#else +#if SERIAL_1_PB6_PB7 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); - stm_moder_set(&stm_gpiob, 6, STM_MODER_ALTERNATE); - stm_moder_set(&stm_gpiob, 7, STM_MODER_ALTERNATE); stm_afr_set(&stm_gpiob, 6, STM_AFR_AF7); stm_afr_set(&stm_gpiob, 7, STM_AFR_AF7); - +#else +#error "No SERIAL_1 port configuration specified" +#endif +#endif /* Enable USART */ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN); - ao_stm_usart1.reg = &stm_usart1; + ao_stm_usart1.reg = &stm_usart1; ao_usart_init(&ao_stm_usart1); stm_nvic_set_enable(STM_ISR_USART1_POS); stm_nvic_set_priority(STM_ISR_USART1_POS, 4); -#if USE_SERIAL_STDIN - ao_add_stdio(ao_serial_pollchar, - ao_serial_putchar, +#if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN + ao_add_stdio(_ao_serial1_pollchar, + ao_serial1_putchar, NULL); #endif #endif @@ -235,21 +458,53 @@ ao_serial_init(void) * PD5 PD6 */ +#if SERIAL_2_PA2_PA3 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); - stm_moder_set(&stm_gpioa, 2, STM_MODER_ALTERNATE); - stm_moder_set(&stm_gpioa, 3, STM_MODER_ALTERNATE); 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_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 +#else +#if SERIAL_2_PD5_PD6 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN); + + stm_afr_set(&stm_gpiod, 5, STM_AFR_AF7); + stm_afr_set(&stm_gpiod, 6, STM_AFR_AF7); +#if USE_SERIAL_2_FLOW +#error "Don't know how to set flowcontrol for serial 2 on PD" +#endif +#else +#error "No SERIAL_2 port configuration specified" +#endif +#endif /* Enable USART */ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN); - ao_usart_init(&stm_usart1); ao_stm_usart2.reg = &stm_usart2; + ao_usart_init(&ao_stm_usart2); +#if USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW + ao_usart_set_flow(&ao_stm_usart2); +#endif stm_nvic_set_enable(STM_ISR_USART2_POS); stm_nvic_set_priority(STM_ISR_USART2_POS, 4); +#if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN + ao_add_stdio(_ao_serial2_pollchar, + ao_serial2_putchar, + NULL); +#endif #endif #if HAS_SERIAL_3 @@ -259,44 +514,40 @@ ao_serial_init(void) * PC10 PC11 * PD8 PD9 */ +#if SERIAL_3_PB10_PB11 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); - stm_moder_set(&stm_gpiob, 10, STM_MODER_ALTERNATE); - stm_moder_set(&stm_gpiob, 11, STM_MODER_ALTERNATE); stm_afr_set(&stm_gpiob, 10, STM_AFR_AF7); stm_afr_set(&stm_gpiob, 11, STM_AFR_AF7); - +#else +#if SERIAL_3_PC10_PC11 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN); + + stm_afr_set(&stm_gpioc, 10, STM_AFR_AF7); + stm_afr_set(&stm_gpioc, 11, STM_AFR_AF7); +#else +#if SERIAL_3_PD8_PD9 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN); + + stm_afr_set(&stm_gpiod, 8, STM_AFR_AF7); + stm_afr_set(&stm_gpiod, 9, STM_AFR_AF7); +#else +#error "No SERIAL_3 port configuration specified" +#endif +#endif +#endif /* Enable USART */ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART3EN); - ao_usart_init(&stm_usart1); ao_stm_usart3.reg = &stm_usart3; + ao_usart_init(&ao_stm_usart3); stm_nvic_set_enable(STM_ISR_USART3_POS); stm_nvic_set_priority(STM_ISR_USART3_POS, 4); +#if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN + ao_add_stdio(_ao_serial3_pollchar, + ao_serial3_putchar, + NULL); #endif -} - -#if HAS_SERIAL_1 -char -ao_serial_getchar(void) -{ - return ao_usart_getchar(&ao_stm_usart1); -} - -#if USE_SERIAL_STDIN -char -ao_serial_pollchar(void) -{ - return ao_usart_pollchar(&ao_stm_usart1); -} #endif - -void -ao_serial_putchar(char c) -{ - ao_usart_putchar(&ao_stm_usart1, c); } -#endif /* HAS_SERIAL_1 */ - -