SPI с DMA в Arduino Due

У меня есть проект, в котором мне нужно хранить данные (~ 16 месяцев) в памяти и иметь возможность быстро извлекать данные (<36000 бит/с) с помощью DMA, поскольку у меня есть другие сигналы, о которых нужно заботиться.

>

В настоящее время я использую SD-карту с библиотекой SD, но, похоже, она не использует DMA из-за задержки между отправкой.

Многие люди говорили мне, что это не должно быть так уж сложно, и я так думаю. Я предполагаю, что я не могу правильно настроить DMA и/или SPI.

Я давно пробовал кое-что: Отправить данные через SPI с DMA

Может ли кто-нибудь показать мне пример SPI с DMA или советы по настройке обоих.

Еще раз спасибо

, 👍-1


1 ответ


0
#include <dmac.h>
#include <SPI.h>
#include <Arduino.h>
#include <sam.h>

uint8_t sourceBuffer[256];

void setup() {
  SPI.begin();
  SPI.setClockDivider(21);  // тактовая частота 4 МГц (при условии, что системная тактовая частота 84 МГц)
  setupDMA();
}

void loop() {

  for(int i = 0; i < sizeof(sourceBuffer); i++) {
    sourceBuffer[i] = i;
  }
  startDMATransfer();
  delay(1000);
}

void setupDMA() {
  // Включаем контроллер DMA
  PMC->PMC_PCER1 |= PMC_PCER1_PID34;  // Идентификатор DMA для срока — 34

  // Отключаем SPI DMA TX и RX
  SPI0->SPI_PTCR = SPI_PTCR_RXTDIS | SPI_PTCR_TXTDIS;

  // Настраиваем канал DMA для передачи (в данном примере канал 1)
  DmacChannel* channel = &(DMAC->DMAC_CH_NUM[1]);

  // Отключаем канал DMA
  channel->DMAC_CHDR = DMAC_CHDR_DIS;

  // Очистим все флаги и сбросим статус
  channel->DMAC_CHDR = DMAC_CHDR_RES;

  // Устанавливаем указатели источника и назначения
  channel->DMAC_SADDR = (uint32_t) sourceBuffer;
  channel->DMAC_DADDR = (uint32_t) &(SPI0->SPI_TDR);

  // Настраиваем указатели источника и назначения: источник увеличивается, пункт назначения нет
  channel->DMAC_CTRLA = DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;

  // Устанавливаем рукопожатие источника и назначения (связанное с SPI0 Tx)
  channel->DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR_FETCH_DISABLE | DMAC_CTRLB_DST_DSCR_FETCH_DISABLE |
                        DMAC_CTRLB_FC_MEM2PER_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING |
                        DMAC_CTRLB_DST_INCR_FIXED;

  channel->DMAC_CFG = DMAC_CFG_SRC_PER(1) | DMAC_CFG_DST_PER(1) | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG;
}

void startDMATransfer() {
  // Предполагаем, что используется канал 1
  DmacChannel* channel = &(DMAC->DMAC_CH_NUM[1]);

  // Устанавливаем размер буфера
  channel->DMAC_CUBC = sizeof(sourceBuffer);

  // Включаем SPI DMA для TX
  SPI0->SPI_PTCR = SPI_PTCR_TXTEN;

  // Включаем канал DMA, чтобы начать передачу
  channel->DMAC_CHER = DMAC_CHER_ENA;
}

Если вы хотите отправить данные через SPI с использованием DMA, вы можете заполнить sourceBuffer и вызвать startDMATransfer().

Не забывайте всегда обращаться к техническому описанию Atmel SAM3X8E и схеме Arduino Due, когда вы работаете на этом уровне, поскольку они предоставляют подробную информацию о том, как работает оборудование. Я не могу запустить код или протестировать его. Но я считаю, что логика кода правильная. Обработка ошибок зависит от вас.

,