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

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

pvvx

Активный участник сообщества
Непонятен алгоритм смены значения регистра FRC1_LOAD_VALUE в прерывании. Также если отключен auto-feed-mode в регистр заносится максимальное значение и счет продолжается. А когда же нужно заносить в регистр новое значение?
Определяется опытным путем. В прерывании закатайте ему новый счетчик и смотрите ослом.
 

pvvx

Активный участник сообщества
посмотрел в этой теме Ускорение esp8266 работу с GPIO и не могу понять, почему у товарища CodeNameHawk
функция digitalWrite занимает 0,46 мкс. А у меня тот же ногодрыг с использованием прерывания от таймера 1 забирает на полтора порядка больше времени.
Пишите конкретнее и с примером. И что измеряете - время между двумя выводами или?
Предельный такт смены состояния GPIO 26 МГц (возможно и деленный на 2 - надо глядеть что было при ковырянии пять лет назад...)
 

Melandr

Member
вопрос по использованию функции
gpio_output_set(0, (1 << LED_BUILTIN), 0, 0);
сделал простой скетч мигания светодиодом
Код:
#include "gpio.h"
#include "user_interface.h"

bool state = 0;

void ICACHE_FLASH_ATTR user_init(void) {

  // init gpio subsytem
  //gpio_init();
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
  // set gpio low
  gpio_output_set((1 << LED_BUILTIN), 0, 0, 0);

} // End of user_init

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

// the loop function runs over and over again forever
void loop() {
  gpio_output_set(0, (1 << LED_BUILTIN), 0, 0);   // Turn the LED on (Note that LOW is the voltage level
  // but actually the LED is on; this is because
  // it is active low on the ESP-01)
  state = 1;
  Serial.print("LED = ");
  Serial.println(state);
  delay(1000);                      // Wait for a second
  gpio_output_set((1 << LED_BUILTIN), 0, 0, 0);  // Turn the LED off by making the voltage HIGH
  state = 0;
  Serial.print("LED = ");
  Serial.println(state);
  delay(2000);                      // Wait for two seconds (to demonstrate the active low LED)
}
светодиод не мигает, что делаю неправильно?
 

Melandr

Member
А вот так работает
// init gpio subsytem
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
// set gpio high
GPIO_OUTPUT_SET(LED_BUILTIN, 1);
 

Melandr

Member
как второй вывод GPIO2 можно в коде использовать в макросе GPIO_OUTPUT_SET(LED_BUILTIN, 1);
 

pvvx

Активный участник сообщества
До использования функций управления GPIO из ROM надо запустить
C:
/*
 * Initialize GPIO.  This includes reading the GPIO Configuration DataSet
 * to initialize "output enables" and pin configurations for each gpio pin.
 * Must be called once during startup.
 */
void gpio_init(void);
 

Melandr

Member
Странно, наверное я ESP8266 готовить не умею.
Вот код
Код:
#include "gpio.h"
#include "user_interface.h"

bool state = 0;

void ICACHE_FLASH_ATTR user_init(void) {

  // init gpio subsytem
  gpio_init();
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
  // set gpio high
  gpio_output_set((1 << LED_BUILTIN), 0, 0, 0);

} // End of user_init

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

// the loop function runs over and over again forever
void loop() {
  gpio_output_set(0, (1 << LED_BUILTIN), 0, 0);   // Turn the LED on (Note that LOW is the voltage level
  // but actually the LED is on; this is because
  // it is active low on the ESP-01)
  state = 1;
  Serial.print("LED = ");
  Serial.println(state);
  delay(1000);                      // Wait for a second
  gpio_output_set((1 << LED_BUILTIN), 0, 0, 0);  // Turn the LED off by making the voltage HIGH
  state = 0;
  Serial.print("LED = ");
  Serial.println(state);
  delay(2000);                      // Wait for two seconds (to demonstrate the active low LED)
}
Не работает, а если использую GPIO_OUTPUT_SET то светодиод мигает
 

pvvx

