GPIO Interrupt from a class file

chukitoes
Posts: 10
Joined: Mon Jan 17, 2022 5:50 pm

GPIO Interrupt from a class file

Postby chukitoes » Wed Feb 02, 2022 7:56 pm

I want to use GPIO Interrupts from a .cpp class file and so far, everything I've tested isn't working properly.

Checking the return from the gpio_isr_handler_add function, it's always 0 (ESP_OK).

I've tried:
static function outside the class;
static method inside the class;

Here's the minimum working project if you want to test it out.
rotary_encoder_help.zip
(19.08 KiB) Downloaded 415 times
  1. #include "esp_event.h"
  2. #include "driver/gpio.h"
  3.  
  4. #include "RotaryEncoder.hpp"
  5.  
  6. #define ESP_INTR_FLAG_DEFAULT 0
  7.  
  8. uint32_t cnt;
  9.  
  10. static void IRAM_ATTR main_isr_handler(void* arg)
  11. {
  12.     cnt++;
  13. }
  14.  
  15. extern "C" void app_main(void)
  16. {
  17.     encoder_t encoder;
  18.  
  19.     encoder_config_t conf;
  20.  
  21.     conf.enc1_pin = GPIO_NUM_34;
  22.     conf.enc2_pin = GPIO_NUM_35;
  23.  
  24.     /* Interrupt = 0 -> Interrupt in Main
  25.      * Interrupt = 1 -> Interrupt Inside Class
  26.      * Interrupt = 2 -> Interrupt Outside Class
  27.      */
  28.     conf.interrupt = 0;
  29.  
  30.     if(conf.interrupt == 0) {
  31.  
  32.         gpio_config_t gpio_conf;
  33.  
  34.         gpio_conf.intr_type = GPIO_INTR_ANYEDGE;
  35.         gpio_conf.mode = GPIO_MODE_INPUT;
  36.         gpio_conf.pin_bit_mask = 1ULL<<conf.enc1_pin | 1ULL<<conf.enc2_pin;
  37.         gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
  38.         gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
  39.  
  40.         gpio_config(&gpio_conf);
  41.  
  42.         printf("----Install ISR Service %x----\n",
  43.                 gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT));
  44.  
  45.         printf("----Install Main ISR Handler 1: %x----\n",
  46.             gpio_isr_handler_add(GPIO_NUM_34, main_isr_handler, (void*) 34));
  47.         printf("----Install Main ISR Handler 1: %x----\n",
  48.             gpio_isr_handler_add(GPIO_NUM_35, main_isr_handler, (void*) 35));
  49.     }
  50.     else {
  51.  
  52.         encoder.encoder_init(&conf);
  53.     }
  54.  
  55.     gpio_set_direction(GPIO_NUM_32, GPIO_MODE_OUTPUT);
  56.     gpio_set_direction(GPIO_NUM_33, GPIO_MODE_OUTPUT);
  57.     int level = 0;
  58.  
  59.     while (true) {
  60.         gpio_set_level(GPIO_NUM_32, level);
  61.         gpio_set_level(GPIO_NUM_33, !level);
  62.         level = !level;
  63.         printf("Counter Main: %d\t\tCounter Class: %d\n", cnt, enc_cnt);
  64.         vTaskDelay(500 / portTICK_PERIOD_MS);
  65.     }
  66. }
  1. /*
  2.  * RotaryEncoder.hpp
  3.  *
  4.  *  Created on: 30 de jan. de 2022
  5.  *      Author: igor_
  6.  */
  7.  
  8. #ifndef _ROTARYENCODER_HPP_
  9. #define _ROTARYENCODER_HPP_
  10.  
  11. #include "driver/gpio.h"
  12.  
  13. static uint32_t enc_cnt;
  14.  
  15. /* ^^^^^^^^^^^^^
  16.  * RotaryEncoder
  17.  * ^^^^^^^^^^^^^ */
  18. namespace RotaryEncoder {
  19. class encoder;
  20. } /* namespace RotaryEncoder */
  21.  
  22. // TB6612FNG type
  23. using encoder_t = RotaryEncoder::encoder;
  24.  
  25. typedef struct {
  26.     gpio_num_t enc1_pin;
  27.     gpio_num_t enc2_pin;
  28.     int interrupt;
  29. } encoder_config_t;
  30.  
  31. typedef struct {
  32.     gpio_num_t gpio_num;
  33.     encoder_t* encoder_ptr;
  34. } encoder_isr_config_t;
  35.  
  36. namespace RotaryEncoder {
  37.  
  38. class encoder {
  39.  
  40. public:
  41.     static void inside_class_isr_handler(void* arg);
  42.  
  43.     gpio_num_t
  44.         enc1_pin,
  45.         enc2_pin;
  46.  
  47.     void encoder_init(encoder_config_t *enc_conf);
  48.  
  49. }; /* Class encoder */
  50. } /* Namespace RotaryEncoder */
  51.  
  52. #endif /* ROTARYENCODER_SRC_ROTARYENCODER_HPP_ */
  1. /*
  2.  * RotaryEncoder.cpp
  3.  *
  4.  *  Created on: 30 de jan. de 2022
  5.  *      Author: igor_
  6.  */
  7.  
  8. #include "RotaryEncoder.hpp"
  9.  
  10. #include "esp_timer.h"
  11. #include "driver/gpio.h"
  12.  
  13. #define ESP_INTR_FLAG_DEFAULT 0
  14.  
  15. static void outside_class_isr_handler(void* arg) {
  16.     enc_cnt++;
  17. }
  18.  
  19. namespace RotaryEncoder{
  20.  
  21. void encoder::inside_class_isr_handler(void* arg) {
  22.     enc_cnt++;
  23. }
  24.  
  25. void encoder::encoder_init(encoder_config_t *enc_conf) {
  26.  
  27.     printf("Printing Encoder Configs:\n"
  28.             "\tEnc1: %d\n"
  29.             "\tEnc2: %d\n"
  30.             "\tPtr: %p\n", enc_conf->enc1_pin, enc_conf->enc2_pin, this);
  31.  
  32.     this->enc1_pin = enc_conf->enc1_pin;
  33.     this->enc2_pin = enc_conf->enc2_pin;
  34.  
  35.     // GPIO configuration structure
  36.     gpio_config_t gpio_conf;
  37.  
  38.     gpio_conf.intr_type = GPIO_INTR_ANYEDGE;
  39.     gpio_conf.mode = GPIO_MODE_INPUT;
  40.     gpio_conf.pin_bit_mask = 1ULL<<this->enc1_pin | 1ULL<<this->enc2_pin;
  41.     gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
  42.     gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
  43.  
  44.     // Configures the GPIOs
  45.     gpio_config(&gpio_conf);
  46.  
  47.     //install gpio isr service
  48.     printf("----Install ISR Service %x----\n",
  49.             gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT));
  50.  
  51.     encoder_isr_config_t isr_args;
  52.     isr_args.encoder_ptr = this;
  53.  
  54.     //hook isr handler for specific gpio pin
  55.     if (enc_conf->interrupt == 1) {
  56.  
  57.         isr_args.gpio_num = enc_conf->enc1_pin;
  58.         printf("----Install Inside ISR Handler 1: %x----\n",
  59.                 gpio_isr_handler_add(this->enc1_pin, this->inside_class_isr_handler, (void*) &isr_args));
  60.  
  61.         isr_args.gpio_num = enc_conf->enc2_pin;
  62.         printf("----Install Inside ISR Handler 2: %x----\n",
  63.                 gpio_isr_handler_add(this->enc2_pin, this->inside_class_isr_handler, (void*) &isr_args));
  64.     }
  65.     else if (enc_conf->interrupt == 2){
  66.  
  67.         isr_args.gpio_num = enc_conf->enc1_pin;
  68.         printf("----Install Outside ISR Handler 1: %x----\n",
  69.                 gpio_isr_handler_add(this->enc1_pin, outside_class_isr_handler, (void*) &isr_args));
  70.  
  71.         isr_args.gpio_num = enc_conf->enc2_pin;
  72.         printf("----Install Outside ISR Handler 2: %x----\n",
  73.                 gpio_isr_handler_add(this->enc2_pin, outside_class_isr_handler, (void*) &isr_args));
  74.     }
  75. }
  76. }
