blob: d1b51f84bcda9fa12a7da9373b24dc1eef46c283 [file] [log] [blame]
/*
* Copyright (c) 2012 Kent Ryhorchuk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdarg.h>
#include <reg.h>
#include <debug.h>
#include <stdio.h>
#include <assert.h>
#include <lib/cbuf.h>
#include <kernel/thread.h>
#include <platform/debug.h>
#include <arch/ops.h>
#include <dev/uart.h>
#include <target/debugconfig.h>
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_usart.h>
#include <arch/arm/cm.h>
#ifdef ENABLE_UART1
cbuf_t uart1_rx_buf;
#ifndef UART1_FLOWCONTROL
#define UART1_FLOWCONTROL USART_HardwareFlowControl_None
#endif
#ifndef UART1_BAUDRATE
#define UART1_BAUDRATE 115200
#endif
#ifndef UART1_RXBUF_SIZE
#define UART1_RXBUF_SIZE 64
#endif
#endif
#ifdef ENABLE_UART2
cbuf_t uart2_rx_buf;
#ifndef UART2_FLOWCONTROL
#define UART2_FLOWCONTROL USART_HardwareFlowControl_None
#endif
#ifndef UART2_BAUDRATE
#define UART2_BAUDRATE 115200
#endif
#ifndef UART2_RXBUF_SIZE
#define UART2_RXBUF_SIZE 64
#endif
#endif
#ifdef ENABLE_UART3
cbuf_t uart3_rx_buf;
#ifndef UART3_FLOWCONTROL
#define UART3_FLOWCONTROL USART_HardwareFlowControl_None
#endif
#ifndef UART3_BAUDRATE
#define UART3_BAUDRATE 115200
#endif
#ifndef UART3_RXBUF_SIZE
#define UART3_RXBUF_SIZE 64
#endif
#endif
#ifdef ENABLE_UART6
cbuf_t uart6_rx_buf;
#ifndef UART6_FLOWCONTROL
#define UART6_FLOWCONTROL USART_HardwareFlowControl_None
#endif
#ifndef UART6_BAUDRATE
#define UART6_BAUDRATE 115200
#endif
#ifndef UART6_RXBUF_SIZE
#define UART6_RXBUF_SIZE 64
#endif
#endif
static void usart_init1_early(USART_TypeDef *usart, uint32_t baud, uint16_t flowcontrol, int irqn)
{
USART_InitTypeDef init;
init.USART_BaudRate = baud;
init.USART_WordLength = USART_WordLength_8b;
init.USART_StopBits = USART_StopBits_1;
init.USART_Parity = USART_Parity_No;
init.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;
init.USART_HardwareFlowControl = flowcontrol;
USART_Init(usart, &init);
USART_ITConfig(usart, USART_IT_RXNE, DISABLE);
NVIC_DisableIRQ(irqn);
USART_Cmd(usart, ENABLE);
}
static void usart_init1(USART_TypeDef *usart, int irqn, cbuf_t *rxbuf, size_t rxsize)
{
cbuf_initialize(rxbuf, rxsize);
USART_ITConfig(usart, USART_IT_RXNE, ENABLE);
NVIC_EnableIRQ(irqn);
USART_Cmd(usart, ENABLE);
}
void uart_init_early(void)
{
#ifdef ENABLE_UART1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
usart_init1_early(USART1, UART1_BAUDRATE, UART1_FLOWCONTROL, USART1_IRQn);
#endif
#ifdef ENABLE_UART2
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
usart_init1_early(USART2, UART2_BAUDRATE, UART2_FLOWCONTROL, USART2_IRQn);
#endif
#ifdef ENABLE_UART3
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
usart_init1_early(USART3, UART3_BAUDRATE, UART3_FLOWCONTROL, USART3_IRQn);
#endif
#ifdef ENABLE_UART6
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);
usart_init1_early(USART6, UART6_BAUDRATE, UART6_FLOWCONTROL, USART6_IRQn);
#endif
}
void uart_init(void)
{
#ifdef ENABLE_UART1
usart_init1(USART1, USART1_IRQn, &uart1_rx_buf, UART1_RXBUF_SIZE);
#endif
#ifdef ENABLE_UART2
usart_init1(USART2, USART2_IRQn, &uart2_rx_buf, UART2_RXBUF_SIZE);
#endif
#ifdef ENABLE_UART3
usart_init1(USART3, USART3_IRQn, &uart3_rx_buf, UART3_RXBUF_SIZE);
#endif
#ifdef ENABLE_UART6
usart_init1(USART6, USART6_IRQn, &uart6_rx_buf, UART6_RXBUF_SIZE);
#endif
}
void uart_rx_irq(USART_TypeDef *usart, cbuf_t *rxbuf)
{
arm_cm_irq_entry();
bool resched = false;
while (USART_GetFlagStatus(usart, USART_FLAG_RXNE)) {
if (!cbuf_space_avail(rxbuf)) {
// Overflow - let flow control do its thing by not
// reading the from the FIFO.
USART_ITConfig(usart, USART_IT_RXNE, DISABLE);
break;
}
char c = USART_ReceiveData(usart);
cbuf_write_char(rxbuf, c, false);
resched = true;
}
arm_cm_irq_exit(resched);
}
#ifdef ENABLE_UART1
void stm32_USART1_IRQ(void)
{
uart_rx_irq(USART1, &uart1_rx_buf);
}
#endif
#ifdef ENABLE_UART2
void stm32_USART2_IRQ(void)
{
uart_rx_irq(USART2, &uart2_rx_buf);
}
#endif
#ifdef ENABLE_UART3
void stm32_USART3_IRQ(void)
{
uart_rx_irq(USART3, &uart3_rx_buf);
}
#endif
#ifdef ENABLE_UART6
void stm32_USART6_IRQ(void)
{
uart_rx_irq(USART6, &uart6_rx_buf);
}
#endif
static void usart_putc(USART_TypeDef *usart, char c)
{
while (USART_GetFlagStatus(usart, USART_FLAG_TXE) == 0);
USART_SendData(usart, c);
while (USART_GetFlagStatus(usart, USART_FLAG_TC) == 0);
}
static int usart_getc(USART_TypeDef *usart, cbuf_t *rxbuf, bool wait)
{
unsigned char c;
if (cbuf_read_char(rxbuf, (char*) &c, wait) == 0)
return -1;
if (cbuf_space_avail(rxbuf) > cbuf_size(rxbuf))
USART_ITConfig(usart, USART_IT_RXNE, ENABLE);
return c;
}
static USART_TypeDef *get_usart(int port)
{
switch (port) {
#ifdef ENABLE_UART1
case 1: return USART1;
#endif
#ifdef ENABLE_UART2
case 2: return USART2;
#endif
#ifdef ENABLE_UART3
case 3: return USART3;
#endif
#ifdef ENABLE_UART6
case 6: return USART6;
#endif
default:
ASSERT(false);
return 0;
}
}
static cbuf_t *get_rxbuf(int port)
{
switch (port) {
#ifdef ENABLE_UART1
case 1: return &uart1_rx_buf;
#endif
#ifdef ENABLE_UART2
case 2: return &uart2_rx_buf;
#endif
#ifdef ENABLE_UART3
case 3: return &uart3_rx_buf;
#endif
#ifdef ENABLE_UART6
case 6: return &uart6_rx_buf;
#endif
default:
ASSERT(false);
return 0;
}
}
int uart_putc(int port, char c)
{
USART_TypeDef *usart = get_usart(port);
usart_putc(usart, c);
return 1;
}
int uart_getc(int port, bool wait)
{
cbuf_t *rxbuf = get_rxbuf(port);
USART_TypeDef *usart = get_usart(port);
return usart_getc(usart, rxbuf, wait);
}
void uart_flush_tx(int port) {}
void uart_flush_rx(int port) {}
void uart_init_port(int port, uint baud) {
USART_TypeDef *usart = get_usart(port);
uint32_t treg = 0;
uint32_t apbclk = 0;
uint32_t intdiv = 0;
uint32_t fracdiv = 0;
RCC_ClocksTypeDef RCC_ClksStat;
RCC_GetClocksFreq(&RCC_ClksStat);
if ((usart == USART1) || (usart == USART6)) {
apbclk = RCC_ClksStat.PCLK2_Frequency;
} else {
apbclk = RCC_ClksStat.PCLK1_Frequency;
}
if ((usart->CR1 & USART_CR1_OVER8) != 0) {
intdiv = ((25 * apbclk) / (2 * (baud)));
} else {
intdiv = ((25 * apbclk) / (4 * (baud)));
}
treg = (intdiv / 100) << 4;
fracdiv = intdiv - (100 * (treg >> 4));
if ((usart->CR1 & USART_CR1_OVER8) != 0) {
treg |= ((((fracdiv * 8) + 50) / 100)) & ((uint8_t) 0x07);
} else {
treg |= ((((fracdiv * 16) + 50) / 100)) & ((uint8_t) 0x0F);
}
usart->BRR = (uint16_t) treg;
}
// inject a character into the console uart rx buffer
void __debugger_console_putc(char c) {
cbuf_t *rxbuf = get_rxbuf(DEBUG_UART);
if (rxbuf && cbuf_space_avail(rxbuf)) {
cbuf_write_char(rxbuf, c, false);
}
}