Активный участник сообщества
А вот так работает
// init gpio subsytem
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
// set gpio high
GPIO_OUTPUT_SET(LED_BUILTIN, 1);
Ну функцию вы сменили, а режим работы вывода в GPIO не задали. Т.е. в каком оно у вас там режиме - вход, выход push-pull или open drain?
 

pvvx

Активный участник сообщества
Странно, наверное я ESP8266 готовить не умею.
Вот код
Код:
#include "gpio.h"
#include "user_interface.h"

bool state = 0;

void ICACHE_FLASH_ATTR user_init(void) {

  // init gpio subsytem
  gpio_init();
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
  // set gpio high
  gpio_output_set((1 << LED_BUILTIN), 0, 0, 0);

} // End of user_init

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

// the loop function runs over and over again forever
void loop() {
  gpio_output_set(0, (1 << LED_BUILTIN), 0, 0);   // Turn the LED on (Note that LOW is the voltage level
  // but actually the LED is on; this is because
  // it is active low on the ESP-01)
  state = 1;
  Serial.print("LED = ");
  Serial.println(state);
  delay(1000);                      // Wait for a second
  gpio_output_set((1 << LED_BUILTIN), 0, 0, 0);  // Turn the LED off by making the voltage HIGH
  state = 0;
  Serial.print("LED = ");
  Serial.println(state);
  delay(2000);                      // Wait for two seconds (to demonstrate the active low LED)
}
Не работает, а если использую GPIO_OUTPUT_SET то светодиод мигает
Слово enable вам о чем-нибудь говорит в:
void gpio_output_set(uint32 set_mask, uint32 clear_mask, uint32 enable_mask, uint32 disable_mask);
 

pvvx

Активный участник сообщества
Вот там вам пример как мигать пином:
Код:
#include "ets_sys.h"
#include "osapi.h"
#include "gpio.h"
#include "os_type.h"

// ESP-12 modules have LED on GPIO2. Change to another GPIO
// for other boards.
static const int pin = 2;
static volatile os_timer_t some_timer;

void some_timerfunc(void *arg)
{
  //Do blinky stuff
  if (GPIO_REG_READ(GPIO_OUT_ADDRESS) & (1 << pin))
  {
    // set gpio low
    gpio_output_set(0, (1 << pin), 0, 0);
  }
  else
  {
    // set gpio high
    gpio_output_set((1 << pin), 0, 0, 0);
  }
}

void ICACHE_FLASH_ATTR user_init()
{
  // init gpio subsytem
  gpio_init();

  // configure UART TXD to be GPIO1, set as output
  PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1);
  gpio_output_set(0, 0, (1 << pin), 0);

  // setup timer (500ms, repeating)
  os_timer_setfn(&some_timer, (os_timer_func_t *)some_timerfunc, NULL);
  os_timer_arm(&some_timer, 500, 1);
}
 

Melandr

Member
Слово enable вам о чем-нибудь говорит в:
void gpio_output_set(uint32 set_mask, uint32 clear_mask, uint32 enable_mask, uint32 disable_mask);
А ниже Вы показываете пример, по которому я делал Выше указанный скетч, но без использования программного таймера.
// configure UART TXD to be GPIO1, set as output PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1); gpio_output_set(0, 0, (1 << pin), 0);
Скорее всего, эти функции можно использовать только под SDK
 

pvvx

Активный участник сообщества
Сейчас чего накалякаю, вспомним что там в ESP8266 - вроде тут есть ещё в ящике хлама какой-то...
 

Melandr

Member
Всем спасибо за помощь. Вот этот код удалось запустить
Код:
#include "gpio.h"
#include "user_interface.h"
#include "hw_timer.h"

#define LED_PIN 2
#define TIME_PULSE 10000
#define TIME_PAUSE 50

static bool status = false;

void Led_Cmd(bool status) {
  if (status == true) {
    GPIO_OUTPUT_SET(GPIO_ID_PIN(LED_PIN), 0);
  } else {
    GPIO_OUTPUT_SET(GPIO_ID_PIN(LED_PIN), 1);
  }
}