So my question is, am I doing something wrong in the code or is it impossible to use interrupts inside a class file?

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

Re: GPIO Interrupt from a class file

Postby ESP_Sprite » Thu Feb 03, 2022 5:18 am

Define 'isn't working properly', what specifically does not work? (Also note that the ESP32 has a pulse counter that is pretty capable of handling rotary encoders without much software help as well; you might want to keep that in mind for further development.)

chukitoes
Posts: 10
Joined: Mon Jan 17, 2022 5:50 pm

Re: GPIO Interrupt from a class file

Postby chukitoes » Thu Feb 03, 2022 6:45 pm

Thanks for your reply. I forgot to specify this, my bad.

By "isn't working properly" I mean that the interrupts aren't being activated when there's a state change in the GPIO pins, but only when the function gpio_isr_handler_add is called inside the class file.

When called from the main, it works as expected.

For example, when calling from the main, the 'cnt' counter goes up as it should, but when calling from the class the 'enc_cnt' doesn't.

P.S. I'll keep in mind and research more about the PCNT lib, thanks for the suggestion.

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

Re: GPIO Interrupt from a class file

Postby ESP_Sprite » Fri Feb 04, 2022 4:51 am

My C++ chops aren't what they used to be, but does this->inside_class_isr_handler function for a static class function? I'd personally put RotatryEncoder::inside_class_isr_handler there.

