• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ESP8266 и аппаратный таймер hw_timer

pvvx

Активный участник сообщества
4. При следующем вызове обработчика прерывания от hw_timer, проверяем что импульс открытия симистора уже был и теперь необходимо ожидать опять переход через "0". Для этого необходимо отключить прерывание от hw_timer. Как это правильно сделать? Задать заведомо больший интервал, чтобы гарантировано раньше пришло внешнее прерывание по входу и в нем уже изменить значение счетного регистра функцией hw_timer_set_func(onTimerISR);
Зачем вам отключать прерывание таймера? Он же прерывается один раз по концу счета, если задан режим без автоповтора загрузки нового счета.
 

Melandr

Member
FRC1 считает вниз, при этом значение COUNT_VALUE с каждым тиком уменьшается на 1.
FRC1 можно сконфигурировать в режимах auto-feed-mode или non-auto-feed-mode. Auto-feed-mode: когда сработало прерывание, регистр COUNT_VALUE автоматически получит значение из FRC1_LOAD_VALUE, и начнет операцию декрементирования. Non-auto-feed-mode: когда сработает прерывание, регистр COUNT_VALUE будет установлен в максимальное значение 0x7fffff, и операция декремента продолжится.
вот выше перевод FAQ Espressif, и получается, что если объявлено прерывание от таймера, то счет не останавливается, а продолжает считать.
Вот код мигания светодиодом
Код:
#include "gpio.h"
#include "user_interface.h"
#include "hw_timer.h"

#define LED_PIN 2

bool state = 0;
long ledOn = 300000, ledOff = 1000000;
unsigned long lastMillis = 0;

void ICACHE_RAM_ATTR hw_test_timer_cb() {

  if (state == 0) {
    GPIO_OUTPUT_SET(LED_PIN, 0);
    state = 1;
    hw_timer_arm(ledOn);
  }
  else if (state == 1) {
    // set gpio high
    GPIO_OUTPUT_SET(LED_PIN, 1);
    state = 0;
    hw_timer_arm(ledOff);
  }
}

void ICACHE_FLASH_ATTR user_init(void) {

  // init gpio subsytem
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
  // set gpio high
  GPIO_OUTPUT_SET(LED_PIN, 0);

  hw_timer_init(NMI_SOURCE, 0);
  //hw_timer_init(FRC1_SOURCE, 0);
  hw_timer_set_func(hw_test_timer_cb);
  hw_timer_arm(ledOn);
} // End of user_init

void setup() {
  Serial.begin(115200);
  user_init();
}

// the loop function runs over and over again forever
void loop() {

  if (millis() - lastMillis > 1000) {
    lastMillis = millis();

    Serial.print("LED = ");
    Serial.println(state);
  }
}
И он одинаково работает что при объявлении
hw_timer_init(NMI_SOURCE, 0);
что при объявлении
hw_timer_init(NMI_SOURCE, 1);
 

pvvx

Активный участник сообщества
И когда вы дойдете до того, что большинство выводов у ESP8266 влияет на вариант загрузки, а так-же после включения или перезагрузки до начала исполнения кода уже вашей программы большинство пинов переключаются включая и выключая ваш диммер? Т.е. пины дергаются как это хочет Espressif и он будет управлять вашим диммером, а не вы.
 

pvvx

Активный участник сообщества
вот выше перевод FAQ Espressif, и получается, что если объявлено прерывание от таймера, то счет не останавливается, а продолжает считать.
Какая разница, даже если он начнет счет с 0x7fffff. Пусть хоть обсчитается через 1.7 секунды. К тому времени все уже умрут, да и третий вход и последующие в прерывание таймера ничего не делает (если конечно вы правильно всё написали, а не копировали из инета).
 

Melandr

Member
Попробовал останавливать таймер вот таким способом. Вроде бы работает
Код:
#include "gpio.h"
#include "user_interface.h"
#include "hw_timer.h"

#define LED_PIN 2

bool state = 0;
long ledOn = 300000, ledOff = 1000000;
unsigned long lastMillis = 0;
unsigned long mSecond = 0;
int countTick = 0;

