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

Зависание и сброс по WDT при срабатывании прерывания от GPIO

pvvx

Активный участник сообщества
CPU сохраняет регистры до выполнения первого оператора в функции колбека.
т е запрет прерываний будет выполнен после сохранения.
и CPU восстановит регистры после разрешения прерывания
Все элементарно Ватсон!
Неправильно.
Кроме того CPU сам не сохраняет "регистры", а только несколько шт. чтобы сделать reti - типа указателя PC. Читайте доку по IP модели проца - она в доступе. Но фигу что найдете по контроллеру прерываний реализованном в данном SoC.
Так-же есть разные прерывания - маскируемые и нет (NMI). NMI тоже можно использовать для GPIO...
 

nikolz

Well-known member
Я выпилил из программы все лишнее, оставил необходимый минимум, чтобы контроллер вообще стартовал. Получилось вот так:
C:
#include "ets_sys.h"
#include "gpio.h"
#include "user_interface.h"

#define SPI_FLASH_SIZE_MAP 4
#define SYSTEM_PARTITION_OTA_SIZE                            0x6A000
#define SYSTEM_PARTITION_OTA_2_ADDR                            0x81000
#define SYSTEM_PARTITION_RF_CAL_ADDR                        0x3fb000
#define SYSTEM_PARTITION_PHY_DATA_ADDR                        0x3fc000
#define SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR                0x3fd000

static const partition_item_t at_partition_table[] = {
    { SYSTEM_PARTITION_BOOTLOADER,                         0x0,                                                 0x1000},
    { SYSTEM_PARTITION_OTA_1,                           0x1000,                                             SYSTEM_PARTITION_OTA_SIZE},
    { SYSTEM_PARTITION_OTA_2,                           SYSTEM_PARTITION_OTA_2_ADDR,                         SYSTEM_PARTITION_OTA_SIZE},
    { SYSTEM_PARTITION_RF_CAL,                          SYSTEM_PARTITION_RF_CAL_ADDR,                         0x1000},
    { SYSTEM_PARTITION_PHY_DATA,                         SYSTEM_PARTITION_PHY_DATA_ADDR,                     0x1000},
    { SYSTEM_PARTITION_SYSTEM_PARAMETER,                 SYSTEM_PARTITION_SYSTEM_PARAMETER_ADDR,             0x3000},
};

void ICACHE_FLASH_ATTR user_pre_init(void)
{
    if(!system_partition_table_regist(at_partition_table,
                                      sizeof(at_partition_table) / sizeof(at_partition_table[0]),
                                      SPI_FLASH_SIZE_MAP))
    {
        while(1);
    }
}

#define GPIO_OUT_W1TS (*(volatile uint32_t *)0x60000304)
#define GPIO_OUT_W1TC (*(volatile uint32_t *)0x60000308)

static void gpio_intr_handler(int *dummy)
{
    (void)dummy;

    uint32_t gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
    GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);

    if (gpio_status & BIT(4))
    {
        GPIO_OUT_W1TS = (1 << 2);
    }
    if (gpio_status & BIT(5))
    {
        GPIO_OUT_W1TC = (1 << 2);
    }
}

void ICACHE_FLASH_ATTR user_init(void)
{
    gpio_init();
    // Configure as GPIO
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);    // LED
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);    // Button
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5);    // Wire

    gpio_output_set(0, 0, (1 << 2), (1 << 4) | (1 << 5));

    // Disable interrupts by GPIO
    ETS_GPIO_INTR_DISABLE();

    gpio_pin_intr_state_set(GPIO_ID_PIN(4), GPIO_PIN_INTR_NEGEDGE);
    gpio_pin_intr_state_set(GPIO_ID_PIN(5), GPIO_PIN_INTR_NEGEDGE);

    ETS_GPIO_INTR_ATTACH(gpio_intr_handler, NULL);

    ETS_GPIO_INTR_ENABLE();
}

Остальное максимально привел к такому же как у вас виду, кроме разве что таймера. Макросы ETS_GPIO_... и GPIO_REG_... разыменовываются в те же конструкции, что и у вас.
Результат тот же. После запуска светодиод загорается, замыкание любого входа на землю приводит к зависанию и перезагрузке.
Проверил Ваш код.
Он работает.
 

nikolz

Well-known member
Доброго времени суток всем. Продолжаю ковыряться с esp8266, и вот понадобилось мне получить прерывание от двух пинов GPIO.
Делаю следующим образом:
C:
#define user_procTaskPrio 0
#define user_procTaskQueueLen 1
os_event_t user_procTaskQueue[user_procTaskQueueLen];