chukitoes
Posts: 10
Joined: Mon Jan 17, 2022 5:50 pm

Re: GPIO Interrupt from a class file

Postby chukitoes » Fri Feb 04, 2022 3:56 pm

I've tested it, and it also doesn't seem to work.

Printing the pointer value for both this->inside_class_isr_handler and RotaryEncoder::encoder::inside_class_isr_handler brings out the same value, so it seems like they're the same.

liebman
Posts: 18
Joined: Wed Dec 09, 2020 7:03 pm

Re: GPIO Interrupt from a class file

Postby liebman » Fri Feb 04, 2022 6:50 pm

In `encoder_init`. You have `encoder_isr_config_t isr_args;`. thats on the stack and is no longer valid after the function returns. You need to declare that as static. You also need one for each interrupt, you're overwriting the first when you setup the second.

chukitoes
Posts: 10
Joined: Mon Jan 17, 2022 5:50 pm

Re: GPIO Interrupt from a class file

Postby chukitoes » Sun Feb 06, 2022 2:44 am

liebman wrote:
Fri Feb 04, 2022 6:50 pm
In `encoder_init`. You have `encoder_isr_config_t isr_args;`. thats on the stack and is no longer valid after the function returns. You need to declare that as static. You also need one for each interrupt, you're overwriting the first when you setup the second.
You're right, thank you!

Sadly, it doesn't solve the interrupt problem. Maybe if the interrupt was working, it would've caused problems with my logic inside the interrupt, but since it isn't being triggered, it didn't and so, I didn't notice.

I've also tried passing a constant and not passing anything at all, so that doesn't seem to be the cause of this issue.

