• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе 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() то пустой получается...
 
Сверху Снизу