High Level Interrupt on external GPIO Interrupt

opcode_x64
Posts: 13
Joined: Sun Jan 13, 2019 5:39 pm

High Level Interrupt on external GPIO Interrupt

Postby opcode_x64 » Sun Jan 13, 2019 6:07 pm

Hello everybody,

currently I'm trying to assign a High Level Interrupt (ESP-IDF) to a GPIO Interrupt (positive edge). For this I read the information on https://docs.espressif.com/projects/esp ... rupts.html first.

My main question: How can I assign the external GPIO interrupt e.g. to GPIO PIN 4 to the high level interrupt in assembler ?

I have performed the following steps:

Step 1:
A file with the extension .S created: "my_hint.S" with the following content:

Code: Select all

#Include <xtensa/coreasm.h>
#include <xtensa/corebits.h>
#include <xtensa/config/system.h>
#include "freertos/xtensa_context.h"
#include "esp_panic.h"
#include "sdkconfig.h"
#include "soc/soc.h"
#include "soc/dport_reg.h"

.section .iram1, "ax"
 .global xt_highint5
 .type xt_highint5,@function
 .align 4
xt_highint5:
jx a1 %This intentionally generates a crash to see if the interrupt handler is running.
;nop
rsr a0, EXCSAVE_5
rfi 5

.global ld_include_highint_hdl
ld_include_highint_hdl:
Step 2:
In the components.mk file under COMPONENT_ADD_LDFLAGS I added the assembler file via the symbol "ld_include_highint_hdl". When compiling the program the assembler file is linked and compiled.

Step 3:
My main.c looks like this:

Code: Select all

const gpio_num_t gpio_intr_pin = GPIO_NUM_4;

void app_main(){

gpio_config_t gpio_intr={
    .intr_type=GPIO_INTR_POSEDGE,
    .pin_bit_mask=(1ULL<<<gpio_intr_pin),
    .mode=GPIO_MODE_INPUT,
    .pull_up_en=GPIO_PULLUP_DISABLE,
    .pull_down_en=GPIO_PULLDOWN_DISABLE,
  };
  ESP_ERROR_CHECK(gpio_config(&gpio_intr));

gpio_install_isr_service(ESP_INTR_FLAG_HIGH);

intr_matrix_set(0, ETS_GPIO_INTR_SOURCE, gpio_intr_pin);

esp_intr_alloc(ETS_GPIO_INTR_SOURCE,(int)ESP_INTR_FLAG_HIGH,NULL,NULL,&gpio_intr_handle);

ESP_INTR_ENABLE(gpio_intr_pin);
}
Unfortunately my "assembler" interrupt handler is never executed. What am I doing wrong?

Thanks a lot !

Best regards,
opcode_x64




Translated with www.DeepL.com/Translator

opcode_x64
Posts: 13
Joined: Sun Jan 13, 2019 5:39 pm

Re: High Level Interrupt on external GPIO Interrupt

Postby opcode_x64 » Mon Jan 14, 2019 6:39 pm

No one any idea ? ;-(

WiFive
Posts: 2375
Joined: Tue Dec 01, 2015 7:35 am

Re: High Level Interrupt on external GPIO Interrupt

Postby WiFive » Tue Jan 15, 2019 3:26 am

Are you sure ESP_INTR_FLAG_HIGH returns a level 5 interrupt since it matches more than one level?

opcode_x64
Posts: 13
Joined: Sun Jan 13, 2019 5:39 pm

Re: High Level Interrupt on external GPIO Interrupt

Postby opcode_x64 » Tue Jan 15, 2019 11:25 am

Hello WiFive!,

thank you for your reply. I just tried ESP_INTR_FLAG_LEVEL5, but the Serial Monitor (I am working with platformIO in ATOM) floods the console with the following message: "Unhandled interrupt 8 on CPU0"

ESP_Sprite
Posts: 2659
Joined: Thu Nov 26, 2015 4:08 am

Re: High Level Interrupt on external GPIO Interrupt

Postby ESP_Sprite » Wed Jan 16, 2019 8:39 am

So, I think your original code is not doing what you think it does... For one, you have to remember that in hardware, all GPIOs that are enabled for an interrupt will trigger the same interrupt. When you call gpio_install_isr_service, the GPIO driver will install an ISR for that interrupt that will then figure out what pin triggered the interrupt and call the associated callback function.

When you want a high-level interrupt, you cannot use this function, as the GPIO driver function is written in C and high-level interrupts need to be in assembler. So gpio_install_isr_service should not be called.

Furthermore, you call intr_matrix_set, but with the pin number as the second argument. From memory, this should be the interrupt number. Same goes for ESP_INTR_ENABLE later on. Also, calls to those functions are unneeded if you use the intr_alloc function below that.

Suggest you try fixing up this first, see if it makes a difference.

opcode_x64
Posts: 13
Joined: Sun Jan 13, 2019 5:39 pm

Re: High Level Interrupt on external GPIO Interrupt

Postby opcode_x64 » Wed Jan 16, 2019 11:34 am

Hello ESP_Sprite,

thank you very much for your help. Now I have some questions:

1.)
I have put my "interrupt handler code to be executed" in the assembly (.S) file, for example:
Is this correct ?

