El DMA se maneja con una prioridad fija o una secuencia round-robing, por lo tanto comienza desde el canal 1 si es que esta round-robing.
DMAPriorityOrder simplemente hace un cambio de prioridades, dejando siempre al primer argumento con mayor prioridad ( menor canal ).
Por lo tanto la idea es que dmaSPI0rx tenga la mayor prioridad en el DMA, el codigo por si lo buscas:
void DMAPriorityOrder(DMAChannel &ch1, DMAChannel &ch2)
{
if (priority(ch1) < priority(ch2)) swap(ch1, ch2);
}
static uint32_t priority(const DMAChannel &c)
{
return 3 - c.channel;
}
La funcion enableDMAPreemption hace que aquellas transferencias habilitadas, puedan ser interrumpidas por otra transferencia de mayor prioridad, suponete que tenes el UpdateTimer transfiriendose y se da el disparo del SPI, entonces dejaria lo que estaba haciendo para atender el del SPI
----------------
// Habilitar solicitud de drenaje FIFO DMA (Enable FIFO Drain Request DMA)
SPI0_RSER = SPI_RSER_RFDF_RE | SPI_RSER_RFDF_DIRS;
dmaSPI0rx = new DMAChannel();
dmaSPI0rx->source((volatile uint16_t&) SPI0_POPR);
Esa parte del codigo, lo que hace al editar el registro SPI0_RSER, es habilitar primero la interrupcion al momento que el buffer del SPI ( que posee 4 lugares ) no este lleno. Y luego ademas le dice que no genere una interrupcion sino que genere una solicitud al DMA.
Finalmente crea el objeto DMA que posee toda la informacion ( descriptor ) y le dice donde sacar el dato, que es atraves del registro SPI0_POPR en cual funciona como un stack, donde haces un POP del buffer del SPI y vas sacando de a bytes.
--------------------------------------
// Flush the receive buffer, in case we're out of sync
SPI0_MCR |= SPI_MCR_HALT;
SPI0_MCR |= SPI_MCR_CLR_RXF;
Basicamente detiene cualquier transferencia del SPI (TX,RX) y hace un flush de los buffer de Recepcion, limpiando tambien los contadores de cantidad de datos que poseen.
Pero si esta configurado como modo continuo entonces no hace nada.
--------------------------------------
Como bien dice, Resetea la trnasferencia.
// Reset the DMA transfer
dmaSPI0rx->disable();
dmaSPI0rx->clearComplete();
dmaSPI0rx->destinationBuffer(plane_buffer, ROW_LENGTH * sizeof(uint16_t)); // ORIGINAL
dmaSPI0rx->enable();
Deshabilita, Si habia terminado, limpia el flag de completo del descriptor, asi le permite cargar nuevamente la cantidad a enviarse.
Le agrega la direccion de destino, y la cantidad de veces a repetir el mismo traslado de 1 byte.
Y finalmente lo habilita nuevamente.
------------------------------------------------------------------------
A lo que yo apunto es que Supongamos que tenes un SPI perfecto, Y este es tu esclavo. Partimos de la suposicion de que llega todo correctamente, es edcir desde el primer bit al ultimo enviado al SPI. Entonces apenas llegue el primer byte, este va a pasar a la FIFO del SPI, el flag va a indicar que no esta vacio, por lo tanto va a disparar el DMA, el DMA toma el byte y lo lleva a su correspondiente direccion Y listo...
Ves, todo es por "bytes", entonces el unico momento que se me ocurre que pueda ocurrir