Configuring UART registers and peripheral clock

coderooni
Posts: 11
Joined: Tue Apr 04, 2023 4:35 pm

Configuring UART registers and peripheral clock

Postby coderooni » Tue Apr 04, 2023 7:29 pm

Hi,

I've been trying for days now to configure UART by playing around with the bare registers themselves. The workflow that I believe should work is (currently, I'm only figuring out the transmission part):

1. Selecting clock source as PLL_CLK (80 MHz)
2. Enabling the UART clock
3. Selecting the APB_CLK and determining the integral part as well as the fractional part to set the baud rate
4... Configuring the stop bits, data length, allocating TX buffer memory, and writing data into the TX FIFO buffer

However, when I try to set these individual bits and/or registers, they don't necessarily work with every register. Moreover, when I try to set the clock as APB_CLK for UART0 it works but when I try it for UART1, it doesn't set that bit. The same goes for selecting the integral and fractional values; it sets the wanted values for UART0 but not for UART1.

Is there something I'm missing in the workflow, or doing something wrong to begin with? I do have further questions regarding configuring UART registers but would like to get this sorted out first.

Here's the code:
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "driver/uart.h"
  4. #include "freertos/FreeRTOS.h"
  5. #include "esp_err.h"
  6. #include "include/soc/uart_reg.h"
  7. #include "include/soc/rtc_cntl_reg.h"
  8. #include "include/soc/dport_reg.h"
  9. #include "include/soc/apb_ctrl_reg.h"
  10.  
  11. #define UART0 (0)
  12. #define UART1 (1)
  13. #define UART2 (2)
  14.  
  15. #define BYTE_TO_BINARY_PATTERN "%c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c %c%c%c%c"
  16. #define BYTE_TO_BINARY(byte)  \
  17.   ((byte) & 0x80000000 ? '1' : '0'), \
  18.   ((byte) & 0x40000000 ? '1' : '0'), \
  19.   ((byte) & 0x20000000 ? '1' : '0'), \
  20.   ((byte) & 0x10000000 ? '1' : '0'), \
  21.   ((byte) & 0x08000000 ? '1' : '0'), \
  22.   ((byte) & 0x04000000 ? '1' : '0'), \
  23.   ((byte) & 0x02000000 ? '1' : '0'), \
  24.   ((byte) & 0x01000000 ? '1' : '0'), \
  25.   ((byte) & 0x00800000 ? '1' : '0'), \
  26.   ((byte) & 0x00400000 ? '1' : '0'), \
  27.   ((byte) & 0x00200000 ? '1' : '0'), \
  28.   ((byte) & 0x00100000 ? '1' : '0'), \
  29.   ((byte) & 0x00080000 ? '1' : '0'), \
  30.   ((byte) & 0x00040000 ? '1' : '0'), \
  31.   ((byte) & 0x00020000 ? '1' : '0'), \
  32.   ((byte) & 0x00010000 ? '1' : '0'), \
  33.   ((byte) & 0x00008000 ? '1' : '0'), \
  34.   ((byte) & 0x00004000 ? '1' : '0'), \
  35.   ((byte) & 0x00002000 ? '1' : '0'), \
  36.   ((byte) & 0x00001000 ? '1' : '0'), \
  37.   ((byte) & 0x00000800 ? '1' : '0'), \
  38.   ((byte) & 0x00000400 ? '1' : '0'), \
  39.   ((byte) & 0x00000200 ? '1' : '0'), \
  40.   ((byte) & 0x00000100 ? '1' : '0'), \
  41.   ((byte) & 0x00000080 ? '1' : '0'), \
  42.   ((byte) & 0x00000040 ? '1' : '0'), \
  43.   ((byte) & 0x00000020 ? '1' : '0'), \
  44.   ((byte) & 0x00000010 ? '1' : '0'), \
  45.   ((byte) & 0x00000008 ? '1' : '0'), \
  46.   ((byte) & 0x00000004 ? '1' : '0'), \
  47.   ((byte) & 0x00000002 ? '1' : '0'), \
  48.   ((byte) & 0x00000001 ? '1' : '0')
  49.  
  50. void app_main(void)
  51. {
  52.     char *test = "HEY BIG BOI\n";
  53.    
  54.     // Select CPU clock source as PLL_CLK by configuring the RTC_CNTL_SOC_CLK_SEL bit to 1
  55.     REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, (BIT(27))); // Done
  56.     printf("CPU source PLL " BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(READ_PERI_REG(RTC_CNTL_CLK_CONF_REG)));
  57.  
  58.     // Set CPU clock to 0 to get 80 MHz PLL_CLK
  59.     DPORT_REG_CLR_BIT(DPORT_CPU_PER_CONF_REG, (BIT(0))); // Done correctly
  60.     printf("CLK reference " BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(DPORT_REG_READ(DPORT_CPU_PER_CONF_REG)));
  61.     // printf("CPU CLOCK SHOULD BE ZERO: %lx\n", DPORT_REG_READ(DPORT_CPU_PER_CONF_REG));
  62.    
  63.     // Enable UART1 clock
  64.     DPORT_REG_SET_BIT(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN | DPORT_UART_MEM_CLK_EN); // Done correctly
  65.     printf("UART1 Clock " BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(DPORT_REG_READ(DPORT_PERIP_CLK_EN_REG)));
  66.  
  67.     // Select APB clock
  68.     REG_SET_BITS(UART_CONF0_REG(UART1), (BIT(27)), 0x01000000); // ????
  69.     printf("APB_CLK_SOURCE " BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(READ_PERI_REG(UART_CONF0_REG(UART1))));
  70.  
  71.     // Drive UART module by generating clock signals
  72.     WRITE_PERI_REG(UART_CLKDIV_REG(UART1), 0x0002B6); // Integer part
  73.     // WRITE_PERI_REG(UART_CLKDIV_REG(UART_CLKDIV_FRAG), 0x); // Decimal part
  74.     printf("Integral clock " BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(READ_PERI_REG(UART_CLKDIV_REG(UART1))));
  75.  
  76.     // Set length of data (8 bits)
  77.     // WRITE_PERI_REG(UART_CONF0_REG(UART_BIT_NUM), 0x00000003);
  78.     printf("Length of data set is: %lx\n", READ_PERI_REG(UART_CONF0_REG(3 << 1)));
  79.  
  80.     // Set length of stop bit (1 bit)
  81.     WRITE_PERI_REG(UART_CONF0_REG(UART_STOP_BIT_NUM), 0x01);
  82.  
  83.     // Allocate TX memory
  84.     WRITE_PERI_REG(UART_MEM_CONF_REG(UART_TX_SIZE), 0x80);
  85.  
  86.     // Enable transmitter flow control function
  87.     // WRITE_PERI_REG(UART_CONF0_REG(UART_SW_RTS), 0x01);
  88.     // WRITE_PERI_REG(UART_CONF0_REG(UART_TX_FLOW_EN), 0x01);
  89.     // WRITE_PERI_REG(UART_CONF1_REG(UART_RX_FLOW_EN), 0x00);
  90.  
  91.     // Enable interrupt pin for UART_TX_DONE_INT
  92.     // WRITE_PERI_REG(UART_INT_ENA_REG(UART_TX_DONE_INT_ENA), 0x01);
  93.  
  94.     // Write data into Tx buffer | UART0 TX FIFO Buffer - 0x3FF4005C
  95.     for (int i=0; i<strlen(test); i++) {
  96.         WRITE_PERI_REG(UART_MEM_TX_STATUS_REG(UART_MEM_TX_WR_ADDR), test[i]);
  97.     }
  98.  
  99.     // Read number of bytes stored in Tx buffer
  100.     printf("%ld\n", READ_PERI_REG(UART_STATUS_REG(UART_TXFIFO_CNT)));
  101.    
  102.  
  103.     // UART controller serializes data
  104.  
  105.  
  106.     // UART sends data
  107.  
  108.  
  109.    
  110.  
  111.     // Start is 0 or LOW while Stop is 1 or HIGH
  112.     // UART_TX_DONE_INT - Interrupt raised when transmitter has sent out all FIFO data
  113. }
  114.  
  115. /* void UART_SEND() {
  116.  
  117. } */
  118.  
  119. /* void UART_RECEIVE() {
  120.    
  121. } */

