diff --git a/src/gpio.h b/src/gpio.h index 298fd88..5b6e159 100644 --- a/src/gpio.h +++ b/src/gpio.h @@ -17,6 +17,10 @@ struct gpio { 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_PORT_OFFSET (0x400U) #define GPIO(port) ((struct gpio*)(uintptr_t)(GPIO_BASE_ADDR + (GPIO_PORT_OFFSET * port))) diff --git a/src/rcc.h b/src/rcc.h index 153e57a..d898f6b 100644 --- a/src/rcc.h +++ b/src/rcc.h @@ -118,6 +118,9 @@ struct rcc { #define RCC_APB1ENR_PWREN_BIT 28 #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_ENABLE (1 << RCC_APB1ENR_TIM4_BIT) diff --git a/src/usart.c b/src/usart.c new file mode 100644 index 0000000..e90bdaa --- /dev/null +++ b/src/usart.c @@ -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++); +} diff --git a/src/usart.h b/src/usart.h new file mode 100644 index 0000000..7f94b9c --- /dev/null +++ b/src/usart.h @@ -0,0 +1,50 @@ +#ifndef USART_H_ +#define USART_H_ + +#include + +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