Скрыть объявление
На нашем форуме недоступен просмотр изображений для неавторизованных пользователей. Если Вы уже зарегистрированы на нашем форуме, то можете войти. Если у Вас еще нет аккаунта, мы будем рады, если Вы к нам присоединитесь. Зарегистрироваться Вы можете здесь.

SPI

Тема в разделе "Общие вопросы по esp8266", создана пользователем Andrey, 7 янв 2015.

  1. sharikov

    sharikov Авторитетный участник сообщества

    Сообщения:
    604
    Симпатии:
    52
    Переделал на ассемблере
    Код:
    Код (C):
    1. oid __attribute__((optimize("O2"))) write_test(uint32_t i)
    2. {
    3.     uint32_t j=0;
    4.     uint32_t t1, t2;
    5.     uint32_t* ptr =(uint32_t *)SPI_W0(HSPI);
    6.  
    7.     ets_uart_printf("\n--------\n");
    8.     os_delay_us(100000);
    9.     do
    10.     {
    11.         ets_uart_printf("\twithout MEMW\n");
    12.         os_delay_us(100000);
    13.         __asm__ __volatile__("memw" : : : "memory");
    14.         ets_intr_lock();
    15.         GET_CCOUNT(t1);
    16.         //t1=get_ccount();
    17.         __asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
    18.                 "S32I.N %0, %1, 4 \n\t"
    19.                 "S32I.N %0, %1, 8 \n\t"
    20.                 "S32I.N %0, %1, 12 \n\t"
    21.                 "S32I.N %0, %1, 16 \n\t"
    22.                 "S32I.N %0, %1, 20 \n\t"
    23.                 "S32I.N %0, %1, 24 \n\t"
    24.                 "S32I.N %0, %1, 28 \n\t"
    25.                 : : "r"(j), "r"(ptr));
    26.         //__asm__ __volatile__("memw" : : : "memory");
    27.         GET_CCOUNT(t2);
    28.         //t2=get_ccount();
    29.         ets_intr_unlock();
    30.         ets_uart_printf(" 8 writes: time= %d\n", calcdelta(t1, t2));
    31.         os_delay_us(100000);
    32.  
    33.         __asm__ __volatile__("memw" : : : "memory");
    34.         ets_intr_lock();
    35.         GET_CCOUNT(t1);
    36.         //t1=get_ccount();
    37.         __asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
    38.                 "S32I.N %0, %1, 4 \n\t"
    39.                 "S32I.N %0, %1, 8 \n\t"
    40.                 "S32I.N %0, %1, 12 \n\t"
    41.                 "S32I.N %0, %1, 16 \n\t"
    42.                 "S32I.N %0, %1, 20 \n\t"
    43.                 "S32I.N %0, %1, 24 \n\t"
    44.                 "S32I.N %0, %1, 28 \n\t"
    45.                 "S32I.N %0, %1, 32 \n\t"
    46.                 "S32I.N %0, %1, 36 \n\t"
    47.                 "S32I.N %0, %1, 40 \n\t"
    48.                 "S32I.N %0, %1, 44 \n\t"
    49.                 "S32I.N %0, %1, 48 \n\t"
    50.                 "S32I.N %0, %1, 52 \n\t"
    51.                 "S32I.N %0, %1, 56 \n\t"
    52.                 "S32I.N %0, %1, 60 \n\t"
    53.                 : : "r"(j), "r"(ptr));
    54.         //__asm__ __volatile__("memw" : : : "memory");
    55.         GET_CCOUNT(t2);
    56.         //t2=get_ccount();
    57.         ets_intr_unlock();
    58.         ets_uart_printf("16 writes: time= %d\n", calcdelta(t1, t2));
    59.         os_delay_us(100000);
    60.  
    61.  
    62.         ets_uart_printf("\twith MEMW\n");
    63.         os_delay_us(100000);
    64.         __asm__ __volatile__("memw" : : : "memory");
    65.         ets_intr_lock();
    66.         GET_CCOUNT(t1);
    67.         //t1=get_ccount();
    68.         __asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
    69.                 "S32I.N %0, %1, 4 \n\t"
    70.                 "S32I.N %0, %1, 8 \n\t"
    71.                 "S32I.N %0, %1, 12 \n\t"
    72.                 "S32I.N %0, %1, 16 \n\t"
    73.                 "S32I.N %0, %1, 20 \n\t"
    74.                 "S32I.N %0, %1, 24 \n\t"
    75.                 "S32I.N %0, %1, 28 \n\t"
    76.                 : : "r"(j), "r"(ptr));
    77.         __asm__ __volatile__("memw" : : : "memory");
    78.         GET_CCOUNT(t2);
    79.         //t2=get_ccount();
    80.         ets_intr_unlock();
    81.         ets_uart_printf(" 8 writes: time= %d\n", calcdelta(t1, t2));
    82.         os_delay_us(100000);
    83.  
    84.         ptr=(uint32_t *)SPI_W0(HSPI);
    85.         __asm__ __volatile__("memw" : : : "memory");
    86.         ets_intr_lock();
    87.         GET_CCOUNT(t1);
    88.         //t1=get_ccount();
    89.         __asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
    90.                 "S32I.N %0, %1, 4 \n\t"
    91.                 "S32I.N %0, %1, 8 \n\t"
    92.                 "S32I.N %0, %1, 12 \n\t"
    93.                 "S32I.N %0, %1, 16 \n\t"
    94.                 "S32I.N %0, %1, 20 \n\t"
    95.                 "S32I.N %0, %1, 24 \n\t"
    96.                 "S32I.N %0, %1, 28 \n\t"
    97.                 "S32I.N %0, %1, 32 \n\t"
    98.                 "S32I.N %0, %1, 36 \n\t"
    99.                 "S32I.N %0, %1, 40 \n\t"
    100.                 "S32I.N %0, %1, 44 \n\t"
    101.                 "S32I.N %0, %1, 48 \n\t"
    102.                 "S32I.N %0, %1, 52 \n\t"
    103.                 "S32I.N %0, %1, 56 \n\t"
    104.                 "S32I.N %0, %1, 60 \n\t"
    105.                 : : "r"(j), "r"(ptr));
    106.         __asm__ __volatile__("memw" : : : "memory");
    107.         GET_CCOUNT(t2);
    108.         //t2=get_ccount();
    109.         ets_intr_unlock();
    110.         ets_uart_printf("16 writes: time= %d\n\n", calcdelta(t1, t2));
    111.         os_delay_us(100000);
    112.     }
    113.     while (--i);
    114.     ets_uart_printf("\n--------\n");
    115. }
    Дизассеблер:
    Код (Text):
    1. __asm__ __volatile__("memw" : : : "memory");
    2. 40100f9e:    0020c0            memw
    3.         ets_intr_lock();
    4. 40100fa1:    fd2c01            l32r    a0, 40100454 <ets_timer_arm_new+0xd0>
    5. 40100fa4:    0000c0            callx0    a0
    6.         GET_CCOUNT(t1);
    7. 40100fa7:    03ea30            rsr.ccount    a3
    8.         //t1=get_ccount();
    9.         __asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
    10. 40100faa:    0128          l32i.n    a2, a1, 0
    11. 40100fac:    02c9          s32i.n    a12, a2, 0
    12. 40100fae:    12c9          s32i.n    a12, a2, 4
    13. 40100fb0:    22c9          s32i.n    a12, a2, 8
    14. 40100fb2:    32c9          s32i.n    a12, a2, 12
    15. 40100fb4:    42c9          s32i.n    a12, a2, 16
    16. 40100fb6:    52c9          s32i.n    a12, a2, 20
    17. 40100fb8:    0662c2            s32i    a12, a2, 24
    18. 40100fbb:    72c9          s32i.n    a12, a2, 28
    19.                 "S32I.N %0, %1, 20 \n\t"
    20.                 "S32I.N %0, %1, 24 \n\t"
    21.                 "S32I.N %0, %1, 28 \n\t"
    22.                 : : "r"(j), "r"(ptr));
    23.         //__asm__ __volatile__("memw" : : : "memory");
    24.         GET_CCOUNT(t2);
    25. 40100fbd:    03ead0            rsr.ccount    a13
    Результаты
    Код (Text):
    1. --------
    2.     without MEMW
    3. 8 writes: time= 17
    4. 16 writes: time= 70
    5.     with MEMW
    6. 8 writes: time= 47
    7. 16 writes: time= 96
    8.  
    9.     without MEMW
    10. 8 writes: time= 17
    11. 16 writes: time= 70
    12.     with MEMW
    13. 8 writes: time= 47
    14. 16 writes: time= 96
    15.  
    16.     without MEMW
    17. 8 writes: time= 17
    18. 16 writes: time= 70
    19.     with MEMW
    20. 8 writes: time= 47
    21. 16 writes: time= 96
    22.  
    23.     without MEMW
    24. 8 writes: time= 17
    25. 16 writes: time= 70
    26.     with MEMW
    27. 8 writes: time= 47
    28. 16 writes: time= 96
    29.  
    30. --------
    Чем предлагаете компилить после выкидывания UDK ????
    Использование спираченного компилера в открытом проекте абсолютно неприемлемо.
    У xtensa компилятора есть бесплатные варианты ?

    Наверно это потому что смещение задается в коде. Было бы в регистре - все было бы в порядке. А оптимизатор на уровне Arm процессоров никто писать не хочет.

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


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

    pvvx Активный участник сообщества

    Сообщения:
    10.169
    Симпатии:
    1.347
    Другой версией сборки GCC, не из комплекта UDK. :)

    А какова разница (время) межу двумя 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- ре кратности адреса и не ясно что это такое...
     
    Последнее редактирование: 26 апр 2015
  3. sharikov

    sharikov Авторитетный участник сообщества

    Сообщения:
    604
    Симпатии:
    52
    Обеими руками за! А где другую сборку берут ?

    Код (C):
    1.  
    2.     ets_intr_lock();
    3.      GET_CCOUNT(t1);
    4.      GET_CCOUNT(t2);
    5.      ets_intr_unlock();
    6.      ets_uart_printf("GET_CCOUNT: time= %d\n", calcdelta(t1, t2));
    7.  
    GET_CCOUNT: time= 1

    Автоматическое управление flash отключено - я выполняю тест после инициализации hspi для работы с mcp2515.
    Проверил двойное обращение к младшим 8 регистрам вместо 16-ти.
    код:
    Код (C):
    1. __asm__ __volatile__("S32I.N %0, %1, 0 \n\t"
    2.                 "S32I.N %0, %1, 4 \n\t"
    3.                 "S32I.N %0, %1, 8 \n\t"
    4.                 "S32I.N %0, %1, 12 \n\t"
    5.                 "S32I.N %0, %1, 16 \n\t"
    6.                 "S32I.N %0, %1, 20 \n\t"
    7.                 "S32I.N %0, %1, 24 \n\t"
    8.                 "S32I.N %0, %1, 28 \n\t"
    9.  
    10.                 "S32I.N %0, %1, 0 \n\t"
    11.                 "S32I.N %0, %1, 4 \n\t"
    12.                 "S32I.N %0, %1, 8 \n\t"
    13.                 "S32I.N %0, %1, 12 \n\t"
    14.                 "S32I.N %0, %1, 16 \n\t"
    15.                 "S32I.N %0, %1, 20 \n\t"
    16.                 "S32I.N %0, %1, 24 \n\t"
    17.                 "S32I.N %0, %1, 28 \n\t"
    18. /*
    19.                 "S32I.N %0, %1, 32 \n\t"
    20.                 "S32I.N %0, %1, 36 \n\t"
    21.                 "S32I.N %0, %1, 40 \n\t"
    22.                 "S32I.N %0, %1, 44 \n\t"
    23.                 "S32I.N %0, %1, 48 \n\t"
    24.                 "S32I.N %0, %1, 52 \n\t"
    25.                 "S32I.N %0, %1, 56 \n\t"
    26.                 "S32I.N %0, %1, 60 \n\t"
    27.                 */
    28.                 : : "r"(j), "r"(ptr));
    Результат не изменился.
    Еще хочу попробовать обращение только к старшим регистрам и обращение в обратном порядке.
    Задержку до выставление прерывания вы убрали ? Может она нужна ? Потому что очень странный бит, возможно завязан на dma и обмен с памятью.
     
  4. pvvx

    pvvx Активный участник сообщества

    Сообщения:
    10.169
    Симпатии:
    1.347
    Ошибка как всегда была связана с глюками 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 работает плотно....
    Вообще всё в наглую:
    Код (C):
    1.  
    2.             SPI0_ADDR = faddr | (blksize << 24);
    3.             SPI0_CMD = SPI_READ;
    4.             while(SPI0_CMD);
    5.             uint32 *srcdw = (uint32 *)(SPI0_BASE+0x40);
    6.             while(blksize >> 2) {
    7.                 *((uint32 *)des) = *srcdw++;
    8. ...
    9.  
    Даже без volatile :) у указателя на буфер.
    В конечном коде между ожиданиями безусловно перенес и вставил код который возможно было туда перенести, чтобы сократить время исполнения процедуры...
    Буфер SPI вообще лучше описать как сегмент.
    Уже писал самый простой метод:
    Задать массив или переменную по спец.адресу можно только путем объявления в ld или лезть в Makefile
    и добавлять: ld --section-start=rtc_mem_section=0x60001100
    для: unsigned int rtc_mem[192] __attribute__ ((section ("rtc_mem_section")));

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

    CHERTS Moderator Команда форума

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

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

    pvvx Активный участник сообщества

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

    CHERTS Moderator Команда форума

    Сообщения:
    483
    Симпатии:
    108
    Все, что я вставляю в UDK идет по открытым лицензиям и я обязательно указываю авторов оригинальных исходников/репозитарии в changelog. Никакого плагиата тут нет, если Вы намекаете на это.
     
  8. pvvx

    pvvx Активный участник сообщества

    Сообщения:
    10.169
    Симпатии:
    1.347
    Описал в eagle.app.v6.ld segment .io3 и с UDK:
    Код (C):
    1. volatile uint32 spi1_buf[16] __attribute__ ((section (".io3.spi")));
    2. /*
    3.         spi1_buf[3] = i;
    4. 4010008d:    0020c0           memw
    5. 40100090:    3ef9         s32i.n    a15, a14, 12
    6.         spi1_buf[4] = i;
    7. 40100092:    0020c0           memw
    8. 40100095:    4ef9         s32i.n    a15, a14, 16
    9.  
    10.  
    11. Pointer spi1_buf: 0x60000140
    12.  8 writes: time= 59
    13.  16 writes: time= 108
    14.  
    15.  
    16. 401000e3:    cef9         s32i.n    a15, a14, 48
    17.         spi1_buf[13] = i;
    18. 401000e5:    def9         s32i.n    a15, a14, 52
    19.         spi1_buf[14] = i;
    20. 401000e7:    eef9         s32i.n    a15, a14, 56
    21.  
    22. Pointer spi1_buf: 0x60000140
    23.  8 writes: time= 21
    24.  16 writes: time= 63  */
    25. void __attribute__((optimize("O2"))) write_test(uint32_t i)
    26. {
    27.     uint32_t t1, t2;
    28.     ets_uart_printf("\n--------\n");
    29.     ets_delay_us(100000);
    30.     do    {
    31.         ets_uart_printf("Pointer spi1_buf: %p\n", spi1_buf);
    32.         ets_delay_us(100000);
    33.         ets_intr_lock();
    34.         GET_CCOUNT(t1);
    35.         spi1_buf[0] = i;
    36.         spi1_buf[1] = i;
    37.         spi1_buf[2] = i;
    38.         spi1_buf[3] = i;
    39.         spi1_buf[4] = i;
    40.         spi1_buf[5] = i;
    41.         spi1_buf[6] = i;
    42.         spi1_buf[7] = i;
    43.         spi1_buf[8] = i;
    44.         GET_CCOUNT(t2);
    45.         ets_intr_unlock();
    46.         ets_uart_printf(" 8 writes: time= %d\n", calcdelta(t1, t2));
    47.         ets_delay_us(100000);
    48.         ets_intr_lock();
    49.         GET_CCOUNT(t1);
    50.         spi1_buf[0] = i;
    51.         spi1_buf[1] = i;
    52.         spi1_buf[2] = i;
    53.         spi1_buf[3] = i;
    54.         spi1_buf[4] = i;
    55.         spi1_buf[5] = i;
    56.         spi1_buf[6] = i;
    57.         spi1_buf[7] = i;
    58.         spi1_buf[8] = i;
    59.         spi1_buf[9] = i;
    60.         spi1_buf[10] = i;
    61.         spi1_buf[11] = i;
    62.         spi1_buf[12] = i;
    63.         spi1_buf[13] = i;
    64.         spi1_buf[14] = i;
    65.         spi1_buf[15] = i;
    66.         GET_CCOUNT(t2);
    67.         ets_intr_unlock();
    68.         ets_uart_printf(" 16 writes: time= %d\n", calcdelta(t1, t2));
    69.     }
    70.     while (--i);
    71.     ets_uart_printf("\n--------\n");
    72. }
     
  9. jcmvbkbc

    jcmvbkbc Читатель

    Сообщения:
    179
    Симпатии:
    17
    Это потому что базовый адрес -- константа в этой же функции. Передайте его как параметр в функцию или получите его вызовом не-inline функции -- и всё будет ок:
     
  10. pvvx

    pvvx Активный участник сообщества

    Сообщения:
    10.169
    Симпатии:
    1.347
    Ничего подобного.
    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.
     
    Последнее редактирование: 27 апр 2015
  11. sharikov

    sharikov Авторитетный участник сообщества

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

    pvvx Активный участник сообщества

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

    Вложения:

    • SpiFlash.zip
      Размер файла:
      2,4 КБ
      Просмотров:
      13
    Последнее редактирование: 27 апр 2015
  13. sharikov

    sharikov Авторитетный участник сообщества

    Сообщения:
    604
    Симпатии:
    52
    Ниже все цифры при частоте процессора 80МГц.
    Протестировал чтение на ассемблере.
    Итак имеем: все обращения к обоим блокам SPI и GPIO идут с частотой 26MHz, на запись есть фифо предположительно глубиной 8 обращений. Запись в фифо производится за 2 такта, если фифо заполнено - за 6 тактов. Сброс фифо происходит по команде memw или по его заполнению.
    С чтением печальнее. Фифо себя никак не проявляет и чтение всегда выполняется вдвое медленнее записи - за 12 тактов.

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

    pvvx Активный участник сообщества

    Сообщения:
    10.169
    Симпатии:
    1.347
    Я исходную не дореверсил - там лажово сделано - транслятор накрутил зигзагов... но в принципе там обычное чтение spi_wx в цикле и закидывание в память, всё dword-ами, а между ними куча вычислений какой следующий и надо ли его читать (неоптимальный код - по тому и не стал переписывать)...
    Сделал по своему, чтобы был доступ хоть по байтный и по любому нечетному адресу (void *dest кароче и без ограничения по размеру flash из её заголовка - для больших flash до 16M, в остальном отличий от ROM-BIOS-ной функции нет) :
    Код (C):
    1.  
    2. /******************************************************************************
    3. * FunctionName : spi_flash_read
    4. * Description  : чтение массива байт из flash
    5. *              читает из flash по QSPI блоками по SPI_FBLK байт
    6. *              в ROM-BIOS SPI_FBLK = 32 байта, 64 - предел SPI буфера
    7. * Parameters   : flash Addr, pointer, кол-во
    8. * Returns      : SpiFlashOpResult 0 - ok
    9. * Опции gcc: -mno-serialize-volatile !
    10. *******************************************************************************/
    11. #define SPI_FBLK 32
    12. SpiFlashOpResult __attribute__((optimize("O3"))) spi_flash_read(uint32 faddr, void *des, uint32 size)
    13. {
    14.     if(des == NULL) return SPI_FLASH_RESULT_ERR;
    15.     if(size != 0) {
    16.         faddr <<= 8; faddr >>= 8; //    faddr &= (1 << 24) - 1; //    if((faddr >> 24) || ((faddr + size) >> 24)) return SPI_FLASH_RESULT_ERR;
    17.         Cache_Read_Disable();
    18.         Wait_SPI_Idle(flashchip);
    19.         uint32 blksize = (uint32)des & 3;
    20.         if(blksize) {
    21.             blksize = 4 - blksize;
    22.             if(size < blksize) blksize = size;
    23.             SPI0_ADDR = faddr | (blksize << 24);
    24.             SPI0_CMD = SPI_READ;
    25.             size -= blksize;
    26.             faddr += blksize;
    27.             while(SPI0_CMD);
    28.             register uint32 data_buf = SPI0_W0;
    29.             do {
    30.                 *(uint8 *)des = data_buf;
    31.                 des = (uint8 *)des + 1;
    32.                 data_buf >>= 8;
    33.             } while(--blksize);
    34.         }
    35.         while(size) {
    36.             if(size < SPI_FBLK) blksize = size;
    37.             else blksize = SPI_FBLK;
    38.             SPI0_ADDR = faddr | (blksize << 24);
    39.             SPI0_CMD = SPI_READ;
    40.             size -= blksize;
    41.             faddr += blksize;
    42.             while(SPI0_CMD);
    43.             uint32 *srcdw = (uint32 *)(&SPI0_W0);
    44.             while(blksize >> 2) {
    45.                 *((uint32 *)des) = *srcdw++;
    46.                 des = ((uint32 *)des) + 1;
    47.                 blksize -= 4;
    48.             }
    49.             if(blksize) {
    50.                 uint32 data_buf = *srcdw;
    51.                 do {
    52.                     *(uint8 *)des = data_buf;
    53.                     des = (uint8 *)des + 1;
    54.                     data_buf >>= 8;
    55.                 } while(--blksize);
    56.                 break;
    57.             }
    58.         }
    59.         Cache_Read_Enable(0, 0, 1);
    60.     }
    61.     return SPI_FLASH_RESULT_OK;
    62. }
    Оптимизировано под UDK транслятор. В моем SDK работает и всё к ней обращается из либ оставшихся кусков Espressif SDK, проверено кароче. Скорость отдачи Web сервера увеличилась.
     
    Последнее редактирование: 27 апр 2015
  15. pvvx

    pvvx Активный участник сообщества

    Сообщения:
    10.169
    Симпатии:
    1.347
    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 - нет
     
    Последнее редактирование: 28 апр 2015
  16. pvvx

    pvvx Активный участник сообщества

    Сообщения:
    10.169
    Симпатии:
    1.347
    @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

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

    pvvx Активный участник сообщества

    Сообщения:
    10.169
    Симпатии:
    1.347
    Никто не пробовал работать с 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_"...().
     

Поделиться этой страницей