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). Провода одинаковые :)