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

SPI

sharikov

Active member
Переделал на ассемблере
Код:
Код:
oid __attribute__((optimize("O2"))) write_test(uint32_t i)
{
    uint32_t j=0;
    uint32_t t1, t2;
    uint32_t* ptr =(uint32_t *)SPI_W0(HSPI);

    ets_uart_printf("\n--------\n");
    os_delay_us(100000);
    do
    {
        ets_uart_printf("\twithout MEMW\n");
        os_delay_us(100000);
        __asm__ __volatile__("memw" : : : "memory");
        ets_intr_lock();
        GET_CCOUNT(t1);
        //t1=get_ccount();
        __asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
                "S32I.N %0, %1, 4 \n\t"
                "S32I.N %0, %1, 8 \n\t"
                "S32I.N %0, %1, 12 \n\t"
                "S32I.N %0, %1, 16 \n\t"
                "S32I.N %0, %1, 20 \n\t"
                "S32I.N %0, %1, 24 \n\t"
                "S32I.N %0, %1, 28 \n\t"
                : : "r"(j), "r"(ptr));
        //__asm__ __volatile__("memw" : : : "memory");
        GET_CCOUNT(t2);
        //t2=get_ccount();
        ets_intr_unlock();
        ets_uart_printf(" 8 writes: time= %d\n", calcdelta(t1, t2));
        os_delay_us(100000);

        __asm__ __volatile__("memw" : : : "memory");
        ets_intr_lock();
        GET_CCOUNT(t1);
        //t1=get_ccount();
        __asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
                "S32I.N %0, %1, 4 \n\t"
                "S32I.N %0, %1, 8 \n\t"
                "S32I.N %0, %1, 12 \n\t"
                "S32I.N %0, %1, 16 \n\t"
                "S32I.N %0, %1, 20 \n\t"
                "S32I.N %0, %1, 24 \n\t"
                "S32I.N %0, %1, 28 \n\t"
                "S32I.N %0, %1, 32 \n\t"
                "S32I.N %0, %1, 36 \n\t"
                "S32I.N %0, %1, 40 \n\t"
                "S32I.N %0, %1, 44 \n\t"
                "S32I.N %0, %1, 48 \n\t"
                "S32I.N %0, %1, 52 \n\t"
                "S32I.N %0, %1, 56 \n\t"
                "S32I.N %0, %1, 60 \n\t"
                : : "r"(j), "r"(ptr));
        //__asm__ __volatile__("memw" : : : "memory");
        GET_CCOUNT(t2);
        //t2=get_ccount();
        ets_intr_unlock();
        ets_uart_printf("16 writes: time= %d\n", calcdelta(t1, t2));
        os_delay_us(100000);


        ets_uart_printf("\twith MEMW\n");
        os_delay_us(100000);
        __asm__ __volatile__("memw" : : : "memory");
        ets_intr_lock();
        GET_CCOUNT(t1);
        //t1=get_ccount();
        __asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
                "S32I.N %0, %1, 4 \n\t"
                "S32I.N %0, %1, 8 \n\t"
                "S32I.N %0, %1, 12 \n\t"
                "S32I.N %0, %1, 16 \n\t"
                "S32I.N %0, %1, 20 \n\t"
                "S32I.N %0, %1, 24 \n\t"
                "S32I.N %0, %1, 28 \n\t"
                : : "r"(j), "r"(ptr));
        __asm__ __volatile__("memw" : : : "memory");
        GET_CCOUNT(t2);
        //t2=get_ccount();
        ets_intr_unlock();
        ets_uart_printf(" 8 writes: time= %d\n", calcdelta(t1, t2));
        os_delay_us(100000);

        ptr=(uint32_t *)SPI_W0(HSPI);
        __asm__ __volatile__("memw" : : : "memory");
        ets_intr_lock();
        GET_CCOUNT(t1);
        //t1=get_ccount();
        __asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
                "S32I.N %0, %1, 4 \n\t"
                "S32I.N %0, %1, 8 \n\t"
                "S32I.N %0, %1, 12 \n\t"
                "S32I.N %0, %1, 16 \n\t"
                "S32I.N %0, %1, 20 \n\t"
                "S32I.N %0, %1, 24 \n\t"
                "S32I.N %0, %1, 28 \n\t"
                "S32I.N %0, %1, 32 \n\t"
                "S32I.N %0, %1, 36 \n\t"
                "S32I.N %0, %1, 40 \n\t"
                "S32I.N %0, %1, 44 \n\t"
                "S32I.N %0, %1, 48 \n\t"
                "S32I.N %0, %1, 52 \n\t"
                "S32I.N %0, %1, 56 \n\t"
                "S32I.N %0, %1, 60 \n\t"
                : : "r"(j), "r"(ptr));
        __asm__ __volatile__("memw" : : : "memory");
        GET_CCOUNT(t2);
        //t2=get_ccount();
        ets_intr_unlock();
        ets_uart_printf("16 writes: time= %d\n\n", calcdelta(t1, t2));
        os_delay_us(100000);
    }
    while (--i);
    ets_uart_printf("\n--------\n");
}
Дизассеблер:
Код:
__asm__ __volatile__("memw" : : : "memory");
40100f9e:    0020c0            memw
        ets_intr_lock();
