En tu línea de escaneo interrumpe donde tienes:
// Then write first DMA words. Successive words requested by SPI module.
// TODO: offset DMA by one word, or we will get duplicates. OR, just write
// a null word first... Whichever is easiest/best.
SPI2BUF = scanline_level_out_dma[0];
SPI1BUF = scanline_mask_out_dma[0];
Sólo hay que poner DMAxCONbits.FORCE = 1
antes de habilitar el canal DMA y forzará el primer byte tan pronto como se habilite el canal DMA.
También puedes configurar tus canales de lectura ficticios en modo continuo (en lugar de un solo disparo) con un búfer de 1 palabra e iniciarlos cuando arranques e ignorar la interrupción, sin necesidad de volver a pensar en ellos después.
En tu ejemplo de DMA todavía tienes definidas las interrupciones SPI:
/**
* _SPI1Interrupt: Primary ISR for SPI1.
*
* Only clears interrupt flag at the moment.
*/
void _MY_ISR _SPI1Interrupt()
{
uint16_t nullread;
nullread = SPI1BUF;
nullread = SPI2BUF;
IFS0bits.SPI1IF = 0;
}
Creo que esto todavía se llama cuando el DMA está habilitado a menos que deshabilites la interrupción de la CPU, es decir, tanto el controlador DMA como la CPU responden a la interrupción.
Esto parece repetir el trabajo del canal de lectura DMA y encima es lento (basta con usar una variable global en lugar de una de pila en un ISR como este). También puede estar bloqueando tu transferencia, no sé si el controlador DMA reiniciaría la interrupción mientras la CPU estuviera en un manejador para esa interrupción.
¡Aquí está lo de impar! Si lo hago usando una rutina de bucle continuamente escribiendo en el registro SPI, no hay ¡no hay huecos!
Esto es peligroso sin comprobar el SPIxIF, bien podrías estar garbando lo que sale y tus bytes de prueba harían que eso fuera realmente difícil de encontrar.
EDIT : Con tu reloj SPI siendo sólo 1/7 de tu reloj de instrucción necesitas ser muy cuidadoso en el manejador de interrupción de arriba para borrar SPI1IF ASAP o simplemente deshabilitarlo todo junto y dejar que el controlador DMA lo maneje. Para conseguir que no haya ningún hueco tienes menos de 7 ciclos de instrucción para sacar la siguiente palabra de la unidad SPI. Creo que tienes que deshabilitar completamente la intervención de la CPU y dejar que el controlador DMA se encargue de ello para tener alguna posibilidad, pero incluso entonces tienes 2 transferencias DMA y cualquier latencia de activación que haya desde el SPI -> DMA (es 1 reloj de instrucción para que el SPIxIF se dispare, por ejemplo). Así que va a estar cerca.
0 votos
Pon tu código.
0 votos
@Leon Mi código es largo, pero lo he pegado aquí para DMA: pastebin.com/FRzp77EN y aquí para los que no son DMA: pastebin.com/CF1QvaCB
0 votos
¿cuál es la velocidad de instrucción del PIC, cuál es la velocidad del reloj SPI y cuánto duran los intervalos?
0 votos
@Mark DsPIC = ~36,85 MHz, SPI = ~5-6 MHz.
1 votos
Asegúrate de no tener un arbitraje de bus que bloquee tu DMA. (Es decir, si la CPU está usando el mismo bus que el DMA necesita usar para obtener datos de la RAM al SPI, entonces el DMA puede verse forzado a esperar a la CPU, perdiendo su tiempo, si la CPU tiene una mayor prioridad en el bus o tiene un "modo de ráfaga" que le permite varios ciclos de bus seguidos antes de la rearbitración).