void ICACHE_RAM_ATTR hw_test_timer_cb() {

  if (state == 0) {
    GPIO_OUTPUT_SET(LED_PIN, 0);
    state = 1;
    hw_timer_arm(ledOn);
    countTick++;
  }
  else if (state == 1) {
    // set gpio high
    GPIO_OUTPUT_SET(LED_PIN, 1);
    state = 0;
    hw_timer_arm(ledOff);
  }
  if (countTick == 5)
  {
    GPIO_OUTPUT_SET(LED_PIN, 1);
    hw_timer_set_func(0);
  }
}

void ICACHE_FLASH_ATTR user_init(void) {

  // init gpio subsytem
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
  // set gpio high
  GPIO_OUTPUT_SET(LED_PIN, 0);

  hw_timer_init(NMI_SOURCE, 1);
  //hw_timer_init(FRC1_SOURCE, 0);
  hw_timer_set_func(hw_test_timer_cb);
  hw_timer_arm(ledOn);
} // End of user_init

void setup() {
  Serial.begin(115200);
  user_init();
}

// the loop function runs over and over again forever
void loop() {

  if (millis() - lastMillis > 1000) {
    lastMillis = millis();
    mSecond++;
  }

  if (mSecond == 1)
  {
    Serial.print("LED = ");
    Serial.println(state);
  }
  if (mSecond == 10)
  {
    hw_timer_set_func(hw_test_timer_cb);
  }
}
Вечером если успею, перепишу для диммера и проверю, отпишусь по результату.
 

pvvx

Активный участник сообщества
Вечером если успею, перепишу для диммера и проверю, отпишусь по результату.
Прошел уже месяц как вы этим занимаетесь...
C++:
#include "ets_sys.h"
#include "gpio.h"

#define INTC_EDGE_EN  (*(volatile uint32_t *)0x3FF00004)
#define TIMER_LOAD (*(volatile uint32_t *)0x60000600)
#define TIMER_COUNT (*(volatile uint32_t *)0x60000604)
#define TIMER_CTRL (*(volatile uint32_t *)0x60000608)
#define TIMER_INT  (*(volatile uint32_t *)0x6000060c)
#define GPIO_OUT_W1TS (*(volatile uint32_t *)0x60000304)
#define GPIO_OUT_W1TC (*(volatile uint32_t *)0x60000308)
#define GPIO_OUTP (*(volatile uint32_t *)0x60000300)
#define GPIO_STATUS (*(volatile uint32_t *)0x6000031C)
#define GPIO_PIN2_CFG (*(volatile uint32_t *)0x60000330)
#define GPIO_STATUS_W1TC (*(volatile uint32_t *)0x60000324)

static const int GPIO_OUT = 2; // GPIO2 ?
static const int GPIO_IN = 0; // GPIO0 ?

uint32_t volatile pulse1_in_0us2 = 50 * 5; // in 0.2 us (0x007fffff max), min 12*5
uint32_t volatile pulse2_in_0us2 = 50 * 5; // in 0.2 us (0x007fffff max), min 12*5

void ICACHE_RAM_ATTR GPIOs_intr_handler(void *arg) {
  (void)arg;
  uint32_t tmp = GPIO_STATUS;
  GPIO_STATUS_W1TC = tmp;
  if (tmp & BIT(GPIO_IN)) {
    TIMER_LOAD = pulse1_in_0us2;
    TIMER_CTRL = 4 | BIT(7); // TM_DIVDED_BY_16, NO TM_AUTO_RELOAD_CNT, TM_ENABLE_TIMER
  }
}

void ICACHE_RAM_ATTR TIMER_intr_cb(void *arg) {
  (void)arg;
  if (GPIO_OUTP & BIT(GPIO_OUT)) {
    GPIO_OUT_W1TC = BIT(GPIO_OUT);
    TIMER_CTRL = 0; // stop timer
    gpio_pin_intr_state_set(GPIO_IN, GPIO_PIN_INTR_POSEDGE);
  } else {
    GPIO_OUT_W1TS = BIT(GPIO_OUT);
    TIMER_LOAD = pulse2_in_0us2;
  }
}