Aside from that, I've tested initializing the interrupt from a C file, included both in a CPP and a C main, with no success as well.
  1. #include "esp_event.h"
  2. #include "driver/gpio.h"
  3.  
  4. #include "ANSI_ENCODER.h"
  5.  
  6. uint32_t cnt;
  7.  
  8. void app_main(void)
  9. {
  10.  
  11.     gpio_num_t pin1, pin2;
  12.     pin1 = GPIO_NUM_34;
  13.     pin2 = GPIO_NUM_35;
  14.  
  15.     int interrupt = 1;
  16.  
  17.     if(interrupt == 0) {
  18.         encoder_C_init(pin1, pin2);
  19.     }
  20.     else {
  21.         gpio_config_t gpio_conf;
  22.  
  23.         gpio_conf.intr_type = GPIO_INTR_ANYEDGE;
  24.         gpio_conf.mode = GPIO_MODE_INPUT;
  25.         gpio_conf.pin_bit_mask = 1ULL<<34 | 1ULL<<35;
  26.         gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
  27.         gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
  28.  
  29.         // Configures the GPIOs
  30.         gpio_config(&gpio_conf);
  31.  
  32.         printf("----Install ISR Service %x----\n",
  33.                 gpio_install_isr_service(0));
  34.  
  35.         printf("----Install C Main ISR Handler 1: %x----\n",
  36.             gpio_isr_handler_add(pin1, C_isr_handler, (void*) NULL));
  37.         printf("----Install C Main ISR Handler 1: %x----\n",
  38.             gpio_isr_handler_add(pin2, C_isr_handler, (void*) NULL));
  39.     }
  40.     while (true) {
  41.         printf("CNT C: %d\n", C_cnt);
  42.         vTaskDelay(1000 / portTICK_PERIOD_MS);
  43.     }
  44. }
  1. /*
  2.  * ANSI_Encoder.h
  3.  *
  4.  *  Created on: 5 de fev. de 2022
  5.  *      Author: igor_
  6.  */
  7.  
  8. #ifndef _ANSI_ENCODER_H_
  9. #define _ANSI_ENCODER_H_
  10.  
  11. #ifdef __cplusplus
  12. extern "C" {
  13. #endif
  14.  
  15. uint32_t C_cnt;
  16.  
  17. void C_isr_handler(void* arg);
  18.  
  19. void encoder_C_init(gpio_num_t pin1, gpio_num_t pin2);
  20.  
  21. #ifdef __cplusplus
  22. }
  23. #endif
  24. #endif /* _ANSI_ENCODER_H_ */
  1. /*
  2.  * ANSI_Encoder.c
  3.  *
  4.  *  Created on: 5 de fev. de 2022
  5.  *      Author: igor_
  6.  */
  7.  
  8. #include "driver/gpio.h"
  9. #include "ANSI_Encoder.h"
  10.  
  11. #ifdef __cplusplus
  12. extern "C" {
  13. #endif
  14.  
  15. uint32_t C_cnt;
  16.  
  17. void C_isr_handler(void* arg) {
  18.     C_cnt++;
  19. }
  20.  
  21. void encoder_C_init(gpio_num_t pin1, gpio_num_t pin2) {
  22.     // GPIO configuration structure
  23.         gpio_config_t gpio_conf;
  24.  
  25.         gpio_conf.intr_type = GPIO_INTR_ANYEDGE;
  26.         gpio_conf.mode = GPIO_MODE_INPUT;
  27.         gpio_conf.pin_bit_mask = 1ULL<<34 | 1ULL<<35;
  28.         gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
  29.         gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
  30.  
  31.         // Configures the GPIOs
  32.         gpio_config(&gpio_conf);
  33.  
  34.         printf("----Install ISR Service %x----\n",
  35.                 gpio_install_isr_service(0));
  36.  
  37.         printf("----Install C ISR Handler 1: %x----\n",
  38.             gpio_isr_handler_add(pin1, C_isr_handler, (void*) NULL));
  39.         printf("----Install C ISR Handler 1: %x----\n",
  40.             gpio_isr_handler_add(pin2, C_isr_handler, (void*) NULL));
  41. }
  42.  
  43. #ifdef __cplusplus
  44. }
  45. #endif

boarchuz
Posts: 606
Joined: Tue Aug 21, 2018 5:28 am

Re: GPIO Interrupt from a class file

Postby boarchuz » Sun Feb 06, 2022 5:50 am

chukitoes wrote:
Sun Feb 06, 2022 2:44 am

ANSI_Encoder.h:
  1. uint32_t C_cnt;
rotary_encoder_example_main.c:
  1. #include "ANSI_ENCODER.h"
  2.  
  3. printf("CNT C: %d\n", C_cnt);
ANSI_Encoder.c:
  1. uint32_t C_cnt;
  2. C_cnt++;

By including ANSI_ENCODER.h in your main.c, you declare a C_cnt in that translation unit. This is not the same memory as the C_cnt in the ANSI_Encoder.c translation unit.

main.c doesn't know about the other C_cnt in ANSI_Encoder.c, it just prints its own C_cnt which is never updated (ie. always 0).

