Особенности FIFO буфера UART в ESP32
У ESP32 есть три UART-а. Каждый из которых размещает FIFO буфер приемника и FIFO буфер передатчика в общей памяти размером 1024 байта (ESP32 technical reference manual 3.5):
Однако при попытке увеличить размер FIFO буфера передатчика UART2 с 128 до 256 байт получил неожиданный эффект — передаваемые данные портили FIFO буфер приемника UART0, чего согласно документации быть не должно.
К сожалению в документации (ESP32 technical reference manual 3.5) описание регистров FIFO буферов отсутствует. Однако в заголовочных файлах esp-idf (в uart_struct.h) обнаружились:
1) регистр состояния FIFO буфера передатчика (смещение относительно базового адреса 0×5c):
union {
struct {
uint32_t status:24;
uint32_t reserved24: 8;
};
uint32_t val;
} mem_tx_status;
2) регистр состояния FIFO буфера приемника (смещение относительно базового адреса 0×60):
union {
struct {
uint32_t status: 24;
uint32_t reserved24: 8;
};
struct {
uint32_t reserved0: 2;
uint32_t rd_addr: 11; /*This register stores the rx mem read address.*/
uint32_t wr_addr: 11; /*This register stores the rx mem write address.*/
uint32_t reserved: 8;
};
uint32_t val;
} mem_rx_status;
Полагая что mem_tx_status соответствует по назначению бит mem_rx_status пишем для получения адресов FIFO буферов следующий код:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include
void print_uart_st(uart_dev_t *u,int num)
{
printf("UART%d:\n",num);
printf("rx_st=0x%X\n",(unsigned int)u->mem_rx_status.val);
printf("rx_rd=0x%X\n",(unsigned int)u->mem_rx_status.rd_addr);
printf("rx_wr=0x%X\n",(unsigned int)u->mem_rx_status.wr_addr);
uint32_t tx_s = u->mem_tx_status.val;
printf("tx_st=0x%X\n",tx_s);
printf("tx_rd=0x%X\n",(tx_s>>2)&2047);
printf("tx_wr=0x%X\n",(tx_s>>13)&2047);
}
uart_config_t uart_config =
{
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
void UARTtest(void * param)
{
uart_param_config(UART_NUM_1,&uart_config);
uart_param_config(UART_NUM_2,&uart_config);
uart_driver_install(UART_NUM_1, 256, 0, 0, NULL, 0);
uart_driver_install(UART_NUM_2, 256, 0, 0, NULL, 0);
uart_set_pin(UART_NUM_1, UART_PIN_NO_CHANGE, GPIO_NUM_16, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_set_pin(UART_NUM_2, UART_PIN_NO_CHANGE, GPIO_NUM_16, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
vTaskDelay(1000/portTICK_PERIOD_MS);
while (1)
{
print_uart_st(&UART0,0);
print_uart_st(&UART1,1);
print_uart_st(&UART2,2);
vTaskDelay(2000/portTICK_PERIOD_MS);
char s[256];
uart_write_bytes(UART_NUM_1, s, 1);
uart_write_bytes(UART_NUM_2, s, 2);
if(gets(s)!=NULL)
{
printf("recived=%s\n",s);
}
}
}
void app_main(void)
{
xTaskCreate(UARTtest, "UARTtest", 4096, NULL, 5, NULL);
}
После запуска получаем:
UART0:
rx_st=0×300600
rx_rd=0×180
rx_wr=0×180
tx_st=0xCE058
tx_rd=0×16
tx_wr=0×67
UART1:
rx_st=0×400800
rx_rd=0×200
rx_wr=0×200
tx_st=0×100200
tx_rd=0×80
tx_wr=0×80
UART2:
rx_st=0×500A00
rx_rd=0×280
rx_wr=0×280
tx_st=0×200400
tx_rd=0×100
tx_wr=0×100
Вывод осуществляется через UART0, поэтому tx_wr и tx_rd отличны от 0. Согласно полученным результатам распределение памяти между FIFO буферами UART0,1,2 следующее:
Адреса | UART |
---|---|
0×00…0×7F | UART0 TX_FIFO |
0×80…0xFF | UART1 TX_FIFO |
0×100…0×17F | UART2 TX_FIFO |
0×180…0×1FF | UART0 RX_FIFO |
0×200…0×27F | UART1 RX_FIFO |
0×280…0×2FF | UART2 RX_FIFO |
Кроме того регистры состояния FIFO буферов имеют разрядность 11 бит, значит возможно размер памяти отводимой под FIFO буфера = 2Кб. При задании UART0.mem_conf.tx_size=15 (память выделяется кусками длинной 128 байт) будет выделено 1920 байт, и регистр tx_wr при передаче досчитает до 1919 и с последующим переходом через 0 продолжит счет. Однако память при этом адресуется только мл. 10 битами, т.е. реальный объем общей памяти отведенной под FIFO буфера = 1Кб.
Итого:
1) Распределение общей памяти, отводимой ESP32 под FIFO UART не соответствует приведенной в technical reference manual 3.5;
2) Объем общей памяти FIFO UART = 1Кб.