Code: Select all

.section .iram1,"ax"
    .global     xt_highint5
    .type       xt_highint5,@function
    .align      4
xt_highint5:
    *** HERE IS MY CODE IN ASSEMBLER (XTENSA), FOR EXAMPLE, SETTING A PIN HIGH
    rsr     a0, EXCSAVE_5
    rfi     5
2.) Because I am using a High Level Interrupt which only supports assembly interrupt handler codes, I cannot / should not use:

Code: Select all

gpio_install_isr_service(....);
Correct ?

3.) Because I am using the esp_intr_alloc() function, I dont need to call:

Code: Select all

intr_matrix_set(....);
ESP_INTR_ENABLE(....);
Correct ?
4.) When I use the esp_intr_alloc() function, I have to pass NULL for the ISR_Handler and ARG arguments, when using High Level Interrupts. An interrupt handle (handle!!) is optional ? Do I have to return a handle to start the interrupt via the handle with the esp_intr_enable(....); function ?

5.) Last question: What should I use for the interrupt flag for the esp_intr_alloc() function?
ESP_INTR_FLAG_HIGH or ESP_INTR_FLAG_LEVEL5 ?
As far as I know, the ESP_INTR_FLAG_HIGH is a ORed combination of the other "HIGH" Level Flags (4 to....)

Thank you very much !

Best regards,
opcode_x64

opcode_x64
Posts: 13
Joined: Sun Jan 13, 2019 5:39 pm

Re: High Level Interrupt on external GPIO Interrupt

Postby opcode_x64 » Sun Jan 20, 2019 10:39 pm

@ESP_Sprite,

I tried the "esp_intr_alloc(...)" function following with "esp_intr_enable(...)" function like this:

Code: Select all

  
esp_intr_alloc(ETS_GPIO_INTR_SOURCE,ESP_INTR_FLAG_LEVEL5,NULL,NULL,&gpio_intr_handle);
esp_intr_enable(gpio_intr_handle);
with no success, but when I using the intr_matrix_set(...) function, then my high level interrupt is raising !! I used the following code:

Code: Select all

  
  int intr_number = 31; //(got the 31 from the Tech Manual from the ESP32, Section: Interrupts)
  ESP_INTR_DISABLE(intr_number);
  intr_matrix_set(xPortGetCoreID(),ETS_GPIO_INTR_SOURCE, intr_number);
  ESP_INTR_ENABLE(intr_number);
To see if the high level interrupt is raising I am setting the GPIO PIN15 on high level in the interrupt handler which is working (checked on my DSO!). My interrupt handler in assembly is looking like this.

Code: Select all

.section .iram1,"ax"
 .global     xt_highint5
 .type       xt_highint5,@function
 .align      4
 .literal .GPIO_OUT_W1TS_REG, 0x3FF44008
 .literal .GPIO_OUT_W1TC_REG, 0x3FF4400C
 .literal .GPIO__NUM_15, (1<<15)