ESP_Sprite
Posts: 9730
Joined: Thu Nov 26, 2015 4:08 am

Re: Configuring UART registers and peripheral clock

Postby ESP_Sprite » Wed Apr 05, 2023 12:12 am

Make sure you de-clockgate and de-reset UART1, otherwise it'll indeed not do much. Basically, do this for UART1.

coderooni
Posts: 11
Joined: Tue Apr 04, 2023 4:35 pm

Re: Configuring UART registers and peripheral clock

Postby coderooni » Wed Apr 05, 2023 12:43 am

ESP_Sprite wrote:
Wed Apr 05, 2023 12:12 am
Make sure you de-clockgate and de-reset UART1, otherwise it'll indeed not do much. Basically, do this for UART1.
Thank you for the link. So, reading in the register values after resetting them will result in the correct values? Does the TRM indicate resetting certain register values because as far as I've read, I didn't come across anything like that.
Also, why doesn't UART0 require the same de-clockgating and de-resetting?

coderooni
Posts: 11
Joined: Tue Apr 04, 2023 4:35 pm

Re: Configuring UART registers and peripheral clock

Postby coderooni » Thu Apr 06, 2023 12:17 am

Make sure you de-clockgate and de-reset UART1, otherwise it'll indeed not do much. Basically, do this for UART1.
I responded to this but it hasn't gotten approved yet? What I replied with was thank you for providing me with the link. Why do we need to de-clockgate and de-reset the peripheral clock and why does it work without it for UART0?
Also, this was not mentioned in the TRM about de-resetting or de-clockgating, may I know where to read more on this?