40100fa1:    fd2c01            l32r    a0, 40100454 <ets_timer_arm_new+0xd0>
40100fa4:    0000c0            callx0    a0
        GET_CCOUNT(t1);
40100fa7:    03ea30            rsr.ccount    a3
        //t1=get_ccount();
        __asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
40100faa:    0128          l32i.n    a2, a1, 0
40100fac:    02c9          s32i.n    a12, a2, 0
40100fae:    12c9          s32i.n    a12, a2, 4
40100fb0:    22c9          s32i.n    a12, a2, 8
40100fb2:    32c9          s32i.n    a12, a2, 12
40100fb4:    42c9          s32i.n    a12, a2, 16
40100fb6:    52c9          s32i.n    a12, a2, 20
40100fb8:    0662c2            s32i    a12, a2, 24
40100fbb:    72c9          s32i.n    a12, a2, 28
                "S32I.N %0, %1, 20 \n\t"
                "S32I.N %0, %1, 24 \n\t"
                "S32I.N %0, %1, 28 \n\t"
                : : "r"(j), "r"(ptr));
        //__asm__ __volatile__("memw" : : : "memory");
        GET_CCOUNT(t2);
40100fbd:    03ead0            rsr.ccount    a13
Результаты
Код:
--------
    without MEMW
8 writes: time= 17
16 writes: time= 70
    with MEMW
8 writes: time= 47
16 writes: time= 96

    without MEMW
8 writes: time= 17
16 writes: time= 70
    with MEMW
8 writes: time= 47
16 writes: time= 96

    without MEMW
8 writes: time= 17
16 writes: time= 70
    with MEMW
8 writes: time= 47
16 writes: time= 96

    without MEMW
8 writes: time= 17
16 writes: time= 70
    with MEMW
8 writes: time= 47
16 writes: time= 96

--------
Выкинуть компилятор UDK на помойку.
Чем предлагаете компилить после выкидывания UDK ????
Использование спираченного компилера в открытом проекте абсолютно неприемлемо.
У xtensa компилятора есть бесплатные варианты ?

Он ваши *ptr++= i раскладывает на load в регистр 32-х битный адрес по смещению, потом запись по этому регистру со смещением ноль. По другому он не умеет. И вообще не умеет работать со смещениями - адрес в регистре + смещение. Только нулевое смещение.
Наверно это потому что смещение задается в коде. Было бы в регистре - все было бы в порядке. А оптимизатор на уровне Arm процессоров никто писать не хочет.

И то что он наплодил в _stext констант - они не объединяются, т.к. каждая эксклюзивная.
У меня константы объединяются, во всяком случае в пределах одного исходника. Четко вижу по дизассемблеру что (uint32_t *)SPI_W0(HSPI) берется из обработчика прерывания где эта константа была ранее задана.
Для разных файлов наверно объединяться не будут.


Обсуждение кривизны UDK не для этой темы.
Давайте обсудим разницу во времени записи для 8 и 16 регистров.
 

pvvx

Активный участник сообщества
Чем предлагаете компилить после выкидывания UDK ????
Другой версией сборки GCC, не из комплекта UDK. :)