void dimmer_stop() {
  ets_isr_mask(BIT(ETS_FRC_TIMER1_INUM) | BIT(ETS_GPIO_INUM)); // запретить прерывания GPIOs & Timer0
  GPIO_OUT_W1TC = BIT(GPIO_OUT);
  TIMER_CTRL = 0; // stop timer
}

void dimmer_start() {
  dimmer_stop();
  TIMER_COUNT = 0;
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
  gpio_output_set(0, 0, BIT(GPIO_OUT), BIT(GPIO_IN));
  GPIO_PIN2_CFG &= ~BIT(GPIO_OUT); // normal out (push-pull)
  gpio_pin_intr_state_set(GPIO_IN, GPIO_PIN_INTR_POSEDGE);
  ets_isr_attach(ETS_GPIO_INUM, GPIOs_intr_handler, NULL);
  ets_isr_attach(ETS_FRC_TIMER1_INUM, TIMER_intr_cb, NULL);
  INTC_EDGE_EN |= BIT(1); // + timer0
  ets_isr_unmask(BIT(ETS_FRC_TIMER1_INUM) | BIT(ETS_GPIO_INUM)); // разрешить прерывания GPIOs & Timer0
}

void setup() {
  gpio_init();
  dimmer_start();
}

void loop() {
  uint32_t tmp = pulse1_in_0us2;
  if (++tmp > 9000 * 5)
    tmp = 10 * 5;
  pulse1_in_0us2 = tmp;
}
Но так и не справились, а впереди ещё нерешаемая задача по пинам для модуля ESP-01:
GPIO0 - Нужен для выбора правильного режима загрузки ESP и не может быть подключен к компаратору фронта, кроме того это выход, выдающий по старту ESP8266 26 MHz, пока его не вырубит загруженный код.
GPIO2 - Это тоже выход TX UART и туда выводятся загрузочные сообщения из ROM.

Обратитесь к enjoynering - он вам и раскажет, что его любимый ESP8266 не может решать даже простые задачи, ну кроме его часов. И наверняка посоветует вам купить что-то другое :)
 

Melandr

Member
Прошел уже месяц как вы этим занимаетесь...
Что поделаешь, работа, ремонт в ванной, тренировки в тренажерном зале. Потом очередь сынулю укладывать спать, поэтому получается добраться до ESP нечасто.
Но так и не справились, а впереди ещё нерешаемая задача по пинам для модуля ESP-01:
GPIO0 - Нужен для выбора правильного режима загрузки ESP и не может быть подключен к компаратору фронта, кроме того это выход, выдающий по старту ESP8266 26 MHz, пока его не вырубит загруженный код.
GPIO2 - Это тоже выход TX UART и туда выводятся загрузочные сообщения из ROM.
По поводу пинов, в действующем устройстве будет использоваться ESP-12, а сейчас так сказать, изучается работа с ESP на отладочной плате, которую не всунешь распределительную коробку ванной комнаты
А не подскажите, почему Вы используете такую запись
pulse1_in_0us2 = 50 * 5
......
if (++tmp > 9000 * 5)
tmp = 10 * 5;
Чтобы в переменной было видно значение задаваемого времени?, но в самую переменную заносилось значение тиков?
 

Melandr

Member
Спасибо за код, не знаю, зачем Вы помогаете таким неучам, если так не нравится ESP. Но спасибо. Лишний раз убедился, что хоть Ардуино и подкупает большим количеством библиотек и простотой кода, но уж очень она обрезана.
PS: кстати код переписал под таймер, но что-то не пошло. Еще и поломалось обновление по OTA. :)
 

Melandr

Member
GPIO0 - Нужен для выбора правильного режима загрузки ESP и не может быть подключен к компаратору фронта, кроме того это выход, выдающий по старту ESP8266 26 MHz, пока его не вырубит загруженный код.
Для детектора нуля использую GPIO1
 

iG2019

