diff --git a/arch/arm/src/stm32/stm32_lowputc.c b/arch/arm/src/stm32/stm32_lowputc.c index 4ed14ee231c..61a4765e8c5 100644 --- a/arch/arm/src/stm32/stm32_lowputc.c +++ b/arch/arm/src/stm32/stm32_lowputc.c @@ -44,6 +44,9 @@ #include "up_arch.h" #include "chip.h" +#include "stm32_rcc.h" +#include "stm32_gpio.h" +#include "stm32_uart.h" #include "stm32_internal.h" /************************************************************************** @@ -77,18 +80,21 @@ #if defined(CONFIG_USART1_SERIAL_CONSOLE) # define STM32_CONSOLE_BASE STM32_USART1_BASE +# define STM32_APBCLOCK STM32_PCLK2_FREQUENCY # define STM32_CONSOLE_BAUD CONFIG_USART1_BAUD # define STM32_CONSOLE_BITS CONFIG_USART1_BITS # define STM32_CONSOLE_PARITY CONFIG_USART1_PARITY # define STM32_CONSOLE_2STOP CONFIG_USART1_2STOP #elif defined(CONFIG_USART2_SERIAL_CONSOLE) # define STM32_CONSOLE_BASE STM32_USART2_BASE +# define STM32_APBCLOCK STM32_PCLK1_FREQUENCY # define STM32_CONSOLE_BAUD CONFIG_USART2_BAUD # define STM32_CONSOLE_BITS CONFIG_USART2_BITS # define STM32_CONSOLE_PARITY CONFIG_USART2_PARITY # define STM32_CONSOLE_2STOP CONFIG_USART2_2STOP #elif defined(CONFIG_USART3_SERIAL_CONSOLE) # define STM32_CONSOLE_BASE STM32_USART2_BASE +# define STM32_APBCLOCK STM32_PCLK1_FREQUENCY # define STM32_CONSOLE_BAUD CONFIG_USART2_BAUD # define STM32_CONSOLE_BITS CONFIG_USART2_BITS # define STM32_CONSOLE_PARITY CONFIG_USART2_PARITY @@ -97,7 +103,62 @@ # error "No CONFIG_USARTn_SERIAL_CONSOLE Setting" #endif -/* Calculate BAUD rate from the SYS clock */ +/* CR1 settings */ + +#if CONFIG_USART2_BITS == 9 +# define USART_CR1_M_VALUE USART_CR1_M +#else +# define USART_CR1_M_VALUE 0 +#endif + +#if CONFIG_USART2_PARITY == 1 +# define USART_CR1_PARITY_VALUE (USART_CR1_PCE|USART_CR1_PS) +#elif CONFIG_USART2_PARITY == 2 +# define USART_CR1_PARITY_VALUE USART_CR1_PCE +#else +# define USART_CR1_PARITY_VALUE 0 +#endif + +#define USART_CR1_CLRBITS (USART_CR1_M|USART_CR1_PCE|USART_CR1_PS|USART_CR1_TE|USART_CR1_RE|USART_CR1_ALLINTS) +#define USART_CR1_SETBITS (USART_CR1_M_VALUE|USART_CR1_PARITY_VALUE) + +/* CR2 settings */ + +#if CONFIG_USART2_2STOP != 0 +# define USART_CR2_STOP2_VALUE USART_CR2_STOP2 +#else +# define USART_CR2_STOP2_VALUE 0 +#endif + +#define USART_CR2_CLRBITS (USART_CR2_STOP_MASK|USART_CR2_CLKEN|USART_CR2_CPOL|USART_CR2_CPHA|USART_CR2_LBCL|USART_CR2_LBDIE) +#define USART_CR2_SETBITS USART_CR2_STOP2_VALUE + +/* CR3 settings */ + +#define USART_CR3_CLRBITS (USART_CR3_CTSIE|USART_CR3_CTSE|USART_CR3_RTSE|USART_CR3_EIE) +#define USART_CR3_SETBITS 0 + +/* Calculate USART BAUD rate divider + * + * The baud rate for the receiver and transmitter (Rx and Tx) are both set to + * the same value as programmed in the Mantissa and Fraction values of USARTDIV. + * + * baud = fCK / (16 * usartdiv) + * usartdiv = fCK / (16 * baud) + * + * Where fCK is the input clock to the peripheral (PCLK1 for USART2, 3, 4, 5 + * or PCLK2 for USART1) + * + * First calculate (NOTE: all stand baud values are even so dividing by two + * does not lose precision): + * + * usartdiv32 = 32 * usartdiv = fCK / (baud/2) + */ + +#define STM32_USARTDIV32 (STM32_APBCLOCK / (STM32_CONSOLE_BAUD >> 1)) +#define STM32_MANTISSA (STM32_USARTDIV32 >> 5) +#define STM32_FRACTION ((STM32_USARTDIV32 - (STM32_MANTISSA << 5) + 1) >> 1) +#define STM32_BRR_VALUE ((STM32_MANTISSA << USART_BRR_MANT_SHIFT) | (STM32_FRACTION << USART_BRR_FRAC_SHIFT)) /************************************************************************** * Private Types @@ -136,8 +197,11 @@ void up_lowputc(char ch) #ifdef HAVE_CONSOLE /* Wait until the TX FIFO is not full */ + while ((getreg16(STM32_CONSOLE_BASE + STM32_USART_SR_OFFSET) & USART_SR_TXE) != 0); /* Then send the character */ + + putreg16((uint16)ch, STM32_CONSOLE_BASE + STM32_USART_DR_OFFSET); #endif } @@ -153,24 +217,122 @@ void up_lowputc(char ch) void up_lowsetup(void) { +#if !defined(CONFIG_USART1_DISABLE) || !defined(CONFIG_USART2_DISABLE) || !defined(CONFIG_USART3_DISABLE) + uint32 enr; + uint32 mapr; +#if defined(HAVE_CONSOLE) && !defined(CONFIG_SUPPRESS_USART_CONFIG) + uint32 cr; +#endif + /* Enable the selected USARTs and configure GPIO pins need byed the * the selected USARTs. NOTE: The serial driver later depends on * this pin configuration -- whether or not a serial console is selected. */ -#ifndef CONFIG_USART1_DISABLE -#endif + mapr = getreg32(STM32_AFIO_MAPR); #ifndef CONFIG_USART1_DISABLE -#endif + /* Enable USART1 clocking */ + + enr = getreg32(STM32_RCC_APB2ENR_OFFSET); + enr |= RCC_APB2ENR_USART1EN; + putreg32(enr, STM32_RCC_APB2ENR_OFFSET); + + /* Assume default pin mapping: + * + * Alternate USART1_REMAP USART1_REMAP + * Function = 0 = 1 + * ---------- ------------ ------------ + * USART1_TX PA9 PB6 + * USART1_RX PA10 PB7 + */ + + mapr &= ~AFIO_MAPR_USART1_REMAP; + +#endif /* !CONFIG_USART1_DISABLE */ + +#if !defined(CONFIG_USART2_DISABLE) && !defined(CONFIG_USART3_DISABLE) + enr = getreg32(STM32_RCC_APB1ENR_OFFSET); #ifndef CONFIG_USART2_DISABLE -#endif + /* Enable USART2 clocking */ + + enr |= RCC_APB1ENR_USART2EN; + + /* Assume default pin mapping: + * + * Alternate USART2_REMAP USART2_REMAP + * Function = 0 = 1 + * ---------- ------------ ------------ + * USART2_TX PA2 PD5 + * USART2_RX PA3 PD6 + */ + + mapr &= ~AFIO_MAPR_USART2_REMAP; + +#endif /* !CONFIG_USART2_DISABLE */ + +#ifndef CONFIG_USART3_DISABLE + /* Enable USART3 clocking */ + + enr |= RCC_APB1ENR_USART3EN; + + /* Assume default pin mapping: + * + * + * Alternate USART3_REMAP[1:0] USART3_REMAP[1:0] USART3_REMAP[1:0] + * Function = “00” (no remap) = “01” (partial remap) = “11” (full remap) + * --------- ------------------ ---------------------- -------------------- + * USART3_TX PB10 PC10 PD8 + * USART3_RX PB11 PC11 PD9 + */ + + mapr &= ~AFIO_MAPR_USART3_REMAP_MASK; + +#endif /* !CONFIG_USART3_DISABLE */ + /* Save the UART enable settings */ + + putreg32(enr, STM32_RCC_APB1ENR_OFFSET); +#endif /* !CONFIG_USART2_DISABLE && !CONFIG_USART3_DISABLE */ + /* Save the USART pin mappings */ + + putreg32(mapr, STM32_AFIO_MAPR); /* Enable and configure the selected console device */ #if defined(HAVE_CONSOLE) && !defined(CONFIG_SUPPRESS_USART_CONFIG) + /* Configure CR2 */ + + cr = getreg16(STM32_CONSOLE_BASE + STM32_USART_CR2_OFFSET); + cr &= ~USART_CR2_CLRBITS; + cr |= USART_CR2_SETBITS; + putreg16(cr, STM32_CONSOLE_BASE + STM32_USART_CR2_OFFSET); + + /* Configure CR1 */ + + cr = getreg16(STM32_CONSOLE_BASE + STM32_USART_CR1_OFFSET); + cr &= ~USART_CR1_CLRBITS; + cr |= USART_CR1_SETBITS; + putreg16(cr, STM32_CONSOLE_BASE + STM32_USART_CR1_OFFSET); + + /* Configure CR3 */ + + cr = getreg16(STM32_CONSOLE_BASE + STM32_USART_CR3_OFFSET); + cr &= ~USART_CR3_CLRBITS; + cr |= USART_CR3_SETBITS; + putreg16(cr, STM32_CONSOLE_BASE + STM32_USART_CR3_OFFSET); + + /* Configure the USART Baud Rate */ + + putreg32(STM32_BRR_VALUE, STM32_CONSOLE_BASE + STM32_USART_BRR_OFFSET); + + /* Enable Rx, Tx, and the USART */ + + cr = getreg16(STM32_CONSOLE_BASE + STM32_USART_CR2_OFFSET); + cr |= (USART_CR1_UE|USART_CR1_TE|USART_CR1_RE); + putreg16(cr, STM32_CONSOLE_BASE + STM32_USART_CR2_OFFSET); #endif +#endif /* !CONFIG_USART1_DISABLE && !CONFIG_USART2_DISABLE && !CONFIG_USART3_DISABLE */ } diff --git a/arch/arm/src/stm32/stm32_rcc.h b/arch/arm/src/stm32/stm32_rcc.h index 81a5d6d83e5..21dd0efc57f 100755 --- a/arch/arm/src/stm32/stm32_rcc.h +++ b/arch/arm/src/stm32/stm32_rcc.h @@ -117,7 +117,7 @@ #define RCC_CFGR_PPRE1_SHIFT (8) /* Bits 10-8: APB Low speed prescaler (APB1) */ #define RCC_CFGR_PPRE1_MASK (7 << RCC_CFGR_PPRE1_SHIFT) # define RCC_CFGR_PPRE1_HCLK (0 << RCC_CFGR_PPRE1_SHIFT) /* 0xx: HCLK not divided */ -# define RCC_CFGR_PPRE2_HCLKd2 (4 << RCC_CFGR_PPRE1_SHIFT) /* 100: HCLK divided by 2 */ +# define RCC_CFGR_PPRE1_HCLKd2 (4 << RCC_CFGR_PPRE1_SHIFT) /* 100: HCLK divided by 2 */ # define RCC_CFGR_PPRE1_HCLKd4 (5 << RCC_CFGR_PPRE1_SHIFT) /* 101: HCLK divided by 4 */ # define RCC_CFGR_PPRE1_HCLKd8 (6 << RCC_CFGR_PPRE1_SHIFT) /* 110: HCLK divided by 8 */ # define RCC_CFGR_PPRE1_HCLKd16 (7 << RCC_CFGR_PPRE1_SHIFT) /* 111: HCLK divided by 16 */ @@ -230,7 +230,7 @@ #define RCC_AHBENR_SRAMEN (1 << 2) /* Bit 2: SRAM interface clock enable */ #define RCC_AHBENR_FLITFEN (1 << 4) /* Bit 4: FLITF clock enable */ #define RCC_AHBENR_CRCEN (1 << 6) /* Bit 6: CRC clock enable */ -#define RCC_AHBENR_SDIOEN (1 << 8) /* Bit 8: FSMC clock enable */ +#define RCC_AHBENR_FSMCEN (1 << 8) /* Bit 8: FSMC clock enable */ #define RCC_AHBENR_SDIOEN (1 << 10) /* Bit 10: SDIO clock enable */ /* APB2 Peripheral Clock enable register */ diff --git a/arch/arm/src/stm32/stm32_serial.c b/arch/arm/src/stm32/stm32_serial.c index 59970eb0070..5561708ef5f 100644 --- a/arch/arm/src/stm32/stm32_serial.c +++ b/arch/arm/src/stm32/stm32_serial.c @@ -52,6 +52,7 @@ #include #include "chip.h" +#include "stm32_uart.h" #include "up_arch.h" #include "up_internal.h" #include "os_internal.h" @@ -99,54 +100,54 @@ /* Which USART with be tty0/console and which tty1? */ #if defined(CONFIG_USART1_SERIAL_CONSOLE) -# define CONSOLE_DEV g_USART1port /* USART1 is console */ -# define TTYS0_DEV g_USART1port /* USART1 is ttyS0 */ +# define CONSOLE_DEV g_usart1port /* USART1 is console */ +# define TTYS0_DEV g_usart1port /* USART1 is ttyS0 */ # ifndef CONFIG_USART2_DISABLE -# define TTYS1_DEV g_USART2port /* USART2 is ttyS1 */ +# define TTYS1_DEV g_usart2port /* USART2 is ttyS1 */ # ifndef CONFIG_USART3_DISABLE -# define TTYS2_DEV g_USART3port /* USART3 is ttyS2 */ +# define TTYS2_DEV g_usart3port /* USART3 is ttyS2 */ # else # undef TTYS1_DEV /* No ttyS2 */ # endif # else # ifndef CONFIG_USART3_DISABLE -# define TTYS1_DEV g_USART3port /* USART3 is ttyS1 */ +# define TTYS1_DEV g_usart3port /* USART3 is ttyS1 */ # else # undef TTYS1_DEV /* No ttyS1 */ # endif # undef TTYS2_DEV /* No ttyS2 */ # endif #elif defined(CONFIG_USART2_SERIAL_CONSOLE) -# define CONSOLE_DEV g_USART2port /* USART2 is console */ -# define TTYS0_DEV g_USART2port /* USART2 is ttyS0 */ +# define CONSOLE_DEV g_usart2port /* USART2 is console */ +# define TTYS0_DEV g_usart2port /* USART2 is ttyS0 */ # ifndef CONFIG_USART1_DISABLE -# define TTYS1_DEV g_USART1port /* USART1 is ttyS1 */ +# define TTYS1_DEV g_usart1port /* USART1 is ttyS1 */ # ifndef CONFIG_USART3_DISABLE -# define TTYS2_DEV g_USART3port /* USART3 is ttyS2 */ +# define TTYS2_DEV g_usart3port /* USART3 is ttyS2 */ # else # undef TTYS1_DEV /* No ttyS2 */ # endif # else # ifndef CONFIG_USART3_DISABLE -# define TTYS1_DEV g_USART3port /* USART3 is ttyS1 */ +# define TTYS1_DEV g_usart3port /* USART3 is ttyS1 */ # else # undef TTYS1_DEV /* No ttyS1 */ # endif # undef TTYS2_DEV /* No ttyS2 */ # endif #elif defined(CONFIG_USART3_SERIAL_CONSOLE) -# define CONSOLE_DEV g_USART3port /* USART3 is console */ -# define TTYS0_DEV g_USART3port /* USART3 is ttyS0 */ +# define CONSOLE_DEV g_usart3port /* USART3 is console */ +# define TTYS0_DEV g_usart3port /* USART3 is ttyS0 */ # ifndef CONFIG_USART1_DISABLE -# define TTYS1_DEV g_USART1port /* USART1 is ttyS1 */ +# define TTYS1_DEV g_usart1port /* USART1 is ttyS1 */ # ifndef CONFIG_USART2_DISABLE -# define TTYS2_DEV g_USART2port /* USART2 is ttyS2 */ +# define TTYS2_DEV g_usart2port /* USART2 is ttyS2 */ # else # undef TTYS1_DEV /* No ttyS2 */ # endif # else # ifndef CONFIG_USART2_DISABLE -# define TTYS1_DEV g_USART2port /* USART2 is ttyS1 */ +# define TTYS1_DEV g_usart2port /* USART2 is ttyS1 */ # else # undef TTYS1_DEV /* No ttyS1 */ # endif @@ -160,9 +161,11 @@ struct up_dev_s { - uint32 USARTbase; /* Base address of USART registers */ + uint32 usartbase; /* Base address of USART registers */ + uint32 apbclock; /* PCLK 1 or 2 frequency */ uint32 baud; /* Configured baud */ - uint32 im; /* Saved IM value */ + uint16 ie; /* Saved interrupt mask bits value */ + uint16 sr; /* Saved status bits */ ubyte irq; /* IRQ associated with this USART */ ubyte parity; /* 0=none, 1=odd, 2=even */ ubyte bits; /* Number of bits (7 or 8) */ @@ -173,25 +176,24 @@ struct up_dev_s * Private Function Prototypes ****************************************************************************/ -static int up_setup(struct USART_dev_s *dev); -static void up_shutdown(struct USART_dev_s *dev); -static int up_attach(struct USART_dev_s *dev); -static void up_detach(struct USART_dev_s *dev); +static int up_setup(struct uart_dev_s *dev); +static void up_shutdown(struct uart_dev_s *dev); +static int up_attach(struct uart_dev_s *dev); +static void up_detach(struct uart_dev_s *dev); static int up_interrupt(int irq, void *context); static int up_ioctl(struct file *filep, int cmd, unsigned long arg); -static int up_receive(struct USART_dev_s *dev, uint32 *status); -static void up_rxint(struct USART_dev_s *dev, boolean enable); -static boolean up_rxavailable(struct USART_dev_s *dev); -static void up_send(struct USART_dev_s *dev, int ch); -static void up_txint(struct USART_dev_s *dev, boolean enable); -static boolean up_txready(struct USART_dev_s *dev); -static boolean up_txempty(struct USART_dev_s *dev); +static int up_receive(struct uart_dev_s *dev, uint32 *status); +static void up_rxint(struct uart_dev_s *dev, boolean enable); +static boolean up_rxavailable(struct uart_dev_s *dev); +static void up_send(struct uart_dev_s *dev, int ch); +static void up_txint(struct uart_dev_s *dev, boolean enable); +static boolean up_txready(struct uart_dev_s *dev); /**************************************************************************** * Private Variables ****************************************************************************/ -struct USART_ops_s g_USART_ops = +struct uart_ops_s g_uart_ops = { .setup = up_setup, .shutdown = up_shutdown, @@ -204,30 +206,31 @@ struct USART_ops_s g_USART_ops = .send = up_send, .txint = up_txint, .txready = up_txready, - .txempty = up_txempty, + .txempty = up_txready, }; /* I/O buffers */ #ifndef CONFIG_USART1_DISABLE -static char g_USART1rxbuffer[CONFIG_USART1_RXBUFSIZE]; -static char g_USART1txbuffer[CONFIG_USART1_TXBUFSIZE]; +static char g_usart1rxbuffer[CONFIG_USART1_RXBUFSIZE]; +static char g_usart1txbuffer[CONFIG_USART1_TXBUFSIZE]; #endif #ifndef CONFIG_USART2_DISABLE -static char g_USART2rxbuffer[CONFIG_USART2_RXBUFSIZE]; -static char g_USART2txbuffer[CONFIG_USART2_TXBUFSIZE]; +static char g_usart2rxbuffer[CONFIG_USART2_RXBUFSIZE]; +static char g_usart2txbuffer[CONFIG_USART2_TXBUFSIZE]; #endif #ifndef CONFIG_USART3_DISABLE -static char g_USART3rxbuffer[CONFIG_USART3_RXBUFSIZE]; -static char g_USART3txbuffer[CONFIG_USART3_TXBUFSIZE]; +static char g_usart3rxbuffer[CONFIG_USART3_RXBUFSIZE]; +static char g_usart3txbuffer[CONFIG_USART3_TXBUFSIZE]; #endif /* This describes the state of the STM32 USART1 ports. */ #ifndef CONFIG_USART1_DISABLE -static struct up_dev_s g_USART1priv = +static struct up_dev_s g_usart1priv = { - .USARTbase = STM32_USART1_BASE, + .usartbase = STM32_USART1_BASE, + .apbclock = STM32_PCLK2_FREQUENCY, .baud = CONFIG_USART1_BAUD, .irq = STM32_IRQ_USART1, .parity = CONFIG_USART1_PARITY, @@ -235,29 +238,30 @@ static struct up_dev_s g_USART1priv = .stopbits2 = CONFIG_USART1_2STOP, }; -static USART_dev_t g_USART1port = +static uart_dev_t g_usart1port = { .recv = { .size = CONFIG_USART1_RXBUFSIZE, - .buffer = g_USART1rxbuffer, + .buffer = g_usart1rxbuffer, }, .xmit = { .size = CONFIG_USART1_TXBUFSIZE, - .buffer = g_USART1txbuffer, + .buffer = g_usart1txbuffer, }, - .ops = &g_USART_ops, - .priv = &g_USART1priv, + .ops = &g_uart_ops, + .priv = &g_usart1priv, }; #endif /* This describes the state of the STM32 USART2 port. */ #ifndef CONFIG_USART2_DISABLE -static struct up_dev_s g_USART2priv = +static struct up_dev_s g_usart2priv = { - .USARTbase = STM32_USART2_BASE, + .usartbase = STM32_USART2_BASE, + .apbclock = STM32_PCLK1_FREQUENCY, .baud = CONFIG_USART2_BAUD, .irq = STM32_IRQ_USART2, .parity = CONFIG_USART2_PARITY, @@ -265,29 +269,30 @@ static struct up_dev_s g_USART2priv = .stopbits2 = CONFIG_USART2_2STOP, }; -static USART_dev_t g_USART2port = +static uart_dev_t g_usart2port = { .recv = { .size = CONFIG_USART2_RXBUFSIZE, - .buffer = g_USART2rxbuffer, + .buffer = g_usart2rxbuffer, }, .xmit = { .size = CONFIG_USART2_TXBUFSIZE, - .buffer = g_USART2txbuffer, + .buffer = g_usart2txbuffer, }, - .ops = &g_USART_ops, - .priv = &g_USART2priv, + .ops = &g_uart_ops, + .priv = &g_usart2priv, }; #endif /* This describes the state of the STM32 USART3 port. */ #ifndef CONFIG_USART3_DISABLE -static struct up_dev_s g_USART3priv = +static struct up_dev_s g_usart3priv = { - .USARTbase = STM32_USART3_BASE, + .usartbase = STM32_USART3_BASE, + .apbclock = STM32_PCLK1_FREQUENCY, .baud = CONFIG_USART3_BAUD, .irq = STM32_IRQ_USART3, .parity = CONFIG_USART3_PARITY, @@ -295,20 +300,20 @@ static struct up_dev_s g_USART3priv = .stopbits2 = CONFIG_USART3_2STOP, }; -static USART_dev_t g_USART3port = +static uart_dev_t g_usart3port = { .recv = { .size = CONFIG_USART3_RXBUFSIZE, - .buffer = g_USART3rxbuffer, + .buffer = g_usart3rxbuffer, }, .xmit = { .size = CONFIG_USART3_TXBUFSIZE, - .buffer = g_USART3txbuffer, + .buffer = g_usart3txbuffer, }, - .ops = &g_USART_ops, - .priv = &g_USART3priv, + .ops = &g_uart_ops, + .priv = &g_usart3priv, }; #endif @@ -320,94 +325,210 @@ static USART_dev_t g_USART3port = * Name: up_serialin ****************************************************************************/ -static inline uint32 up_serialin(struct up_dev_s *priv, int offset) +static inline uint16 up_serialin(struct up_dev_s *priv, int offset) { - return getreg32(priv->USARTbase + offset); + return getreg16(priv->usartbase + offset); } /**************************************************************************** * Name: up_serialout ****************************************************************************/ -static inline void up_serialout(struct up_dev_s *priv, int offset, uint32 value) +static inline void up_serialout(struct up_dev_s *priv, int offset, uint16 value) { - putreg32(value, priv->USARTbase + offset); + putreg16(value, priv->usartbase + offset); +} + +/**************************************************************************** + * Name: up_serialout32 + ****************************************************************************/ + +static inline void up_serialout32(struct up_dev_s *priv, int offset, uint32 value) +{ + putreg32(value, priv->usartbase + offset); } /**************************************************************************** * Name: up_disableusartint ****************************************************************************/ -static inline void up_disableusartint(struct up_dev_s *priv, uint32 *im) +static inline void up_disableusartint(struct up_dev_s *priv, uint16 *ie) { - /* Return the current interrupt mask value */ - - if (im) + if (ie) { - *im = priv->im; + uint16 cr1; + uint16 cr3; + + /* USART interrupts: + * + * Enable Bit Status Meaning Usage + * ------------------ --- --------------- ------------------------------ ---------- + * USART_CR1_IDLEIE 4 USART_SR_IDLE Idle Line Detected (not used) + * USART_CR1_RXNEIE 5 USART_SR_RXNE Received Data Ready to be Read + * " " USART_SR_ORE Overrun Error Detected + * USART_CR1_TCIE 6 USART_SR_TC Transmission Complete (not used) + * USART_CR1_TXEIE 7 USART_SR_TXE Transmit Data Register Empty + * USART_CR1_PEIE 8 USART_SR_PE Parity Error + * + * USART_CR2_LBDIE 6 USART_SR_LBD Break Flag (not used) + * USART_CR3_EIE 0 USART_SR_FE Framing Error + * " " USART_SR_NE Noise Error + * " " USART_SR_ORE Overrun Error Detected + * USART_CR3_CTSIE 10 USART_SR_CTS CTS flag (not used) + */ + + cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); + cr3 = up_serialin(priv, STM32_USART_CR3_OFFSET); + + /* Return the current interrupt mask value for the used interrupts. Notice + * that this depends on the fact that none of the used interrupt enable bits + * overlap. This logic would fail if we needed the break interrupt! + */ + + *ie = (cr1 & (USART_CR1_RXNEIE|USART_CR1_TXEIE|USART_CR1_PEIE)) | (cr3 & USART_CR3_EIE); } /* Disable all interrupts */ - priv->im = 0; + up_restoreusartint(priv, 0); } /**************************************************************************** * Name: up_restoreusartint ****************************************************************************/ -static inline void up_restoreusartint(struct up_dev_s *priv, uint32 im) +static inline void up_restoreusartint(struct up_dev_s *priv, uint16 ie) { - priv->im = im; + uint16 cr; + + /* Save the interrupt mask */ + + priv->ie = ie; + + /* And restore the interrupt state (see the interrupt enable/usage table above) */ + + cr = up_serialin(priv, STM32_USART_CR1_OFFSET); + cr &= ~(USART_CR1_RXNEIE|USART_CR1_TXEIE|USART_CR1_PEIE); + cr |= (cr1 & (USART_CR1_RXNEIE|USART_CR1_TXEIE|USART_CR1_PEIE)); + up_serialout((priv, STM32_USART_CR1_OFFSET, cr) + + cr = up_serialin(priv, STM32_USART_CR3_OFFSET); + cr &= ~USART_CR3_EIE; + cr |= (cr1 & USART_CR3_EIE); + up_serialout((priv, STM32_USART_CR3_OFFSET, cr) } /**************************************************************************** * Name: up_setup * * Description: - * Configure the USART baud, bits, parity, fifos, etc. This - * method is called the first time that the serial port is - * opened. + * Configure the USART baud, bits, parity, fifos, etc. This method is + * called the first time that the serial port is opened. * ****************************************************************************/ -static int up_setup(struct USART_dev_s *dev) +static int up_setup(struct uart_dev_s *dev) { struct up_dev_s *priv = (struct up_dev_s*)dev->priv; - - /* Note: The logic here depends on the fact that that the USART module - * was enabled and the GPIOs were configured in up_lowsetup(). - */ - - /* Disable the USART */ - - /* Calculate BAUD rate from the SYS clock */ - - /* Set the USART to interrupt whenever the TX FIFO is almost empty or when - * any character is received. - */ - - /* Flush the Rx and Tx FIFOs */ - - /* Enable Rx interrupts from the USART except for Tx interrupts. We don't want - * Tx interrupts until we have something to send. We will check for serial - * errors as part of Rx interrupt processing (no interrupts will be received - * yet because the interrupt is still disabled at the interrupt controller. - */ - - /* Enable the FIFOs */ - #ifdef CONFIG_SUPPRESS_USART_CONFIG -#endif + uint32 uartdiv32; + uint32 mantissa; + uint32 fraction; + uint32 brr; + uint16 regval; + + /* Note: The logic here depends on the fact that that the USART module + * was enabled and the pins were configured in up_lowsetup(). + */ + + /* Configure CR2 */ + /* Clear STOP, CLKEN, CPOL, CPHA, LBCL, and interrupt enable bits */ + + regval = up_serialin(priv, STM32_USART_CR2_OFFSET); + regval &= ~(USART_CR2_STOP_MASK|USART_CR2_CLKEN|USART_CR2_CPOL| + USART_CR2_CPHA|USART_CR2_LBCL|USART_CR2_LBDIE); + + /* Configure STOP bits */ + + if (priv->stopbits2) + { + regval |= USART_CR2_STOP2; + } + up_serialout(priv, STM32_USART_CR2_OFFSET, regval); + + /* Configure CR1 */ + /* Clear M, PCE, PS, TE, REm and all interrupt enable bits */ + + regval = up_serialin(priv, STM32_USART_CR1_OFFSET); + regval &= ~(USART_CR1_M|USART_CR1_PCE|USART_CR1_PS|USART_CR1_TE| + USART_CR1_RE|USART_CR1_ALLINTS); + + /* Configure word length and parity mode */ + + if (priv->bits == 9) /* Default: 1 start, 8 data, n stop */ + { + regval |= USART_CR1_M; /* 1 start, 9 data, n stop */ + } + + if (priv->parity == 1) /* Odd parity */ + { + regval |= (USART_CR1_PCE|USART_CR1_PS); + } + else if (priv->parity == 2) /* Even parity */ + { + regval |= USART_CR1_PCE; + } + up_serialout(priv, STM32_USART_CR1_OFFSET, regval); + + /* Configure CR3 */ + /* Clear CTSE, RTSE, and all interrupt enable bits */ + + regval = up_serialin(priv, STM32_USART_CR3_OFFSET); + regval &= ~(USART_CR3_CTSIE|USART_CR3_CTSE|USART_CR3_RTSE|USART_CR3_EIE); + + /* Configure hardware flow control -- Not yet supported */ + + up_serialout(priv, STM32_USART_CR1_OFFSET, regval); + + /* Configure the USART Baud Rate. The baud rate for the receiver and + * transmitter (Rx and Tx) are both set to the same value as programmed + * in the Mantissa and Fraction values of USARTDIV. + * + * baud = fCK / (16 * usartdiv) + * usartdiv = fCK / (16 * baud) + * + * Where fCK is the input clock to the peripheral (PCLK1 for USART2, 3, 4, 5 + * or PCLK2 for USART1) + * + * First calculate (NOTE: all stand baud values are even so dividing by two + * does not lose precision): + * + * usartdiv32 = 32 * usartdiv = fCK / (baud/2) + */ + + usartdiv32 = priv->apbclock / (priv->baud >> 1); + + /* The mantissa part is then */ + + mantissa = usartdiv32 >> 5; + brr = mantissa << USART_BRR_MANT_SHIFT; + + /* The fractional remainder (with rounding) */ + + fraction = (usartdiv32 - (mantissa << 5) + 1) >> 1; + brr |= fraction << USART_BRR_FRAC_SHIFT; + up_serialout32(priv, STM32_USART1_BRR, brr); /* Enable Rx, Tx, and the USART */ -#ifdef CONFIG_SUPPRESS_USART_CONFIG + regval = up_serialin(priv, STM32_USART_CR1_OFFSET); + regval |= (USART_CR1_UE|USART_CR1_TE|USART_CR1_RE); + up_serialout(priv, STM32_USART_CR1_OFFSET, regval); #endif - /* Set up the cache IM value */ + /* Set up the cache interrupt enables value */ -// priv->im = + priv->ie = 0; return OK; } @@ -420,10 +541,20 @@ static int up_setup(struct USART_dev_s *dev) * ****************************************************************************/ -static void up_shutdown(struct USART_dev_s *dev) +static void up_shutdown(struct uart_dev_s *dev) { struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + uint16 regval; + + /* Disable all interrupts */ + up_disableusartint(priv, NULL); + + /* Disable Rx, Tx, and the UART */ + + regval = up_serialin(priv, STM32_USART_CR1_OFFSET); + regval &= ~(USART_CR1_UE|USART_CR1_TE|USART_CR1_RE + up_serialout(priv, STM32_USART_CR1_OFFSET, regval); } /**************************************************************************** @@ -441,7 +572,7 @@ static void up_shutdown(struct USART_dev_s *dev) * ****************************************************************************/ -static int up_attach(struct USART_dev_s *dev) +static int up_attach(struct uart_dev_s *dev) { struct up_dev_s *priv = (struct up_dev_s*)dev->priv; int ret; @@ -470,7 +601,7 @@ static int up_attach(struct USART_dev_s *dev) * ****************************************************************************/ -static void up_detach(struct USART_dev_s *dev) +static void up_detach(struct uart_dev_s *dev) { struct up_dev_s *priv = (struct up_dev_s*)dev->priv; up_disable_irq(priv->irq); @@ -485,35 +616,35 @@ static void up_detach(struct USART_dev_s *dev) * interrupt received on the 'irq' It should call uart_transmitchars or * uart_receivechar to perform the appropriate data transfers. The * interrupt handling logic must be able to map the 'irq' number into the - * approprite USART_dev_s structure in order to call these functions. + * approprite uart_dev_s structure in order to call these functions. * ****************************************************************************/ static int up_interrupt(int irq, void *context) { - struct USART_dev_s *dev = NULL; + struct uart_dev_s *dev = NULL; struct up_dev_s *priv; int passes; boolean handled; #ifndef CONFIG_USART1_DISABLE - if (g_USART1priv.irq == irq) + if (g_usart1priv.irq == irq) { - dev = &g_USART1port; + dev = &g_usart1port; } else #endif #ifndef CONFIG_USART2_DISABLE - if (g_USART2priv.irq == irq) + if (g_usart2priv.irq == irq) { - dev = &g_USART2port; + dev = &g_usart2port; } else #endif #ifndef CONFIG_USART3_DISABLE - if (g_USART3priv.irq == irq) + if (g_usart3priv.irq == irq) { - dev = &g_USART3port; + dev = &g_usart3port; } else #endif @@ -533,10 +664,35 @@ static int up_interrupt(int irq, void *context) /* Get the masked USART status and clear the pending interrupts. */ + priv->sr = up_serialin(priv, STM32_USART_SR_OFFSET); + + /* USART interrupts: + * + * Enable Bit Status Meaning Usage + * ------------------ --- --------------- ------------------------------- ---------- + * USART_CR1_IDLEIE 4 USART_SR_IDLE Idle Line Detected (not used) + * USART_CR1_RXNEIE 5 USART_SR_RXNE Received Data Ready to be Read + * " " USART_SR_ORE Overrun Error Detected + * USART_CR1_TCIE 6 USART_SR_TC Transmission Complete (not used) + * USART_CR1_TXEIE 7 USART_SR_TXE Transmit Data Register Empty + * USART_CR1_PEIE 8 USART_SR_PE Parity Error + * + * USART_CR2_LBDIE 6 USART_SR_LBD Break Flag (not used) + * USART_CR3_EIE 0 USART_SR_FE Framing Error + * " " USART_SR_NE Noise Error + * " " USART_SR_ORE Overrun Error Detected + * USART_CR3_CTSIE 10 USART_SR_CTS CTS flag (not used) + * + * NOTE: Some of these status bits must be cleared by explicity writing zero + * to the SR register: USART_SR_CTS, USART_SR_LBD. Note of those are currently + * being used. + */ + /* Handle incoming, receive bytes (with or without timeout) */ + if ((priv->sr & USART_SR_RXNE) != 0 && (priv->ie & USART_CR1_RXNEIE) != 0) { - /* Rx buffer not empty ... process incoming bytes */ + /* Received data ready... process incoming bytes */ uart_recvchars(dev); handled = TRUE; @@ -544,8 +700,9 @@ static int up_interrupt(int irq, void *context) /* Handle outgoing, transmit bytes */ + if ((priv->sr & USART_SR_TXE) != 0 && (priv->ie & USART_CR1_TXEIE) != 0) { - /* Tx FIFO not full ... process outgoing bytes */ + /* Transmit data regiser empty ... process outgoing bytes */ uart_xmitchars(dev); handled = TRUE; @@ -565,7 +722,10 @@ static int up_interrupt(int irq, void *context) static int up_ioctl(struct file *filep, int cmd, unsigned long arg) { struct inode *inode = filep->f_inode; - struct USART_dev_s *dev = inode->i_private; + struct uart_dev_s *dev = inode->i_private; +#ifdef CONFIG_USART_BREAKS + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; +#endif int ret = OK; switch (cmd) @@ -584,6 +744,27 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) } break; +#ifdef CONFIG_USART_BREAKS + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + { + irqstate_t flags = irqsave(); + uint32 cr2 = up_serialin(priv, STM32_USART_CR2_OFFSET); + up_serialout(priv, STM32_USART_CR2_OFFSET, cr2 | USART_CR2_LINEN); + irqrestore(flags); + } + break; + + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + { + irqstate_t flags; + flags = irqsave(); + uint32 cr1 = up_serialin(priv, STM32_USART_CR2_OFFSET); + up_serialout(priv, STM32_USART_CR2_OFFSET, cr2 & ~USART_CR2_LINEN); + irqrestore(flags); + } + break; +#endif + default: ret = -ENOTTY; break; @@ -602,18 +783,23 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) * ****************************************************************************/ -static int up_receive(struct USART_dev_s *dev, uint32 *status) +static int up_receive(struct uart_dev_s *dev, uint32 *status) { struct up_dev_s *priv = (struct up_dev_s*)dev->priv; - uint32 rxd; + uint16 dr; + + /* Get the Rx byte */ + + dr = up_serialin(priv, STM32_USART_DR_OFFSET); /* Get the Rx byte plux error information. Return those in status */ - *status = rxd; + *status = (uint32)priv->sr << 16 | dr; + priv->sr = 0; /* Then return the actual received byte */ - return rxd & 0xff; + return dr & 0xff; } /**************************************************************************** @@ -624,9 +810,27 @@ static int up_receive(struct USART_dev_s *dev, uint32 *status) * ****************************************************************************/ -static void up_rxint(struct USART_dev_s *dev, boolean enable) +static void up_rxint(struct uart_dev_s *dev, boolean enable) { struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + uint16 ie; + + /* USART receive interrupts: + * + * Enable Bit Status Meaning Usage + * ------------------ --- --------------- ------------------------------- ---------- + * USART_CR1_IDLEIE 4 USART_SR_IDLE Idle Line Detected (not used) + * USART_CR1_RXNEIE 5 USART_SR_RXNE Received Data Ready to be Read + * " " USART_SR_ORE Overrun Error Detected + * USART_CR1_PEIE 8 USART_SR_PE Parity Error + * + * USART_CR2_LBDIE 6 USART_SR_LBD Break Flag (not used) + * USART_CR3_EIE 0 USART_SR_FE Framing Error + * " " USART_SR_NE Noise Error + * " " USART_SR_ORE Overrun Error Detected + */ + + ie = priv->ie; if (enable) { /* Receive an interrupt when their is anything in the Rx FIFO (or an Rx @@ -634,13 +838,21 @@ static void up_rxint(struct USART_dev_s *dev, boolean enable) */ #ifndef CONFIG_SUPPRESS_SERIAL_INTS -// priv->im |= ; +#ifdef CONFIG_USART_ERRINTS + ie |= (USART_CR1_RXNEIE|USART_CR1_PEIE|USART_CR3_EIE); +#else + ie |= USART_CR1_RXNEIE; +#endif #endif } else { -// priv->im &= ~(); + ie &= ~(USART_CR1_RXNEIE|USART_CR1_PEIE|USART_CR3_EIE); } + + /* Then set the new interrupt state */ + + up_restoreusartint(priv, ie); } /**************************************************************************** @@ -651,10 +863,10 @@ static void up_rxint(struct USART_dev_s *dev, boolean enable) * ****************************************************************************/ -static boolean up_rxavailable(struct USART_dev_s *dev) +static boolean up_rxavailable(struct uart_dev_s *dev) { struct up_dev_s *priv = (struct up_dev_s*)dev->priv; - return 0; + return ((up_serialin(priv, STM32_USART_SR_OFFSET) & USART_SR_RXNE) != 0); } /**************************************************************************** @@ -665,9 +877,10 @@ static boolean up_rxavailable(struct USART_dev_s *dev) * ****************************************************************************/ -static void up_send(struct USART_dev_s *dev, int ch) +static void up_send(struct uart_dev_s *dev, int ch) { struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + up_serialout(priv, STM32_USART_DR_OFFSET, (uint16)ch); } /**************************************************************************** @@ -678,23 +891,31 @@ static void up_send(struct USART_dev_s *dev, int ch) * ****************************************************************************/ -static void up_txint(struct USART_dev_s *dev, boolean enable) +static void up_txint(struct uart_dev_s *dev, boolean enable) { struct up_dev_s *priv = (struct up_dev_s*)dev->priv; irqstate_t flags; + uint16 ie; + /* USART transmit interrupts: + * + * Enable Bit Status Meaning Usage + * ------------------ --- --------------- ---------------------------- ---------- + * USART_CR1_TCIE 6 USART_SR_TC Transmission Complete (not used) + * USART_CR1_TXEIE 7 USART_SR_TXE Transmit Data Register Empty + * USART_CR3_CTSIE 10 USART_SR_CTS CTS flag (not used) + */ + flags = irqsave(); if (enable) { /* Set to receive an interrupt when the TX fifo is half emptied */ #ifndef CONFIG_SUPPRESS_SERIAL_INTS -// priv->im |= ; - up_serialout(priv, stm32_USART_IM_OFFSET, priv->im); + up_restoreusartint(priv, priv->ie | USART_CR1_TXEIE); /* Fake a TX interrupt here by just calling uart_xmitchars() with - * interrupts disabled (note that the may recurse and that priv->im - * may be altered. + * interrupts disabled (note this may recurse). */ uart_xmitchars(dev); @@ -704,7 +925,7 @@ static void up_txint(struct USART_dev_s *dev, boolean enable) { /* Disable the TX interrupt */ -// priv->im &= ~(); + up_restoreusartint(priv, priv->ie & ~USART_CR1_TXEIE); } irqrestore(flags); } @@ -717,24 +938,10 @@ static void up_txint(struct USART_dev_s *dev, boolean enable) * ****************************************************************************/ -static boolean up_txready(struct USART_dev_s *dev) +static boolean up_txready(struct uart_dev_s *dev) { struct up_dev_s *priv = (struct up_dev_s*)dev->priv; - return 0; -} - -/**************************************************************************** - * Name: up_txempty - * - * Description: - * Return TRUE if the transmit fifo is empty - * - ****************************************************************************/ - -static boolean up_txempty(struct USART_dev_s *dev) -{ - struct up_dev_s *priv = (struct up_dev_s*)dev->priv; - return 0; + return ((up_serialin(priv, STM32_USART_SR_OFFSET) & USART_SR_TXE) != 0); } /**************************************************************************** @@ -815,9 +1022,9 @@ int up_putc(int ch) { #ifdef HAVE_CONSOLE struct up_dev_s *priv = (struct up_dev_s*)CONSOLE_DEV.priv; - uint32 im; + uint16 ie; - up_disableusartint(priv, &im); + up_disableusartint(priv, &ie); /* Check for LF */ @@ -829,7 +1036,7 @@ int up_putc(int ch) } up_lowputc(ch); - up_restoreusartint(priv, im); + up_restoreusartint(priv, ie); #endif return ch; } diff --git a/arch/arm/src/stm32/stm32_uart.h b/arch/arm/src/stm32/stm32_uart.h index 1bfb47a155c..37a15721950 100755 --- a/arch/arm/src/stm32/stm32_uart.h +++ b/arch/arm/src/stm32/stm32_uart.h @@ -113,6 +113,9 @@ #define USART_SR_LBD (1 << 8) /* Bit 8: LIN Break Detection Flag */ #define USART_SR_CTS (1 << 9) /* Bit 9: CTS Flag */ +#define USART_SR_ALLBITS (0x03ff) +#define USART_SR_CLRBITS (USART_SR_CTS|USART_SR_LBD) /* Cleared by SW write to SR */ + /* Data register */ #define USART_DR_SHIFT (0) /* Bits 8:0: Data value */ @@ -142,6 +145,8 @@ #define USART_CR1_M (1 << 12) /* Bit 12: word length */ #define USART_CR1_UE (1 << 13) /* Bit 13: USART Enable */ +#define USART_CR1_ALLINTS (USART_CR1_IDLEIE|USART_CR1_RXNEIE|USART_CR1_TCIE|USART_CR1_PEIE) + /* Control register 2 */ #define USART_CR2_ADD_SHIFT (0) /* Bits 3-0: Address of the USART node */