Давайте обсудим разницу во времени записи для 8 и 16 регистров.
А какова разница (время) межу двумя GET_CCOUNT(t1) ?
xthal_get_ccount() = { rsr.ccount a2; ret.n; }
Ну шина наверно тормозит - fifo какое...
Но, c SPI не всё так просто. Она наворочена для автоматического обслуживания внешней последовательной flash. И flash читается по 32 байта. Это ваши 8 регистров там.
Отключите автоматическое управление системой flash и возможно всё измениться. Может там прерывание или ещё чего в кишках включается при более 8 регистрах...
Как раз с этим вожусь сегодня - постоянно падает система на протектед (9) и с непонятными ошибками при чтении flash из этого буфера, и адрес ошибки дает не кратный 4, а пишу-читаю в память dword-ами :
PvSDK ver: 0.0.0(b1)
Old reset: Fatal exception (9):
epc1=0x40100386, epc2=0x00000000, epc3=0x00000000, excvaddr=0x3fff41f6, depc=0x00000000
Память RAM имеет доступ по 2 и 4- ре кратности адреса и не ясно что это такое...
 
Последнее редактирование:

sharikov

Active member
Другой версией сборки GCC, не из комплекта UDK.
Обеими руками за! А где другую сборку берут ?

А какова разница (время) межу двумя GET_CCOUNT(t1) ?
Код:
    ets_intr_lock();
     GET_CCOUNT(t1);
     GET_CCOUNT(t2);
     ets_intr_unlock();
     ets_uart_printf("GET_CCOUNT: time= %d\n", calcdelta(t1, t2));
GET_CCOUNT: time= 1

Но, c SPI не всё так просто. Она наворочена для автоматического обслуживания внешней последовательной flash. И flash читается по 32 байта. Это ваши 8 регистров там.
Отключите автоматическое управление системой flash и возможно всё измениться. Может там прерывание или ещё чего в кишках включается при более 8 регистрах...
Автоматическое управление flash отключено - я выполняю тест после инициализации hspi для работы с mcp2515.
Проверил двойное обращение к младшим 8 регистрам вместо 16-ти.
код:
Код:
__asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
                "S32I.N %0, %1, 4 \n\t"
                "S32I.N %0, %1, 8 \n\t"
                "S32I.N %0, %1, 12 \n\t"
                "S32I.N %0, %1, 16 \n\t"
                "S32I.N %0, %1, 20 \n\t"
                "S32I.N %0, %1, 24 \n\t"
                "S32I.N %0, %1, 28 \n\t"

                "S32I.N %0, %1, 0 \n\t"
                "S32I.N %0, %1, 4 \n\t"
                "S32I.N %0, %1, 8 \n\t"
                "S32I.N %0, %1, 12 \n\t"
                "S32I.N %0, %1, 16 \n\t"
                "S32I.N %0, %1, 20 \n\t"
                "S32I.N %0, %1, 24 \n\t"
                "S32I.N %0, %1, 28 \n\t"
/*
                "S32I.N %0, %1, 32 \n\t"
                "S32I.N %0, %1, 36 \n\t"
                "S32I.N %0, %1, 40 \n\t"
                "S32I.N %0, %1, 44 \n\t"
                "S32I.N %0, %1, 48 \n\t"
                "S32I.N %0, %1, 52 \n\t"
                "S32I.N %0, %1, 56 \n\t"
                "S32I.N %0, %1, 60 \n\t"
                */
                : : "r"(j), "r"(ptr));
Результат не изменился.
Еще хочу попробовать обращение только к старшим регистрам и обращение в обратном порядке.
Как раз с этим вожусь сегодня - постоянно падает система на протектед (9) и с непонятными ошибками при чтении flash из этого буфера, и адрес ошибки дает не кратный 4, а пишу-читаю в память dword-ами :
Задержку до выставление прерывания вы убрали ? Может она нужна ? Потому что очень странный бит, возможно завязан на dma и обмен с памятью.
 

pvvx