New member
Обратитесь к @enjoynering - он вам и раскажет, что его любимый ESP8266 не может решать даже простые задачи, ну кроме его часов. И наверняка посоветует вам купить что-то другое
Самовлюбленный индюк. Не удивлюсь если ПВВХ и николз окажется одним лицом страдающим раздвоением личности из-за раздутого ЧСВ. Задели бедного, не бьют ему поклоны ...
 

sdsm

New member
Самовлюбленный индюк. Не удивлюсь если ПВВХ и николз окажется одним лицом страдающим раздвоением личности из-за раздутого ЧСВ. Задели бедного, не бьют ему поклоны ...
Прекрати пачкать форум. Ничего не понимаешь а умничаешь! Лучше б попробовал поучиться.
 

pvvx

Активный участник сообщества
А не подскажите, почему Вы используете такую запись
pulse1_in_0us2 = 50 * 5
Чтобы вы задали нужное вам время импульса. Тут 50*5 = 50 us
А менее 10*5 незя, т.к. уже указывал, что время входа в прерывания и прочее исполняется долго и при меньшем возможно повторное вхождение в прерывание...
Для детектора нуля использую GPIO1
А это выход другого TX UART, в который тоже идут (дублируются) сообщения загрузки из ROM. При старте GPIO1 и GPIO2 дублируются в коде ROM.
 

pvvx

Активный участник сообщества
Спасибо за код, не знаю, зачем Вы помогаете таким неучам, если так не нравится ESP.
А я учусь решать задачи чужими руками, через форум и непрямые ответы, чтобы и чужая голова тоже работала. :)
Это защищает от таких как iG2019 и сортирует с кем можно связываться. Готового кода нет как и ответа для ЕГЭ-шника, а их так не учили, да сами они не учатся - мертвый материал для функционирования в качестве рабов.
Ведь любое предложение писанное на форуме имеет много смыслов, а они выбирают только по себе.
 

Melandr

Member
Добрый день!
pvvx, от Вы мне задачку помогли решить. Это, конечно, хорошо, что Вы за меня программу написали. Но у меня больше стоит задача разобраться, а не получить готовую программу. Но буду по Вашему коду смотреть. Жаль только, что обертка SDK для Ардуино не хочет работать нормально. Так как почитал реализацию FOTA на SDK и как-то тяжко, по сравнению с кодом OTA на Ардуино.
 

Melandr

Member
Добрый день! Всех с наступившим Новым годом!
pvvx, хотел поинтересоваться, а в чем Вы вели разработку под ESP8266. Поставил Platformio, так теперь не могу разобраться, как подкинуть библиотеки, которые в Arduino IDE уже есть. Их нужно теперь копировать в папку проекта?
 

pvvx

Активный участник сообщества
хотел поинтересоваться, а в чем Вы вели разработку под ESP8266. Поставил Platformio, так теперь не могу разобраться, как подкинуть библиотеки, которые в Arduino IDE уже есть. Их нужно теперь копировать в папку проекта?
с наступившим!
Я не пользуюсь Arduino, т.е. очень редко, поглазеть как там дела... Тем более не ставил на неё никаких расширений.
Если на Ардурину повесить нормальный редактор типа VS или Eclipse, то смысл её использования пропадает. Уж проще воткнуть туда SDK и вперед - возможностей больше.
 

Melandr

Member
Добрый день!
Вы знаете, PlatformIO понравился, но допустим, я создаю новый проект. Выбираю плату - ESP8266 generic . Но на этой плате перепаяна микросхема памяти с 512 кБ, на 4 МБ. А в списке доступны только 512 кБ и 1 МБ.
Уж проще воткнуть туда SDK и вперед - возможностей больше.
Не подскажите, как его добавить в PlatformIO? При создании проекта выбрать фреймворк другой? Для этого нужно с сайта Espressif скачать SDK NONOS и установить в систему?
 

iG2019

New member
Во как бомбануло! Говорили мне не трогай ка*у, вонять не будет. Не послушался. Еще и защитнечков притащил ...
А я учусь решать задачи чужими руками
Любителей загребать жар чужими руками издалека видно
 

svs2007m

Active member
Дружище. Так было всегда и везде. Лучше 100 человек с коэффициентом 1, чем 1 с коэффициентом 100 )))
 
Сверху Снизу