1

I know this is an incredibly long questions but ive posted as much detail so I can give the most context and hopefully make it easier to answer.

I am currently creating a program to receive messages via UART from another device and then it should read and analyze the received message. I have the read and analyze functions working properly, but right now when I am trying to implement UART Rx interrupts I am having trouble calling other functions within the interrupt handler. It gives me the below error. I can build and flash with no errors, but as soon as the first message is received it throws back this :

      Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x402133a2  PS      : 0x00000033  A0      : 0x4021cb8c  A1      : 0x3ffe8220  
A2      : 0x00000000  A3      : 0x3ffe92fc  A4      : 0x4021339c  A5      : 0x00000003  
A6      : 0x00000000  A7      : 0x00000000  A8      : 0x00000000  A9      : 0x00000000  
A10     : 0x00000000  A11     : 0x00000000  A12     : 0x00000000  A13     : 0x00000020  
A14     : 0x00000020  A15     : 0x3ffe8c0c  SAR     : 0x0000001b  EXCCAUSE: 0x0000001c  

Backtrace: 0x402133a2:0x3ffe8220 0x4021cb8c:0x3ffe8230 0x40100552:0x3ffe8240 0x40100a7c:0x3ffe8260 

For context I am using Espressif's RTOS SDK to code onto an ESP8266 NodeMCU. Ive tried numerous ways to implement the handler function (the only way that worked was by changing a global volatile variable *1, but that brings up other problems which I will explain below), but most are to no avail. I know generally you're not supposed to create other static variables or call blocking functions within the handler, but within the source code for RTOS SDK line520 I I found what looked to be the default UART Rx handler the driver comes with and it uses a lot of things which I tried to mimic *2:


