/* * (c) danielinux 2019 * * GPLv.2 * * See LICENSE for details */ #include #include #include "uart.h" #include "system.h" #define UART2 (0x40004400) #define UART2_SR (*(volatile uint32_t *)(UART2)) #define UART2_DR (*(volatile uint32_t *)(UART2 + 0x04)) #define UART2_BRR (*(volatile uint32_t *)(UART2 + 0x08)) #define UART2_CR1 (*(volatile uint32_t *)(UART2 + 0x0c)) #define UART2_CR2 (*(volatile uint32_t *)(UART2 + 0x10)) #define UART_CR1_UART_ENABLE (1 << 13) #define UART_CR1_SYMBOL_LEN (1 << 12) #define UART_CR1_PARITY_ENABLED (1 << 10) #define UART_CR1_PARITY_ODD (1 << 9) #define UART_CR1_TX_ENABLE (1 << 3) #define UART_CR1_RX_ENABLE (1 << 2) #define UART_CR2_STOPBITS (3 << 12) #define UART_SR_TX_EMPTY (1 << 7) #define UART_SR_RX_NOTEMPTY (1 << 5) #define APB1_CLOCK_ER (*(volatile uint32_t *)(0x40023840)) #define UART2_APB1_CLOCK_ER_VAL (1 << 17) #define AHB1_CLOCK_ER (*(volatile uint32_t *)(0x40023830)) #define GPIO_MODE_AF (2) #define UART2_PIN_AF 7 #define UART2_RX_PIN 2 #define UART2_TX_PIN 3 static void uart2_pins_setup(void) { uint32_t reg; AHB1_CLOCK_ER |= GPIOA_AHB1_CLOCK_ER; /* Set mode = AF */ reg = GPIOA_MODE & ~ (0x03 << (UART2_RX_PIN * 2)); GPIOA_MODE = reg | (2 << (UART2_RX_PIN * 2)); reg = GPIOA_MODE & ~ (0x03 << (UART2_TX_PIN * 2)); GPIOA_MODE = reg | (2 << (UART2_TX_PIN * 2)); /* Alternate function: use low pins */ reg = GPIOA_AFL & ~(0xf << ((UART2_TX_PIN) * 4)); GPIOA_AFL = reg | (UART2_PIN_AF << ((UART2_TX_PIN) * 4)); reg = GPIOA_AFL & ~(0xf << ((UART2_RX_PIN) * 4)); GPIOA_AFL = reg | (UART2_PIN_AF << ((UART2_RX_PIN) * 4)); } int uart2_setup(uint32_t bitrate, uint8_t data, char parity, uint8_t stop) { uint32_t reg; int pin_rx, pin_tx, pin_af; /* Enable pins and configure for AF7 */ uart2_pins_setup(); /* Turn on the device */ APB1_CLOCK_ER |= UART2_APB1_CLOCK_ER_VAL; /* Configure for TX */ UART2_CR1 |= UART_CR1_TX_ENABLE; /* Configure clock */ UART2_BRR = cpu_freq / bitrate; /* Configure data bits */ if (data == 8) UART2_CR1 &= ~UART_CR1_SYMBOL_LEN; else UART2_CR1 |= UART_CR1_SYMBOL_LEN; /* Configure parity */ switch (parity) { case 'O': UART2_CR1 |= UART_CR1_PARITY_ODD; /* fall through to enable parity */ case 'E': UART2_CR1 |= UART_CR1_PARITY_ENABLED; break; default: UART2_CR1 &= ~(UART_CR1_PARITY_ENABLED | UART_CR1_PARITY_ODD); } /* Set stop bits */ reg = UART2_CR2 & ~UART_CR2_STOPBITS; if (stop > 1) UART2_CR2 = reg & (2 << 12); else UART2_CR2 = reg; /* Turn on uart */ UART2_CR1 |= UART_CR1_UART_ENABLE; return 0; } int _write(void *r, uint8_t *text, int len) { char *p = (char *)text; int i; volatile uint32_t reg; text[len - 1] = 0; while(*p) { do { reg = UART2_SR; } while ((reg & UART_SR_TX_EMPTY) == 0); UART2_DR = *p; p++; } return len; } /* commodity to print binary buffers */ void printbin(const uint8_t *buf, int len) { int i; for (i = 0; i < len; i++) { if ((i % 16) == 0) printf("\r\n%08x: ", i); printf("%02x ", buf[i]); } printf("\r\n"); }