Активный участник сообщества
Ошибка как всегда была связана с глюками SDK. Не грузилась таблица инициализации для phy, wifi и т.д. (я же с кодом работы с flash как раз экспериментировал и наверно побил :)) и что-то SDK конфигурила эдакое....
Ну и про QSPI - почему не читает flash блоками по 64 байта (полный буфер)?
Биос читает по 32 байта. Я написал и отладил свою читалку, с заменой в PvSDK на spi_flash_read(uint32 faddr, void *des, uint32 size).
Но - по 60 байт блоками в буфер (fifo spi) читает, а по 64 - нет. С чем это связано?
Да - никаких "memw" - без них всё хорошо, а с flash работает плотно....
Вообще всё в наглую:
Код:
            SPI0_ADDR = faddr | (blksize << 24);
            SPI0_CMD = SPI_READ;
            while(SPI0_CMD);
            uint32 *srcdw = (uint32 *)(SPI0_BASE+0x40);
            while(blksize >> 2) {
                *((uint32 *)des) = *srcdw++;
...
Даже без volatile :) у указателя на буфер.
В конечном коде между ожиданиями безусловно перенес и вставил код который возможно было туда перенести, чтобы сократить время исполнения процедуры...
Буфер SPI вообще лучше описать как сегмент.
Уже писал самый простой метод:
Задать массив или переменную по спец.адресу можно только путем объявления в ld или лезть в Makefile
и добавлять: ld --section-start=rtc_mem_section=0x60001100
для: unsigned int rtc_mem[192] __attribute__ ((section ("rtc_mem_section")));

Но опять-же - это бесполезно для текущего UDK, т.к. он все равно будет обращаться по нулевому смещению в регистрах...
 
Последнее редактирование:

CHERTS

Moderator
Команда форума
Вполне серьезная причина выкинуть кривой UDK компилятор.
Выкинуть то всегда можно и успеется, Вы вначале предложите сообществу альтернативу. Я бы с радостью в UDK засунул другой компилятор, дак вот нет его, а засовывать туда xtensa компилятор нельзя, дяди могут прижать к стенке.

P.S. По UDK прошу писать в соотв. тему. Что выкинуть, что добавить или как пересобрать GCС, чтобы вес было как нужно.
 

pvvx

Активный участник сообщества
По UDK прошу писать в соотв. тему. Что выкинуть, что добавить или как пересобрать GCС, чтобы вес было как нужно.
Когда займусь сборкой своего компилятора, тогда и напишу :) Не всё сразу...
По началу надо найти что надо и как это исправить, да может взять из того что уже есть, хоть из xtensa и переработать. Вы же вставляете чужие исходники и куски в свой UDK...
Вот открываю ваш UDK и наблюдаю там (c) Espressif System ...
 

CHERTS

Moderator
Команда форума
Вы же вставляете чужие исходники и куски в свой UDK...
Все, что я вставляю в UDK идет по открытым лицензиям и я обязательно указываю авторов оригинальных исходников/репозитарии в changelog. Никакого плагиата тут нет, если Вы намекаете на это.
 

pvvx

Активный участник сообщества
Описал в eagle.app.v6.ld segment .io3 и с UDK:
Код:
volatile uint32 spi1_buf[16] __attribute__ ((section (".io3.spi")));
/*
        spi1_buf[3] = i;
4010008d:    0020c0           memw
40100090:    3ef9         s32i.n    a15, a14, 12
        spi1_buf[4] = i;
40100092:    0020c0           memw
40100095:    4ef9         s32i.n    a15, a14, 16


Pointer spi1_buf: 0x60000140
 8 writes: time= 59
 16 writes: time= 108


401000e3:    cef9         s32i.n    a15, a14, 48
        spi1_buf[13] = i;
401000e5:    def9         s32i.n    a15, a14, 52
        spi1_buf[14] = i;
401000e7:    eef9         s32i.n    a15, a14, 56

Pointer spi1_buf: 0x60000140
 8 writes: time= 21
 16 writes: time= 63  */
