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

не работают потоковые операции spi0

Тема в разделе "Realtek - SDK, прошивки и утилиты", создана пользователем sharikov, 31 мар 2017.

  1. sharikov

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

    Сообщения:
    580
    Симпатии:
    52
    spi_master_write работает а все потоковые как interrupt так dma - нет.

    Код (C):
    1. // SPI0 (S0)
    2. #define SPI0_MOSI  PC_2
    3. #define SPI0_MISO  PC_3
    4. #define SPI0_SCLK  PC_1
    5. #define SPI0_CS    PC_0
    6.  
    7. volatile uint8_t MasterRxDone, MasterTxDone;
    8. spi_t spi_master;
    9.  
    10. void master_tr_done_callback(void *pdata, SpiIrq event)
    11. {
    12.     switch(event){
    13.     case SpiRxIrq:
    14.         //DBG_8195A("Master RX done!\n");
    15.         MasterRxDone = 1;
    16.         break;
    17.     case SpiTxIrq:
    18.         //DBG_8195A("Master TX done!\n");
    19.         MasterTxDone = 1;
    20.         break;
    21.     default:
    22.         DBG_8195A("unknown interrput evnent!\n");
    23.     }
    24. }
    25.  
    26. /* выбор устройства
    27. * ss_code - код для дешифратора,
    28. */
    29. void spi0_slave_select(const uint8_t ssn)
    30. {
    31.     uint8_t ss_code;
    32.     switch (ssn)
    33.     {
    34.     case 0:
    35.         ss_code = 127;
    36.         break;
    37.     case 1:
    38.         ss_code = ~1;
    39.         break;
    40.     case 2:
    41.         ss_code = ~(1<<4);
    42.         break;
    43.     case 3:
    44.         ss_code = ~((1<<4) | 1);
    45.         break;
    46.     case 4:
    47.         ss_code = ~(1<<5);
    48.         break;
    49.     default :
    50.         ss_code = 127;
    51.     }; // switch
    52.     // код CS_x
    53.     // допустимый диапазон cs_code 1...0xff, если 0 - SPI зависает
    54.     // *(volatile uint32_t*)(SSI0_REG_BASE + REG_DW_SSI_SER) = ss_code;  // задаем код слэйва (лучше использовать HAL_SSI_WRITE32())
    55.     HAL_SSI_WRITE32(0, REG_DW_SSI_SER, ss_code);
    56.  
    57. }
    58.  
    59. static void spi0_hw_configure(void)
    60. {
    61.     char* buff;
    62.     int32_t length;
    63.     int32_t c;
    64.  
    65.     ConfigDebugInfo |= _DBG_SSI_;
    66.  
    67.     spi_init(&spi_master, SPI0_MOSI, SPI0_MISO, SPI0_SCLK, SPI0_CS); // CS заданный тут нигде не используется
    68.     spi_format(&spi_master, 16, 0, 0);
    69.     spi_frequency(&spi_master, 200000);
    70.  
    71.     // нужен только чтобы включить SPI0_MULTI_CS_EN в регистре SPI_MUX_CTRL,
    72.     // число любое от 2 до 7
    73.     //spi_slave_select(&spi_master, 2);
    74.  
    75.     buff = pvPortMalloc(256);
    76.     c=0;
    77.     do {
    78.         //spi0_slave_select(c & 7);
    79.         MasterTxDone = 0;
    80.         //length= spi_master_write(&spi_master, c);
    81.         spi_irq_hook(&spi_master, master_tr_done_callback, (uint32_t)&spi_master);
    82.         spi_master_write_stream(&spi_master, buff, 160);
    83.         while(MasterTxDone == 0) {
    84.             //wait_ms(10);
    85.         }
    86.  
    87.         rtl_printf("Master write: %d\n", c);
    88.         c++;
    89.     }
    90.     while (1);
    91.  
    92.     free(buff);
    93. }
    Код (Text):
    1. ===== Enter SRAM-Boot 1 ====
    2. CPU CLK: 83333333 Hz, SOC FUNC EN: 0x20211113
    3. Img Sign: RTKWin, Go @ 0x1000607d
    4. ===== Enter Image: tp6_rtl ====
    5. [SSI  Inf]SystemClock: 166666666
    6. [SSI  Inf]MaxSsiFreq : 20833333
    7. [SSI  Inf]ssi_peri: 2049, ssi_idx: 0, ssi_pinmux: 1
    8. [SSI  Inf]spi_frequency: Set SCLK Freq=200320
    9. Init Heap Region: 0x10003000[12288]
    10. Init Heap Region: 0x100460f8[171784]
    11. [SSI  Inf]HalSsiIntWriteRtl8195a: Idx=0, RxData=0x10003008, Len=0xa0
     
  2. pvvx

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

    Сообщения:
    8.760
    Симпатии:
    1.284
  3. sharikov

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

    Сообщения:
    580
    Симпатии:
    52
    Вопрос почему не работает.
    spi_bus_tx_done_irq не вызывается, передача не начинается
    потоковые операции с spi вообще кто-нибудь тестировал на свежем Sdk ? (они там были отключены)

    есть подозрение что не работают прерывания от spi, но проверить не успел
     
  4. pvvx

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

    Сообщения:
    8.760
    Симпатии:
    1.284
    А зачем прерывания вообще при работе с SPI без DMA?
    Выполнилась процедура передачи/приема - значит данные приняты/переданы. После неё и ставьте свой код.
    По какой причине должен отрабатывать калбак на конец DMA, если DMA не используется? :confused:
     
  5. pvvx

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

    Сообщения:
    8.760
    Симпатии:
    1.284
    Вспомнил. Там только по прерываниям и работает Hal SPI в SDK.
    В Arduino Ameba и возникает ошибка, если дать команду передачи блока, а CS там "ногодрыгом", в классическом стиле Arduino... :)
    Пришлось добавить while(spi_busy((spi_t *)pSpiMaster));
    Код (C):
    1. void SPIClass::transfer(byte _pin, void *_buf, size_t _count, SPITransferMode _mode)
    2. {
    3.     if (_pin != pinSS) {
    4.         pinMode(_pin, OUTPUT);
    5.         digitalWrite(_pin, 0);
    6.     }
    7.     spi_master_write_stream( (spi_t *)pSpiMaster , (char *)_buf, (uint32_t)_count );
    8.     while(spi_busy((spi_t *)pSpiMaster));
    9.     if (_pin != pinSS && _mode == SPI_LAST) {
    10.         digitalWrite(_pin, 1);
    11.     }
    12. }
    А в Ameba Arduino это так и не исправлено... Дуринщинкам всё равно всё пофиг.
     
  6. pvvx

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

    Сообщения:
    8.760
    Симпатии:
    1.284
    Всё работает:
    ATSSI (раскрыть)
    Код (C):
    1. /*
    2.  * spi_test.c
    3.  */
    4. #include <platform_opts.h>
    5. #include "rtl8195a.h"
    6. #include "spi_api.h"
    7. #include "spi_ex_api.h"
    8. #include "rtl8195a/rtl_libc.h"
    9.  
    10. #define atoi(str)    prvAtoi(str)
    11.  
    12. #define SPI0_MOSI  PC_2
    13. #define SPI0_MISO  PC_3
    14. #define SPI0_SCLK  PC_1
    15. #define SPI0_CS    PC_0
    16.  
    17. spi_t spi_master;
    18.  
    19. void fATSSI(int argc, char *argv[])
    20. {
    21.     int len = 128;
    22.     int count = 32;
    23.     int clk = 1000000;
    24.     int ssn = 0;
    25.     if(argc > 1) {
    26.         len = atoi(argv[1]);
    27.         if(len > 32768 || len <= 0) {
    28.             len = 128;
    29.             error_printf("%s: len = %u!\n", __func__, len);
    30.         };
    31.     };
    32.     if(argc > 2) {
    33.         count = atoi(argv[2]);
    34.         if(count > 10000 || count <= 0) {
    35.             count = 32;
    36.             error_printf("%s: count = %u!\n", __func__, count);
    37.         };
    38.     };
    39.     if(argc > 3) {
    40.         clk = atoi(argv[3]);
    41.         if(clk <= 0) {
    42.             clk = 1000000;
    43.             error_printf("%s: clk = %u!\n", __func__, clk);
    44.         };
    45.     };
    46.     if(argc > 4) {
    47.         ssn = atoi(argv[4]);
    48.         if(ssn > 7 || ssn < 0) {
    49.             ssn = 0;
    50.             error_printf("%s: ssn = %u!\n", __func__, ssn);
    51.         };
    52.     };
    53.     char* buff = pvPortMalloc(len);
    54.     if(buff) {
    55.         spi_init(&spi_master, SPI0_MOSI, SPI0_MISO, SPI0_SCLK, SPI0_CS); // CS заданный тут нигде не используется
    56.         spi_format(&spi_master, 16, 0, 0);
    57.         spi_frequency(&spi_master, clk);
    58.           spi_slave_select(&spi_master, ssn);
    59.           for(int i = 0; i < len; i++) buff[i] = (char)i;
    60.         while(count--) {
    61.             spi_master_write_stream(&spi_master, buff, len);
    62.             while(spi_busy(&spi_master));
    63.             rtl_printf("Master write: %d\n", count);
    64.         };
    65.         spi_free(&spi_master);
    66.         free(buff);
    67.     }
    68.     else {
    69.         error_printf("%s: error malloc!\n", __func__);
    70.     }
    71. }
    72.  
    73. MON_RAM_TAB_SECTION COMMAND_TABLE console_commands_spitst[] = {
    74.         {"ATSSI", 0, fATSSI, "[len[,count[,clk[,ssn]]]]: Spi test"}
    75. };
     
    Последнее редактирование: 1 апр 2017
  7. sharikov

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

    Сообщения:
    580
    Симпатии:
    52
    После старта rtos работает, до старта - нет.

    Однако работу с spi придется писать "с нуля" по ДШ. Сейчас spi_master_write_stream передает блок кусочками размером transfer size с передергиванием CS между ними.
    Например хотим передать одиночный блок 4 байта:
    spi_format(&spi_master, 16, 0, 0);
    spi_master_write_stream(&spi_master, buff, 4);
    выдаст 2 пакета по 16 бит. А нужно 1 пакет 32 бита.

    Причем беда как в mbed api так и на уровне hal.
    mbed api заполняет не все поля структур hal;
    hal недоделан, например не для всех вариантов заполняется регистр CTRL1
     
    Последнее редактирование: 3 апр 2017
  8. pvvx

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

    Сообщения:
    8.760
    Симпатии:
    1.284
    Ну и правильно. Как иначе то?
    Вы же сказали ему, что размерность 16 бит. Он и передает по 16 бит с CS.
    Как-бы с VGA там сложнее, крутили разные варианты на API - всё работало. Там одно но - не задать циклические буфера, чтобы вечно и без паузы крутился.
    С DMA CS ведет себя правильно. Без DMA SPI мне не нужен. Попробуйте на SPI1...
    Мульти CS на SPI0 ведет себя не так, как хотелось бы и изменить это никак...
    И почему используете только режимы spi_format(&spi_master, 16, 0, 0) и без DMA?

    Там RTL8710 VGA Driver CS нормально формируется. Но пока, после сокращения размеров буферов не удалось убрать дрожание - привязку к синхро. Когда работают оба SPI и непрерывно, лопатя на выход ненужные фреймы синхронизации, то их синхронность как-то держится. Когда один SPI работет с перерывом, выдавая CS, то синхронность обоих SPI нарушается - бьет от времени старта загрузки регистров, отвлекаясь на другие задачи, а приоритеты всех прерываний, WiFi и прочего в SDK не изменить (очень долго и надо всё переписывать, а толку от этого может быть мало, т.к. бьет (дрожит) на десятки тактов CPU...).
     
    Последнее редактирование: 3 апр 2017
  9. pvvx

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

    Сообщения:
    8.760
    Симпатии:
    1.284
    Если spi_format(&spi_master, 16, 3, 0), то CS ставиться на блок.
    atssi 16 1 0 2
    Снимок1348.gif
    В spi_format(&spi_master, 16, 1, 0) - тоже CS только на блок
    В spi_format(&spi_master, 16 или 32, 0 или 2, 0) - CS каждые 16 бит, spi_format(&spi_master, 8, 0 или 2, 0) - каждые 8.
     
    Последнее редактирование: 3 апр 2017
  10. sharikov

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

    Сообщения:
    580
    Симпатии:
    52
    Поменял на DMA: абсолютно то же что по прерываниям.

    Разрывы пропадают если задать
    spi_format(&spi_master, X, 1, 0) или spi_format(&spi_master, X, 3, 0);
    Размер посылки X не имеет значения, dma или прерывания тоже не имеет значения.

    Читаю интеловский ДШ: не вижу возможности передавать длинные блоки без разрывов при аппаратном CS. Разве что какими нибудь ухищрениями явно не описанными в ДШ (так оно и получается на практике).
     
  11. pvvx

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

    Сообщения:
    8.760
    Симпатии:
    1.284
    В описании к ARM вообще 4..16 бит и CS -> ARM Information Center
     
  12. nkly

    nkly Новичок

    Сообщения:
    24
    Симпатии:
    1
    Как в RtlDuino сделать чтобы SS не дёргался при передаче двух блоков по 8 бит?

    spi_format(&spi_master, X, 1, 0) spi_format(&spi_master, X, 3, 0); не помогает.
     

    Вложения:

  13. nkly

    nkly Новичок

    Сообщения:
    24
    Симпатии:
    1
    Вот так почему-то 15 вывод не дергается?
     

    Вложения:

  14. sharikov

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

    Сообщения:
    580
    Симпатии:
    52
    При передаче именно двух блоков SS обязан дергаться. Передавайте один блок 16 бит.

    Должен дергаться. Проверьте не занят ли порт куда выведен 15 вывод.


    ---
    SPI ужасен, хуже я еще не встречал. Менеджерам которые закупили именно этот IP блок гореть в аду!
    Не предусмотрено прерывание по окончанию передачи (флаг SSI Busy), есть только прерывания по состоянию fifo. Без прерывания по окончанию передачи невозможна эффективная передача раздельных пакетов. В HAL опрашивают флаг в цикле в прерывании. В прерывании, Карл! Писателям HAL гореть в аду вот за это:
    Код (C):
    1. VOID _SsiWriteInterruptRtl8195a(VOID *Adapter)
    2. ...
    3.         HalSsiSetInterruptMaskRtl8195a((VOID*)pHalSsiAdapter);
    4.         for (i=0;i<1000000;i++) {          
    5.             bus_busy = HAL_SSI_READ32(Index, REG_DW_SSI_SR) & BIT_SR_BUSY;
    6.             if (!bus_busy) {
    7.                 break;  // break the for loop
    8.             }
    9.         }
    10.  
    11.         // If it's not a dummy TX for master read SPI, then call the TX_done callback
    12.         if (pHalSsiAdapter->TxData != NULL) {
    13.             if (pHalSsiAdapter->TxIdleCallback != NULL) {
    14.                 pHalSsiAdapter->TxIdleCallback(pHalSsiAdapter->TxIdleCbPara);
    15.             }
    16.         }
    17.      
    18.         return;
    Для чтения небольших блоков данных (например показания ацп) проще использовать gpio и не связываться с кошмарным SPI вовсе.
     
    Последнее редактирование: 5 апр 2017
  15. pvvx

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

    Сообщения:
    8.760
    Симпатии:
    1.284
    А меня устраивает - всё что подключал изумительно работает.
    Наверно пытаетесь подойти как в 8-ми битных MCU и писать всё сами, через регистры ногодрыгом без DMA, а с учетом RTOS...
    Это задержка по причине того, что точно до такта, прерывания и защелку FIFO пользователь не задает, с учетом и частоты CPU и SPI, и приоритетов прерываний.
    Сделано то это исключительно для тупых пользователей перед вызовом пользовательского калбака. :) Вдруг пользователь туда коммутацию CS впишет ногодрыгом?
    Изменение там числа от 100 до 1000000 не влияет на более сложных задачах...
    Ставьте правильно регистры SPI - задержка ожидания передачи последних бит и не потребуется.
    Возьмите HAL и примеры от Intel D2000 - там ещё прикольнее - SPI и DMA те-же..
     
    Последнее редактирование: 6 апр 2017
  16. sharikov

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

    Сообщения:
    580
    Симпатии:
    52
    Что именно вы подключали ?
    Подключение к шине SPI множества слэйвов с раздельными CS реализовывали ?
    Гнать непрерывный битстрим и адресно общаться с множеством устройств на шине - разные задачи.

    Эту задержку некуда задавать: в блоке spi не так много регистров чтобы что-то пропустить. Кроме того задержку в тактах процессора точно вычислить нельзя - она плавает.
    Вы случаем не путаете SSI и SPIC ? Мы о первом разговариваем.

    Именно коммутацию CS и требуется выполнить. Только не ногодрыгом а через регистр SER с использованием MULTU CS.
    Чтобы работал MULTU CS регистр SER нужно обновлять в состоянии Idle а его определить можно только опросом регистра статуса. Финиш!
    Хотелось переключать в прерывании чтобы работало быстро.
    Подобную тему поднимал kissste 30 декабря прошлого года [SPI DMA and toggling CS], решения нет.

    Также API не позволяет перезапустить spi из callback - ругается [SSI Wrn]spi_master_write_and_read_stream: state(0x2) is not ready.
    Пришлось завести семафор и запускать spi обмен в основном потоке, это занимает 24 микросекунды или более в зависимости от работы планировщика rtos при том что данные для обмена заранее подготовлены. Древний AVR передаст быстрее а тут процессор на 160MHz.

    Пример: используется spi0, тактовая spi 200kHz (нужна низкая частота)
    подключено 3 шт. M25P10, cs подключены на SPI0_CS0 - SPI0_CS2.
    Требуется быстро прочитать STATUS REGISTER у всех трех. Ограничение: "чужой" трафик и лишние байты на чипы не гнать, т.е прочитали ровно то что требуется и переключили CS на следующий чип.
    Обмен spi: CS(n)=Low [0x05 0x00 0x00 IN] CS(n)=High, n=0...2

    Что-то не ищутся примеры на D2000. То что есть на форумах обычный ардуино стиль без всяких dma с ручным ногодрыгом cs.
     
  17. pvvx

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

    Сообщения:
    8.760
    Симпатии:
    1.284
    Подключал ADC типа AD7176 и ещё наверно буду другие.
    Нет - не путаю. Не задержка, а счетчики в FIFO до срабатывания прерывания.
    Про то и разговор - никто не использует в процессорах общего применения специфические функции контроллеров. Если хотите их использовать - сначала изучите. А то разводите нытьё, вместо решения.
    Вам показал, что в разных режимах контроллера по разному срабатывают CS.
    C мульти-CS, почему написал не очень - при включении используются все линии CS выходящие из чипа и на них всех происходят переключения при активации- деактивации SPI с включенным мульти-CS.
     
    Последнее редактирование: 6 апр 2017
  18. pvvx

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

    Сообщения:
    8.760
    Симпатии:
    1.284
    M25P10A поддерживает режим 0 и 3. В режиме 3 и использовании имеющегося HAL CS выставляется как надо для M25P10A - блоками.
    Есть 3 калбака - по окончанию передачи блока (мульти-блочном DMA), полного окончания передачи, конца приема. Что ещё то надо? :confused:
     
  19. pvvx

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

    Сообщения:
    8.760
    Симпатии:
    1.284
    А ещё более древние i386ex - дергают ножками портов быстрее, чем любой современный 8-ми головый i7 на 4 ГГц :)
    i7 сравним по этому с i8086 на 10 MГц.
    Такие вот сравнения у вас.
    Это может значить одно - не справились с задачей - не тот контроллер поставили, не ту ОС используете, не того разработчика выбрали :) Ставьте AVR. :)
    Лично для вас, макетка, из того века (1995г вроде) для теста скорости "ногодрыга":
    Снимок1351.jpg
    Представляете, даже в ВыньXP вывод в порт (пусть LPT), сопровождается переключением уровня привилегий до дна у процов cГГц-ами, а затем передачи параметров драйверу, с полными объявами невалидности всех кешей (пару накопленных мегабайт в утиль). Далее, через шину PCI, запрос пойдет (на старых мамках Intel) в аппаратный эмулятор контроллера ISA шины, тактируемый 14 МГц и на это время все процессы встанут от поставленного на ней сигнала READY (пока не описали новую процессорную шину и PCI :) с отложенными транзакциями)… А тот-же i386ex дергает портом с частотой своей шины :)
    Это аналог вашего сравнения с AVR. :)
     
    Последнее редактирование: 6 апр 2017
  20. Simon

    Simon Новичок

    Сообщения:
    37
    Симпатии:
    1
    Пытаюсь запустить с rtl синхронизирующий сигнал 200кгц(шим, 50% заполнение). Попробовал использовать CLK от SPI0(передаю что угодно, беру CLK как нужный мне шим). Чтобы не было пропусков синхронизации(CLK работал непрерывно), запускаю передачу заново по "прерыванию окончания передачи".

    Проблема:
    Как только входит в обработчик, в консоли сообщение:
    RTL8195A[HAL]: ISR 0 had been allocated!!!
    И wifi падает. Видимо, почему-то используется какое-то прерывание, которое нужно wifi. SPI0 при этом работает, как я хочу.

    Делаю так:
    1) обработчик прерываний привязываю через spi_irq_hook()
    2) в обработчике прерываний использую условие if (event == SpiTxIrq) (прерывание по концу передачи)
    3) запускаю передачу через spi_master_write_stream_dma

    Пробовал по образцу pvvx в теме VGA
    https://esp8266.ru/forum/threads/rtl8710-vga-driver.1914/#post-33439

    использовать упрощенную spi_master_write_stream_dma2 и запреты прерываний в обработчике (portDISABLE_INTERRUPTS();), не помогло.

    Как сохранить работающий wifi? Или может есть другой, не съедающий ресурсов способ генерировать 200кгц, 50% duty?
     
    Последнее редактирование: 24 май 2018

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