ESP_Sprite
Posts: 9730
Joined: Thu Nov 26, 2015 4:08 am

Re: Configuring UART registers and peripheral clock

Postby ESP_Sprite » Fri Apr 07, 2023 12:36 am

It works for UART0 as that is the default UART for debug messages; it already is de-clockgated by default. The TRM doesn't really seem to refer to peripheral clock-gating and reset functionality (it only documents the registers used for it), that seems like an omission and I'll file an issue to correct that.

coderooni
Posts: 11
Joined: Tue Apr 04, 2023 4:35 pm

Re: Configuring UART registers and peripheral clock

Postby coderooni » Sat Apr 08, 2023 10:39 am

ESP_Sprite wrote: It works for UART0 as that is the default UART for debug messages; it already is de-clockgated by default. The TRM doesn't really seem to refer to peripheral clock-gating and reset functionality (it only documents the registers used for it), that seems like an omission and I'll file an issue to correct that.
Great, thank you. In the meantime, any resources you think would be good to read about resetting and clockgating on ESP32?

ESP_Sprite
Posts: 9730
Joined: Thu Nov 26, 2015 4:08 am

Re: Configuring UART registers and peripheral clock

Postby ESP_Sprite » Sun Apr 09, 2023 2:53 am

I think the link I posted (to the low-level driver code) covers most of it. It's not really a complex concept.

coderooni
Posts: 11
Joined: Tue Apr 04, 2023 4:35 pm

Re: Configuring UART registers and peripheral clock

Postby coderooni » Mon Apr 17, 2023 9:29 pm

ESP_Sprite wrote:
Sun Apr 09, 2023 2:53 am
I think the link I posted (to the low-level driver code) covers most of it. It's not really a complex concept.
Thanks Sprite, it indeed wasn't a deep topic. I didn't get much time after that to finish what I started. I was diving into the UART section of the TRM and everything is clear except the part where it doesn't specify the sending of the UART dataframe.

Does the Tx FIFO buffer only send out its content when the Rx buffer requests to read? In that case the rtsn_out signal needs to be driven low to send the data?

Am I on the right track or completely off-track? I'm asking because the only thing I haven't figured out is how do I actually configure the registers to send the data in the Tx data buffer and if it's even possible to send to "nothing" without an Rx buffer configured at all.

ESP_Sprite
Posts: 9730
Joined: Thu Nov 26, 2015 4:08 am

Re: Configuring UART registers and peripheral clock

Postby ESP_Sprite » Tue Apr 18, 2023 1:12 am

From memory, the Tx fifo starts sending as soon as you write a byte to it. The idea of the FIFO is that you can write a fair amount of data into it in one go, faster than the data is sent; if you're doing the sending interrupt-based, it means you don't have to fire an interrupt every byte.

coderooni
Posts: 11
Joined: Tue Apr 04, 2023 4:35 pm

Re: Configuring UART registers and peripheral clock

Postby coderooni » Tue Apr 18, 2023 3:23 pm

ESP_Sprite wrote:
Tue Apr 18, 2023 1:12 am
From memory, the Tx fifo starts sending as soon as you write a byte to it. The idea of the FIFO is that you can write a fair amount of data into it in one go, faster than the data is sent; if you're doing the sending interrupt-based, it means you don't have to fire an interrupt every byte.
I see. Essentially, I'll need to set up interrupts for every state relating to the Tx FIFO.

Who is online

Users browsing this forum: No registered users and 144 guests