TurboSPI Dueтово
- Войдите на сайт для отправки комментариев
Стоит задача с максимально высокой скоростью снимать показания с ADC ADS8688 (максимально 500 kHz).
Родной SPI с дивайдером 3 (2 не позволяют провода), дает скорость считывания 5.5uS. TurbоSPI c с побайтовой передачей дает 3.5mS.
Мне необходимо вначале передать 2 байта, и затем снять 2 байта. Заснял процесс осциллографом, видно что в реализации протоколов есть паузы ~1uS между передачей байтов. В TurboSPI есть возможность передавать байты через DMA буфер, без пауз. Все бы хорошо, но при этом вначале передачи возникает пауза длиной ~1.5uS, которая в моем случае сводит на нет результат (получается хуже чем при побайтовой передаче).
Есть ли возможность как то увеличить скорость считывания?
Родной SPI
#include "SPI.h" int result ; void setup() { SPI.begin(10); SPI.setDataMode(10, SPI_MODE1); SPI.setClockDivider(10, 3); SPI.setBitOrder(10, MSBFIRST); Serial.begin(115200); SPI.transfer16(10, 0xD800); SPI.transfer16(10, 0x0000); } void loop() { SPI.transfer16(10, 0x0000, SPI_CONTINUE); // start Ch0 sampling result = SPI.transfer16(10, 0x0000); // get Ch0 conversion Serial.print("RESULT ="); Serial.println(result) ; Serial.print('\n'); delay(1000); }
TurboSPI c побайтовой передачей
//For TurboSPI: #include <TurboSPI.h> TurboSPI g_SPI; DigitalPin g_PinCS, g_PinRS; byte g_Buffer[2]; // some data buffer to transfer byte g_Divisor = 3; // transfer speed set to MCU's clock divide by 2 unsigned long t = 0; int _cs = 27; int result ; void setup() { // setup pins REG_PIOB_PER |= 1 << (_cs); //PIO enable REG_PIOB_OER |= 1 << (_cs); //output enable // setup SPI REG_PIOB_SODR |= 1 << (_cs); Serial.begin(115200); g_SPI.Begin(); g_SPI.Init(g_Divisor); // init ads input REG_PIOB_CODR |= 1 << (_cs); g_SPI.Send(0xD8); g_SPI.Send(0x00); REG_PIOB_SODR |= 1 << (_cs); REG_PIOB_CODR |= 1 << (_cs); g_SPI.Send(0x00); g_SPI.Send(0x00); REG_PIOB_SODR |= 1 << (_cs); } void loop() { REG_PIOB_CODR |= 1 << (_cs); //Buffer Transfer // g_SPI.Send(g_Buffer, sizeof(g_Buffer)); //Bytes transfer g_SPI.Send(0x00); g_SPI.Send(0x00); byte MSB = g_SPI.Receive(); byte LSB = g_SPI.Receive(); result = (MSB << 8) | LSB; REG_PIOB_SODR |= 1 << (_cs); Serial.print("RESULT ="); Serial.println(result) ; Serial.print('\n'); delay(1000); }
TurboSPI c Send через буфер
Ну правильно, DMA же запрограммировать надо, вот и пауза.
Нужно быстро, работайте без библиотек, напрямую с контроллером SPI. ДМА не обязателен, он же не ускоряет, просто CPU освобождает. В вашем случае при частоте процессора 84МГц пихать или получать данные из буфера контроллера со скоростью 2МГц не должно быть проблемой.
Если читаете результаты по одному - вы никогда не получите хорошей скорости. Нужно настроить ацп на работу в пакетном режиме и принимать данные по прерыванию
А вот и нефига если говорить чисто о скорости приема/передачи. Прочитать флаг готовности это быстрее чем входить и выходить в/из прерывания. Так что опрос быстрее прерываний, но тогда ничего другого делать не получается, так что общая производительность падает.
Да и с пакетным режимом вопрос - Насколько это подходит для ADC? Если весь пакет это 2 байта, то смысла с ним возиться нет.
Не очень хотелось углубляться в прямой доступ к контролеру SPI, но может прийдется )
Любопытно, что родная библиотека тоже может работать через буфер, и делает это заметно быстрее TurboSPI. Но что за огромная пауза между send и receive?
Не очень хотелось углубляться в прямой доступ к контролеру SPI, но может прийдется )
Любопытно, что родная библиотека тоже может работать через буфер, и делает это заметно быстрее TurboSPI. Но что за огромная пауза между send и receive?
Надо лезть в код библиотеки и разбираться.
Смотрел, но пока мало понятно. Еще любопытно, что родная библиотека SPI у меня нормально работает с дивайдером 2, а TurboSPI только с дивайдером 4 (иногда 3). Провода одинаковые :)