void __attribute__((optimize("O2"))) write_test(uint32_t i)
{
    uint32_t t1, t2;
    ets_uart_printf("\n--------\n");
    ets_delay_us(100000);
    do    {
        ets_uart_printf("Pointer spi1_buf: %p\n", spi1_buf);
        ets_delay_us(100000);
        ets_intr_lock();
        GET_CCOUNT(t1);
        spi1_buf[0] = i;
        spi1_buf[1] = i;
        spi1_buf[2] = i;
        spi1_buf[3] = i;
        spi1_buf[4] = i;
        spi1_buf[5] = i;
        spi1_buf[6] = i;
        spi1_buf[7] = i;
        spi1_buf[8] = i;
        GET_CCOUNT(t2);
        ets_intr_unlock();
        ets_uart_printf(" 8 writes: time= %d\n", calcdelta(t1, t2));
        ets_delay_us(100000);
        ets_intr_lock();
        GET_CCOUNT(t1);
        spi1_buf[0] = i;
        spi1_buf[1] = i;
        spi1_buf[2] = i;
        spi1_buf[3] = i;
        spi1_buf[4] = i;
        spi1_buf[5] = i;
        spi1_buf[6] = i;
        spi1_buf[7] = i;
        spi1_buf[8] = i;
        spi1_buf[9] = i;
        spi1_buf[10] = i;
        spi1_buf[11] = i;
        spi1_buf[12] = i;
        spi1_buf[13] = i;
        spi1_buf[14] = i;
        spi1_buf[15] = i;
        GET_CCOUNT(t2);
        ets_intr_unlock();
        ets_uart_printf(" 16 writes: time= %d\n", calcdelta(t1, t2));
    }
    while (--i);
    ets_uart_printf("\n--------\n");
}
 

pvvx

Активный участник сообщества
Это потому что базовый адрес -- константа в этой же функции. Передайте его как параметр в функцию или получите его вызовом не-inline функции -- и всё будет ок:
Ничего подобного.
volatile uint32 uart0[64] __attribute__ ((section (".io3.uart0")));
volatile uint32 spi1[64] __attribute__ ((section (".io3.spi1")));
volatile uint32 spi0[64] __attribute__ ((section (".io3.spi0")));
volatile uint32 gpoi[64] __attribute__ ((section (".io3.gpoi")));
volatile uint32 timer[64] __attribute__ ((section (".io3.timer")));
volatile uint32 iomux[64] __attribute__ ((section (".io3.iomux")));
volatile uint32 wdt[64] __attribute__ ((section (".io3.wdt")));
volatile uint32 uart1[64] __attribute__ ((section (".io3.uart1")));
volatile uint32 rtc_ram[64] __attribute__ ((section (".io3.rtc_ram")));
volatile uint32 rtc_mem[64] __attribute__ ((section (".io3.rtc_mem")));


К ним макрос, дающий номер в массиве:

[HASHTAG]#define[/HASHTAG] HWREG(BASE, OFF) BASE[OFF>>2]
[HASHTAG]#define[/HASHTAG] SPI0_BASE spi0_
[HASHTAG]#define[/HASHTAG] SPI0_W0 HWREG(SPI0_BASE, 0x40)
...

(такая кривизна для совместимости хидеров от Espressif)

В итоге код СИ:
SPI1_W0 = i;
SPI1_W1 = i;
SPI1_W2 = i;
SPI1_W3 = i;


дает на выходе:

SPI1_W0 = i;
106ef2 s32i a15, a14, 64
SPI1_W1 = i;
116ef2 s32i a15, a14, 68
SPI1_W2 = i;
126ef2 s32i a15, a14, 72


один раз загрузив регистр a14 за всю процедуру:

ffe2e1 l32r a14, 40100024 <calcdelta+0x24>


--------------------
@sharikov :
clk_wr.gif
Memw действует аналогично extw.
 
Последнее редактирование:

sharikov

Active member
Мне одному кажется что spi сидит на 26-мегагерцовой шине ?
Если так то замена кварца на 40мгц должна несколько повысить быстродействие системы.
Интересно для spi и hspi скорости одинаковые или будут разными ?
 

pvvx

Активный участник сообщества
QSPI работает с flash на 80MHz (CLK), а в тесте программы загружаемой в iram - неизвестно. Может существовать зависимость - не проверял.
Если так то замена кварца на 40мгц должна несколько повысить быстродействие системы.
Где находится байт переключения кварца в прошивке?
Интересно для spi и hspi скорости одинаковые или будут разными ?
Я работал и делал замеры с spi подключенной к flash.
Делители у них одинаковые.
SWAP на SPI тоже есть - это один блок.
Все проверки мы производили с буфером SPI (с её fifo). т.е. со специфическим аппаратным блоком.
Блок GPIO вообще стробируется вроде 75 ns (там кратность 25ns) (испытывал в другой теме)
--------
Ещё не ясно что за IO1:3FF0000C (значение в нем в SDK 0x4000102)
С SPI связан 9 бит, см Wait_SPI_Idle() во вложении:
 

