Estoy usando un Atmel XMEGA128A4U.
Necesito generar una forma de onda digital de alta velocidad con una sobrecarga mínima de la CPU, y configurar un USART para generar la forma de onda y DMA para transferir datos de una tabla al registro de transmisión de USART en segundo plano.
Todo funciona bien, excepto que el primer byte de la tabla es transmitido repetidamente por el USART. El contador de la dirección de origen parece rechazar el incremento.
He revisado cuidadosamente la hoja de datos varias veces. He intentado todo tipo de órdenes de inicialización diferentes, y he agregado cheques para restablecer y ocupado a pesar de que otros ejemplos de DMA en línea parecen no incluirlos. Puedo hacer que DMA funcione correctamente con ambos punteros incrementando en una prueba de copia de RAM. He revisado la errata para el micro y no se menciona nada sobre ningún error de silicona.
¿Alguien puede detectar lo que me he perdido?
/*******************************************************************************
Function Name : dma_out
Description : Initiates background memory write to port
Input : pointer to char source data
: length of block in bytes
: number of blocks to repeat (0 for continual transfer)
Output : None
Return : None
*******************************************************************************/
void dma_out (char *source, unsigned short len, unsigned char rep)
{
// Enable DMA, no double buffering, round robin
DMA.CTRL = 0x80;
// Enable channel for configuration
DMA.CH2.CTRLA = 0x80;
DMA.CH2.CTRLB = 0x00;
// Reset chnnel
DMA.CH2.CTRLA = 0xC0;
while ((DMA.CH2.CTRLA & 0x40) != 0) // wait for reset complete
{
}
// Set source and destination addresses
DMA.CH2.SRCADDR0 = (char)((int)source);
DMA.CH2.SRCADDR1 = (char)((int)source >> 8);
DMA.CH2.SRCADDR2 = 0x00;
DMA.CH2.DESTADDR0 = (char)((int)&USARTC0_DATA);
DMA.CH2.DESTADDR1 = (char)((int)&USARTC0_DATA >> 8);
DMA.CH2.DESTADDR2 = 0x00;
// Wait while channel busy before setting ADDCTRL
while ((DMA.CH2.CTRLB & 0x80) != 0)
{
}
DMA.CH2.ADDRCTRL = 0x50; // inc source and reload each block, dest fixed
// Set block length and repeat count
DMA.CH2.TRFCNT = len;
DMA.CH2.REPCNT = rep;
DMA.CH2.CTRLA |= 0x20; // Set repeat bit only after REPCNT loaded
DMA.CH2.TRIGSRC = 0x4C; // trigger on USARTC0_DRE
DMA.CH2.CTRLA |= 0x40; // Trigger transfer
}
PS. No, no uso ASF, o una notación similar.