volatile int what;

static void ICACHE_FLASH_ATTR loop(os_event_t *event)
{
    static int level;
    os_printf("What: %d\n", what);
    level = !level;
    GPIO_OUTPUT_SET(GPIO_ID_PIN(2), ((level)? 1 : 0));

    os_delay_us(100000);

    system_os_post(user_procTaskPrio, 0, 0);
}

static void gpio_intr_handler(int *dummy)
{
    // clear gpio status. Say ESP8266EX SDK Programming Guide in  5.1.6. GPIO interrupt handler
    uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);

    // if the interrupt was by GPIO
    if (gpio_status & BIT(4))
    {
        // disable interrupt for GPIO
        gpio_pin_intr_state_set(GPIO_ID_PIN(4), GPIO_PIN_INTR_DISABLE);

        // Do something
        (*dummy)++;

        //clear interrupt status for GPIO
        GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(4));

        // Reactivate interrupts for GPIO
        gpio_pin_intr_state_set(GPIO_ID_PIN(4), GPIO_PIN_INTR_NEGEDGE);
    }
    if (gpio_status & BIT(5))
    {
        gpio_pin_intr_state_set(GPIO_ID_PIN(5), GPIO_PIN_INTR_DISABLE);

        // Do something
        (*dummy)--;

        GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(5));
        gpio_pin_intr_state_set(GPIO_ID_PIN(5), GPIO_PIN_INTR_NEGEDGE);
    }
}


void ICACHE_FLASH_ATTR user_init(void)
{
    system_timer_reinit();

    uart_init(115200, 115200);

    gpio_init();

    // Configure as GPIO
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);    // LED
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);    // Button
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5);    // Wire

    // Set logic 1 for output
    GPIO_OUTPUT_SET(GPIO_ID_PIN(2), 1);

    // Disable output
    GPIO_DIS_OUTPUT(GPIO_ID_PIN(4));
    GPIO_DIS_OUTPUT(GPIO_ID_PIN(5));

    // Enable pullup for inputs
    PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO4_U);
    PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO5_U);

    // Disable interrupts by GPIO
    ETS_GPIO_INTR_DISABLE();

    // Attach interrupt handle to gpio interrupts.
    // You can set a void pointer that will be passed to interrupt handler each interrupt
    ETS_GPIO_INTR_ATTACH(gpio_intr_handler, &what);

    // From include file
    //   Set the specified GPIO register to the specified value.
    //   This is a very general and powerful interface that is not
    //   expected to be used during normal operation.  It is intended
    //   mainly for debug, or for unusual requirements.
    //
    // All people repeat this mantra but I don't know what it means
    //
    gpio_register_set(GPIO_PIN_ADDR(4),
                      GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE)  |
                      GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE) |
                      GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE));
    // clear gpio status. Say ESP8266EX SDK Programming Guide in  5.1.6. GPIO interrupt handler
    GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(4));
    // enable interrupt for his GPIO
    //     GPIO_PIN_INTR_... defined in gpio.h
    gpio_pin_intr_state_set(GPIO_ID_PIN(4), GPIO_PIN_INTR_NEGEDGE);

    gpio_register_set(GPIO_PIN_ADDR(5),
                      GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE)  |
                      GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE) |
                      GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE));
    GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(5));
    gpio_pin_intr_state_set(GPIO_ID_PIN(5), GPIO_PIN_INTR_NEGEDGE);

    ETS_GPIO_INTR_ENABLE();

    system_os_task(loop, user_procTaskPrio, user_procTaskQueue, user_procTaskQueueLen);
    system_os_post(user_procTaskPrio, 0, 0);
}

В результате получаю непрерывный вывод в консоль числа 0, однако при попытке замкнуть указанные GPIO на землю контроллер зависает, а потом перезагружается по ватчдогу. Иногда успевает проскочить 1 или -1.
Читал, что нужно обработчик прерывания декларировать как ICACHE_RAM_ATTR, однако в Non-OS SDK такого дефайна нет, код не компилируется. К тому же, если я правильно помню, функции, не описанные как ICACHE_FLASH_ATTR, и так попадают в RAM.
Скажите, что я делаю не так? Может быть, имеет смысл вообще забить на прерывания, и просто опрашивать ноги в таймере?
немного причесал Ваш код и поставил печать пина.
 

Вложения

