ESP 32 прерывание проблемы - PullRequest
0 голосов
/ 12 февраля 2019

Я использую модуль esp32 и на котором я реализую функцию прерывания.Таким образом, в основном, когда происходит прерывание, светодиод должен светиться, а если нет, светодиод должен быть в выключенном состоянии.Удивительно, но если я попробую обратное, то есть «Если прерывание исходит от переключателя, то светодиод выключается, и обычно он находится во включенном положении», это работает.

Вот мой код.:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#define op 18
#define ip 4
#define OP_PIN_SEL 1ULL<<op
#define IP_PIN_SEL 1ULL<<ip
#define ESP_INTR_FLAG_DEFAULT 0
static void gpio_isr_handler(void )
{
        printf("Intrpt Act\n");
        gpio_set_level(op,0);
        vTaskDelay(1000/portTICK_PERIOD_MS);
        fflush(stdout);
}
void app_main()
{
        gpio_config_t io_conf;
//      io_conf=malloc(0);
        gpio_pad_select_gpio(op);
        gpio_pad_select_gpio(ip);
        gpio_set_direction (op,GPIO_MODE_OUTPUT);
        gpio_set_direction(ip,GPIO_MODE_INPUT);

        io_conf.intr_type=GPIO_PIN_INTR_ANYEDGE;
        io_conf.mode=GPIO_MODE_OUTPUT;
        io_conf.pin_bit_mask=OP_PIN_SEL;
        io_conf.pull_down_en=1;
        io_conf.pull_up_en=0;
        gpio_config(&io_conf);

        gpio_set_intr_type(ip,GPIO_INTR_POSEDGE);
        gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
        gpio_isr_handler_add(ip,gpio_isr_handler,(void*)ip);

        int cnt=0;
        while(1)
        {

                printf("cnt: %d",cnt++);
                gpio_set_level(op,1);
                vTaskDelay(1000/portTICK_RATE_MS);
                fflush(stdout);
        }

}

Также эта ошибка возникает, когда я запускаю прерывание через переключатель:

Исключение в потоке Thread-2:

Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/home/dhananjay/esp/esp-idf/tools/idf_monitor.py", line 133, in _run_outer
    self.run()
  File "/home/dhananjay/esp/esp-idf/tools/idf_monitor.py", line 226, in run
    data = self.serial.read(self.serial.in_waiting or 1)
  File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 495, in read
    raise SerialException('device reports readiness to read but returned no data (device disconnected or multiple access on port?)')
SerialException: device reports readiness to read but returned no data (device disconnected or multiple access on port?)

1 Ответ

0 голосов
/ 12 февраля 2019

По крайней мере, вы делаете way слишком много в вашем обработчике прерываний (gpio_isr_handler()).

Обработчики прерываний interrupt поток любого кодав настоящее время работает.Они могут произойти в любое время, между инструкциями в подпрограмме.Если код не принимает меры предосторожности, чтобы гарантировать, что его структуры данных находятся в согласованном состоянии, вы требуете повреждения данных и сбоев.Для этого необходимо заблокировать прерывания в «критических секциях», что является очень дорогой операцией и может привести к пропущенным прерываниям.Так что системные подпрограммы будут делать это очень редко.

Вы также хотите, чтобы обработчики прерываний были краткими, потому что они блокируют все другие действия в системе - поэтому сетевой стек и другие служебные функции не могут выполняться, пока вы ещев обработчике прерываний.

Вы абсолютно не должны вызывать vTaskDelay() из обработчика прерываний.Что это хотя бы значит?В лучшем случае это повлияет на любую задачу, которая была прервана, что, если выполняется несколько задач, будет случайной задачей.

Вам также не следует вызывать какие-либо функции stdio из обработчика прерываний.Опять же, вы можете прервать другую функцию stdio;его структуры данных могут быть в несовместимом состоянии, и если он использует последовательный порт, возможно, что аппаратное обеспечение также может быть в несовместимом состоянии.

Правильный способ сделать это - просто запустить программу обработки прерываний.задача.Поместите ваш текущий код из gpio_isr_handler() в задачу в бесконечном цикле с помощью a, запустите задачу в app_main() и пусть gpio_isr_handler() просто разбудит задачу.Используйте vTaskSuspend() в начале цикла, чтобы задача дожидалась его пробуждения.

Вы можете безопасно вызывать задачу из обработчика прерываний с одним из:

Начать с xTaskResumeFromISR(), это самый простой способ вывести задачу из обработчика прерываний.

Конструктивно вы также должны переместить цикл while() из app_main() в его собственную задачу, которая является задачей, которую ваш код выполняетжил в gpio_isr_handler() должен возобновиться.

...