Custom UART0 and UART1 interrupt implementation with working terminal and programming?

Accept86
Posts: 12
Joined: Fri Jun 02, 2023 9:07 am

Custom UART0 and UART1 interrupt implementation with working terminal and programming?

Postby Accept86 » Fri Jun 02, 2023 10:12 am

Hi,
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);
}
I'm not sure what to do, so that the console prints actual text in Visual Studio Code, and the MCU resetting to bootloader works on UART0 Programming, like normal when you output to stdout with
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.
Last edited by Accept86 on Mon Jun 05, 2023 1:39 pm, edited 1 time in total.

Accept86
Posts: 12
Joined: Fri Jun 02, 2023 9:07 am

Re: Custom UART0 and UART1 interrupt implementation with working terminal and programming?

Postby Accept86 » Mon Jun 05, 2023 7:42 am

This post was about

Code: Select all

int _log_vprintf(const char* format, ...)   

how to figure out the actual lenght of format, but I later figured out myself:

Code: Select all

int _log_vprintf(const char* format, va_list arg_list)   //va_list list; is the ... argument

so we can just use va_list arg_list...
Last edited by Accept86 on Mon Jun 05, 2023 11:29 am, edited 3 times in total.

Accept86
Posts: 12
Joined: Fri Jun 02, 2023 9:07 am

Re: Custom UART0 and UART1 interrupt implementation with working terminal and programming?

Postby Accept86 » Mon Jun 05, 2023 11:22 am

Sadly no one answered, but I figured it out somehow. Heres my solution:

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"

// Interrupt manuell
#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


/*
#if !CONFIG_ESP_CONSOLE_UART
static uart_hal_context_t s_panic_uart = { .dev = &UART0 };

static void panic_print_char_uart(const char c)
{
    uint32_t sz = 0;
    while (!uart_hal_get_txfifo_len(&s_panic_uart));
    uart_hal_write_txfifo(&s_panic_uart, (uint8_t *) &c, 1, &sz);
}
#endif // CONFIG_ESP_CONSOLE_UART
*/

/*
int putc(int c, FILE *)
{
	UART_WriteDataToBuffer((unsigned char*)&c, 1,(short)UART_NUM_0);

    return 0;
}
*/

#define BUF_SIZE (SIZE_OF_TRANSMIT_UART_BUFFER)
#define QUEUE_FREE_SPACES ((BUF_SIZE+1)*2)

static QueueHandle_t uart0_queue;
static QueueHandle_t uart1_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);
}

short MyLogEnoughBufferLeft(short iWantWrite)
{
    short iPossibleWrite = SIZE_OF_TRANSMIT_UART_BUFFER - UART_GetTransmitDataSize( (short)UART_NUM_0 ) -1;

    if(iWantWrite<=iPossibleWrite)
    {
        return 1;
    }

    return 0;
}


#define FORMAT_START 7
int _log_vprintf(const char* format, va_list arg_list)   //va_list list; is the ... argument
{
    char* result = NULL;

    size_t maxBufSize = BUF_SIZE;
    char* buf[BUF_SIZE +1];

    if (format != NULL) 
    {
        short strLen_Format = strlen(format)+1;

        if((strLen_Format>FORMAT_START) && (strLen_Format < BUF_SIZE))
        {
            char* strFormat_afterTag = &format[FORMAT_START];
            int length = 0;

            // In case you want to limit to more than just text, but check for placeholders also...
            /*
            va_list vc;
            int x;
            int count = 0;
            va_copy(vc, arg_list);

            do {
                x = va_arg(vc, int);
                if (x == 0) break;
                count++;
            } while (1);

            va_end(vc);

            if(count != 0)
            {
            */
                length = vsnprintf(buf, maxBufSize, strFormat_afterTag, arg_list);
            //}


            if (length > 0)
            {
                    result = (char*)malloc(length+1);
                    memset(result,0,length+1);

                    if (result != NULL)
                    {
                        if (vsnprintf(result, length, strFormat_afterTag, arg_list) < 0)
                        {
                            free(result);
                            result = NULL;
                            MyLog("Failure: vsnprintf formatting failed.\r\n");
                        }
                    }
                    else
                    {
                        free(result);
                        result = NULL;
                        MyLog("Failure: allocation sprintf value failed.\r\n");
                    }
            }
            else if (length == 0)
            {
                result = NULL;
            }
            else
            {
                result = NULL;
                MyLog("Failure: vsnprintf return 0 length.\r\n");
            }

        }
    }
    else
    {
        MyLog("Failure: invalid argument.\r\n");
        result = NULL;
    }
    
    if(result!=NULL)
    {
        short iWantWrite = strlen(result);
        if(iWantWrite>0)
        {
            if(MyLogEnoughBufferLeft(iWantWrite + 4))
            {
                MyLog(result);
                MyLog("\r\n");
            }
        }

        free(result);
        result = NULL;
    }

    //uart_pattern_queue_reset(UART_NUM_0, QUEUE_FREE_SPACES);
    return 0;
}