pvvx

Активный участник сообщества
немного причесал Ваш код и поставил печать пина.
Это что такое (while(1);)?
C:
void ICACHE_FLASH_ATTR user_pre_init(void)
{    if(!system_partition_table_regist(at_partition_table,
      sizeof(at_partition_table) / sizeof(at_partition_table[0]),SPI_FLASH_SIZE_MAP))
    {ets_printf("system_partition_table_regist fail\r\n");  while(1);  }
}
И почему в "*.h"?
И какой это стиль "причесывания"?
Такого стандарта разметки кода "C" "всё в одну строчку" и как нравится nikolz - пока нет. Это не читаемо... и компилятор будет орать warnig-ами.
 

x8973

Member
Это что такое (while(1);)?
Знакомьтесь, бесконечный цикл. В STM-ах такие стоят в дефолтных обработчиках исключений типа хардфолта. Чтобы программа после возникновения ошибки не поскакала дальше неадекватности городить.
И почему в "*.h"?
И какой это стиль "причесывания"?
А почему нет? Этот код не заказчику показывать, и не в гитхаб выкладывать. Работать он будет, и даже правильно. Главное - самому через полгодика вспомнить, как оно вообще работает.

nikolz, благодарю. Как разберусь с косяками в аппаратной части - вернусь к софту)
 

pvvx

Активный участник сообщества
Знакомьтесь, бесконечный цикл. В STM-ах такие стоят в дефолтных обработчиках исключений типа хардфолта. Чтобы программа после возникновения ошибки не поскакала дальше неадекватности городить.
В STM такое стоит для отладки, для debug, в ожидании того, что вы туда впишите правильное решение к своему проекту.
А в данном случае - SDK ныне не может по default свою partition поставить (Раньше могло и без проблем. Деградирует?) и такие функции не объявляют void.
А почему нет? Этот код не заказчику показывать, и не в гитхаб выкладывать. Работать он будет, и даже правильно. Главное - самому через полгодика вспомнить, как оно вообще работает.
В следующий раз оно просто не соберется, а вывалит кучу ошибок когда правильные опции дадите компилятору. Привыкайте.
 

pvvx

Активный участник сообщества
Если взять даже простой пустой пример в Arduino, то получаем простыню warning в несколько тысяч строк.
Код:
In file included from C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/HardwareSerial.h:33:0,
                 from C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/Arduino.h:245,
                 from t:\Tmp\arduino_build_909089\sketch\sketch_feb19a.ino.cpp:1:
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/uart.h:38:31: warning: binary constants are a GCC extension [enabled by default]
 #define UART_NB_BIT_5         0B00000000
                               ^
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/uart.h:54:20: note: in expansion of macro 'UART_NB_BIT_5'
 #define UART_5N1 ( UART_NB_BIT_5 | UART_PARITY_NONE | UART_NB_STOP_BIT_1 )
                    ^
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/HardwareSerial.h:36:18: note: in expansion of macro 'UART_5N1'
     SERIAL_5N1 = UART_5N1,
                  ^
...

In file included from C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/esp8266_peri.h:25:0,
                 from C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/Arduino.h:38,
                 from t:\Tmp\arduino_build_909089\sketch\sketch_feb19a.ino.cpp:1:
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/esp8266_undocumented.h:38:2: warning: extra ';' [-Wpedantic]
 };
  ^
