Add usart.{h, c}
This commit is contained in:
@@ -17,6 +17,10 @@ struct gpio {
|
|||||||
volatile uint32_t AFRH; // Alternative function high register
|
volatile uint32_t AFRH; // Alternative function high register
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// AFRH, AFRL registers
|
||||||
|
#define GPIO_AF_USART2_RX (0b0111) // Alternative function 7 (AF7)
|
||||||
|
#define GPIO_AF_USART2_TX (0b0111) // Alternative function 7 (AF7)
|
||||||
|
|
||||||
#define GPIO_BASE_ADDR (0x40020000U)
|
#define GPIO_BASE_ADDR (0x40020000U)
|
||||||
#define GPIO_PORT_OFFSET (0x400U)
|
#define GPIO_PORT_OFFSET (0x400U)
|
||||||
#define GPIO(port) ((struct gpio*)(uintptr_t)(GPIO_BASE_ADDR + (GPIO_PORT_OFFSET * port)))
|
#define GPIO(port) ((struct gpio*)(uintptr_t)(GPIO_BASE_ADDR + (GPIO_PORT_OFFSET * port)))
|
||||||
|
|||||||
@@ -118,6 +118,9 @@ struct rcc {
|
|||||||
#define RCC_APB1ENR_PWREN_BIT 28
|
#define RCC_APB1ENR_PWREN_BIT 28
|
||||||
#define RCC_APB1ENR_PWREN_CLOCK_ENABLE (1 << RCC_APB1ENR_PWREN_BIT)
|
#define RCC_APB1ENR_PWREN_CLOCK_ENABLE (1 << RCC_APB1ENR_PWREN_BIT)
|
||||||
|
|
||||||
|
#define RCC_APB1ENR_USART2EN_BIT 17
|
||||||
|
#define RCC_APB1ENR_USART2EN_ENABLE (1 << RCC_APB1ENR_USART2EN_BIT)
|
||||||
|
|
||||||
#define RCC_APB1ENR_TIM4_BIT 2
|
#define RCC_APB1ENR_TIM4_BIT 2
|
||||||
#define RCC_APB1ENR_TIM4_ENABLE (1 << RCC_APB1ENR_TIM4_BIT)
|
#define RCC_APB1ENR_TIM4_ENABLE (1 << RCC_APB1ENR_TIM4_BIT)
|
||||||
|
|
||||||
|
|||||||
66
src/usart.c
Normal file
66
src/usart.c
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#include "rcc.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "usart.h"
|
||||||
|
|
||||||
|
void usart2_init(void) {
|
||||||
|
// Enable clock for GPIOA as USART2 is on PORT A pins
|
||||||
|
RCC->AHB1ENR |= (1 << PORT('A'));
|
||||||
|
|
||||||
|
// Configure PA2 and PA3 (USART2 pins) to use alternative functions
|
||||||
|
uint16_t txPin = PIN('A', 2);
|
||||||
|
gpio_set_mode(txPin, GPIO_MODE_AF);
|
||||||
|
gpio_set_af(txPin, GPIO_AF_USART2_TX);
|
||||||
|
|
||||||
|
uint16_t rxPin = PIN('A', 3);
|
||||||
|
gpio_set_mode(rxPin, GPIO_MODE_AF);
|
||||||
|
gpio_set_af(rxPin, GPIO_AF_USART2_RX);
|
||||||
|
|
||||||
|
|
||||||
|
// Enable USART
|
||||||
|
RCC->APB1ENR |= RCC_APB1ENR_USART2EN_ENABLE;
|
||||||
|
|
||||||
|
// Clear control registers
|
||||||
|
USART2->CR1 = 0;
|
||||||
|
USART2->CR2 = 0;
|
||||||
|
USART2->CR3 = 0;
|
||||||
|
|
||||||
|
// Calculate Baud rate:
|
||||||
|
// baud = f_clck / (8 * (2 - OVER8) * USARTDIV) =>
|
||||||
|
// (8 * (2 - OVER8) * USARTDIV) = f_clock / baud =>
|
||||||
|
// baud * (8 * (2 - OVER8) * USARTDIV) = f_clock =>
|
||||||
|
// USARTDIV = (f_clock / (baud * (8 * (2 - OVER8)))
|
||||||
|
|
||||||
|
// Target Baud rate = 115200, f_clock = 48MHz, OVER8 = 0
|
||||||
|
// USARTDIV = 48E6 / (115200 * 8 * 2) = 26.0416666
|
||||||
|
// mantissa = 26 = 0x1A
|
||||||
|
// fraction = 0.041666 * 16 = 0.666656 ~= 1
|
||||||
|
|
||||||
|
// baud = 48E6 / (8 * 2 * 26) = 115384.61538461539
|
||||||
|
// error of 0.16% (115384.61538461539 / 115200 ) = 1.001602564102564
|
||||||
|
//
|
||||||
|
// skipping fractional part as error rate is good.
|
||||||
|
|
||||||
|
USART2->BRR &= ~(USART_BRR_MANTISSA_MASK << USART_BRR_MANTISSA_BIT);
|
||||||
|
USART2->BRR |= (0x1A << USART_BRR_MANTISSA_BIT);
|
||||||
|
USART2->BRR &= ~(USART_BRR_FRACTION_MASK << USART_BRR_FRACTION_BIT);
|
||||||
|
USART2->BRR |= (0x0 << USART_BRR_MANTISSA_BIT);
|
||||||
|
|
||||||
|
// Enable transmitter and receiver
|
||||||
|
USART2->CR1 |= USART_CR1_TE_ENABLE;
|
||||||
|
USART2->CR1 |= USART_CR1_RE_ENABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usart2_start(void) {
|
||||||
|
USART2->CR1 |= USART_CR1_UE_ENABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usart2_write_byte(uint8_t c) {
|
||||||
|
USART2->DR = c;
|
||||||
|
|
||||||
|
// Wait indefinitely for transmission to be ready for data
|
||||||
|
while (!(USART2->SR & USART_SR_TC_COMPLETED));
|
||||||
|
}
|
||||||
|
|
||||||
|
void usart2_write(char *buf) {
|
||||||
|
while (*buf) usart2_write_byte(*buf++);
|
||||||
|
}
|
||||||
50
src/usart.h
Normal file
50
src/usart.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#ifndef USART_H_
|
||||||
|
#define USART_H_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
struct usart {
|
||||||
|
volatile uint32_t SR; // Status register
|
||||||
|
volatile uint32_t DR; // Data register
|
||||||
|
volatile uint32_t BRR; // Baud rate register
|
||||||
|
volatile uint32_t CR1; // Control register 1
|
||||||
|
volatile uint32_t CR2; // Control register 2
|
||||||
|
volatile uint32_t CR3; // Control register 3
|
||||||
|
volatile uint32_t GTPR; // Guard time and prescaler register
|
||||||
|
};
|
||||||
|
|
||||||
|
#define USART2_BASE_ADDR (0x40004400U)
|
||||||
|
#define USART2 ((struct usart *) USART2_BASE_ADDR)
|
||||||
|
|
||||||
|
// SR Register
|
||||||
|
// Transmission complete
|
||||||
|
#define USART_SR_TC_BIT 6
|
||||||
|
#define USART_SR_TC_COMPLETED (1 << USART_SR_TC_BIT)
|
||||||
|
|
||||||
|
// CR Register
|
||||||
|
// USART enable
|
||||||
|
#define USART_CR1_UE_BIT 13
|
||||||
|
#define USART_CR1_UE_ENABLE (1 << USART_CR1_UE_BIT)
|
||||||
|
|
||||||
|
// Trasmitter enable
|
||||||
|
#define USART_CR1_TE_BIT 3
|
||||||
|
#define USART_CR1_TE_ENABLE (1 << USART_CR1_TE_BIT)
|
||||||
|
|
||||||
|
// Receiver enable
|
||||||
|
#define USART_CR1_RE_BIT 2
|
||||||
|
#define USART_CR1_RE_ENABLE (1 << USART_CR1_RE_BIT)
|
||||||
|
|
||||||
|
// BRR Register
|
||||||
|
#define USART_BRR_MANTISSA_BIT 4 // Bits [15:4]
|
||||||
|
#define USART_BRR_MANTISSA_MASK (0b111111111111)
|
||||||
|
|
||||||
|
#define USART_BRR_FRACTION_BIT 0 // Bits [3:0]
|
||||||
|
#define USART_BRR_FRACTION_MASK (0b111)
|
||||||
|
|
||||||
|
void usart2_init(void);
|
||||||
|
void usart2_start(void);
|
||||||
|
|
||||||
|
void usart2_write_byte(uint8_t byte);
|
||||||
|
void usart2_write(char *buf);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user