TurboSPI Dueтово

marth
Offline
Зарегистрирован: 24.09.2019

Стоит задача с максимально высокой скоростью снимать показания с 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 через буфер 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Ну правильно, DMA же запрограммировать надо, вот и пауза. 

Нужно быстро, работайте без библиотек, напрямую с контроллером SPI. ДМА не обязателен, он же не ускоряет, просто CPU освобождает. В вашем случае при частоте процессора 84МГц пихать или получать данные из буфера контроллера со скоростью 2МГц не должно быть проблемой. 

b707
Онлайн
Зарегистрирован: 26.05.2017

Если читаете результаты по одному - вы никогда не получите хорошей скорости. Нужно настроить ацп на работу в пакетном режиме и принимать данные по прерыванию

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

b707 пишет:
Если читаете результаты по одному - вы никогда не получите хорошей скорости. Нужно настроить ацп на работу в пакетном режиме и принимать данные по прерыванию

А вот и нефига если говорить чисто о скорости приема/передачи. Прочитать флаг готовности это быстрее чем входить и выходить в/из прерывания. Так что опрос быстрее прерываний, но тогда ничего другого делать не получается, так что  общая производительность падает. 

Да и с пакетным режимом вопрос - Насколько это подходит для ADC?  Если весь пакет это 2 байта, то смысла с ним возиться нет. 

marth
Offline
Зарегистрирован: 24.09.2019

Не очень хотелось углубляться в прямой доступ к контролеру SPI, но может прийдется )

Любопытно, что родная библиотека тоже может работать через буфер, и делает это заметно быстрее TurboSPI. Но что за огромная пауза между send и receive?

SPI.transfer(10, g_Buffer, sizeof(g_Buffer), SPI_CONTINUE);

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

marth пишет:

Не очень хотелось углубляться в прямой доступ к контролеру SPI, но может прийдется )

Любопытно, что родная библиотека тоже может работать через буфер, и делает это заметно быстрее TurboSPI. Но что за огромная пауза между send и receive?

SPI.transfer(10, g_Buffer, sizeof(g_Buffer), SPI_CONTINUE);

 

Надо лезть в код библиотеки и разбираться.

marth
Offline
Зарегистрирован: 24.09.2019

Смотрел, но пока мало понятно. Еще любопытно, что родная библиотека SPI  у меня нормально работает с дивайдером 2, а TurboSPI только с дивайдером 4 (иногда 3). Провода одинаковые :)