#include "esp32-c3-uart-interface.h" #include <stdint.h> #include <stdbool.h> #include <stddef.h> #include <mdk.h> static void clearBits(volatile uint32_t *registerAddress, uint32_t bitPositions, uint32_t numBits) { uint32_t mask = (uint32_t)(1 << numBits) - 1; // Create a mask with the specified number of bits set to 1 mask <<= bitPositions; // Shift the mask to the correct bit positions *registerAddress &= ~mask; // Clear the bits in the register using bitwise AND with the inverse of the mask } static void setBit(volatile uint32_t *registerAddress, uint32_t bitPositions) { uint32_t mask = (uint32_t)(1 << bitPositions); *registerAddress |= ~mask; } static void setSpecificBitsInRegister(volatile uint32_t *reg, uint32_t *bits, size_t numBits) { uint32_t rx_fifo = *reg; for (size_t i = 0; i < numBits; i++) { uint32_t bitPos = bits[i]; rx_fifo |= (1 << bitPos); } *reg = rx_fifo; } static void init_uart_enable_clk(){ // enable the clock for UART RAM by setting SYSTEM_UART_MEM_CLK_EN to 1; // enable APB_CLK for UARTn by setting SYSTEM_UARTn_CLK_EN to 1; uint32_t perip_clk_en0 = *C3_SYSTEM_PERIP_CLK_EN0_REG; perip_clk_en0 |= 1<<24; perip_clk_en0 |= 1<<5; perip_clk_en0 |= 1<<2; *C3_SYSTEM_PERIP_CLK_EN0_REG = perip_clk_en0; } static void init_uart_toggle_rst(){ // Detailed steps explained in 26.5.2.1 // for resetting and initilizing of uart // get current regestry values uint32_t rx_filt = *C3_UART_RX_FILT_REG(0); uint32_t core_value = *C3_UART_CLK_CONF_REG(0); // clear UARTn_RST rx_filt &= (uint32_t)~(1<<5); rx_filt &= (uint32_t)~(1<<2); *C3_UART_RX_FILT_REG(0) = rx_filt; // set UART_RST_CORE core_value |= 1<<23; *C3_UART_CLK_CONF_REG(0) = core_value; // set UARTn_RST rx_filt |= 1<<5; rx_filt |= 1<<2; *C3_UART_RX_FILT_REG(0) = rx_filt; // clear UARTn_RST rx_filt &= (uint32_t)~(1<<5); rx_filt &= (uint32_t)~(1<<2); *C3_UART_RX_FILT_REG(0) = rx_filt; // clear UART_RST_CORE core_value &= (uint32_t)~(1<<23); *C3_UART_CLK_CONF_REG(0) = core_value; } static void init_uart_clear_update(){ // enable register synchronization by clearing UART_UPDATE_CTRL. uint32_t id_value = *C3_UART_ID_REG(0); id_value &= (uint32_t)~(1<<30); *C3_UART_ID_REG(0) = id_value; } static void config_clock_freq(){ //freq = clock source rate / (UART_SCLK_DIV_NUM+UART_SCLK_DIV_A/UART_SCLK_DIV_B) // baud rate = freq / (UART_CLKDIV + UART_CLKDIV_FRAG / 16) // select the clock source via UART_SCLK_SEL; uint32_t clockSelect = *C3_UART_CLK_CONF_REG(0); // making sure we start with 0 clockSelect &= (uint32_t)~(1<<20); clockSelect &= (uint32_t)~(1<<21); // 01 is ABP_CLK with 80 MHz // 10 is RC_FAST_CLK with default of 17.5 MHz // 11 is XTAL_CLK with 40 MHz clockSelect |= 1<<20; *C3_UART_CLK_CONF_REG(0) = clockSelect; // selected ABP_CLK with 80 MHz // dividing clock to 6 Mhz (divisor should be 13+1/3) // UART_SCLK_DIV_NUM clockSelect |= 1<<12; clockSelect |= 1<<14; clockSelect |= 1<<15; // UART_SCLK_DIV_A clockSelect |= 1<<6; // UART_SCLK_DIV_B clockSelect |= 1<<1; clockSelect |= 1<<0; *C3_UART_CLK_CONF_REG(0) = clockSelect; // calculate Baud rate to be 9600 (6Mhz/625) uint32_t baudRateDivs = *C3_UART_CLKDIV_REG(0); baudRateDivs |= 1<<0; baudRateDivs |= 1<<4; baudRateDivs |= 1<<5; baudRateDivs |= 1<<6; baudRateDivs |= 1<<9; *C3_UART_CLKDIV_REG(0) = baudRateDivs; } static void disable_parity(){ uint32_t uart_conf = *C3_UART_CONF0_REG(0); uart_conf &= (uint32_t)~(1<<0); uart_conf &= (uint32_t)~(1<<1); *C3_UART_CONF0_REG(0) = uart_conf; } static void set_max_data_lenght(){ uint32_t uart_conf = *C3_UART_CONF0_REG(0); uart_conf |= (1<<2); uart_conf |= (1<<3); *C3_UART_CONF0_REG(0) = uart_conf; } void config_uart(){ // wait for UART_REG(0)_UPDATE to become 0, which indicates the completion of the last synchronization; uint32_t reg_update = *C3_UART_ID_REG(0); while((bool)(reg_update & (uint32_t)(1<<31))){ __asm__("ADDI x0, x0, 0"); } // configure static registers (if any) following Section 26.5.1.2; // set clock freq to 6MHz // baud rate to 9600 config_clock_freq(); // configure data length via UART_BIT_NUM; set_max_data_lenght(); // configure odd or even parity check via UART_PARITY_EN and UART_PARITY; disable_parity(); // synchronize the configured values to the Core Clock domain by writing 1 to UART_REG_UPDATE. reg_update |= (uint32_t)(1<<31); *C3_UART_ID_REG(0) = reg_update; } void writeSomething(){ uint32_t bitPositions[] = {0,1,7}; size_t numBits = sizeof(bitPositions) / sizeof(bitPositions[0]); setSpecificBitsInRegister(C3_UART_FIFO_REG(0), bitPositions, numBits); //uint32_t rx_fifo = *C3_UART_FIFO_REG(0); //rx_fifo |= 1<<7; //rx_fifo |= 1<<6; //rx_fifo |= 1<<5; //*C3_UART_FIFO_REG(0) = rx_fifo; } void enable_uart_transmitter(){ for(int i = 0; i < 100; i++){ delay_ms(10); // configure TX FIFO’s empty threshold via UART_TXFIFO_EMPTY_THRHD; clearBits(C3_UART_CONF1_REG(0), 9, 9); setBit(C3_UART_CONF1_REG(0),3); // disable UART_TXFIFO_EMPTY_INT interrupt by clearing UART_TXFIFO_EMPTY_INT_ENA; clearBits(C3_UART_INT_ENA_REG(0), 1, 1); // write data to be sent to UART_RXFIFO_RD_BYTE; writeSomething(); // clear UART_TXFIFO_EMPTY_INT interrupt by setting UART_TXFIFO_EMPTY_INT_CLR; setBit(C3_UART_INT_CLR_REG(0), 1); // enable UART_TXFIFO_EMPTY_INT interrupt by setting UART_TXFIFO_EMPTY_INT_ENA; setBit(C3_UART_INT_ENA_REG(0), 1); } } void reset_uart(){ // 26.4.1 Clock and Reset init_uart_enable_clk(); init_uart_toggle_rst(); } void init_uart(){ // from technical reference manual 543 f init_uart_enable_clk(); init_uart_toggle_rst(); init_uart_clear_update(); }