// internal isr handler for default driver code. (line 520)
uart_obj_t *p_uart = (uart_obj_t *) param;
    uint8_t uart_num = p_uart->uart_num;
    uart_dev_t *uart_reg = UART[uart_num];
    int rx_fifo_len = uart_reg->status.rxfifo_cnt;
    uint8_t buf_idx = 0;
    uint32_t uart_intr_status = UART[uart_num]->int_st.val;
    uart_event_t uart_event;
    BaseType_t task_woken = 0;

    while (uart_intr_status != 0x0) { //if an interrupt is trigger

       /// many lines later .... (line 636) ///

       //checks it the RX Timeout or Rx Buffer Filled interrupt are triggered
       } else if ((uart_intr_status & UART_RXFIFO_TOUT_INT_ST_M)
                   || (uart_intr_status & UART_RXFIFO_FULL_INT_ST_M)
                  ) {
            rx_fifo_len = uart_reg->status.rxfifo_cnt; //stores the length of buffered data

            if (p_uart->rx_buffer_full_flg == false) {
                // We have to read out all data in RX FIFO to clear the interrupt signal
                while (buf_idx < rx_fifo_len) {
                    p_uart->rx_data_buf[buf_idx++] = uart_reg->fifo.rw_byte;
                }

                // Get the buffer from the FIFO
                // After Copying the Data From FIFO ,Clear intr_status
                uart_clear_intr_status(uart_num, UART_RXFIFO_TOUT_INT_CLR_M |                  UART_RXFIFO_FULL_INT_CLR_M);
                uart_event.type = UART_DATA;
                uart_event.size = rx_fifo_len;
                p_uart->rx_stash_len = rx_fifo_len;


First I will paste my UART Rx Interrupt configuration settings :

      ///        UART Interrupt Configurations       ///
           uart_intr_config_t uartConfig = {
                   .intr_enable_mask = UART_RXFIFO_TOUT_INT_ENA,//which interrupts to enable
                   .rx_timeout_thresh = 1, //how much time to wait to trigger after last byte has been sent to Rx
                   .txfifo_empty_intr_thresh = 1, //How many bytes in Tx buffer to be left
                   .rxfifo_full_thresh = 10, //How many bytes within Rx buffer before interrupt is called
           };
  
           uart_intr_config(UART_NUM_0, &uartConfig); //configures UART interrupt using the above mask and paramaters
           uart_isr_register(UART_NUM_0, uart_intr_handle, NULL); //registers which function to call

1* When creating a volatile int variable and then changing the value within the handler function it seemed to work without any errors. I would be fine using this method but a problem with using UART Rx interrupts with RTOS SDK is that to clear the interrupt mask I need to read the function. Unfortunately I cannot read the function using the uart_read_bytes() function because that results in an error. If I flush the input buffer within the interrupt handler, then when I try to read the buffer inside the main or wherever else I read I presume there wont be anything to read after the flush which is why I dont want to use this volatile flag method. uart_flush_input() and uart_clear_intr_status() function given by RTOS SDK seem to work, but not other functions which make me even more confused.

 void uart_intr_handle(void *arg){
         //changes flag value. Inside main a loop will check change it to 0 if it is 1
         flag = 1;
  
         uart_flush_input(UART_NUM_0); //I need to flush because I cant use any function to read

         //clear the bits
         uart_clear_intr_status(UART_NUM_0, UART_RXFIFO_TOUT_INT_CLR );
}

*2 Instead of relying on the functions seen in the RTOS SDK API guide I decided to try and copy the way they do it in the source code. I didnt get all the way through, but even with the small amount of code I have so far, I am able to build and flash and then once again when the first message is received it throws back the guru mediation error.

 void uart_intr_handle(void *arg){


         //first we create the defintions we use
         uart_obj_t *p_uart = (uart_obj_t *) arg; //uart_obj_t is a struct which holds lots of info
         uint8_t uart_num = p_uart->uart_num; //holds which uart is being used
         uart_dev_t *uart_reg = UART[uart_num]; //idk
         int rx_fifo_len = uart_reg->status.rxfifo_cnt; //holds the length of data in the rx buffer
         uint8_t buf_idx = 0; //will indicate the buffer index value when populating the reference buffer
         uint32_t uart_intr_status = UART[uart_num]->int_st.val; //holds the intr status mask
         uart_event_t uart_event; //maybe I can delete this
         BaseType_t task_woken = 0; //prob I can delete this too

         //Havent implemented the second part yet
         uart_flush_input(UART_NUM_0);
         uart_clear_intr_status(UART_NUM_0, UART_RXFIFO_TOUT_INT_CLR );



}

Any help and insights you may have are greatly appreciated

5
  • For clarity, which of the above code fragments caused the exception mentioned at the start. If neither, then you really do need to post the code that produced the error. Commented Jul 13, 2024 at 11:33
  • I think you have provided a lot of superflous detail at the expense of clarity and succinctness, and omitted more useful detail. As far as I can tell arg is a copy of the pointer passed to uart_isr_register() but you have not shown that. Seems likely to me that pointer is invalid or does not point to valid uart_obj_t. Commented Jul 13, 2024 at 11:46
  • You seem irrationally fixated that it is something specific about function implementation in interrupts. The only requirement there is that they should be non-blocking and re-entrant, and should in ideally have short and deterministic execution time. But your approach to coding and diagnosis has a sniff of "cargo-cult" about it. Commented Jul 13, 2024 at 11:49
  • rxfifo_full_thresh = 10, //How many bytes within Rx buffer before interrupt is called What happens if you get a message shorter than 10 bytes? Wait forever? Commented Jul 13, 2024 at 17:29
  • @stark I believe rx_timeout_thresh=1 deals with that. After a one character break, the interrupt occurs regardless of FIFO threshold. Commented Jul 13, 2024 at 19:27

1 Answer 1

2

You use the argument arg in your ISR, but you provide a null pointer:

This is the call to register the ISR:

    uart_isr_register(UART_NUM_0, uart_intr_handle, NULL);

This is the part of your ISR that uses the provided null pointer for access. Of course this will crash:

void uart_intr_handle(void *arg) {
        uart_obj_t *p_uart = (uart_obj_t *) arg;
        uint8_t uart_num = p_uart->uart_num;
        /* ... */
}

The solution is to build the uart_obj_t object and provide its address:

    uart_obj_t my_uart_object = {
        // fill with your values
    };
    uart_isr_register(UART_NUM_0, uart_intr_handle, &my_uart_object);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.