• Система автоматизации с открытым исходным кодом на базе 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
 
Последнее редактирование:
Сверху Снизу