In file included from C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/Arduino.h:41:0,
                 from t:\Tmp\arduino_build_909089\sketch\sketch_feb19a.ino.cpp:1:
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/core_esp8266_version.h: In function 'constexpr int conststr::atoi(const char (&)[N], unsigned int)':
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/core_esp8266_version.h:89:12: warning: ISO C++ forbids braced-groups within expressions [-Wpedantic]
     return ({ // <= c++11 requires a "return statement"
            ^
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/core_esp8266_version.h:89:13: warning: compound-statement in constexpr function [-Wpedantic]
     return ({ // <= c++11 requires a "return statement"
             ^
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/core_esp8266_version.h:93:9: warning: compound-statement in constexpr function [-Wpedantic]
         {
         ^
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/core_esp8266_version.h: In function 'constexpr int conststr::parseNthInteger(const char (&)[N], unsigned int)':
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/core_esp8266_version.h:106:12: warning: ISO C++ forbids braced-groups within expressions [-Wpedantic]
     return ({ // <= c++11 requires a "return statement"
            ^
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/core_esp8266_version.h:106:13: warning: compound-statement in constexpr function [-Wpedantic]
     return ({ // <= c++11 requires a "return statement"
             ^
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/core_esp8266_version.h: At global scope:
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/core_esp8266_version.h:120:2: warning: extra ';' [-Wpedantic]
 }; // namespace conststr
  ^
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266/core_esp8266_version.h:177:2: warning: extra ';' [-Wpedantic]
 }; // namespace esp8266
  ^
...

C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\umm_malloc\umm_info.c:244:0: warning: ISO C forbids an empty translation unit [-Wpedantic]
 #endif  // defined(BUILD_UMM_MALLOC_C)
 ^
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\umm_malloc\umm_poison.c:246:0: warning: ISO C forbids an empty translation unit [-Wpedantic]
 #endif  // defined(BUILD_UMM_MALLOC_C)
 ^
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\umm_malloc\umm_integrity.c:137:0: warning: ISO C forbids an empty translation unit [-Wpedantic]
 #endif  // defined(BUILD_UMM_MALLOC_C)
 ^
C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\umm_malloc\umm_local.c:218:0: warning: ISO C forbids an empty translation unit [-Wpedantic]
 #endif // BUILD_UMM_MALLOC_C
 ^

C:\Users\test\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\StackThunk.cpp:143:2: warning: extra ';' [-Wpedantic]
 };
  ^
Очень удобно такое читать и искать среди них свои ошибки.
x8973 Пропагандируйте дальше.
 

x8973

Member
SDK ныне не может по default свою partition поставить (Раньше могло и без проблем. Деградирует?) и такие функции не объявляют void.
Полностью согласен, и в первый раз я был в недоумении, почему оно не собирается. Благо, догадался ридми прочитать.
У меня тоже есть некоторые вопросы к официальному СДК. Но на мой взгляд, это пока что лучшее, что может предложить производитель, а писать свой СДК - к сожалению, у меня пока не хватит опыта.
В следующий раз оно просто не соберется, а вывалит кучу ошибок когда правильные опции дадите компилятору. Привыкайте.
Да, я люблю ходить по собственным граблям, привык уже)
 

x8973

Member
Имелось в виду - В чем причина неработоспособности первоначального варианта программы, при тесте на "пинцет"?
Ну так все же было описано в треде. Я неправильно развел цепи питания и сброса, из-за чего получал наводки, ядро сходило с ума. Думаю, если бы не наводки, оно бы работало вполне корректно. Оно и работало, кстати, просто раз через десять) Я бросился искать ошибку в коде, а оказалось, что надо было смотреть на железо.
 

pvvx

Активный участник сообщества
Ну так все же было описано в треде. Я неправильно развел цепи питания и сброса, из-за чего получал наводки, ядро сходило с ума. Думаю, если бы не наводки, оно бы работало вполне корректно. Оно и работало, кстати, просто раз через десять) Я бросился искать ошибку в коде, а оказалось, что надо было смотреть на железо.
Я просто подумал, что вы уже конкретизировали причину, а то в прошлых описаниях отсылки на питание, разводку и помехи - т.е. всё одновременно и ничего конкретного.
Когда я испытывал ваш код был в очередной раз удивлен что модуль такой горячий, а выполняет всего функцию 2-х триггеров - после BLE и прочих малых современных SoC с WiFi это вновь удивляет.
 

x8973

Member
Я просто подумал, что вы уже конкретизировали причину,
К сожалению, нет. У меня не всегда хватает времени и сил на хобби после основной работы) Однако впереди длинные выходные, так что можно будет поковыряться.
выполняет всего функцию 2-х триггеров
Насколько я знаю, WiFi на 8266 включен постоянно. Не уверен, что это большая проблема - ведь 8266 в принципе и предназначен для работы с WiFi, а если нужно просто дергать ногами, то для этого есть STM8, AVR и еще куча более подходящих для этого чипов. Как говорится, кесарю - кесарево, не надо палить главным калибром Звезды Смерти по воробьям.
 

pvvx

Активный участник сообщества
По докам на IP проца значится:
1.2.6 Low-Power
The Xtensa ISA has several energy-efficient attributes that enhance battery-operated systems. The core ISA is built on 32-bit operations; some embedded processors of similar performance have 64-bit base operations, which consumes additional power, often unnecessarily. (TIE does allow 64-bit or greater computations to be added to the processor for those algorithms that require it, but these can be used selectively to achieve a balance between performance and power consumption.)
The core ISA uses a register file with only two read ports and one write port, a configuration that requires fewer transistors and less power than architectures with more ports.
The Xtensa Windowed Registers Option saves power by reducing the number of dynamic data-memory references and increasing the opportunities for variables to reside in registers, where accesses require less power than memory accesses.
The WAITI (Wait for Interrupt) instruction, which is a part of the Interrupt Option, saves power by setting the current interrupt level, powering down the processor’s logic, and waiting for an interrupt.
1.2.6 Низкая мощность
Xtensa ISA имеет несколько характеристик энергоэффективности, которые улучшают работу систем с батарейным питанием. Ядро ISA построено на 32-битных операциях; некоторые встроенные процессоры с аналогичной производительностью имеют 64-разрядные базовые операции, которые потребляют дополнительную мощность, часто без необходимости. (TIE позволяет добавлять в процессор 64-битные или более мощные вычисления для тех алгоритмов, которые этого требуют, но их можно использовать выборочно для достижения баланса между производительностью и потребляемой мощностью.)
Ядро ISA использует регистровый файл только с двумя портами чтения и одним портом записи, конфигурация, которая требует меньше транзисторов и меньше энергии, чем архитектуры с большим количеством портов.
Опция Xtensa Windowed Registers позволяет экономить электроэнергию за счет уменьшения количества ссылок на динамическую память данных и увеличения возможностей для размещения переменных в регистрах, для доступа к которым требуется меньше энергии, чем для доступа к памяти.
Команда WAITI (ожидание прерывания), которая является частью опции прерывания, экономит энергию, устанавливая текущий уровень прерывания, отключая логику процессора и ожидая прерывания.
---

И в данной программе 99.99% времени исполняется команда
asm volatile ("waiti 0;"); // Wait for Interrupt
в ROM. Но что так греет чип?

Потребление включенного радиоканала на прием (при лучших характеристиках по уровню шумов и т.д.) во всех современных и не очень SoC находится на уровне 3..6 мА.
 

pvvx

Активный участник сообщества
При этом XIP - кэш Flash тоже не задействуется - а она может дать + 20 mA при работе... Прерывания находятся в IRAM, "waiti 0;" в ets_run() в ROM и команды проц не выбирает, а ждет прерывания по пинам и таймера...
Это жрет PLL и 64-х битный счетчик в us в чипе? Кошмарный чип...
 

x8973

Member
И в данной программе 99.99% времени исполняется команда
Не знаю, как у вас, а у меня ESP сразу после запуска автоматически поднимает точку доступа с дефолтными параметрами. Может быть, это как-то отключается.
Плюс греться может какой-нибудь внутренний LDO, к примеру.
 

nikolz

Well-known member
Это что такое (while(1);)?
C:
void ICACHE_FLASH_ATTR user_pre_init(void)
{    if(!system_partition_table_regist(at_partition_table,
      sizeof(at_partition_table) / sizeof(at_partition_table[0]),SPI_FLASH_SIZE_MAP))
    {ets_printf("system_partition_table_regist fail\r\n");  while(1);  }
}
И почему в "*.h"?
И какой это стиль "причесывания"?
Такого стандарта разметки кода "C" "всё в одну строчку" и как нравится nikolz - пока нет. Это не читаемо... и компилятор будет орать warnig-ами.
Вы очевидно не читали документацию на SDK 3.x.x.
Предполагаю, что разработчики таким образом предотвращают бесконечную перегрузку.
 

nikolz

Well-known member
Это что такое (while(1);)?
C:
void ICACHE_FLASH_ATTR user_pre_init(void)
{    if(!system_partition_table_regist(at_partition_table,
      sizeof(at_partition_table) / sizeof(at_partition_table[0]),SPI_FLASH_SIZE_MAP))
    {ets_printf("system_partition_table_regist fail\r\n");  while(1);  }
}
И почему в "*.h"?
И какой это стиль "причесывания"?
Такого стандарта разметки кода "C" "всё в одну строчку" и как нравится nikolz - пока нет. Это не читаемо... и компилятор будет орать warnig-ами.
Вы очевидно не читали документацию на SDK 3.x.x. Верно?
Можете задать этот вопрос разработчикам ESP.
Предполагаю, что разработчики таким образом предотвращают бесконечную перезагрузку.
----
про тип *.h читайте учебники
----------------
про причесывание:
сравните файл main.c исходный и мой. Для меня - мой нагляднее.
Если нравится исходный, используйте его.
 
Сверху Снизу