• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Вопрос Как повесить прерывание с кнопки на GPIO16

Привет, пытаюсь разобраться с прерываниями на плате. Считывать значение статуса нажатой кнопки – получается, отлавливать прерывание кнопки на другом GPIO - получается, собрать вместе - нет :(

Я понимаю, что я могу запустить бесконечный таймер и проверять нажата кнопка или нет, но не хочется "городить". Может кто-то сталкивался?

Например для GPIO13 работающий код для кнопки вот такой:
Код:
//Set up GPIO
    PIN_FUNC_SELECT(pin_mux[13], pin_func[13]);
    PIN_PULLUP_EN(pin_mux[13]);
    GPIO_DIS_OUTPUT(button_gpio);

    //Set up Interrupts
    ETS_GPIO_INTR_DISABLE();
    ETS_GPIO_INTR_ATTACH(button_handler, NULL);
    GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(button_gpio));
    gpio_pin_intr_state_set(GPIO_ID_PIN(button_gpio), GPIO_PIN_INTR_ANYEDGE);
    ETS_GPIO_INTR_ENABLE();

Где pin_mux и pin_func - массивы с соответствующими значениями.

Для GPIO16 у меня получается вот такой вот кусок кода:
Код:
//Set up GPIO
    ETS_GPIO_INTR_DISABLE();
    PIN_FUNC_SELECT(pin_mux[16], pin_func[16]);
    PIN_PULLUP_EN(pin_mux[16]);
    GPIO_DIS_OUTPUT(16);


      WRITE_PERI_REG(PAD_XPD_DCDC_CONF,
                   (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1);     // mux configuration for XPD_DCDC and rtc_gpio0 connection

        WRITE_PERI_REG(RTC_GPIO_CONF,
                       (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0);    //mux configuration for out enable

        WRITE_PERI_REG(RTC_GPIO_ENABLE,
                       READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe);    //out disable


    //Set up Interrupts
    ETS_GPIO_INTR_ATTACH(button_handler, NULL);
    GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(16));
    gpio_pin_intr_state_set(GPIO_ID_PIN(16), GPIO_PIN_INTR_ANYEDGE);
    ETS_GPIO_INTR_ENABLE();
Не срабатывают прерывания :( Что не так?
 

nikolz

Well-known member
надо не таймер вешать, а использовать колбек функцию для прерывания от GPIO.
 

Garmin

Member
Почитайте мои объявления периферии для ESP8266. Тогда поймёте, что GPIO16 - совершенно отдельная периферия относительно других GPIO.
 
надо не таймер вешать, а использовать колбек функцию для прерывания от GPIO.
Все так, поэтому и хочу на GPIO16 повесить callback. Может я что-то не понимаю, что судя по описанию API:
Код:
ETS_GPIO_INTR_ATTACH(func, arg); //Register GPIO interrupt control function
Для кнопки на GPIO13 - это прерывание отлично отрабатывает, для GPIO16 - нет.

Почитайте мои объявления периферии для ESP8266. Тогда поймёте, что GPIO16 - совершенно отдельная периферия относительно других GPIO.
Можете дать конкретную ссылку, очень хочется с этим разобраться пока в голове полная каша :(


Есть еще один вопрос по прерываниям и GPIO - если я хочу повесить разные функции прерываний на разные GPIO. Например, я хочу реализовать такую логику:
Если нажимается кнопка на GPIO12 – срабатывается функция funcA, если я нажал на кнопку GPIO13 – срабатывает функция funcB. В API об этом ничего не сказано, но в результате экспериментов у меня, две кнопки, то при нажатии на любую из кнопок у меня срабатывает функция, которая была выполнена позже. Т.е. при использовании ETS_GPIO_INTR_ATTACH - срабатывает только последняя функция? Как тогда определить с какого GPIO пришло прерывание?
 

Garmin

Member
Можете дать конкретную ссылку, очень хочется с этим разобраться пока в голове полная каша :(
Вот, в соседней теме
GPIO16 находится в блоке регистров RTC, и управляется совсем иначе, смотрите описания структур. Только его мультиплексор находится в IOMUX.
 
Если порт не работает в режиме ввода, то как вы собираетесь прерывание с него получить?
Эм, почему он не работает в режиме ввода? Значение на GPIO16 получить же получается. Вопрос именно в том, как получить прерывание.


Вот, в соседней теме
GPIO16 находится в блоке регистров RTC, и управляется совсем иначе, смотрите описания структур. Только его мультиплексор находится в IOMUX.
Да, прочитал, пробовал разобраться, но получилось только запутаться еще больше. Сейчас в официальном API хотя бы описаны макросы. Если же вы, фактичсеки, переписываете эти макросы своими функциями - без дополнительного объяснение - для новичка вроде меня - это становится похожим на магию.

Например для всех GPIO кроме 16 этот код будет нормально работать(на примере GPIO13): GPIO_INPUT_GET(13);
Для GPIO16: для того, чтобы получить значение нужно использовать (READ_PERI_REG(RTC_GPIO_IN_DATA) & 1)

Почему? Где описание функции, почему с какими-то GPIO работают макросы, а для работы с какими нужно использовать побитовые функции?

Если я правильно понял ваш ESP8266_REGISTERS.H(кстати титанический труд, ага) – вы обернули в _xpd_dcdc_conf_t, и фактически инициация GPIO идет путем формирования значений регистров. Но это никак не приводит к пониманию, как же настроить его так, чтобы он стал реагировать на прерывания.
 

Garmin

Member
Например для всех GPIO кроме 16 этот код будет нормально работать(на примере GPIO13): GPIO_INPUT_GET(13);
Для GPIO16: для того, чтобы получить значение нужно использовать (READ_PERI_REG(RTC_GPIO_IN_DATA) & 1)
Для меня было бы понятнее так:
[inline]dummy = GPIO->in_bits.pin_12;[/inline]
и
[inline]u8 temp2 = RTC->gpio_in_bits.gpio0;[/inline]
Тут на вкус и цвет фломастеры разные.
Почему? Где описание функции, почему с какими-то GPIO работают макросы, а для работы с какими нужно использовать побитовые функции?
Вот об этом спрашивайте у китайцев. Мне это не понравилось, и я накатал свою простынку.
Если я правильно понял ваш ESP8266_REGISTERS.H, фактически инициация GPIO идет путем формирования значений регистров. Но это никак не приводит к пониманию, как же настроить его так, чтобы он стал реагировать на прерывания.
Здесь вам помогут примеры, и говорящие названия регистров и битовых полей. В своё время я перевёл на регистры много примеров UART и GPIO. Стало намного понятнее.
Я не использовал прерывание GPIO16, и сейчас у меня нет времени с этим разбираться, так что попробуйте осилить самостоятельно периферию ESP8266.
Для других ножек очень просто:
Код:
static void ICACHE_FLASH_ATTR gpio5_setup (void)
{
    ets_isr_mask ((1 << ETS_GPIO_INUM));
      
    IOMUX->gpio5_mux &= ~GPIO_MUX_FUNC_MASK;    //
    IOMUX->gpio5_mux |= GPIO5_FUNC_GPIO;        //
    IOMUX->gpio5_mux_bits.pullup = 1;
  
    GPIO->enable_w1tc_bits.pin_5 = 1;            // GPIO5 input
  
    GPIO->pin_5_bits.gpio_source = GPIO_DATA;
    GPIO->pin_5_bits.pin_driver = PUSH_PULL;
    GPIO->pin_5_bits.pin_int = 2;    // GPIO_PIN_INTR_NEGEDGE = 2 прерывание по спаду
    GPIO->pin_5_bits.config = 0;    // ???
  
    ets_isr_attach (ETS_GPIO_INUM, pin_int_handler, (void *)NULL);
    GPIO->int_st_w1tc = GPIO_INT_STATUS_MASK;    // стереть маски прерываний по пинам
    ets_isr_unmask ((1 << ETS_GPIO_INUM));
}
И прерывание:
Код:
static void __attribute__((optimize("O2"))) pin_int_handler (void *para)
{
    gpio_int_st_t    status;
    status = GPIO->int_st_bits;
    GPIO->int_st_w1tc = GPIO->int_st;    // стёрли все флаги прерывания по пинам
   
    if (status.pin_5)    // прерывание по пину 5 
    {   
......
    }
}
 

pvvx

Активный участник сообщества
От куда у GPIO16 тут вообще взяли "Прерывание" ? :confused::eek:
GPIO16 (Name: XPD_DCDC )
Function 0: XPD_DCDC,
Function 1: RTC_GPIO0,
Function 2: EXT_WAKEUP,
Function 3: DEEPSLEEP,
Function 4: BT_XTAL_EN
pin_func.gif
gpio16.gif
 
Последнее редактирование:
Сверху Снизу