I am trying to create a new UART interrupt service routine and have looked at many examples and the ESP-IDF documentation on how to do this. Everything I have seen points to the function uart_intr_free() as the function to call in order to free the default handle and then assign your own using esp_intr_alloc() or uart_intr_alloc(). However, in version 5.2 of ESP-IDF framework it seems that the uart_intr_free function has been deprecated as I (and more importantly the build chain) cannot find it. It was not too hard to setup esp_intr_alloc() in place of the also missing uart_intr_alloc(), but uart_intr_free() requires access to the UART object and its member parameters. This object and its members are all private meaning I cannot reference the default handle by name nor can I free a non-default handle without access to uart_intr_free().
I have found no existing documentation to resolve this issue and was wondering if anyone had advice on how to proceed.
Freeing default UART ISR in ESP-IDF v5.2
-
- Posts: 9727
- Joined: Thu Nov 26, 2015 4:08 am
Re: Freeing default UART ISR in ESP-IDF v5.2
Unless you install the UART driver beforehand, the UART for stdout doesn't use any interrupts (it's a simple polling driver) so you shouldn't have to uninstall anything.
Re: Freeing default UART ISR in ESP-IDF v5.2
Do you not need to install the UART drivers for the peripheral to work? I am using non-default settings (baud, parity, stop bits, and data bit length) so how would I set that up without installing drivers?ESP_Sprite wrote: ↑Sat Jun 03, 2023 6:28 amUnless you install the UART driver beforehand, the UART for stdout doesn't use any interrupts (it's a simple polling driver) so you shouldn't have to uninstall anything.
Overall it seems counterintuitive that I have to seemingly not setup UART in order to use UART interrupts.
-
- Posts: 9727
- Joined: Thu Nov 26, 2015 4:08 am
Re: Freeing default UART ISR in ESP-IDF v5.2
If you want to set up the uart parameters, you're probably better off using the HALlayer. (Note that it says use in applications is unsupported, but I'd say your setup of relying on a driver uninstall to keep the settings intact is more unsupported-er.)
Re: Freeing default UART ISR in ESP-IDF v5.2
It feels like this doesn't answer my original question. After a driver install specifying the UART operating parameters, is there no longer a way to use a custom interrupt? Should I convert back to a previous version of ESP-IDF where this was still possible? Why was this functionality removed?ESP_Sprite wrote: ↑Mon Jun 05, 2023 2:25 pmIf you want to set up the uart parameters, you're probably better off using the HALlayer. (Note that it says use in applications is unsupported, but I'd say your setup of relying on a driver uninstall to keep the settings intact is more unsupported-er.)
I see no reason why I should have to use an unsupported API module in order to do something as standard as configuring a UART interrupt.
-
- Posts: 9727
- Joined: Thu Nov 26, 2015 4:08 am
Re: Freeing default UART ISR in ESP-IDF v5.2
You are right, it doesn't answer the question. Her'e's why an answer is hard.johnab wrote: ↑Mon Jun 05, 2023 2:34 pmIt feels like this doesn't answer my original question. After a driver install specifying the UART operating parameters, is there no longer a way to use a custom interrupt? Should I convert back to a previous version of ESP-IDF where this was still possible? Why was this functionality removed?
I see no reason why I should have to use an unsupported API module in order to do something as standard as configuring a UART interrupt.
The issue is that the previous API had two functionalities that clashed: one is to act as a high-level driver, the other one is to act as a low-level driver. Installing a driver handle is a high-level operation, installing an interrupt is a low-level one. It was kinda-sorta implicit that you shouldn't use the two combined, and having to do things like relying on a partial driver uninstal to keep the uart parameters untouched is really relying on undefined, unspecified behaviour, but that happens to be the only sane way you can do things in the old system.
If you think that is a shitty architecture, we agreed, so we split it into an actual driver (that doesn't allow you to mess with the internally-used interrupt anymore), and the HAL that allows you to do the low-level peripheral poking. Unfortunately, with HAL layers, we do not have the same guarantees wrt semantic versioning as with the rest of ESP-IDF (which is that the API only changes on major revisions, e.g. 4.x.y -> 5.x.y, not 5.a.b -> 5.x.y), hence the 'unsupported' warning. I personally disagree with marking it entirely unsupported because of that and I know in practice the HAL layer is pretty solid, but that's how it is now.
Re: Freeing default UART ISR in ESP-IDF v5.2
I am shocked at the step backwards that is required with IDF-v5.x.x using Uart Interrupts. My application requires very specific timing between received characters and transmitted characters. There is no way that your standard interrupt driver can fill that need. To remove completely the functionality in V4.3 and say use HAL and it is unsupported, is ridiculous for such an otherwise great platform that IDF is. At a minimum, an example of how to do it would have given some hope. I started my programming with Atmel and Microchip devices using assembly language and can do magic with interrupts and basic registers. So I am at an advantage over many other users. Still it feels like half the 'shitty architecture' that worked was thrown away without regards for the days of work required for someone to invent a new 'unsupported' way of doing things when our code worked flawlessly before.ESP_Sprite wrote: ↑Tue Jun 06, 2023 2:07 pmYou are right, it doesn't answer the question. Her'e's why an answer is hard.johnab wrote: ↑Mon Jun 05, 2023 2:34 pmIt feels like this doesn't answer my original question. After a driver install specifying the UART operating parameters, is there no longer a way to use a custom interrupt? Should I convert back to a previous version of ESP-IDF where this was still possible? Why was this functionality removed?
I see no reason why I should have to use an unsupported API module in order to do something as standard as configuring a UART interrupt.
The issue is that the previous API had two functionalities that clashed: one is to act as a high-level driver, the other one is to act as a low-level driver. Installing a driver handle is a high-level operation, installing an interrupt is a low-level one. It was kinda-sorta implicit that you shouldn't use the two combined, and having to do things like relying on a partial driver uninstal to keep the uart parameters untouched is really relying on undefined, unspecified behaviour, but that happens to be the only sane way you can do things in the old system.
If you think that is a shitty architecture, we agreed, so we split it into an actual driver (that doesn't allow you to mess with the internally-used interrupt anymore), and the HAL that allows you to do the low-level peripheral poking. Unfortunately, with HAL layers, we do not have the same guarantees wrt semantic versioning as with the rest of ESP-IDF (which is that the API only changes on major revisions, e.g. 4.x.y -> 5.x.y, not 5.a.b -> 5.x.y), hence the 'unsupported' warning. I personally disagree with marking it entirely unsupported because of that and I know in practice the HAL layer is pretty solid, but that's how it is now.
Re: Freeing default UART ISR in ESP-IDF v5.2
Here is what I came up with when using IDF v5.2
For conversion from IDF V4 to V5 drop the 'install driver' and uart_isr_free/register commands. Keep the uart_param_config functions and use esp_intr_alloc to hook the interrupt.
Something like this:
For conversion from IDF V4 to V5 drop the 'install driver' and uart_isr_free/register commands. Keep the uart_param_config functions and use esp_intr_alloc to hook the interrupt.
Something like this:
Code: Select all
#include "hal/uart_ll.h"
#include "soc/interrupts.h"
static void IRAM_ATTR my_uart_isr( void *arg )
{
if( UART1.int_st.txfifo_empty_int_st ) {
// build reply
uart_ll_write_txfifo(&UART1, "sendstr",7 );
uart_clear_intr_status(UART_NUM_1, UART_TXFIFO_EMPTY_INT_CLR);
return;
}
if( UART1.int_st.parity_err_int_st ) {
uart_clear_intr_status(UART_NUM_1, UART_PARITY_ERR_INT_CLR);
return;
// handle other interrupt sources and clear them.
if( UART1.status.rxfifo_cnt ) {
// read bytes from UART1.fifo.rxfifo_rd_byte until UART1.status.rxfifo_cnt == 0
uart_clear_intr_status(UART_NUM_1, UART_RXFIFO_FULL_INT_CLR);
}
}
const uart_config_t uart_config = {
.baud_rate = 9600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_EVEN,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DIABLE,
.source_clk = UART_SCLK_APB,
};
uart_isr_handle_t isr_handle;
ESP_ERROR_CHECK(uart_param_config(UART_NUM_1, &uart_config ));
ESP_ERROR_CHECK(uart_set_pin(UART_NUM_1, 17, 18, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
ESP_ERROR_CHECK(uart_set_line_inverse(UART_NUM_1,UART_SIGNAL_TXD_INV));
ESP_ERROR_CHECK(esp_intr_alloc(ETS_UART1_INTR_SOURCE, (void *)NULL, my_uart_isr, NULL, &isr_handle,));
uart_intr_config_t uintr_cfg = {
.rxfifo_full_thresh = 1,
.intr_enable_mask = (UART_RXFIFO_FULL_INT_ENA_M)
};
uintr_cfg.txfifo_empty_intr_thresh = 1;
uintr_cfg.intr_enable_mask = (UART_RXFIFO_FULL_INT_ENA_M | UART_TXFIFO_EMPTY_INT_ENA_M);
ESP_ERROR_CHECK(uart_intr_config(UART_NUM_1,&uintr_cfg));
uart_intr_config_t intr_config = {
.intr_enable_mask = UART_TX_DONE_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M,
};