void ICACHE_RAM_ATTR hw_test_timer_cb() {
  hw_timer_init(NMI_SOURCE, 0);
  if (status == true) {
    status = false;
    Serial.println("Led_Cmd false");
    hw_timer_arm(TIME_PAUSE);
  } else {
    status = true;
    Serial.println("Led_Cmd true");
    hw_timer_arm(TIME_PULSE);
  }
  Led_Cmd(status);
}

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, 1);
  hw_timer_set_func(hw_test_timer_cb);
  hw_timer_arm(1000000);
} // End of user_init

void setup() {

  Serial.begin(115200);
  Serial.println();
  Serial.println();

  Serial.println("");
  Serial.println("--------------------------");
  Serial.println("ESP8266 Timer Test");
  Serial.println("--------------------------");

  user_init();

}

void loop() {

} //end loop
С этими настройками получается импульс 74 мкс.
Если TIME_PULSE делаю 1000, то импульс уже получается 1,22 мс
Если TIME_PULSE делаю 100, то импульс тоже получается 1,2 мс
Если TIME_PULSE делаю 100000, то импульс уже получается 71,6 мкс
Почему при увеличении частоты импульсов начинает увеличиваться импульс
 

Melandr

Member
Правда это еще не диммер :), но прогресс уже есть. Но конечно ESP ведет себя совсем не предсказуемо. И это я еще не подключал WiFi
 

pvvx

Активный участник сообщества
Взял пример из своей Web-свалки и тупо вписал в Arduino:
C++:
#include "ets_sys.h"
#include "gpio.h"

#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 INTC_EDGE_EN  (*(volatile uint32_t *)0x3FF00004)
#define GPIO_OUT_W1TS (*(volatile uint32_t *)0x60000304)
#define GPIO_OUT_W1TC (*(volatile uint32_t *)0x60000308)
#define GPIO_STATUS (*(volatile uint32_t *)0x6000031C)
#define GPIO_STATUS_W1TC (*(volatile uint32_t *)0x60000324)

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

uint32_t pulse_in_0us2 = 1000 * 5; // in 0.2 us (0x007fffff max)

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)) {
    GPIO_OUT_W1TS = BIT(GPIO_OUT);
    TIMER_LOAD = pulse_in_0us2;
    TIMER_COUNT = 0;
    TIMER_CTRL = 4 // TM_DIVDED_BY_16
                 //| BIT(6) // TM_AUTO_RELOAD_CNT
                 | BIT(7) //  TM_ENABLE_TIMER
                 ;
  }
}

void ICACHE_RAM_ATTR hw_test_timer_cb(void *arg)
{
  (void)arg;
  GPIO_OUT_W1TC = BIT(GPIO_OUT);
  gpio_pin_intr_state_set(GPIO_IN, GPIO_PIN_INTR_POSEDGE);
}

void setup() {
  gpio_init();
  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, (1 << GPIO_OUT), (1 << GPIO_IN));
  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, hw_test_timer_cb, NULL);
  TIMER_CTRL = 0;
  INTC_EDGE_EN |= BIT(1); // + timer0
  ets_isr_unmask(BIT(ETS_FRC_TIMER1_INUM) | BIT(ETS_GPIO_INUM)); // разрешить прерывания GPIOs & Timer0
}

void loop() {
  // put your main code here, to run repeatedly:
}
Ничего не знаю что там у вас Arduino используется и какие есть #incliude - запихал прямыми адресами :)
Блин - эт чаго оно Дурино такое жирное в flash пишет? Кода всё на дцать байт и ему ничего из SDK не надо!
 

pvvx

Активный участник сообщества
10 us пульс работает. Но сам вход в прерывание по пину - около 1 us. Тормоз ESP...

Я вам на прерывание по кнопочке (фронт вверх) и на светодиодик слепил. :)
 

Melandr

Member
Залил Ваш код, светодиодик конечно не видно, как тухнет, но ослик показал
SDS00017.png
импульс по отжатию кнопки 1 мс
ЗЫ: Нужно будет посидеть покурить Ваш код, может разберусь почему у меня эти функции не работали
 

pvvx

Активный участник сообщества
Потому что никто не пишет два прерывания на NMI для dimmer-а - боятся наверно.
Любимый Loop() то пустой получается...
 
Сверху Снизу