The interrupt handler is probably working fine, but it would be incrementing the C_cnt in ANSI_Encoder.c instead.

It's analogous to this:

rotary_encoder_example_main.c:
  1. uint32_t main_C_cnt; // always 0
  2. printf("CNT C: %d\n", main_C_cnt);
ANSI_Encoder.c:
  1. uint32_t encoder_C_cnt;
  2. encoder_C_cnt++; // incrementing away...

You could change

Code: Select all

uint32_t C_cnt;
->

Code: Select all

extern uint32_t C_cnt;
in ANSI_Encoder.h so the linker knows to go looking for it somewhere else for main.c.

chukitoes
Posts: 10
Joined: Mon Jan 17, 2022 5:50 pm

Re: GPIO Interrupt from a class file

Postby chukitoes » Sun Feb 06, 2022 6:31 pm

boarchuz wrote:
Sun Feb 06, 2022 5:50 am
By including ANSI_ENCODER.h in your main.c, you declare a C_cnt in that translation unit. This is not the same memory as the C_cnt in the ANSI_Encoder.c translation unit.

main.c doesn't know about the other C_cnt in ANSI_Encoder.c, it just prints its own C_cnt which is never updated (ie. always 0).

The interrupt handler is probably working fine, but it would be incrementing the C_cnt in ANSI_Encoder.c instead.

It's analogous to this:

rotary_encoder_example_main.c:
  1. uint32_t main_C_cnt; // always 0
  2. printf("CNT C: %d\n", main_C_cnt);
ANSI_Encoder.c:
  1. uint32_t encoder_C_cnt;
  2. encoder_C_cnt++; // incrementing away...

You could change

Code: Select all

uint32_t C_cnt;
->

Code: Select all

extern uint32_t C_cnt;
in ANSI_Encoder.h so the linker knows to go looking for it somewhere else for main.c.
Thank you for your reply!

But, it actually does work. Before posting that comment, I tested by initializing the C_cnt variable with a starting value, and it got picked up by the main.c.

Since my last post, I updated my esp-idf version to the v4.4 that just launched (I was using the v4.1-dirty) because I read in the release notes that there was a fix on the GPIO Driver "GPIO: Fixed a typo on register struct that results in interrupt cannot be triggered on ESP32 core 1" and it actually fixed the interrupt problem while using a C component file in both C and CPP mains, but not when creating an interrupt from a CPP file.

Maybe there's another issue in the GPIO driver that is preventing it from triggering normally when using a CPP file.

liebman
Posts: 18
Joined: Wed Dec 09, 2020 7:03 pm

Re: GPIO Interrupt from a class file

Postby liebman » Sun Feb 06, 2022 8:47 pm

