Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:06

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2020 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031 
0032 #include <stm32h7/hal.h>
0033 
0034 #include <bsp.h>
0035 #include <bsp/irq.h>
0036 #include <bsp/fatal.h>
0037 #include <rtems/console.h>
0038 
0039 #include <inttypes.h>
0040 #include <stdio.h>
0041 #include <unistd.h>
0042 
0043 static stm32h7_uart_context * const stm32h7_uart_instances[] = {
0044 #ifdef STM32H7_CONSOLE_ENABLE_USART1
0045   &stm32h7_usart1_instance,
0046 #endif
0047 #ifdef STM32H7_CONSOLE_ENABLE_USART2
0048   &stm32h7_usart2_instance,
0049 #endif
0050 #ifdef STM32H7_CONSOLE_ENABLE_USART3
0051   &stm32h7_usart3_instance,
0052 #endif
0053 #ifdef STM32H7_CONSOLE_ENABLE_UART4
0054   &stm32h7_uart4_instance,
0055 #endif
0056 #ifdef STM32H7_CONSOLE_ENABLE_UART5
0057   &stm32h7_uart5_instance,
0058 #endif
0059 #ifdef STM32H7_CONSOLE_ENABLE_USART6
0060   &stm32h7_usart6_instance,
0061 #endif
0062 #ifdef STM32H7_CONSOLE_ENABLE_UART7
0063   &stm32h7_uart7_instance,
0064 #endif
0065 #ifdef STM32H7_CONSOLE_ENABLE_UART8
0066   &stm32h7_uart8_instance,
0067 #endif
0068 #if defined(STM32H7_CONSOLE_ENABLE_UART9) && defined(UART9)
0069   &stm32h7_uart9_instance,
0070 #endif
0071 #if defined(STM32H7_CONSOLE_ENABLE_USART10) && defined(USART10)
0072   &stm32h7_usart10_instance
0073 #endif
0074 };
0075 
0076 static bool stm32h7_uart_set_attributes(
0077   rtems_termios_device_context *base,
0078   const struct termios *term
0079 )
0080 {
0081   stm32h7_uart_context *ctx;
0082   uint32_t previous_baud;
0083   uint32_t previous_stop_bits;
0084   uint32_t previous_parity;
0085   uint32_t previous_mode;
0086   HAL_StatusTypeDef status;
0087 
0088   if ((term->c_cflag & CSIZE) != CS8) {
0089     return false;
0090   }
0091 
0092   ctx = stm32h7_uart_get_context(base);
0093 
0094   previous_baud = ctx->uart.Init.BaudRate;
0095   ctx->uart.Init.BaudRate = rtems_termios_baud_to_number(term->c_ospeed);
0096 
0097   previous_stop_bits = ctx->uart.Init.StopBits;
0098   if ((term->c_cflag & CSTOPB) != 0) {
0099     ctx->uart.Init.StopBits = UART_STOPBITS_2;
0100   } else {
0101     ctx->uart.Init.StopBits = UART_STOPBITS_1;
0102   }
0103 
0104   previous_parity = ctx->uart.Init.Parity;
0105   if ((term->c_cflag & PARENB) != 0) {
0106     if ((term->c_cflag & PARODD) != 0) {
0107       ctx->uart.Init.Parity = UART_PARITY_ODD;
0108     } else {
0109       ctx->uart.Init.Parity = UART_PARITY_EVEN;
0110     }
0111   } else {
0112     ctx->uart.Init.Parity = UART_PARITY_NONE;
0113   }
0114 
0115   previous_mode = ctx->uart.Init.Mode;
0116   if ((term->c_cflag & CREAD) != 0) {
0117     ctx->uart.Init.Mode = UART_MODE_TX_RX;
0118   } else {
0119     ctx->uart.Init.Mode = UART_MODE_RX;
0120   }
0121 
0122   status = UART_SetConfig(&ctx->uart);
0123   if (status != HAL_OK) {
0124     ctx->uart.Init.BaudRate = previous_baud;
0125     ctx->uart.Init.StopBits = previous_stop_bits;
0126     ctx->uart.Init.Parity = previous_parity;
0127     ctx->uart.Init.Mode = previous_mode;
0128     return false;
0129   }
0130 
0131   return true;
0132 }
0133 
0134 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0135 static void stm32h7_uart_interrupt(void *arg)
0136 {
0137   rtems_termios_tty *tty;
0138   rtems_termios_device_context *base;
0139   stm32h7_uart_context *ctx;
0140   USART_TypeDef *regs;
0141   uint32_t isr;
0142 
0143   tty = arg;
0144   base = rtems_termios_get_device_context(tty);
0145   ctx = stm32h7_uart_get_context(base);
0146   regs = ctx->uart.Instance;
0147   isr = regs->ISR;
0148 
0149   while ((isr & USART_ISR_RXNE_RXFNE) != 0) {
0150     char c;
0151 
0152     c = (uint8_t) regs->RDR;
0153     rtems_termios_enqueue_raw_characters(tty, &c, 1);
0154 
0155     isr = regs->ISR;
0156   }
0157 
0158   if (ctx->transmitting && (isr & USART_ISR_TXE_TXFNF) != 0) {
0159     rtems_termios_dequeue_characters(tty, 1);
0160   }
0161 
0162   regs->ICR = USART_ICR_ORECF;
0163 }
0164 #endif
0165 
0166 static bool stm32h7_uart_first_open(
0167   rtems_termios_tty *tty,
0168   rtems_termios_device_context *base,
0169   struct termios *term,
0170   rtems_libio_open_close_args_t *args
0171 )
0172 {
0173   stm32h7_uart_context *ctx;
0174   UART_HandleTypeDef *uart;
0175 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0176   rtems_status_code sc;
0177 #endif
0178 
0179   ctx = stm32h7_uart_get_context(base);
0180   uart = &ctx->uart;
0181 
0182   rtems_termios_set_initial_baud(tty, BSP_CONSOLE_BAUD);
0183 
0184   (void) HAL_UART_Init(uart);
0185   (void) HAL_UARTEx_SetTxFifoThreshold(uart, UART_TXFIFO_THRESHOLD_1_8);
0186   (void) HAL_UARTEx_SetRxFifoThreshold(uart, UART_RXFIFO_THRESHOLD_1_8);
0187   (void) HAL_UARTEx_EnableFifoMode(uart);
0188 
0189 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0190   sc = rtems_interrupt_handler_install(
0191     ctx->config->irq,
0192     "UART",
0193     RTEMS_INTERRUPT_SHARED,
0194     stm32h7_uart_interrupt,
0195     tty
0196   );
0197   if (sc != RTEMS_SUCCESSFUL) {
0198     return false;
0199   }
0200 
0201   ctx->uart.Instance->CR1 |= USART_CR1_RXNEIE_RXFNEIE;
0202 #endif
0203 
0204   stm32h7_uart_set_attributes(base, term);
0205 
0206   return true;
0207 }
0208 
0209 static void stm32h7_uart_last_close(
0210   rtems_termios_tty *tty,
0211   rtems_termios_device_context *base,
0212   rtems_libio_open_close_args_t *args
0213 )
0214 {
0215 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0216   stm32h7_uart_context *ctx;
0217 
0218   ctx = stm32h7_uart_get_context(base);
0219 
0220   (void) rtems_interrupt_handler_remove(
0221     ctx->config->irq,
0222     stm32h7_uart_interrupt,
0223     tty
0224   );
0225 #endif
0226 }
0227 
0228 static void stm32h7_uart_write(
0229   rtems_termios_device_context *base,
0230   const char *buf,
0231   size_t len
0232 )
0233 {
0234 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0235   stm32h7_uart_context *ctx;
0236   USART_TypeDef *regs;
0237 
0238   ctx = stm32h7_uart_get_context(base);
0239   regs = ctx->uart.Instance;
0240 
0241   if (len > 0) {
0242     ctx->transmitting = true;
0243     regs->TDR = (uint8_t) buf[0];
0244     regs->CR1 |= USART_CR1_TXEIE_TXFNFIE;
0245   } else {
0246     ctx->transmitting = false;
0247     regs->CR1 &= ~USART_CR1_TXEIE_TXFNFIE;
0248   }
0249 #else
0250   size_t i;
0251 
0252   for (i = 0; i < len; ++i) {
0253     stm32h7_uart_polled_write(base, buf[i]);
0254   }
0255 #endif
0256 }
0257 
0258 static const rtems_termios_device_handler stm32h7_uart_handler = {
0259   .first_open = stm32h7_uart_first_open,
0260   .last_close = stm32h7_uart_last_close,
0261   .write = stm32h7_uart_write,
0262   .set_attributes = stm32h7_uart_set_attributes,
0263 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0264   .mode = TERMIOS_IRQ_DRIVEN
0265 #else
0266   .poll_read = stm32h7_uart_polled_read,
0267   .mode = TERMIOS_POLLED
0268 #endif
0269 };
0270 
0271 rtems_status_code console_initialize(
0272   rtems_device_major_number major,
0273   rtems_device_minor_number minor,
0274   void *arg
0275 )
0276 {
0277   size_t i;
0278 
0279   rtems_termios_initialize();
0280 
0281   for (i = 0; i < RTEMS_ARRAY_SIZE(stm32h7_uart_instances); ++i) {
0282     stm32h7_uart_context *ctx;
0283     char path[sizeof("/dev/ttySXXX")];
0284 
0285     ctx = stm32h7_uart_instances[i];
0286     snprintf(path, sizeof(path), "/dev/ttyS%" PRIu8, ctx->config->device_index);
0287 
0288     rtems_termios_device_install(
0289       path,
0290       &stm32h7_uart_handler,
0291       NULL,
0292       &ctx->device
0293     );
0294 
0295     if (ctx == &STM32H7_PRINTK_INSTANCE) {
0296       link(path, CONSOLE_DEVICE_NAME);
0297     }
0298   }
0299 
0300   return RTEMS_SUCCESSFUL;
0301 }