void uartESPInitUARTAndInterrupt_int(void);
void uartEBUSInitUARTAndInterrupt(void);

void IRAM_ATTR uartESPInitUARTAndInterrupt(void) 
{
    uartESPInitUARTAndInterrupt_int();
    //esp_rom_install_channel_putc(1, putc);  // channelnumbers start with 1_ //////This seems unnecessary//////

    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, QUEUE_FREE_SPACES, &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
    static unsigned char uartnum = UART_NUM_0;
	ESP_ERROR_CHECK(esp_intr_alloc(ETS_UART0_INTR_SOURCE, NULL/*ESP_INTR_FLAG_LEVEL3*/, 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_TXD_INV*/ 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, QUEUE_FREE_SPACES, &uart1_queue, 0);

    InitUARTStruct(EX_UART_NUM);
    UART_InitEWBus(eBusUART, 2400, 400L); // eBus UART1

    static unsigned char uartnum = EX_UART_NUM;
	ESP_ERROR_CHECK(esp_intr_alloc(ETS_UART1_INTR_SOURCE /*ETS_UART2_INTR_SOURCE*/, NULL/*ESP_INTR_FLAG_LEVEL3*/, 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_intr_mask(EX_UART_NUM, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT));   // TBDTBDESP ?
}




// 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_enable_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));
    if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) {
        uart_hal_set_rts(&(uart_context[uart_num].hal), 0);
        uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE);
    }
    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 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 uint32_t uart_get_tx_write_fifo_size(uart_port_t uart_num)
{
    uint32_t len = 0;
    UART_ENTER_CRITICAL_SAFE(&(uart_context[uart_num].spinlock));
    len = uart_ll_get_txfifo_len(&(uart_context[uart_num].hal));
    UART_EXIT_CRITICAL_SAFE(&(uart_context[uart_num].spinlock));
    return 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)
{
    //while( curTX_Char!=-1 ){}
    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);

            /*
                uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE);
                UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
                uart_hal_tx_break(&(uart_context[uart_num].hal), BREAK_LENGTH);            // TBD Break-lenght TBD (cur 1)
                uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE);
                UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
                //break_flag = 1;
            */
            }
}


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)
                /*|| (uart_intr_status & UART_INTR_CMD_CHAR_DET)*/
            ) 
        {
            // 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_pattern_queue_reset(uart_num, QUEUE_FREE_SPACES);

            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*/
        }

        // after reading bytes from buffer clear UART interrupt status
        //uart_clear_intr_status(uart_num, UART_INTR_RXFIFO_FULL|UART_INTR_RXFIFO_TOUT );
    } //if(1)
}


// ____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));

        //uart_intr_MyTXHandling(uart_num);
    }
    else // disable
    {
        /*
        while(uart_get_tx_write_fifo_size(uart_num)!=0){}   // TBD prüfen

        //Sending item done, now we need to send break if there is a record.
        //Set TX break signal after FIFO is empty
        uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE);
        UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
        uart_hal_tx_break(&(uart_context[uart_num].hal), BREAK_LENGTH);            // TBD Break-lenght TBD (cur 1)
        uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE);
        UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock));
        */
    }
}
It would be interesting to get infos on how to improve it....

