Custom UART driver via CMSIS for STM32c031c6
Hello my friends, I hope you are doing great.
I am trying to create a custom driver for UART peripheral with CMSIS register header files.
I have created a build system using the board files and linkers and make. So far I have been able to make drivers for the GPIO pins.
Now I am trying to create my own driver for the UART peripheral via the CMSIS. So far I have created this:
int uart_params_init(uart_t *uart){
if (!uart) return -1;
// defualt configs:
uart->tx_pin = 9;
uart->rx_pin = 10;
uart->baudrate = 115200;
uart->tx_port = GPIOA;
uart->rx_port = GPIOA;
uart->instance = USART1;
uart->tx_af = 1;
uart->rx_af = 1;
return 0;
}
int uart_init(uart_t *uart) {
if (!uart || !uart->tx_port || !uart->rx_port) return -1;
if (uart_initialized) return 0;
// Enable GPIO clocks for the port:
if (uart->tx_port == GPIOA || uart->rx_port == GPIOA){
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
} else if (uart->tx_port == GPIOB || uart->rx_port == GPIOB){
RCC->IOPENR |= RCC_IOPENR_GPIOBEN;
} else {
return -2;
}
// activate the USART clock
// (Advanced Peripheral Bus Enable Register)
if (uart->instance == USART1){
RCC->APBENR2 |= RCC_APBENR2_USART1EN;
}else if (uart->instance == USART2){
RCC->APBENR1 |= RCC_APBENR1_USART2EN;
} else {
return -3;
}
// set the gpio port mode to AF (another peripheral uses this port)
// (clear & set)
uart->tx_port->MODER &= ~(3U << (uart->tx_pin * 2));
uart->tx_port->MODER |= (GPIO_MODE_AF << (uart->tx_pin * 2));
uart->rx_port->MODER &= ~(3U << (uart->rx_pin * 2));
uart->rx_port->MODER |= (GPIO_MODE_AF << (uart->rx_pin * 2));
// Tx and Rx AFR registers:
uart->tx_port->AFR[uart->tx_pin / AFR_PIN_COUNT] &= ~(0xFU << ((uart->tx_pin % AFR_PIN_COUNT) * AFR_PERPIN_WIDTH));
uart->tx_port->AFR[uart->tx_pin / AFR_PIN_COUNT] |= (uart->tx_af << ((uart->tx_pin % AFR_PIN_COUNT) * AFR_PERPIN_WIDTH));
uart->rx_port->AFR[uart->rx_pin / AFR_PIN_COUNT] &= ~(0xFU << ((uart->rx_pin % AFR_PIN_COUNT) * AFR_PERPIN_WIDTH));
uart->rx_port->AFR[uart->rx_pin / AFR_PIN_COUNT] |= (uart->rx_af << ((uart->rx_pin % AFR_PIN_COUNT) * AFR_PERPIN_WIDTH));
// Disable USART to avoid unwanted peripheral behavior
uart->instance->CR1 &= ~USART_CR1_UE;
// Force USART1 to use PCLK (safest, matches your BRR math)
RCC->CCIPR &= ~RCC_CCIPR_USART1SEL; // 00 = PCLK
// Set baud rate
uart->instance->BRR = UART_PCLK / uart->baudrate;
// Enable TX and RX
uart->instance->CR1 |= USART_CR1_TE | USART_CR1_RE;
// Enable back the USART
uart->instance->CR1 |= USART_CR1_UE;
// setting the flag to indicate this uart instance is initialized:
uart_initialized = true;
return 0;
}
int uart_write_byte(uart_t *uart, uint8_t data){
if (!uart) return -1;
// wait until transmit buffer is acepting:
uint32_t timeout_counter = 2500000;
while (!(uart->instance->ISR & USART_ISR_TXE_TXFNF)){
if (--timeout_counter == 0){
return -5;
}
};
// write data to transmit register
uart->instance->TDR = data;
return 0;
}
I build the application with `Make` and then flash the .elf file onto the MCU via the STM32CubeProgrammer.
However, when I do the screen on the com port I do not see anything being logged. I have tried a variety of different configs for initialization of the peripheral in this function:
int uart_params_init(uart_t *uart){
if (!uart) return -1;
// defualt configs:
uart->tx_pin = 9;
uart->rx_pin = 10;
uart->baudrate = 115200;
uart->tx_port = GPIOA;
uart->rx_port = GPIOA;
uart->instance = USART1;
uart->tx_af = 1;
uart->rx_af = 1;
return 0;
}Nevertheless, no matter what pin I use for the tx and rx pin or USART port, I will not see any logs being printed on the com port.
I am wondering what I am missing in my driver set up.
I would be thankful if you could help me out.
Thanks for your help.
