I'm trying to switch my application UART0 implementation to a custom interrupt implementation and implement a custom UART1 interrupt soluation - the terminal and programming via UART should be kept working.
I currently tried following:
The UART0/UART1 custom Interrupt implementation:
Code: Select all
#include "uartTransfer.h"
#include "main.h"
#include "esp_event.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_intr_alloc.h"
#include "driver/uart_select.h"
#include <stdint.h>
#include "hal/uart_ll.h"
#include "hal/uart_hal.h"
#include "esp_private/critical_section.h"
#include "FreeRTOSConfig.h"
#include "include_all.h"
#include "../APPL/usercode.h"
#include "uarts.h"
#include "o_uart_isrHandler.h"
#include "stdarg.h"
#include "stdio.h"
// from uart.c ESP-IDF
#define UART_EMPTY_THRESH_MY (2)
#define UART_FULL_THRESH_MY (30)
#define UART_TOUT_THRESH_MY (2)
#define UART_CLKDIV_FRAG_BIT_WIDTH (3)
#define UART_TX_IDLE_NUM_DEFAULT (0)
#define UART_PATTERN_DET_QLEN_DEFAULT (1)
#define UART_MIN_WAKEUP_THRESH (UART_LL_MIN_WAKEUP_THRESH)
#define UART_INTR_CONFIG_FLAG ((UART_INTR_RXFIFO_FULL) \
| (UART_INTR_RXFIFO_TOUT) \
| (UART_INTR_RXFIFO_OVF) \
| (UART_INTR_BRK_DET) \
| (UART_INTR_PARITY_ERR))
// _from uart.c ESP-IDF
#define BUF_SIZE (SIZE_OF_TRANSMIT_UART_BUFFER)
static QueueHandle_t uart0_queue;
void IRAM_ATTR uart_intr_handle(void *arg);
vprintf_like_t esp_log_set_vprintf(vprintf_like_t func);
void MyLog(char* toLog)
{
short length = strlen(toLog);
UART_WriteDataToBuffer((unsigned char*)toLog, length, (short)UART_NUM_0);
}
int _log_vprintf(const char* format, ...)
{
char* result = NULL;
size_t maxBufSize = 300;
char* buf[301];
if (format != NULL)
{
va_list arg_list;
int length;
va_start(arg_list, format);
length = vsnprintf(buf, maxBufSize, format, arg_list);
va_end(arg_list);
if (length > 0)
{
result = (char*)malloc(length+1);
if (result != NULL)
{
va_start(arg_list, format);
if (vsnprintf(result, length+1, format, arg_list) < 0)
{
free(result);
result = NULL;
MyLog("Failure: vsnprintf formatting failed.");
}
va_end(arg_list);
}
else
{
free(result);
result = NULL;
MyLog("Failure: allocation sprintf value failed.");
}
}
else if (length == 0)
{
result = NULL;
}
else
{
result = NULL;
MyLog("Failure: vsnprintf return 0 length");
}
}
else
{
MyLog("Failure: invalid argument.");
result = NULL;
}
if(result!=NULL)
{
MyLog(result);
}
return 0;
}
void uartESPInitUARTAndInterrupt_int(void);
void uartEBUSInitUARTAndInterrupt(void);
void IRAM_ATTR uartESPInitUARTAndInterrupt(void)
{
uartESPInitUARTAndInterrupt_int();
esp_log_set_vprintf(&_log_vprintf);
uartEBUSInitUARTAndInterrupt();
}
void IRAM_ATTR uartESPInitUARTAndInterrupt_int(void)
{
const 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,
.source_clk = UART_SCLK_APB,
};
uart_param_config(UART_NUM_0, &uart_config);
//Set UART log level
esp_log_level_set(TAG_Main, ESP_LOG_INFO);
//Set UART pins (using UART0 default pins ie no changes.)
//uart_set_pin(UART_NUM_0, GPIO_NUM_1 , GPIO_NUM_3 , UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
//Install UART driver, and get the queue.
uart_driver_install(UART_NUM_0, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
InitUARTStruct(UART_NUM_0);
// changed uart.c from ESP-IDF - see line 1628 in esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int event_queue_size, QueueHandle_t *uart_queue, int intr_alloc_flags)
/*
ret = esp_intr_alloc(uart_periph_signal[uart_num].irq, intr_alloc_flags,
uart_rx_intr_handler_default, p_uart_obj[uart_num],
&p_uart_obj[uart_num]->intr_handle);
ESP_GOTO_ON_ERROR(ret, err, UART_TAG, "Could not allocate an interrupt for UART");
ret = uart_intr_config(uart_num, &uart_intr);
ESP_GOTO_ON_ERROR(ret, err, UART_TAG, "Could not configure the interrupt for UART");
*/
// OWN ISR
// release the pre registered UART handler/subroutine
static unsigned char uartnum = UART_NUM_0;
// register new UART subroutine
ESP_ERROR_CHECK(esp_intr_alloc(ETS_UART0_INTR_SOURCE, NULL, uart_intr_handle, (void*)(&uartnum), NULL));
uart_intr_config_t uart_intr = {
.intr_enable_mask = UART_INTR_CONFIG_FLAG,
.rxfifo_full_thresh = UART_FULL_THRESH_MY,
.rx_timeout_thresh = UART_TOUT_THRESH_MY, // the timeout Threshold after which TOUT Int arrives - std 10 TBD
.txfifo_empty_intr_thresh = UART_EMPTY_THRESH_MY,
};
ESP_ERROR_CHECK(uart_intr_config(UART_NUM_0, &uart_intr));
// enable RX interrupt
ESP_ERROR_CHECK(uart_enable_rx_intr(UART_NUM_0));
}
// ____The Interrupt initialisation_____
void IRAM_ATTR uartEBUSInitUARTAndInterrupt(void)
{
const uart_config_t uart_config = {
.baud_rate = 2400,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
uart_param_config(EX_UART_NUM, &uart_config);
uart_set_line_inverse(EX_UART_NUM, UART_SIGNAL_IRDA_TX_INV /*| UART_SIGNAL_RXD_INV*/ );
//Set UART log level
esp_log_level_set(TAG_Main, ESP_LOG_INFO);
//Set UART pins (using UART0 default pins ie no changes.)
uart_set_pin(EX_UART_NUM, GPIO_NUM_33 , GPIO_NUM_2 , UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
//Install UART driver, and get the queue.
uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
InitUARTStruct(EX_UART_NUM);
UART_InitEWBus(eBusUART, 2400, 400L); // eBus UART1
static unsigned char uartnum = EX_UART_NUM;
// register new UART subroutine
ESP_ERROR_CHECK(esp_intr_alloc(ETS_UART1_INTR_SOURCE, NULL, uart_intr_handle, (void*)(&uartnum), NULL));
uart_intr_config_t uart_intr = {
.intr_enable_mask = UART_INTR_CONFIG_FLAG,
.rxfifo_full_thresh = UART_FULL_THRESH_MY,
.rx_timeout_thresh = UART_TOUT_THRESH_MY, // the timeout Threshold after which TOUT Int arrives - std 10 TBD
.txfifo_empty_intr_thresh = UART_EMPTY_THRESH_MY,
};
ESP_ERROR_CHECK(uart_intr_config(EX_UART_NUM, &uart_intr));
// enable RX interrupt
ESP_ERROR_CHECK(uart_enable_rx_intr(EX_UART_NUM));
}
// from uart.c ESP-IDF
#define UART_ENTER_CRITICAL_SAFE(spinlock) esp_os_enter_critical_safe(spinlock)
#define UART_EXIT_CRITICAL_SAFE(spinlock) esp_os_exit_critical_safe(spinlock)
#define UART_ENTER_CRITICAL_ISR(spinlock) esp_os_enter_critical_isr(spinlock)
#define UART_EXIT_CRITICAL_ISR(spinlock) esp_os_exit_critical_isr(spinlock)
#define UART_ENTER_CRITICAL(spinlock) esp_os_enter_critical(spinlock)
#define UART_EXIT_CRITICAL(spinlock) esp_os_exit_critical(spinlock)
#define UART_CONTEX_INIT_DEF(uart_num) {\
.hal.dev = UART_LL_GET_HW(uart_num),\
INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock)\
.hw_enabled = false,\
}
typedef struct {
uart_hal_context_t hal; // UART hal context
DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(spinlock)
bool hw_enabled;
} uart_context_t;
static uart_context_t uart_context[UART_NUM_MAX] = {
UART_CONTEX_INIT_DEF(UART_NUM_0),
UART_CONTEX_INIT_DEF(UART_NUM_1),
#if UART_NUM_MAX > 2
UART_CONTEX_INIT_DEF(UART_NUM_2),
#endif
};
#define UART_IS_MODE_SET(uart_number, mode) (1)
// _from uart.c ESP-IDF
#define UART_ISR_ATTR
#define BREAK_LENGTH 1
static uint32_t UART_ISR_ATTR uart_tx_write_fifo(uart_port_t uart_num, const uint8_t *pbuf, uint32_t len)
{
uint32_t sent_len = 0;
UART_ENTER_CRITICAL_SAFE(&(uart_context[uart_num].spinlock));
uart_hal_write_txfifo(&(uart_context[uart_num].hal), pbuf, len, &sent_len);
UART_EXIT_CRITICAL_SAFE(&(uart_context[uart_num].spinlock));
return sent_len;
}
static unsigned char uart_get_tx_write_fifo_empty(uart_port_t uart_num)
{
unsigned char result = 0;
UART_ENTER_CRITICAL_SAFE(&(uart_context[uart_num].spinlock));
if(uart_ll_get_txfifo_len(&(uart_context[uart_num].hal)) == UART_LL_FIFO_DEF_LEN)
result = 1;
UART_EXIT_CRITICAL_SAFE(&(uart_context[uart_num].spinlock));
return result;
}
// The actual Interrupt handling
unsigned char curRX_Char[D_UART_NUMBER_OF_MODULES] = {0};
short curTX_Char[D_UART_NUMBER_OF_MODULES] = {0};
void IRAM_ATTR putuart(short md, unsigned char b) // in o_uart_isrHandler.c
{
curTX_Char[md] = b;
while( uart_get_tx_write_fifo_empty(md)==0 ){}
}
uint32_t send_len;
uint32_t uart_intr_status = 0;
//unsigned char break_flag = 0;
/*
* Define UART interrupt subroutine to ackowledge interrupt
*/
// uart.c static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param)
void IRAM_ATTR uart_intr_MyTXHandling(short uart_num)
{
UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY);
UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY);
//SENDING
if (UART_GetTransmitDataSize(uart_num)!=0)
{
UART_ProceedDataFromBuffer(uart_num);
// To fill the TX FIFO.
if(curTX_Char[uart_num]!=-1)
{
send_len = uart_tx_write_fifo(uart_num, (const uint8_t *) &curTX_Char[uart_num], 1);
}
if(send_len)
{
curTX_Char[uart_num] = -1;
}
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY);
UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY);
UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
}
else
{
UART_ProceedDataFromBuffer(uart_num);
}
}
void IRAM_ATTR uart_intr_handle(void *arg)
{
unsigned char* p_uart = (unsigned char*) arg;
uart_port_t uart_num = (uart_port_t)(*p_uart);
if((uart_num==UART_NUM_0)||(uart_num==EX_UART_NUM))
{
// The `continue statement` may cause the interrupt to loop infinitely
// we exit the interrupt here
uart_intr_status = uart_hal_get_intsts_mask(&(uart_context[uart_num].hal));
if ((uart_intr_status & UART_INTR_RXFIFO_TOUT)
|| (uart_intr_status & UART_INTR_RXFIFO_FULL)
)
{
// RECEIVING
uint32_t rx_fifo_len = uart_hal_get_rxfifo_len(&(uart_context[uart_num].hal));
if(rx_fifo_len>1)
rx_fifo_len = 1;
uart_hal_read_rxfifo(&(uart_context[uart_num].hal), (unsigned char*)&curRX_Char[uart_num], &rx_fifo_len);
UART_PutReceivedDataIntoBuffer(curRX_Char[uart_num], uart_num);
uart_clear_intr_status(uart_num, UART_INTR_RXFIFO_FULL|UART_INTR_RXFIFO_TOUT );
}
else if (uart_intr_status & UART_INTR_TXFIFO_EMPTY)
{
uart_intr_MyTXHandling(uart_num);
}
else if ( uart_intr_status & UART_INTR_CMD_CHAR_DET
)
{
uart_clear_intr_status(uart_num, UART_INTR_CMD_CHAR_DET );
}
else if (uart_intr_status & UART_INTR_RXFIFO_OVF)
{
// When fifo overflows, we reset the fifo.
UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_RXFIFO_OVF);
}
else if (uart_intr_status & UART_INTR_BRK_DET)
{
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_BRK_DET);
}
else if (uart_intr_status & UART_INTR_FRAM_ERR)
{
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_FRAM_ERR);
}
else if (uart_intr_status & UART_INTR_PARITY_ERR)
{
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_PARITY_ERR);
}
else if (uart_intr_status & UART_INTR_TX_BRK_DONE)
{
UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE);
/*
if (break_flag == 1) {
uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY); // TBD prüfen
break_flag = 0;
}
*/
UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE);
}
else if (uart_intr_status & UART_INTR_TX_BRK_IDLE)
{
UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_IDLE);
UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_IDLE);
}
else if (uart_intr_status & UART_INTR_CMD_CHAR_DET)
{
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_CMD_CHAR_DET);
}
else if (uart_intr_status & UART_INTR_TX_DONE)
{
// Workaround for RS485: If the RS485 half duplex mode is active
// and transmitter is in idle state then reset received buffer and reset RTS pin
// skip this behavior for other UART modes
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE);
UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE);
UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
}
else
{
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), uart_intr_status); /*simply clear all other intr status*/
}
}
}
// The UART TX Interrupt enabler
void IRAM_ATTR enable_disable_UART_TX_Int(uart_port_t uart_num, unsigned char enable)
{
if(enable)
{
uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY);
UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY);
UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
}
else // disable
{
}
}
The interrupt handling seemed to work, but the UART0 console only prints "?????????" and the UART0-Programming via Command line doesnt work anymore.
The UART0/UART1 data Queue handling:
Code: Select all
unsigned char IRAM_ATTR UART_ProceedDataFromBuffer(short md)
{
UART_DATA_STRUCT *p = &g_uart[md];
if (p->TransmitReadIndex != p->TransmitWriteIndex)
{
if (p->TransmitReadIndex >= SIZE_OF_TRANSMIT_UART_BUFFER) {
p->TransmitReadIndex = 0;
}
putuart(md, p->Transmit[ p->TransmitReadIndex ]);
p->TransmitReadIndex++;
if (p->TransmitReadIndex >= SIZE_OF_TRANSMIT_UART_BUFFER) {
p->TransmitReadIndex = 0;
}
}
else
{
p->TransmitProceedFlag = FALSE;
enable_disable_UART_TX_Int(md,g_uart[md].TransmitProceedFlag);
}
return 0;
}
void IRAM_ATTR UART_PutReceivedDataIntoBuffer(unsigned char data, short md)
{
register UART_DATA_STRUCT *p = &g_uart[md];
...
p->Receive[p->ReceiveWriteIndex++] = data;
if (p->ReceiveWriteIndex >= SIZE_OF_RECEIVE_UART_BUFFER)
p->ReceiveWriteIndex = 0;
....
}
void IRAM_ATTR UART_WriteDataToBuffer(unsigned char *puc, short size, short md)
{
unsigned char c;
for (; size; size--)
{
g_uart[md].TransmitProceedFlag = TRUE;
c = *puc++;
g_uart[md].Transmit[ g_uart[md].TransmitWriteIndex++ ] = c;
if (g_uart[md].TransmitWriteIndex >= SIZE_OF_TRANSMIT_UART_BUFFER)
{
g_uart[md].TransmitWriteIndex = 0;
}
}
enable_disable_UART_TX_Int(md,g_uart[md].TransmitProceedFlag);
}
vprintf_DRIVER
that you give to:
esp_log_set_vprintf(&vprintf_DRIVER);
I need the custom interrupt implementation for different reasons. the UART1 implementation of the eBus-Bus has timing restrictions, and needs to send certain responses on UART input Bytes very fast;
The UART0 Terminal implementation I want to extend with a second switchable usage case of something else (a custom Visualization interface that is not the standard terminal)
I could just switch back to normal Usage over specific handshakes to use normal Terminal and Programming again.