Back to home page

LXR

 
 

    


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

0001 /*
0002  * Copyright (c) 2012 Sebastian Huber.  All rights reserved.
0003  *
0004  * The license and distribution terms for this file may be
0005  * found in the file LICENSE in this distribution or at
0006  * http://www.rtems.org/license/LICENSE.
0007  */
0008 
0009 #include <libchip/sersupp.h>
0010 
0011 #include <bsp.h>
0012 #include <bsp/io.h>
0013 #include <bsp/rcc.h>
0014 #include <bsp/irq.h>
0015 #include <bsp/usart.h>
0016 #include <bsp/stm32f4.h>
0017 #include <termios.h>
0018 #include <string.h>
0019 
0020 static volatile stm32f4_usart *usart_get_regs(const console_tbl *ct)
0021 {
0022   return (stm32f4_usart *) ct->ulCtrlPort1;
0023 }
0024 
0025 #if 0
0026 static rtems_vector_number usart_get_irq_number(const console_tbl *ct)
0027 {
0028   return ct->ulIntVector;
0029 }
0030 #endif
0031 
0032 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0033 /**
0034  * Read characters in an interrupt
0035  */
0036 static void stm32f4_usart_interrupt(void *arg)
0037 {
0038   rtems_termios_tty *tty = (rtems_termios_tty *) arg;
0039   const console_tbl *ct = Console_Port_Tbl [tty->minor];
0040   volatile stm32f4_usart *usart = usart_get_regs(ct);
0041 
0042   while ((usart->sr & STM32F4_USART_SR_RXNE) == STM32F4_USART_SR_RXNE)
0043   {
0044     char data = STM32F4_USART_DR_GET(usart->dr);
0045     rtems_termios_enqueue_raw_characters(tty, &data, sizeof(data));
0046   }
0047 }
0048 #endif
0049 
0050 static const stm32f4_rcc_index usart_rcc_index [] = {
0051   STM32F4_RCC_USART1,
0052   STM32F4_RCC_USART2,
0053   STM32F4_RCC_USART3,
0054   STM32F4_RCC_UART4,
0055   STM32F4_RCC_UART5,
0056 #ifdef STM32F4_FAMILY_F4XXXX
0057   STM32F4_RCC_USART6
0058 #endif /* STM32F4_FAMILY_F4XXXX */
0059 };
0060 
0061 static stm32f4_rcc_index usart_get_rcc_index(const console_tbl *ct)
0062 {
0063   return usart_rcc_index [ct->ulCtrlPort2];
0064 }
0065 
0066 static const uint8_t usart_pclk_index [] = { 1, 0, 0, 0, 0, 1 };
0067 
0068 static const uint32_t usart_pclk_by_index [] = {
0069   STM32F4_PCLK1,
0070   STM32F4_PCLK2
0071 };
0072 
0073 static uint32_t usart_get_pclk(const console_tbl *ct)
0074 {
0075   return usart_pclk_by_index [usart_pclk_index [ct->ulCtrlPort2]];
0076 }
0077 
0078 static uint32_t usart_get_baud(const console_tbl *ct)
0079 {
0080   return ct->ulClock;
0081 }
0082 
0083 /*
0084  * a = 8 * (2 - CR1[OVER8])
0085  *
0086  * usartdiv = div_mantissa + div_fraction / a
0087  *
0088  * baud = pclk / (a * usartdiv)
0089  *
0090  * usartdiv = pclk / (a * baud)
0091  *
0092  * Calculation in integer arithmetic:
0093  *
0094  * 1. div_mantissa = pclk / (a * baud)
0095  *
0096  * 2. div_fraction = pclk / (baud - a * div_mantissa)
0097  */
0098 static uint32_t usart_get_bbr(
0099   volatile stm32f4_usart *usart,
0100   uint32_t pclk,
0101   uint32_t baud
0102 )
0103 {
0104   uint32_t a = 8 * (2 - ((usart->cr1 & STM32F4_USART_CR1_OVER8) != 0));
0105   uint32_t div_mantissa_low = pclk / (a * baud);
0106   uint32_t div_fraction_low = pclk / (baud - a * div_mantissa_low);
0107   uint32_t div_mantissa_high;
0108   uint32_t div_fraction_high;
0109   uint32_t high_err;
0110   uint32_t low_err;
0111   uint32_t div_mantissa;
0112   uint32_t div_fraction;
0113 
0114   if (div_fraction_low < a - 1) {
0115     div_mantissa_high = div_fraction_low;
0116     div_fraction_high = div_fraction_low + 1;
0117   } else {
0118     div_mantissa_high = div_fraction_low + 1;
0119     div_fraction_high = 0;
0120   }
0121 
0122   high_err = pclk - baud * (a * div_mantissa_high + div_fraction_high);
0123   low_err = baud * (a * div_mantissa_low + div_fraction_low) - pclk;
0124 
0125   if (low_err < high_err) {
0126     div_mantissa = div_mantissa_low;
0127     div_fraction = div_fraction_low;
0128   } else {
0129     div_mantissa = div_mantissa_high;
0130     div_fraction = div_fraction_high;
0131   }
0132 
0133   return STM32F4_USART_BBR_DIV_MANTISSA(div_mantissa)
0134     | STM32F4_USART_BBR_DIV_FRACTION(div_fraction);
0135 }
0136 
0137 static void usart_initialize(int minor)
0138 {
0139   const console_tbl *ct = Console_Port_Tbl [minor];
0140   volatile stm32f4_usart *usart = usart_get_regs(ct);
0141   uint32_t pclk = usart_get_pclk(ct);
0142   uint32_t baud = usart_get_baud(ct);
0143   stm32f4_rcc_index rcc_index = usart_get_rcc_index(ct);
0144 
0145   stm32f4_rcc_set_clock(rcc_index, true);
0146 
0147   usart->cr1 = 0;
0148   usart->cr2 = 0;
0149   usart->cr3 = 0;
0150   usart->bbr = usart_get_bbr(usart, pclk, baud);
0151   usart->cr1 = STM32F4_USART_CR1_UE // UART enable
0152 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0153     | STM32F4_USART_CR1_RXNEIE // RX interrupt
0154 #endif
0155     | STM32F4_USART_CR1_TE  // TX enable
0156     | STM32F4_USART_CR1_RE; // RX enable
0157 }
0158 
0159 static int usart_first_open(int major, int minor, void *arg)
0160 {
0161   rtems_status_code sc = RTEMS_SUCCESSFUL;
0162   rtems_libio_open_close_args_t *oc = (rtems_libio_open_close_args_t *) arg;
0163   rtems_termios_tty *tty = (struct rtems_termios_tty *) oc->iop->data1;
0164   const console_tbl *ct = Console_Port_Tbl [minor];
0165   console_data *cd = &Console_Port_Data [minor];
0166 
0167   cd->termios_data = tty;
0168   rtems_termios_set_initial_baud(tty, ct->ulClock);
0169 
0170 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0171   sc = rtems_interrupt_handler_install(ct->ulIntVector,
0172       ct->sDeviceName,
0173       RTEMS_INTERRUPT_UNIQUE,
0174       stm32f4_usart_interrupt,
0175       tty);
0176 #endif
0177 
0178   return sc;
0179 }
0180 
0181 static int usart_last_close(int major, int minor, void *arg)
0182 {
0183   rtems_status_code sc = RTEMS_SUCCESSFUL;
0184 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0185   rtems_libio_open_close_args_t *oc = (rtems_libio_open_close_args_t *) arg;
0186   rtems_termios_tty *tty = (struct rtems_termios_tty *) oc->iop->data1;
0187   const console_tbl *ct = Console_Port_Tbl [minor];
0188 
0189   sc = rtems_interrupt_handler_remove(ct->ulIntVector, stm32f4_usart_interrupt, tty);
0190 #endif
0191   return sc;
0192 }
0193 
0194 #ifndef BSP_CONSOLE_USE_INTERRUPTS
0195 static int usart_read_polled(int minor)
0196 {
0197   const console_tbl *ct = Console_Port_Tbl [minor];
0198   volatile stm32f4_usart *usart = usart_get_regs(ct);
0199 
0200   if ((usart->sr & STM32F4_USART_SR_RXNE) != 0) {
0201     return STM32F4_USART_DR_GET(usart->dr);
0202   } else {
0203     return -1;
0204   }
0205 }
0206 #endif
0207 
0208 static void usart_write_polled(int minor, char c)
0209 {
0210   const console_tbl *ct = Console_Port_Tbl [minor];
0211   volatile stm32f4_usart *usart = usart_get_regs(ct);
0212 
0213   while ((usart->sr & STM32F4_USART_SR_TXE) == 0) {
0214     /* Wait */
0215   }
0216 
0217   usart->dr = STM32F4_USART_DR(c);
0218 }
0219 
0220 static ssize_t usart_write_support_polled(
0221   int minor,
0222   const char *s,
0223   size_t n
0224 )
0225 {
0226   ssize_t i = 0;
0227 
0228   for (i = 0; i < n; ++i) {
0229     usart_write_polled(minor, s [i]);
0230   }
0231 
0232   return n;
0233 }
0234 
0235 /**
0236  * Configure settings from a termios call to tcsetattr()
0237  */
0238 static int usart_set_attributes(int minor, const struct termios *term)
0239 {
0240   console_tbl *ct = Console_Port_Tbl[minor];
0241   volatile stm32f4_usart *usart = usart_get_regs(ct);
0242   uint32_t pclk = usart_get_pclk(ct);
0243   uint32_t baud = term->c_ispeed;
0244 
0245   ct->ulClock = baud;
0246   usart->bbr = usart_get_bbr(usart, pclk, baud);
0247   return 0;
0248 }
0249 
0250 const console_fns stm32f4_usart_fns = {
0251   .deviceProbe = libchip_serial_default_probe,
0252   .deviceFirstOpen = usart_first_open,
0253   .deviceLastClose = usart_last_close,
0254 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0255   .deviceRead = NULL,
0256 #else
0257   .deviceRead = usart_read_polled,
0258 #endif
0259   .deviceWrite = usart_write_support_polled,
0260   .deviceInitialize = usart_initialize,
0261   .deviceWritePolled = usart_write_polled,
0262   .deviceSetAttributes = usart_set_attributes,
0263   .deviceOutputUsesInterrupts = false
0264 };