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:

Code: Untitled.c Select all


#include <stdio.h>
#include <string.h>
#include "driver/uart.h"
#include "freertos/FreeRTOS.h"
#include "esp_err.h"
#include "include/soc/uart_reg.h"
#include "include/soc/rtc_cntl_reg.h"
#include "include/soc/dport_reg.h"
#include "include/soc/apb_ctrl_reg.h"

#define UART0 (0)
#define UART1 (1)
#define UART2 (2)

#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"
#define BYTE_TO_BINARY(byte) \
((byte) & 0x80000000 ? '1' : '0'), \
((byte) & 0x40000000 ? '1' : '0'), \
((byte) & 0x20000000 ? '1' : '0'), \
((byte) & 0x10000000 ? '1' : '0'), \
((byte) & 0x08000000 ? '1' : '0'), \
((byte) & 0x04000000 ? '1' : '0'), \
((byte) & 0x02000000 ? '1' : '0'), \
((byte) & 0x01000000 ? '1' : '0'), \
((byte) & 0x00800000 ? '1' : '0'), \
((byte) & 0x00400000 ? '1' : '0'), \
((byte) & 0x00200000 ? '1' : '0'), \
((byte) & 0x00100000 ? '1' : '0'), \
((byte) & 0x00080000 ? '1' : '0'), \
((byte) & 0x00040000 ? '1' : '0'), \
((byte) & 0x00020000 ? '1' : '0'), \
((byte) & 0x00010000 ? '1' : '0'), \
((byte) & 0x00008000 ? '1' : '0'), \
((byte) & 0x00004000 ? '1' : '0'), \
((byte) & 0x00002000 ? '1' : '0'), \
((byte) & 0x00001000 ? '1' : '0'), \
((byte) & 0x00000800 ? '1' : '0'), \
((byte) & 0x00000400 ? '1' : '0'), \
((byte) & 0x00000200 ? '1' : '0'), \
((byte) & 0x00000100 ? '1' : '0'), \
((byte) & 0x00000080 ? '1' : '0'), \
((byte) & 0x00000040 ? '1' : '0'), \
((byte) & 0x00000020 ? '1' : '0'), \
((byte) & 0x00000010 ? '1' : '0'), \
((byte) & 0x00000008 ? '1' : '0'), \
((byte) & 0x00000004 ? '1' : '0'), \
((byte) & 0x00000002 ? '1' : '0'), \
((byte) & 0x00000001 ? '1' : '0')

void app_main(void)
{
char *test = "HEY BIG BOI\n";

// Select CPU clock source as PLL_CLK by configuring the RTC_CNTL_SOC_CLK_SEL bit to 1
REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, (BIT(27))); // Done
printf("CPU source PLL " BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(READ_PERI_REG(RTC_CNTL_CLK_CONF_REG)));

// Set CPU clock to 0 to get 80 MHz PLL_CLK
DPORT_REG_CLR_BIT(DPORT_CPU_PER_CONF_REG, (BIT(0))); // Done correctly
printf("CLK reference " BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(DPORT_REG_READ(DPORT_CPU_PER_CONF_REG)));
// printf("CPU CLOCK SHOULD BE ZERO: %lx\n", DPORT_REG_READ(DPORT_CPU_PER_CONF_REG));

// Enable UART1 clock
DPORT_REG_SET_BIT(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN | DPORT_UART_MEM_CLK_EN); // Done correctly
printf("UART1 Clock " BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(DPORT_REG_READ(DPORT_PERIP_CLK_EN_REG)));

// Select APB clock
REG_SET_BITS(UART_CONF0_REG(UART1), (BIT(27)), 0x01000000); // ????
printf("APB_CLK_SOURCE " BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(READ_PERI_REG(UART_CONF0_REG(UART1))));

// Drive UART module by generating clock signals
WRITE_PERI_REG(UART_CLKDIV_REG(UART1), 0x0002B6); // Integer part
// WRITE_PERI_REG(UART_CLKDIV_REG(UART_CLKDIV_FRAG), 0x); // Decimal part
printf("Integral clock " BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(READ_PERI_REG(UART_CLKDIV_REG(UART1))));

// Set length of data (8 bits)
// WRITE_PERI_REG(UART_CONF0_REG(UART_BIT_NUM), 0x00000003);
printf("Length of data set is: %lx\n", READ_PERI_REG(UART_CONF0_REG(3 << 1)));

// Set length of stop bit (1 bit)
WRITE_PERI_REG(UART_CONF0_REG(UART_STOP_BIT_NUM), 0x01);

// Allocate TX memory
WRITE_PERI_REG(UART_MEM_CONF_REG(UART_TX_SIZE), 0x80);

// Enable transmitter flow control function
// WRITE_PERI_REG(UART_CONF0_REG(UART_SW_RTS), 0x01);
// WRITE_PERI_REG(UART_CONF0_REG(UART_TX_FLOW_EN), 0x01);
// WRITE_PERI_REG(UART_CONF1_REG(UART_RX_FLOW_EN), 0x00);

// Enable interrupt pin for UART_TX_DONE_INT
// WRITE_PERI_REG(UART_INT_ENA_REG(UART_TX_DONE_INT_ENA), 0x01);

// Write data into Tx buffer | UART0 TX FIFO Buffer - 0x3FF4005C
for (int i=0; i<strlen(test); i++) {
WRITE_PERI_REG(UART_MEM_TX_STATUS_REG(UART_MEM_TX_WR_ADDR), test[i]);
}

// Read number of bytes stored in Tx buffer
printf("%ld\n", READ_PERI_REG(UART_STATUS_REG(UART_TXFIFO_CNT)));


// UART controller serializes data


// UART sends data




// Start is 0 or LOW while Stop is 1 or HIGH
// UART_TX_DONE_INT - Interrupt raised when transmitter has sent out all FIFO data
}

/* void UART_SEND() {

} */

/* void UART_RECEIVE() {

} */

Sprite
Espressif staff
Espressif staff
Posts: 10599
Joined: Thu Nov 26, 2015 4:08 am

Re: Configuring UART registers and peripheral clock

Postby 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

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?

Sprite
Espressif staff
Espressif staff
Posts: 10599
Joined: Thu Nov 26, 2015 4:08 am

Re: Configuring UART registers and peripheral clock

Postby 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

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?

Sprite
Espressif staff
Espressif staff
Posts: 10599
Joined: Thu Nov 26, 2015 4:08 am

Re: Configuring UART registers and peripheral clock

Postby 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

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.

Sprite
Espressif staff
Espressif staff
Posts: 10599
Joined: Thu Nov 26, 2015 4:08 am

Re: Configuring UART registers and peripheral clock

Postby 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

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: PerplexityBot and 5 guests