This works for me, I've used this pattern many times: (this is a 1hz signal from a DS3231 RTC, ignore the "timer" bits, I use that on a test board that does not have the RTC installed)
  1. /*
  2.  * MIT License
  3.  *
  4.  * Copyright (c) 2022 Christopher B. Liebman
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  7.  * of this software and associated documentation files (the "Software"), to deal
  8.  * in the Software without restriction, including without limitation the rights
  9.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10.  * copies of the Software, and to permit persons to whom the Software is
  11.  * furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included in all
  14.  * copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22.  * SOFTWARE.
  23. */
  24.  
  25. #pragma once
  26. #include "freertos/FreeRTOS.h"
  27. #include "freertos/task.h"
  28. #include "driver/gpio.h"
  29. #include "esp_timer.h"
  30. #include <functional>
  31. #include <vector>
  32.  
  33. class PPS
  34. {
  35.     public:
  36.         PPS(gpio_num_t pin1hz);
  37.         ~PPS();
  38.         bool begin(bool use_timer);
  39.         uint32_t getUptime();
  40.         void notifyEachSecond(TaskHandle_t task);
  41.  
  42.     private:
  43.         volatile uint32_t           _uptime;
  44.         gpio_num_t                  _pin;
  45.         std::vector<TaskHandle_t>   _notify_list;
  46.         esp_timer_handle_t          _timer;
  47.  
  48.         void initPin();
  49.         void initTimer();
  50.         static void isr(void* data);
  51.         static void timerCB(void* data);
  52. };
  1. /*
  2.  * MIT License
  3.  *
  4.  * Copyright (c) 2022 Christopher B. Liebman
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  7.  * of this software and associated documentation files (the "Software"), to deal
  8.  * in the Software without restriction, including without limitation the rights
  9.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10.  * copies of the Software, and to permit persons to whom the Software is
  11.  * furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included in all
  14.  * copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22.  * SOFTWARE.
  23. */
  24.  
  25. #include "PPS.h"
  26. #include "esp_log.h"
  27. #include "driver/timer.h"
  28.  
  29. static const char* TAG = "PPS";
  30.  
  31. PPS::PPS(gpio_num_t pin1hz)
  32. : _uptime(0),
  33.   _pin(pin1hz),
  34.   _timer(nullptr)
  35. {
  36. }
  37.  
  38. PPS::~PPS()
  39. {
  40.     if (_timer)
  41.     {
  42.         ESP_ERROR_CHECK(esp_timer_delete(_timer));
  43.     }
  44. }
  45.  
  46. bool PPS::begin(bool use_timer)
  47. {
  48.     ESP_LOGI(TAG, "::begin using '%s'", use_timer ? "timer" : "pin");
  49.     if (use_timer)
  50.     {
  51.         initTimer();
  52.     }
  53.     else
  54.     {
  55.         initPin();
  56.     }
  57.     return true;
  58. }
  59.  
  60. void PPS::initTimer()
  61. {
  62.     esp_timer_create_args_t cfg = {
  63.         .callback              = timerCB,
  64.         .arg                   = this,
  65.         .dispatch_method       = ESP_TIMER_TASK,
  66.         .name                  = "PPS",
  67.         .skip_unhandled_events = true,
  68.     };
  69.     ESP_ERROR_CHECK(esp_timer_create(&cfg, &_timer));
  70.     ESP_ERROR_CHECK(esp_timer_start_periodic(_timer, 1000000ULL));
  71. }
  72.  
  73. void PPS::initPin()
  74. {
  75.     ESP_LOGI(TAG, "::initPin initialize pin %d as 1hz interrupt source", _pin);
  76.     gpio_config_t io_conf {
  77.         .pin_bit_mask  = 1ULL<<_pin,
  78.         .mode          = GPIO_MODE_INPUT,
  79.         .pull_up_en    = GPIO_PULLUP_ENABLE,
  80.         .pull_down_en  = GPIO_PULLDOWN_DISABLE,
  81.         .intr_type     = GPIO_INTR_NEGEDGE
  82.     };
  83.     ESP_ERROR_CHECK(gpio_config(&io_conf));
  84.     (void)gpio_install_isr_service(0); // ignore errors as it could be already installed
  85.     ESP_ERROR_CHECK(gpio_isr_handler_add(_pin, isr, this));
  86. }
  87.  
  88. uint32_t PPS::getUptime()
  89. {
  90.     return _uptime;
  91. }
  92.  
  93. void PPS::notifyEachSecond(TaskHandle_t task)
  94. {
  95.     _notify_list.push_back(task);
  96. }
  97.  
  98. void IRAM_ATTR PPS::isr(void* data)
  99. {
  100.     PPS* clk = (PPS*)data;
  101.     clk->_uptime += 1;
  102.     bool high_pri_task_woken = false;
  103.     for(TaskHandle_t task : clk->_notify_list)
  104.     {
  105.         BaseType_t hpt;
  106.         xTaskNotifyFromISR(task, 1, eIncrement, &hpt);
  107.         if (hpt)
  108.         {
  109.             high_pri_task_woken = true;
  110.         }
  111.     }
  112.     if (high_pri_task_woken)
  113.     {
  114.         portYIELD_FROM_ISR();
  115.     }
  116. }
  117.  
  118. void PPS::timerCB(void* data)
  119. {
  120.     PPS* clk = (PPS*)data;
  121.     clk->_uptime += 1;
  122.     for(TaskHandle_t task : clk->_notify_list)
  123.     {
  124.         xTaskNotify(task, 1, eIncrement);
  125.     }
  126. }

Who is online

Users browsing this forum: No registered users and 101 guests