From 47e2dd088fe9ef3d69be95ef5f4777a38918c8fe Mon Sep 17 00:00:00 2001
From: Jakob <Jakob.knitter@bettermarks.com>
Date: Tue, 6 Jun 2023 17:04:16 +0200
Subject: [PATCH] copied and adapted example from mdk, added init and config
 uart

---
 src/uart-transmit/Makefile |   3 +
 src/uart-transmit/main.c   | 232 +++++++++++++++++++++++++++++++++++++
 2 files changed, 235 insertions(+)
 create mode 100644 src/uart-transmit/Makefile
 create mode 100644 src/uart-transmit/main.c

diff --git a/src/uart-transmit/Makefile b/src/uart-transmit/Makefile
new file mode 100644
index 0000000..333c4d4
--- /dev/null
+++ b/src/uart-transmit/Makefile
@@ -0,0 +1,3 @@
+SOURCES = main.c
+
+include $(MDK)/$(ARCH)/build.mk
diff --git a/src/uart-transmit/main.c b/src/uart-transmit/main.c
new file mode 100644
index 0000000..703e323
--- /dev/null
+++ b/src/uart-transmit/main.c
@@ -0,0 +1,232 @@
+// Copyright (c) Charles Lohr
+// All rights reserved
+
+#include <mdk.h>
+
+#define C3_SYSTEM_PERIP_CLK_EN0_REG ((volatile uint32_t *)0x0010)
+// SYSTEM_UART_MEM_CLK_EN is on 24
+// SYSTEM_UARTn_CLK_EN n=0 is on 2, n=1 is on 5
+
+#define C3_UART_CLKDIV_REG ((volatile uint32_t *)0x0014)
+// UART_CLKDIV - integer part of baud rate calculator devisor - 0 to 11
+// UART_CLKDIV_FRAG - numerator of devisor in baud rate calculator devisor
+
+#define C3_UART_RX_FILT_REG ((volatile uint32_t *)0x0018)
+// SYSTEM_UARTn_RST n=0 is on 2, n=1 is on 5
+
+#define C3_UART_CONF0_REG ((volatile uint32_t *)0x0020)
+// UART_PARITY is on 0
+// UART_PARITY_EN is on 1
+// UART_BIT_NUM is on 2 and 3
+
+#define C3_UART_CLK_CONF_REG ((volatile uint32_t *)0x0078)
+// UART_RST_CORE is on 23
+// UART_SCLK_SEL is on 20 and 21 (2 bits), selcetion is between 1 and 3
+// UART_SCLK_DIV_NUM - The integral part of the frequency divisor - 12 to 19
+// UART_SCLK_DIV_A - The numerator of the frequency divisor - 6 to 11
+// UART_SCLK_DIV_B - The denominator of the frequency divisor - 0 to 5
+
+#define C3_UART_ID_REG ((volatile uint32_t *)0x0080)
+// UART_UPDATE_CTRL is on 30
+// UART_REG_UPDATE is on 31
+
+// On the ESP32C3 dev boards, the WS2812 LED is connected to GPIO 8
+static int ws_2812_pin = 8;
+
+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_reg = *C3_SYSTEM_PERIP_CLK_EN0_REG;
+  perip_clk_en0_reg |= 1<<24;
+  perip_clk_en0_reg |= 1<<5;
+  perip_clk_en0_reg |= 1<<2;
+  *C3_SYSTEM_PERIP_CLK_EN0_REG = perip_clk_en0_reg;
+}
+
+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_reg = *C3_UART_RX_FILT_REG;
+  uint32_t core_value = *C3_UART_CLK_CONF_REG;
+  // clear UARTn_RST
+  rx_filt_reg &= (uint32_t)~(1<<5);
+  rx_filt_reg &= (uint32_t)~(1<<2);
+  *C3_UART_RX_FILT_REG = rx_filt_reg;
+  // set UART_RST_CORE
+  core_value |= 1<<23;
+  *C3_UART_CLK_CONF_REG = core_value;
+  // set UARTn_RST
+  rx_filt_reg |= 1<<5;
+  rx_filt_reg |= 1<<2;
+  *C3_UART_RX_FILT_REG = rx_filt_reg;
+  // clear UARTn_RST
+  rx_filt_reg &= (uint32_t)~(1<<5);
+  rx_filt_reg &= (uint32_t)~(1<<2);
+  *C3_UART_RX_FILT_REG = rx_filt_reg;
+  // clear UART_RST_CORE
+  core_value &= (uint32_t)~(1<<23);
+  *C3_UART_CLK_CONF_REG = core_value;
+}
+
+static void init_uart_clear_update(){  
+  // enable register synchronization by clearing UART_UPDATE_CTRL.
+  uint32_t id_value = *C3_UART_ID_REG;
+  id_value &= (uint32_t)~(1<<30);
+  *C3_UART_ID_REG = 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;
+  // 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 = 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 = clockSelect;
+
+  // calculate Baud rate to be 9600 (6Mhz/625)
+  uint32_t baudRateDivs = *C3_UART_CLKDIV_REG;
+  baudRateDivs |= 1<<0;
+  baudRateDivs |= 1<<4;
+  baudRateDivs |= 1<<5;
+  baudRateDivs |= 1<<6;
+  baudRateDivs |= 1<<9;
+  *C3_UART_CLKDIV_REG = baudRateDivs;
+}
+
+static void disable_parity(){
+  uint32_t uart_conf_reg = *C3_UART_CONF0_REG;
+  uart_conf_reg &= (uint32_t)~(1<<0);
+  uart_conf_reg &= (uint32_t)~(1<<1);
+  *C3_UART_CONF0_REG = uart_conf_reg;
+}
+
+static void set_max_data_lenght(){
+  uint32_t uart_conf_reg = *C3_UART_CONF0_REG;
+  uart_conf_reg |= (1<<2);
+  uart_conf_reg |= (1<<3);
+  *C3_UART_CONF0_REG = uart_conf_reg;
+}
+
+static void config_uart(){
+  printf("Try to config %d\n", 1);
+  // wait for UART_REG_UPDATE to become 0, which indicates the completion of the last synchronization;
+  uint32_t reg_update = *C3_UART_ID_REG;
+  if ((bool)(reg_update & (uint32_t)(1<<31))){
+    return;
+  }
+
+  printf("Ready to config %d\n", 1);
+
+  // 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 = reg_update;
+}
+
+static void enable_uart_transmitter(){
+  // configure TX FIFO’s empty threshold via UART_TXFIFO_EMPTY_THRHD;
+  // disable UART_TXFIFO_EMPTY_INT interrupt by clearing UART_TXFIFO_EMPTY_INT_ENA;
+  // write data to be sent to UART_RXFIFO_RD_BYTE;
+  // clear UART_TXFIFO_EMPTY_INT interrupt by setting UART_TXFIFO_EMPTY_INT_CLR;
+  // enable UART_TXFIFO_EMPTY_INT interrupt by setting UART_TXFIFO_EMPTY_INT_ENA;
+  // detect UART_TXFIFO_EMPTY_INT and wait for the completion of data transmission.
+}
+
+//static void reset_uart(){
+  // 26.4.1 Clock and Reset
+//  init_uart_enable_clk();
+//  init_uart_toggle_rst();
+//}
+
+static void init_uart(){
+  // from technical reference manual 543 f
+  init_uart_enable_clk();
+  init_uart_toggle_rst();
+  init_uart_clear_update();
+}
+
+// Simple hue function for generation of smooth rainbow.
+static uint8_t hueval(int value) {
+  value = value % 1536;
+  if (value < 256) {
+    return (uint8_t) value;
+  } else if (value < 768) {
+    return 255;
+  } else if (value < 1024) {
+    return (uint8_t) (1023 - value);
+  } else {
+    return 0;
+  }
+}
+
+static void blink(int count, unsigned long delay_millis) {
+  uint8_t green[3] = {1, 0, 0}, black[3] = {0, 0, 0};
+  for (int i = 0; i < count; i++) {
+    ws2812_show(ws_2812_pin, green, sizeof(green));
+    delay_ms(delay_millis);
+    ws2812_show(ws_2812_pin, black, sizeof(black));
+    delay_ms(delay_millis);
+  }
+}
+
+static void rainbow(int count) {
+  for (int i = 0; i < count; i++) {
+    uint8_t val = hueval(i);
+    val = (uint8_t) (val/100);
+    uint8_t rgb[3] = {0, val, val};
+    ws2812_show(ws_2812_pin, rgb, sizeof(rgb));
+    delay_ms(1);
+  }
+}
+
+int main(void) {
+  wdt_disable();
+  gpio_output(ws_2812_pin);
+  init_uart();
+  config_uart();
+  enable_uart_transmitter();
+  uint8_t cycle = 0;
+
+  for (;;) {
+    printf("Cycle %d\n", cycle++);
+    blink(2, 200);
+    rainbow(2500);
+  }
+
+  return 0;
+}
-- 
GitLab