Merge pull request #113 from konkers/pr/stm32f0xx-native-rcc-uart-gpio
stm32f0xx: Convert rcc, uart, and gpio to native drivers.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Travis Geiselbrecht
|
||||
* Copyright (c) 2016 Erik Gilling
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
@@ -20,15 +21,42 @@
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <debug.h>
|
||||
#include <assert.h>
|
||||
#include <dev/gpio.h>
|
||||
#include <platform/stm32.h>
|
||||
#include <platform/gpio.h>
|
||||
#include <stm32f0xx_gpio.h>
|
||||
#include <stm32f0xx_rcc.h>
|
||||
|
||||
static GPIO_TypeDef *port_to_pointer(unsigned int port)
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <dev/gpio.h>
|
||||
#include <platform/gpio.h>
|
||||
#include <platform/rcc.h>
|
||||
#include <platform/stm32.h>
|
||||
#include <stm32f0xx.h>
|
||||
|
||||
typedef GPIO_TypeDef stm32_gpio_t;
|
||||
|
||||
typedef enum {
|
||||
STM32_GPIO_SPEED_2_MHZ = 0x0,
|
||||
STM32_GPIO_SPEED_20_MHZ = 0x1,
|
||||
STM32_GPIO_SPEED_50_MHZ = 0x3,
|
||||
} stm32_goio_speed_t;
|
||||
|
||||
typedef enum {
|
||||
STM32_GPIO_OTYPE_PP = 0x0,
|
||||
STM32_GPIO_OTYPE_OD = 0x1,
|
||||
} stm32_gpio_otype_t;
|
||||
|
||||
typedef enum {
|
||||
STM32_GPIO_MODE_IN = 0x0,
|
||||
STM32_GPIO_MODE_OUT = 0x1,
|
||||
STM32_GPIO_MODE_AF = 0x2,
|
||||
STM32_GPIO_MODE_AN = 0x3,
|
||||
} stm32_gpio_mode_t;
|
||||
|
||||
typedef enum {
|
||||
STM32_GPIO_PUPD_NONE = 0x0,
|
||||
STM32_GPIO_PUPD_UP = 0x1,
|
||||
STM32_GPIO_PUPD_DOWN = 0x2,
|
||||
} stm32_gpio_pupd_t;
|
||||
|
||||
static stm32_gpio_t *stm32_gpio_port_to_pointer(unsigned int port)
|
||||
{
|
||||
switch (port) {
|
||||
default:
|
||||
@@ -47,63 +75,119 @@ static GPIO_TypeDef *port_to_pointer(unsigned int port)
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_port(unsigned int port)
|
||||
static void stm32_gpio_enable_port(unsigned int port)
|
||||
{
|
||||
DEBUG_ASSERT(port <= GPIO_PORT_F);
|
||||
|
||||
/* happens to be the RCC ids are sequential bits, so we can start from A and shift */
|
||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA << port, ENABLE);
|
||||
switch (port) {
|
||||
default:
|
||||
case GPIO_PORT_A:
|
||||
stm32_rcc_set_enable(STM32_RCC_CLK_IOPA, true);
|
||||
break;
|
||||
|
||||
case GPIO_PORT_B:
|
||||
stm32_rcc_set_enable(STM32_RCC_CLK_IOPB, true);
|
||||
break;
|
||||
|
||||
case GPIO_PORT_C:
|
||||
stm32_rcc_set_enable(STM32_RCC_CLK_IOPC, true);
|
||||
break;
|
||||
|
||||
case GPIO_PORT_D:
|
||||
stm32_rcc_set_enable(STM32_RCC_CLK_IOPD, true);
|
||||
break;
|
||||
|
||||
case GPIO_PORT_E:
|
||||
stm32_rcc_set_enable(STM32_RCC_CLK_IOPE, true);
|
||||
break;
|
||||
|
||||
case GPIO_PORT_F:
|
||||
stm32_rcc_set_enable(STM32_RCC_CLK_IOPF, true);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void stm32_gpio_early_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void stm32_gpio_af_config(stm32_gpio_t *gpio, uint32_t pin,
|
||||
uint32_t af_num) {
|
||||
// 8 AF entries per register
|
||||
uint32_t reg_index = pin >> 3;
|
||||
uint32_t entry_shift = (pin & 0x7) * 4;
|
||||
|
||||
gpio->AFR[reg_index] &= ~(0xf << entry_shift);
|
||||
gpio->AFR[reg_index] |= (af_num & 0xf) << entry_shift;
|
||||
}
|
||||
|
||||
int gpio_config(unsigned nr, unsigned flags)
|
||||
{
|
||||
uint port = GPIO_PORT(nr);
|
||||
uint pin = GPIO_PIN(nr);
|
||||
uint32_t port = GPIO_PORT(nr);
|
||||
uint32_t pin = GPIO_PIN(nr);
|
||||
stm32_gpio_t *gpio = stm32_gpio_port_to_pointer(port);
|
||||
|
||||
enable_port(port);
|
||||
assert(pin < 16);
|
||||
|
||||
GPIO_InitTypeDef init;
|
||||
init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
init.GPIO_Pin = (1 << pin);
|
||||
init.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
stm32_gpio_enable_port(port);
|
||||
|
||||
if (flags & GPIO_INPUT) {
|
||||
init.GPIO_Mode = GPIO_Mode_IN;
|
||||
} else if (flags & GPIO_OUTPUT) {
|
||||
init.GPIO_Mode = GPIO_Mode_OUT;
|
||||
if (flags & GPIO_STM32_AF) {
|
||||
stm32_gpio_af_config(gpio, pin, GPIO_AFNUM(flags));
|
||||
}
|
||||
|
||||
if ((flags & GPIO_OUTPUT) || (flags & GPIO_STM32_AF)) {
|
||||
// All pins configured to 50MHz.
|
||||
gpio->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (pin * 2));
|
||||
gpio->OSPEEDR |= STM32_GPIO_SPEED_50_MHZ << (pin * 2);
|
||||
|
||||
// Output mode configuration
|
||||
gpio->OTYPER &= ~((GPIO_OTYPER_OT_0) << pin);
|
||||
if (flags & GPIO_STM32_OD) {
|
||||
gpio->OTYPER |= STM32_GPIO_OTYPE_OD << pin;
|
||||
} else {
|
||||
gpio->OTYPER |= STM32_GPIO_OTYPE_PP << pin;
|
||||
}
|
||||
}
|
||||
|
||||
stm32_gpio_mode_t mode;
|
||||
if (flags & GPIO_OUTPUT) {
|
||||
mode = STM32_GPIO_MODE_OUT;
|
||||
} else if (flags & GPIO_STM32_AF) {
|
||||
init.GPIO_Mode = GPIO_Mode_AF;
|
||||
GPIO_PinAFConfig(port_to_pointer(port), pin, GPIO_AFNUM(flags));
|
||||
}
|
||||
|
||||
if (flags & GPIO_PULLUP) {
|
||||
init.GPIO_PuPd = GPIO_PuPd_UP;
|
||||
} else if (flags & GPIO_PULLDOWN) {
|
||||
init.GPIO_PuPd = GPIO_PuPd_DOWN;
|
||||
}
|
||||
|
||||
if (flags & GPIO_STM32_OD) {
|
||||
init.GPIO_OType = GPIO_OType_OD;
|
||||
mode = STM32_GPIO_MODE_AF;
|
||||
} else {
|
||||
init.GPIO_OType = GPIO_OType_PP;
|
||||
mode = STM32_GPIO_MODE_IN;
|
||||
}
|
||||
|
||||
GPIO_Init(port_to_pointer(port), &init);
|
||||
gpio->MODER &= ~(GPIO_MODER_MODER0 << (pin * 2));
|
||||
gpio->MODER |= (mode << (pin * 2));
|
||||
|
||||
stm32_gpio_pupd_t pupd = STM32_GPIO_PUPD_NONE;
|
||||
if (flags & GPIO_PULLUP) {
|
||||
pupd = STM32_GPIO_PUPD_UP;
|
||||
} else if (flags & GPIO_PULLDOWN) {
|
||||
pupd = STM32_GPIO_PUPD_DOWN;
|
||||
}
|
||||
|
||||
gpio->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << (pin * 2));
|
||||
gpio->PUPDR |= pupd << (pin * 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpio_set(unsigned nr, unsigned on)
|
||||
{
|
||||
GPIO_WriteBit(port_to_pointer(GPIO_PORT(nr)), 1 << GPIO_PIN(nr), on);
|
||||
stm32_gpio_t *gpio = stm32_gpio_port_to_pointer(nr);
|
||||
if (on) {
|
||||
gpio->BSRR = 1 << GPIO_PIN(nr);
|
||||
} else {
|
||||
gpio->BRR = 1 << GPIO_PIN(nr);
|
||||
}
|
||||
}
|
||||
|
||||
int gpio_get(unsigned nr)
|
||||
{
|
||||
return GPIO_ReadInputDataBit(port_to_pointer(GPIO_PORT(nr)), 1 << GPIO_PIN(nr));
|
||||
stm32_gpio_t *gpio = stm32_gpio_port_to_pointer(nr);
|
||||
return (gpio->IDR & (1 << GPIO_PIN(nr))) != 0;
|
||||
}
|
||||
|
||||
|
||||
99
platform/stm32f0xx/include/platform/rcc.h
Normal file
99
platform/stm32f0xx/include/platform/rcc.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Erik Gilling
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __PLATFORM_STM32_RCC_H
|
||||
#define __PLATFORM_STM32_RCC_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stm32f0xx.h>
|
||||
|
||||
enum {
|
||||
STM32_RCC_REG_AHB = 0,
|
||||
STM32_RCC_REG_APB1 = 1,
|
||||
STM32_RCC_REG_APB2 = 2,
|
||||
};
|
||||
|
||||
#define STM32_RCC_CLK(reg, index) (((reg) << 16) | (index))
|
||||
#define STM32_RCC_CLK_AHB(index) STM32_RCC_CLK(STM32_RCC_REG_AHB, index)
|
||||
#define STM32_RCC_CLK_APB1(index) STM32_RCC_CLK(STM32_RCC_REG_APB1, index)
|
||||
#define STM32_RCC_CLK_APB2(index) STM32_RCC_CLK(STM32_RCC_REG_APB2, index)
|
||||
|
||||
#define STM32_RCC_CLK_REG(clk) ((clk) >> 16)
|
||||
#define STM32_RCC_CLK_INDEX(clk) ((clk) & 0xffff)
|
||||
|
||||
typedef enum {
|
||||
// AHB clocks.
|
||||
STM32_RCC_CLK_DMA = STM32_RCC_CLK_AHB(0),
|
||||
STM32_RCC_CLK_DMA2 = STM32_RCC_CLK_AHB(1),
|
||||
STM32_RCC_CLK_SRAM = STM32_RCC_CLK_AHB(2),
|
||||
STM32_RCC_CLK_FLITF = STM32_RCC_CLK_AHB(4),
|
||||
STM32_RCC_CLK_CRC = STM32_RCC_CLK_AHB(6),
|
||||
STM32_RCC_CLK_IOPA = STM32_RCC_CLK_AHB(17),
|
||||
STM32_RCC_CLK_IOPB = STM32_RCC_CLK_AHB(18),
|
||||
STM32_RCC_CLK_IOPC = STM32_RCC_CLK_AHB(19),
|
||||
STM32_RCC_CLK_IOPD = STM32_RCC_CLK_AHB(20),
|
||||
STM32_RCC_CLK_IOPE = STM32_RCC_CLK_AHB(21),
|
||||
STM32_RCC_CLK_IOPF = STM32_RCC_CLK_AHB(22),
|
||||
STM32_RCC_CLK_TSC = STM32_RCC_CLK_AHB(24),
|
||||
|
||||
// APB1 clocks.
|
||||
STM32_RCC_CLK_TIM2 = STM32_RCC_CLK_APB1(0),
|
||||
STM32_RCC_CLK_TIM3 = STM32_RCC_CLK_APB1(1),
|
||||
STM32_RCC_CLK_TIM6 = STM32_RCC_CLK_APB1(4),
|
||||
STM32_RCC_CLK_TIM7 = STM32_RCC_CLK_APB1(5),
|
||||
STM32_RCC_CLK_TIM14 = STM32_RCC_CLK_APB1(8),
|
||||
STM32_RCC_CLK_WWDG = STM32_RCC_CLK_APB1(11),
|
||||
STM32_RCC_CLK_SPI2 = STM32_RCC_CLK_APB1(14),
|
||||
STM32_RCC_CLK_USART2 = STM32_RCC_CLK_APB1(17),
|
||||
STM32_RCC_CLK_USART3 = STM32_RCC_CLK_APB1(18),
|
||||
STM32_RCC_CLK_USART4 = STM32_RCC_CLK_APB1(19),
|
||||
STM32_RCC_CLK_USART5 = STM32_RCC_CLK_APB1(20),
|
||||
STM32_RCC_CLK_I2C1 = STM32_RCC_CLK_APB1(21),
|
||||
STM32_RCC_CLK_I2C2 = STM32_RCC_CLK_APB1(22),
|
||||
STM32_RCC_CLK_USB = STM32_RCC_CLK_APB1(23),
|
||||
STM32_RCC_CLK_CAN = STM32_RCC_CLK_APB1(25),
|
||||
STM32_RCC_CLK_CRS = STM32_RCC_CLK_APB1(27),
|
||||
STM32_RCC_CLK_PWR = STM32_RCC_CLK_APB1(28),
|
||||
STM32_RCC_CLK_DAC = STM32_RCC_CLK_APB1(29),
|
||||
STM32_RCC_CLK_CEC = STM32_RCC_CLK_APB1(30),
|
||||
|
||||
// APB2 clocks.
|
||||
STM32_RCC_CLK_SYSCFGCOMP = STM32_RCC_CLK_APB2(0),
|
||||
STM32_RCC_CLK_USART6 = STM32_RCC_CLK_APB2(5),
|
||||
STM32_RCC_CLK_USART7 = STM32_RCC_CLK_APB2(6),
|
||||
STM32_RCC_CLK_USART8 = STM32_RCC_CLK_APB2(7),
|
||||
STM32_RCC_CLK_ADC = STM32_RCC_CLK_APB2(9),
|
||||
STM32_RCC_CLK_TIM1 = STM32_RCC_CLK_APB2(11),
|
||||
STM32_RCC_CLK_SPI1 = STM32_RCC_CLK_APB2(12),
|
||||
STM32_RCC_CLK_USART1 = STM32_RCC_CLK_APB2(14),
|
||||
STM32_RCC_CLK_TIM15 = STM32_RCC_CLK_APB2(16),
|
||||
STM32_RCC_CLK_TIM16 = STM32_RCC_CLK_APB2(17),
|
||||
STM32_RCC_CLK_TIM17 = STM32_RCC_CLK_APB2(18),
|
||||
STM32_RCC_CLK_DBG_MUC = STM32_RCC_CLK_APB2(22),
|
||||
} stm32_rcc_clk_t;
|
||||
|
||||
void stm32_rcc_set_enable(stm32_rcc_clk_t clock, bool enable);
|
||||
void stm32_rcc_set_reset(stm32_rcc_clk_t clock, bool reset);
|
||||
#endif // __PLATFORM_STM32_RCC_H
|
||||
68
platform/stm32f0xx/rcc.c
Normal file
68
platform/stm32f0xx/rcc.c
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
#include "platform/rcc.h"
|
||||
|
||||
#include <stm32f0xx.h>
|
||||
|
||||
static __IO uint32_t *stm32_rcc_get_clock_en_reg(stm32_rcc_clk_t clock) {
|
||||
switch (STM32_RCC_CLK_REG(clock)) {
|
||||
case STM32_RCC_REG_AHB:
|
||||
return &RCC->AHBENR;
|
||||
|
||||
case STM32_RCC_REG_APB1:
|
||||
return &RCC->APB1ENR;
|
||||
|
||||
case STM32_RCC_REG_APB2:
|
||||
return &RCC->APB2ENR;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static __IO uint32_t *stm32_rcc_get_clock_rst_reg(stm32_rcc_clk_t clock) {
|
||||
switch (STM32_RCC_CLK_REG(clock)) {
|
||||
case STM32_RCC_REG_AHB:
|
||||
return &RCC->AHBRSTR;
|
||||
|
||||
case STM32_RCC_REG_APB1:
|
||||
return &RCC->APB1RSTR;
|
||||
|
||||
case STM32_RCC_REG_APB2:
|
||||
return &RCC->APB2RSTR;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void stm32_rcc_set_enable(stm32_rcc_clk_t clock, bool enable) {
|
||||
__IO uint32_t *reg = stm32_rcc_get_clock_en_reg(clock);
|
||||
if (enable) {
|
||||
*reg |= 1 << STM32_RCC_CLK_INDEX(clock);
|
||||
} else {
|
||||
*reg &= ~(1 << STM32_RCC_CLK_INDEX(clock));
|
||||
}
|
||||
}
|
||||
|
||||
void stm32_rcc_set_reset(stm32_rcc_clk_t clock, bool reset) {
|
||||
switch(clock) {
|
||||
// These clocks to not have reset bits.
|
||||
case STM32_RCC_CLK_DMA:
|
||||
case STM32_RCC_CLK_DMA2:
|
||||
case STM32_RCC_CLK_SRAM:
|
||||
case STM32_RCC_CLK_FLITF:
|
||||
case STM32_RCC_CLK_CRC:
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
__IO uint32_t *reg = stm32_rcc_get_clock_rst_reg(clock);
|
||||
if (reset) {
|
||||
*reg |= 1 << STM32_RCC_CLK_INDEX(clock);
|
||||
} else {
|
||||
*reg &= ~(1 << STM32_RCC_CLK_INDEX(clock));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ MODULE_SRCS += \
|
||||
$(LOCAL_DIR)/dma.c \
|
||||
$(LOCAL_DIR)/gpio.c \
|
||||
$(LOCAL_DIR)/init.c \
|
||||
$(LOCAL_DIR)/rcc.c \
|
||||
$(LOCAL_DIR)/spi.c \
|
||||
$(LOCAL_DIR)/timer.c \
|
||||
$(LOCAL_DIR)/uart.c \
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Kent Ryhorchuk
|
||||
* Copyright (c) 2016 Erik Gilling
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
@@ -20,41 +21,37 @@
|
||||
* 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 <stm32f0xx_rcc.h>
|
||||
#include <stm32f0xx_usart.h>
|
||||
|
||||
#include <arch/arm/cm.h>
|
||||
#include <assert.h>
|
||||
#include <dev/uart.h>
|
||||
#include <lib/cbuf.h>
|
||||
#include <platform/rcc.h>
|
||||
#include <stdint.h>
|
||||
#include <stm32f0xx.h>
|
||||
|
||||
typedef USART_TypeDef stm32_usart_t;
|
||||
|
||||
#define RXBUF_SIZE 16
|
||||
|
||||
#ifdef ENABLE_UART1
|
||||
cbuf_t uart1_rx_buf;
|
||||
#ifndef UART1_FLOWCONTROL
|
||||
#define UART1_FLOWCONTROL USART_HardwareFlowControl_None
|
||||
#define UART1_FLOWCONTROL 0x0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_UART2
|
||||
cbuf_t uart2_rx_buf;
|
||||
#ifndef UART2_FLOWCONTROL
|
||||
#define UART2_FLOWCONTROL USART_HardwareFlowControl_None
|
||||
#define UART2_FLOWCONTROL 0x0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_UART3
|
||||
cbuf_t uart3_rx_buf;
|
||||
#ifndef UART3_FLOWCONTROL
|
||||
#define UART3_FLOWCONTROL USART_HardwareFlowControl_None
|
||||
#define UART3_FLOWCONTROL 0x0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -65,84 +62,99 @@ cbuf_t uart3_rx_buf;
|
||||
#ifdef ENABLE_UART3
|
||||
#endif
|
||||
|
||||
static void usart_init1_early(USART_TypeDef *usart, uint16_t flowcontrol, int irqn)
|
||||
static void stm32_usart_init1_early(stm32_usart_t *usart,
|
||||
uint16_t flow_control, int irqn)
|
||||
{
|
||||
USART_InitTypeDef init;
|
||||
uint32_t baud_rate = 115200;
|
||||
|
||||
init.USART_BaudRate = 115200;
|
||||
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;
|
||||
// Ensure USART is disabled before configuring it.
|
||||
usart->CR1 = 0;
|
||||
|
||||
USART_Init(usart, &init);
|
||||
USART_ITConfig(usart, USART_IT_RXNE, DISABLE);
|
||||
// Set stop bits to 1 (CR2[13:12] = 00b)
|
||||
usart->CR2 = 0;
|
||||
|
||||
|
||||
// Go with the defaults of:
|
||||
// word length: 8 bits
|
||||
// parity: disabled
|
||||
// Enable TX and RX.
|
||||
usart->CR1 = USART_CR1_TE | USART_CR1_RE;
|
||||
|
||||
usart->CR3 = flow_control;
|
||||
|
||||
// TODO(konkers): Add rcc API for querying clock freq.
|
||||
uint32_t apb_clock = 48000000;
|
||||
|
||||
usart->BRR = (apb_clock + baud_rate / 2) / baud_rate;
|
||||
|
||||
// Leave IRQs disabled until init.
|
||||
NVIC_DisableIRQ(irqn);
|
||||
USART_Cmd(usart, ENABLE);
|
||||
|
||||
// Enable UART.
|
||||
usart->CR1 |= USART_CR1_UE;
|
||||
}
|
||||
|
||||
static void usart_init1(USART_TypeDef *usart, int irqn, cbuf_t *rxbuf)
|
||||
static void stm32_usart_init1(stm32_usart_t *usart, int irqn, cbuf_t *rxbuf)
|
||||
{
|
||||
cbuf_initialize(rxbuf, RXBUF_SIZE);
|
||||
USART_ITConfig(usart, USART_IT_RXNE, ENABLE);
|
||||
// Enable RX not empty interrupt.
|
||||
usart->CR1 |= USART_CR1_RXNEIE;
|
||||
NVIC_EnableIRQ(irqn);
|
||||
USART_Cmd(usart, ENABLE);
|
||||
}
|
||||
|
||||
void uart_init_early(void)
|
||||
{
|
||||
#ifdef ENABLE_UART1
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
|
||||
stm32_rcc_set_enable(STM32_RCC_CLK_USART1, true);
|
||||
#endif
|
||||
#ifdef ENABLE_UART2
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
|
||||
stm32_rcc_set_enable(STM32_RCC_CLK_USART2, true);
|
||||
#endif
|
||||
#ifdef ENABLE_UART3
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
|
||||
stm32_rcc_set_enable(STM32_RCC_CLK_USART3, true);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_UART1
|
||||
usart_init1_early(USART1, UART1_FLOWCONTROL, USART1_IRQn);
|
||||
stm32_usart_init1_early(USART1, UART1_FLOWCONTROL, USART1_IRQn);
|
||||
#endif
|
||||
#ifdef ENABLE_UART2
|
||||
usart_init1_early(USART2, UART2_FLOWCONTROL, USART2_IRQn);
|
||||
stm32_usart_init1_early(USART2, UART2_FLOWCONTROL, USART2_IRQn);
|
||||
#endif
|
||||
#ifdef ENABLE_UART3
|
||||
usart_init1_early(USART3, UART3_FLOWCONTROL, USART3_IRQn);
|
||||
stm32_usart_init1_early(USART3, UART3_FLOWCONTROL, USART3_IRQn);
|
||||
#endif
|
||||
}
|
||||
|
||||
void uart_init(void)
|
||||
{
|
||||
#ifdef ENABLE_UART1
|
||||
usart_init1(USART1, USART1_IRQn, &uart1_rx_buf);
|
||||
stm32_usart_init1(USART1, USART1_IRQn, &uart1_rx_buf);
|
||||
#endif
|
||||
#ifdef ENABLE_UART2
|
||||
usart_init1(USART2, USART2_IRQn, &uart2_rx_buf);
|
||||
stm32_usart_init1(USART2, USART2_IRQn, &uart2_rx_buf);
|
||||
#endif
|
||||
#ifdef ENABLE_UART3
|
||||
usart_init1(USART3, USART3_IRQn, &uart3_rx_buf);
|
||||
stm32_usart_init1(USART3, USART3_IRQn, &uart3_rx_buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
// I'm seeing a weird issue with my nucleo-f072rb board where rx interrupts
|
||||
// don't fire right after a reset by the on board programmer. If I hit
|
||||
// the reset button, rx works fine. I can live with this. YMMV.
|
||||
void uart_rx_irq(USART_TypeDef *usart, cbuf_t *rxbuf)
|
||||
static void stm32_uart_rx_irq(stm32_usart_t *usart, cbuf_t *rxbuf)
|
||||
{
|
||||
arm_cm_irq_entry();
|
||||
|
||||
bool resched = false;
|
||||
while (USART_GetFlagStatus(usart, USART_FLAG_RXNE)) {
|
||||
while (usart->ISR & USART_ISR_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);
|
||||
usart->CR1 &= ~USART_CR1_RXNEIE;
|
||||
break;
|
||||
}
|
||||
|
||||
char c = USART_ReceiveData(usart);
|
||||
char c = usart->RDR;
|
||||
cbuf_write_char(rxbuf, c, false);
|
||||
resched = true;
|
||||
}
|
||||
@@ -153,43 +165,43 @@ void uart_rx_irq(USART_TypeDef *usart, cbuf_t *rxbuf)
|
||||
#ifdef ENABLE_UART1
|
||||
void stm32_USART1_IRQ(void)
|
||||
{
|
||||
uart_rx_irq(USART1, &uart1_rx_buf);
|
||||
stm32_uart_rx_irq(USART1, &uart1_rx_buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_UART2
|
||||
void stm32_USART2_IRQ(void)
|
||||
{
|
||||
uart_rx_irq(USART2, &uart2_rx_buf);
|
||||
stm32_uart_rx_irq(USART2, &uart2_rx_buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_UART3
|
||||
void stm32_USART3_IRQ(void)
|
||||
{
|
||||
uart_rx_irq(USART3, &uart3_rx_buf);
|
||||
stm32_uart_rx_irq(USART3, &uart3_rx_buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void usart_putc(USART_TypeDef *usart, char c)
|
||||
static void stm32_usart_putc(stm32_usart_t *usart, char c)
|
||||
{
|
||||
while (USART_GetFlagStatus(usart, USART_FLAG_TXE) == 0);
|
||||
USART_SendData(usart, c);
|
||||
while (USART_GetFlagStatus(usart, USART_FLAG_TC) == 0);
|
||||
while ((usart->ISR & USART_ISR_TXE) == 0);
|
||||
usart->TDR = c;
|
||||
while ((usart->ISR & USART_ISR_TC) == 0);
|
||||
}
|
||||
|
||||
static int usart_getc(USART_TypeDef *usart, cbuf_t *rxbuf, bool wait)
|
||||
static int stm32_usart_getc(stm32_usart_t *usart, cbuf_t *rxbuf, bool wait)
|
||||
{
|
||||
char c;
|
||||
cbuf_read_char(rxbuf, &c, wait);
|
||||
if (cbuf_space_avail(rxbuf) > RXBUF_SIZE/2)
|
||||
USART_ITConfig(usart, USART_IT_RXNE, ENABLE);
|
||||
usart->CR1 |= USART_CR1_RXNEIE;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static USART_TypeDef *get_usart(int port)
|
||||
static stm32_usart_t *stm32_get_usart(int port)
|
||||
{
|
||||
switch (port) {
|
||||
#ifdef ENABLE_UART1
|
||||
@@ -211,7 +223,7 @@ static USART_TypeDef *get_usart(int port)
|
||||
|
||||
}
|
||||
|
||||
static cbuf_t *get_rxbuf(int port)
|
||||
static cbuf_t *stm32_get_rxbuf(int port)
|
||||
{
|
||||
switch (port) {
|
||||
#ifdef ENABLE_UART1
|
||||
@@ -235,17 +247,17 @@ static cbuf_t *get_rxbuf(int port)
|
||||
|
||||
int uart_putc(int port, char c)
|
||||
{
|
||||
USART_TypeDef *usart = get_usart(port);
|
||||
usart_putc(usart, c);
|
||||
stm32_usart_t *usart = stm32_get_usart(port);
|
||||
stm32_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);
|
||||
cbuf_t *rxbuf = stm32_get_rxbuf(port);
|
||||
stm32_usart_t *usart = stm32_get_usart(port);
|
||||
|
||||
return usart_getc(usart, rxbuf, wait);
|
||||
return stm32_usart_getc(usart, rxbuf, wait);
|
||||
}
|
||||
|
||||
void uart_flush_tx(int port) {}
|
||||
|
||||
Reference in New Issue
Block a user