• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Невыровненный доступ

sharikov

Active member
Поддерживается ли в ESP32 работа с невыровенными адресами или будет исключение ?
Например если 32-х битную переменную расположить по адресу не кратному 4.
Такой же вопрос про ESP8266.
Про замедление и плохой стиль я знаю. Вопрос именно про исключения.
 

enjoynering

Well-known member
я экспериментировал с ESP8266 и Arduino framework. разницы размера скеча от в unt8_t, uint16_t и uint32_t не заметил. похоже, какой тип не выбрать, всегда тупо занимается 4 бита

вот тут чел спрашивает почему sizeof возвращает 1+1+4=6 байт
Код:
typedef struct packet_t{
  uint8_t a;     // sizeof(uint8_t) returns 1
  uint8_t b;     // sizeof(uint8_t) returns 1
  float c;         // sizeof(float) returns 4
};
а размер пакета получается 8
Код:
sizeof(packet_t) //returns 8
чтоб этого не происходило надо так
Код:
typedef struct __attribute((__packed__)) packet_t{
  uint8_t a;
  uint8_t b;
  float c;
};
 

pvvx

Активный участник сообщества
Поддерживается ли в ESP32 работа с невыровенными адресами или будет исключение ?
Будет исключение.

В IRAM, (кеш) Flash, registers - всегда должно быть выровнено и желательно чтение/запись по 32 бита.
 

pvvx

Активный участник сообщества
Про замедление и плохой стиль я знаю.
Думаю, что нет.
На версиях NodeMCU LUA ESP8266 по exception читаются байтовые (string/char) переменные из Flash.
Один exception = один char :) Метода такая чтобы не исправлять printf() и прочие процедуры библиотек создана процедура на векторе exception выуживающая байтики из IRAM (кеш) Flash...
За последние годы в некоторых вариантах Aduino такое тоже наблюдалось - вставляли обработку exception по нарушению align(4)... - сотни тактов на байт для Arduino ерунда. Всё равно игрушка...
 

sharikov

Active member
Будет исключение.
В IRAM, (кеш) Flash, registers - всегда должно быть выровнено и желательно чтение/запись по 32 бита.
На ESP32 исключения не возникает.
Тест:
Код:
void unaligned_access_test(void) {
   static char buffer[61];
   unsigned int index, data;
   volatile char *ptr1;

   // fill buffer
   for (index=0; index < sizeof(buffer); index++)
       buffer[index]=index;
   // check buffer alignment
   ptr1=&buffer[0];
   printf("&buffer[0]=0x%x\n", (unsigned int)ptr1);
   if (((unsigned int)ptr1 & 3) !=0) {
       printf("unaligned!\n");
       data = (unsigned int)ptr1;
       data|=3;
       data+=1;  // 4-byte aligned address
       ptr1=(volatile char *)data;
       printf("new: 0x%x\n", (unsigned int)ptr1);
   }
   // unaligned access test
   for (index=0; index<4; index++) {
       printf("[0x%x] : 0x%04x\n", (unsigned int)ptr1, *(unsigned int*)ptr1);
       ptr1++;
   }
}
Результат:
Код:
&buffer[0]=0x3ffb2eb4
[0x3ffb2eb4] : 0x3020100
[0x3ffb2eb5] : 0x4030201
[0x3ffb2eb6] : 0x5040302
[0x3ffb2eb7] : 0x6050403
 

sharikov

Active member
Добавил измерение времени:
Код:
extern unsigned int g_ticks_per_us_pro;
void unaligned_access_test(void) {
    static char buffer[61];
    unsigned int index, data, ccount_now, ccount_prv;
    volatile char *ptr1;

    printf("ticks per us = %u\n", g_ticks_per_us_pro);
    // fill buffer
    for (index=0; index < sizeof(buffer); index++)
        buffer[index]=index;
    // check buffer alignment
    ptr1=&buffer[0];
    printf("&buffer[0]=0x%x\n", (unsigned int)ptr1);
    if (((unsigned int)ptr1 & 3) !=0) {
        printf("unaligned!\n");
        data = (unsigned int)ptr1;
        data|=3;
        data+=1;  // 4-byte aligned address
        ptr1=(volatile char *)data;
        printf("new: 0x%x\n", (unsigned int)ptr1);
    }

    // unaligned access test
    for (index=0; index<4; index++) {
        //ccount_prv = xthal_get_ccount();
        __asm__ __volatile__("rsr %0,ccount":"=a" (ccount_prv));
        data=*(volatile unsigned int*)ptr1;
        //ccount_now = xthal_get_ccount();
        __asm__ __volatile__("rsr %0,ccount":"=a" (ccount_now));

        printf("[0x%x] : 0x%04x  cycles : %d\n",
                (unsigned int)ptr1, data,
                (ccount_now < ccount_prv)? ccount_prv-ccount_now : ccount_now- ccount_prv);
        ptr1++;
    }
}
Результаты:
Код:
ticks per us = 240
&buffer[0]=0x3ffb2eb4
[0x3ffb2eb4] : 0x3020100  cycles : 3
[0x3ffb2eb5] : 0x4030201  cycles : 10
[0x3ffb2eb6] : 0x5040302  cycles : 10
[0x3ffb2eb7] : 0x6050403  cycles : 10
По моему 10 тактов для обработчика исключения недостаточно. А вот на два обращения по шине данных и простой конвейера похоже. Результаты на 240MHz и на 160MHz не отличаются.
 