xt_highint5:
l32r a14, .GPIO_OUT_W1TS_REG
l32r a15, .GPIO__NUM_15
s32i a15, a14, 0
rsr     a0, EXCSAVE_5
rfi     5
But now I have the problem that after raising the interrupt and setting the GPIO PIN15 high the esp32 is crashing... I just checked out via the last PC where the esp32 is crashing. Checking the PC in the disassembled firmware.elf it is in the <esp_vApplicationIdleHook> section.

Do you have any Idea ?

Thank you !

Best regards,
opcode_x64

ESP_Sprite
Posts: 2659
Joined: Thu Nov 26, 2015 4:08 am

Re: High Level Interrupt on external GPIO Interrupt

Postby ESP_Sprite » Tue Jan 22, 2019 1:57 am

Strange, esp_intr_alloc should work for allocating high-level interrupts as well, to my knowledge.

The reason that your ESP32 crashes may be because you use a level interrupt and you don't acknowledge your interrupt. Specifically, in this case, you need to write (1<<15) to the status_w1tc GPIO register, to acknowledge the interrupt that happens on GPIO 15. If you don't do this, the interrupt will keep triggering, and the ESP32 will re-enter the interrupt routine as soon as it has exited it.

opcode_x64
Posts: 13
Joined: Sun Jan 13, 2019 5:39 pm

Re: High Level Interrupt on external GPIO Interrupt

Postby opcode_x64 » Tue Jan 22, 2019 2:43 am

Hello ESP_Sprite !

Thank you for your quick reply. I just changed my "assembler" Interrupt Handler to:

Code: Select all

.section .iram1,"ax"
 .global     xt_highint5
 .type       xt_highint5,@function
 .align      4
 .literal .GPIO_STATUS_W1TC_REG, 0x3FF4404C
 .literal .GPIO_OUT_W1TS_REG, 0x3FF44008
 .literal .GPIO_OUT_W1TC_REG, 0x3FF4400C
 .literal .GPIO__NUM_15, (1<<15)
 .literal .GPIO__NUM_4,  (1<<4)
xt_highint5:
l32r a14, .GPIO_OUT_W1TS_REG
l32r a15, .GPIO__NUM_15
s32i a15, a14, 0

l32r a14, .GPIO_STATUS_W1TC_REG
l32r a14, .GPIO__NUM_4
s32i a15, a14, 0

rsr     a0, EXCSAVE_5
rfi     5
Note: I have to clear the GPIO_NUM_4 in the status_w1tc_reg not in GPIO_NUM_15, because my Interrupt is configured on GPIO_NUM_4 and the "toggle test pin" is GPIO_NUM_15. But at least the GPIO_NUM_15 Pin stays on "High". This means, that the interrupt handler is executing correctly.

But now the esp crashes due to "Core 0 panic'ed" (Unhandled debug exception). Like in the documentation explained, the codes for allocating the interrupt are executed in a separate task which is pinned to a specific core (ID):

Code: Select all

void allocateGPIOInterrupt(void* arg){
  ESP_INTR_DISABLE(intr_number);
  intr_matrix_set(0,ETS_GPIO_INTR_SOURCE, intr_number);
  ESP_INTR_ENABLE(intr_number);

  /* This is not working for me....
  esp_intr_alloc(ETS_GPIO_INTR_SOURCE,ESP_INTR_FLAG_LEVEL5,NULL,NULL,&gpio_intr_handle);
  esp_intr_enable(gpio_intr_handle);
  */

  ets_printf("allocateGPIOInterrupt launched!\n");
  while(1){
      vTaskDelay(1);
  }
}

Code: Select all

void app_main()
{
......
.....
  xTaskCreatePinnedToCore(allocateGPIOInterrupt,"allocEXTGPIOINT",4096,NULL,0,NULL,0);
...
while(1){
 vTaskDelay(1);
   }
}
Thank you for your help ESP_Sprite.

Best regards,
opcode_x64

ESP_Sprite
Posts: 2659
Joined: Thu Nov 26, 2015 4:08 am

Re: High Level Interrupt on external GPIO Interrupt

Postby ESP_Sprite » Tue Jan 22, 2019 9:51 am

Code: Select all

l32r a14, .GPIO_STATUS_W1TC_REG
l32r a14, .GPIO__NUM_4 //<-- don't you mean a15?
s32i a15, a14, 0

Who is online

Users browsing this forum: aldecei and 26 guests