MicroController
Posts: 1738
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Custom UART0 and UART1 interrupt implementation with working terminal and programming?

Postby MicroController » Mon Jun 05, 2023 12:21 pm

Code: Select all

length = vsnprintf(buf, maxBufSize, strFormat_afterTag, arg_list);

if (length > 0)
{
    result = (char*)malloc(length+1);
If length < maxBufSize the string is already complete in buf. No need to allocate a new buffer and try again in that case.

Accept86
Posts: 12
Joined: Fri Jun 02, 2023 9:07 am

Re: Custom UART0 and UART1 interrupt implementation with working terminal and programming?

Postby Accept86 » Mon Jun 05, 2023 1:36 pm

@MicroController: Thank you for the Input :)


my current issue:

ISR:

Code: Select all

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;
}

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)
{
    unsigned char bc = b;
    uart_tx_write_fifo(md, (const uint8_t *) &bc, 1);
    while( uart_get_tx_write_fifo_empty(md)==0 ){}      // till empty - write immediatelly
}


uint32_t send_len;
uint32_t uart_intr_status = 0;

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);

                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);
            }
}

// +++The actual Interrupt handling+++
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));

            unsigned char fFlag = 0;
            if(rx_fifo_len>1)
            {
                rx_fifo_len = 1;
            }
            else
            {
                fFlag = 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);

            if(fFlag)
            {
                uart_clear_intr_status(uart_num, 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);
            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*/
        }

        // after reading bytes from buffer clear UART interrupt status
        //uart_clear_intr_status(uart_num, UART_INTR_RXFIFO_FULL|UART_INTR_RXFIFO_TOUT );
    } //if(1)
}


//+++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
    {
    }
}

Bufferhandling:

Code: Select all


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;

	// set immediatley adress on the bus to arbitrate the bus
	if ((data == 0xAA) && (p->bSetArbitAdress) && (p->IsEWBus))
	{
		p->TransmitProceedFlag = TRUE;

		p->bSetArbitAdress = 0;
		void clearEBusTX();
		clearEBusTX();
		//delayMicros( 10 );
		unsigned char AdressByte = p->ArbitrationAdress;
		
		UART_WriteDataToBuffer(&AdressByte, 1, md);	     // ++++++++++Here the Data should be sent immidiately
		UART_ProceedDataFromBuffer(md);  	// to make it faster!
	}

}

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);
}



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 ]);		// +++++++++++direct writing to uart
        	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;
}

I have to react within like 1-2 ms to the UART-Char 0xAA received, and the ESP32 seems to send the Response to slow, it takes at least 7-10ms :(

MicroController
Posts: 1738
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Custom UART0 and UART1 interrupt implementation with working terminal and programming?

Postby MicroController » Mon Jun 05, 2023 2:29 pm

One factor is probably that the ISR only provides data for further processing when the RX FIFO is full (or timed out), so there may be a delay of up to one FIFO worth of data before the first byte received actually gets processed.

Accept86
Posts: 12
Joined: Fri Jun 02, 2023 9:07 am

Re: Custom UART0 and UART1 interrupt implementation with working terminal and programming?

Postby Accept86 » Mon Jun 05, 2023 4:15 pm

How can I call the ISR processing faster?

MicroController
Posts: 1738
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Custom UART0 and UART1 interrupt implementation with working terminal and programming?

Postby MicroController » Mon Jun 05, 2023 4:40 pm

By setting the RX FIFO size to 1 obviously, or by setting a low-enough RX timeout.
Alternatively, you can try to leverage the UART's pattern-detection feature to give you an interrupt whenever the 1-byte "pattern" 0xAA is detected.

Are you set on using this e-bus kind of thing? Have you thought about how you'll detect a lost arbitration?

Who is online

Users browsing this forum: Bing [Bot] and 81 guests