Вложения

Последнее редактирование:

sharikov

Active member
Я работал и делал замеры с spi подключенной к flash.
Делители у них одинаковые.
SWAP на SPI тоже есть - это один блок.
Все проверки мы производили с буфером SPI (с её fifo). т.е. со специфическим аппаратным блоком.
Блок GPIO вообще стробируется вроде 75 ns (там кратность 25ns) (испытывал в другой теме)
Ниже все цифры при частоте процессора 80МГц.
Протестировал чтение на ассемблере.
Итак имеем: все обращения к обоим блокам SPI и GPIO идут с частотой 26MHz, на запись есть фифо предположительно глубиной 8 обращений. Запись в фифо производится за 2 такта, если фифо заполнено - за 6 тактов. Сброс фифо происходит по команде memw или по его заполнению.
С чтением печальнее. Фифо себя никак не проявляет и чтение всегда выполняется вдвое медленнее записи - за 12 тактов.

В приведенном коде как извлекаются считанные данные после spi_flash_read ?
Применительно к QSPI с частотой 80МГц с шиной 26МГц выходит полная фигня.
1 байт прилетит по QSPI за 2 такта а по шине он предается за 12. Мне как-то слабо верится что якобы имеющийся dma перекидывает данные из SPI для флэшки через другой более скоростной канал данных. В чипе шины данных просто так дублировать не станут.
Нужен тест скорости чтения флэшки QSPI 80Мгц с учетом времени на извлечение данных из буфера SPI.
 

pvvx

Активный участник сообщества
В приведенном коде как извлекаются считанные данные после spi_flash_read ?
Я исходную не дореверсил - там лажово сделано - транслятор накрутил зигзагов... но в принципе там обычное чтение spi_wx в цикле и закидывание в память, всё dword-ами, а между ними куча вычислений какой следующий и надо ли его читать (неоптимальный код - по тому и не стал переписывать)...
Сделал по своему, чтобы был доступ хоть по байтный и по любому нечетному адресу (void *dest кароче и без ограничения по размеру flash из её заголовка - для больших flash до 16M, в остальном отличий от ROM-BIOS-ной функции нет) :
Код:
/******************************************************************************
* FunctionName : spi_flash_read
* Description  : чтение массива байт из flash
*              читает из flash по QSPI блоками по SPI_FBLK байт
*              в ROM-BIOS SPI_FBLK = 32 байта, 64 - предел SPI буфера
* Parameters   : flash Addr, pointer, кол-во
* Returns      : SpiFlashOpResult 0 - ok
* Опции gcc: -mno-serialize-volatile !
*******************************************************************************/
#define SPI_FBLK 32
SpiFlashOpResult __attribute__((optimize("O3"))) spi_flash_read(uint32 faddr, void *des, uint32 size)
{
    if(des == NULL) return SPI_FLASH_RESULT_ERR;
    if(size != 0) {
        faddr <<= 8; faddr >>= 8; //    faddr &= (1 << 24) - 1; //    if((faddr >> 24) || ((faddr + size) >> 24)) return SPI_FLASH_RESULT_ERR;
        Cache_Read_Disable();
        Wait_SPI_Idle(flashchip);
        uint32 blksize = (uint32)des & 3;
        if(blksize) {
            blksize = 4 - blksize;
            if(size < blksize) blksize = size;
            SPI0_ADDR = faddr | (blksize << 24);
            SPI0_CMD = SPI_READ;
            size -= blksize;
            faddr += blksize;
            while(SPI0_CMD);
            register uint32 data_buf = SPI0_W0;
            do {
                *(uint8 *)des = data_buf;
                des = (uint8 *)des + 1;
                data_buf >>= 8;
            } while(--blksize);
        }
        while(size) {
            if(size < SPI_FBLK) blksize = size;
            else blksize = SPI_FBLK;
            SPI0_ADDR = faddr | (blksize << 24);
            SPI0_CMD = SPI_READ;
            size -= blksize;
            faddr += blksize;
            while(SPI0_CMD);
            uint32 *srcdw = (uint32 *)(&SPI0_W0);
            while(blksize >> 2) {
                *((uint32 *)des) = *srcdw++;
                des = ((uint32 *)des) + 1;
                blksize -= 4;
            }
            if(blksize) {
                uint32 data_buf = *srcdw;
                do {
                    *(uint8 *)des = data_buf;
                    des = (uint8 *)des + 1;
                    data_buf >>= 8;
                } while(--blksize);
                break;
            }
        }
        Cache_Read_Enable(0, 0, 1);
    }
    return SPI_FLASH_RESULT_OK;
}
Оптимизировано под UDK транслятор. В моем SDK работает и всё к ней обращается из либ оставшихся кусков Espressif SDK, проверено кароче. Скорость отдачи Web сервера увеличилась.
 