sharikov

Active member
То в простой SRAM. А в других областях "В IRAM, (кеш) Flash, registers"?
При невыровненном чтении данных из области Instruction External Flash (0x400C2000-0x40BFFFFF) возникает исключение LoadStoreAlignment и далее ребут. Выровненное чтение из этой области работает.

Обращение к области Data External Flash (0x3F400000-0x3F7FFFFF) исключение не выдается. Результаты двух тестов:
Код:
ticks per us = 240
&buffer[0]=0x3f402e9e
unaligned!
new: 0x3f402ea0
[0x3f402ea0] : 0x5040302  cycles : 287
[0x3f402ea1] : 0x6050403  cycles : 12
[0x3f402ea2] : 0x7060504  cycles : 12
[0x3f402ea3] : 0x8070605  cycles : 12
ticks per us = 240
&buffer[0]=0x3f402e9e
unaligned!
new: 0x3f402ea0
[0x3f402ea0] : 0x5040302  cycles : 4
[0x3f402ea1] : 0x6050403  cycles : 12
[0x3f402ea2] : 0x7060504  cycles : 12
[0x3f402ea3] : 0x8070605  cycles : 12
287 циклов - подгрузка кэш. Из кэша данные читаются на 1 или 2 такта медленнее чем из SRAM.
 

pvvx

Активный участник сообщества
287 циклов - подгрузка кэш.
Это на одно считывание?
Какая длина блока чтения у "кеш" из SPI-Flash? 16-ть байт или ?
240MHz/287 = 830 кГц 2хCPU :) Супер производительность ESP32 :) :)
У меня, по расчетам, получилось среднее к 10 миллионам операций CPU в секунду (на оба ядра) в процессах типа кодеков и прочего кода (типа рассчет ключей,SSL и подобное), когда он не вмещается в убогий "кеш" ESP32 (а он и не вместится никогда).
 

sharikov

Active member
Это на одно считывание?
Какая длина блока чтения у "кеш" из SPI-Flash? 16-ть байт или ?
240MHz/287 = 830 кГц 2хCPU
В мануале не нашел. На форуме пишут "Cache lines are 32 bytes".
В теории должно быть
40MHz / (32+5) = 1.08 МHz или 0.925us на промах кэш.

Жаль что кэш на 1 такт медленнее SRAM
 

pvvx

Активный участник сообщества
В мануале не нашел. На форуме пишут "Cache lines are 32 bytes".
В теории должно быть
40MHz / (32+5) = 1.08 МHz или 0.925us на промах кэш.
32 байта QSPI -> 64 такта SPI шины + заголовок с адресом (5 байт = 10 тактов + до пары тактов на старте).
Получаем 80MHz/80 = 1 блок в 32 байта -> 1MHz * 32, т.е. QSPI читается в "кеш" со скоростью 32 мегабайта в сек.
А средняя длина команды у ESP - 2 с чем-то байта, к трем ... и учтем работу "кеш" блоками на чтение указателей (лишние чтение вместо 4-х байт 32-х)...
32/3 = 10M команд CPU в сек, если код длиннее "кеш" и идет в линейку или рандом.
STM32 или какой современный PIC, не говоря уже о mips и прочих с большой SRAM, уделывает ESP32 в 10..100 раз.
 

pvvx

Активный участник сообщества
И при такой производительности (в 10МГц) ESP32 жрет так-же, даже немного более из-за постоянной SPI-Flash работы всех контроллеров с тактированием на 240x2МГц ядер. Т.е. и энерго-эффективность так-же падает по сравнению с другими на порядки !
На ESP8266 уже эта бяда, а тут ещё 2 ядра на ту-же шину QSPI повесили... :eek:
 

sharikov

Active member
Интересно что происходит с работой второго ядра во время загрузки кэша ?
Скажем второе ядро исполняет критичный по времени код только из IRAM и в это время первое ядро подгружает кэш.
Шина как я понимаю одна и как пишут на форуме блоков предвыборки в процессорах нет
 

pvvx

Активный участник сообщества
Интересно что происходит с работой второго ядра во время загрузки кэша ?
Скажем второе ядро исполняет критичный по времени код только из IRAM и в это время первое ядро подгружает кэш.
Если оно работает из SRAM (IRAM) - то работает как и работало.
Шина как я понимаю одна и как пишут на форуме блоков предвыборки в процессорах нет
"предвыборки" нет и док-во в лишней команде "memw" и "extw".
 
Сверху Снизу