Последнее редактирование:

pvvx

Активный участник сообщества
Итак имеем: все обращения к обоим блокам SPI и GPIO идут с частотой 26MHz, на запись есть фифо предположительно глубиной 8 обращений. Запись в фифо производится за 2 такта, если фифо заполнено - за 6 тактов. Сброс фифо происходит по команде memw или по его заполнению.
С чтением печальнее. Фифо себя никак не проявляет и чтение всегда выполняется вдвое медленнее записи - за 12 тактов.
26MHz не может. Кратность 25 - да. Осел на GPIO не врет - строб фронта всегда кратен 25 ns в SDK, а не 38.
Замеры я и вы делали без переустановки pll (он в SDK), а в конфиге её от BIOS.
После BIOS у нас частота CPU 52MHz или 104 (если включить умножение). Это всё предположительно, т.к. не измерял частоту CPU.
104/12 = 8.666667MHz строб шины.
jcmvbkbc ещё ни разу ничего правильно не сказал, кроме команд asm для референс дизайна потрахов CPU, а у нас измененный вариант.
extw и memw - пофигу - результат аналогичный. Делал замеры и их времени выполнения.
Запись в фифо производится за 1 такт. У вас между замерами GET_CCOUNT(t1); GET_CCOUNT(t2); - 1 такт.
Первые 3 записи (12 байт) даже на 160MHz = 3 такта.

Частота CPU неизвестна. Это для галочки пишется 80 и 160.
Используется только в BIOS:40002ECC ets_delay_us()
mov.n a12, a2
call0 xthal_get_ccount ; CCOUNT
l32r a0, a_cpu_clk_mhz; <<-------
l32i.n a0, a0, 0
mov.n a13, a2
mull a12, a0, a12
И далее ожидание вычисленной дельты.

Про 26 или 25MHz шину: В чем беда-то? 25*4 байта = 100 - это 100 МегаБайт в секунду (26*32 бита = 832 Mbit/s).
Для QSPI Flash - это 200Mbit/s *4 (x4 - это по каждому каналу). Т.е. при CLK на QSPI в 80MНz тормозит Flash, а не шина.
80MНz на 4 бита = 40 Мегабайт в секунду в пределе.
1.2 Мегабайт в секунду дает Web c flash 16M на загрузку PDF размером в 15 Мегабайт. Тормозит WiFi и SDK (CPU и софт). Разницы между скачиванием RAM (или пустоты) и flash - нет
 
Последнее редактирование:

pvvx

Активный участник сообщества
@sharikov - в SPI_CTRL младшие биты (там их 13 шт неописанных) находится prescaler SPI и коммутатор источника CLK ?
Значения для CLK flash устанавливаются там:
Для 80, 40, 26, 20 MHz
Значения: 0x1000, 0x101, 0x202, 0x313

IOMUX_BASE (0x60000800) bit8 =1 при 80 MHz, =0 при 40, 26, 20 MHz на SPI Flash

Аналогично где-то устанавливается и источник тактирования шины и его делитель...
 
Последнее редактирование:

pvvx

Активный участник сообщества
Никто не пробовал работать с SPI по DMA? Может там быстрее выйдет?
Полной доки по DMA (SLС) как всегда нет, но есть это https://github.com/espressif/esp8266_mp3_decoder/blob/master/mp3/include/sdio_slv.h
По SLC заголовки и пример есть https://github.com/espressif/esp8266_mp3_decoder/blob/master/mp3/include/slc_register.h
Так-же ROM-BIOS работает с чем-то в адресах 0x60000A00. Это интерфейс SD или RF или ? К нему используется SLС и куча процедур в ROM-BIOS начинающихся с "sip_"...().
 
Сверху Снизу