Generación de forma de onda XMega con DMA y USART

1

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.

    
pregunta Billysugger

0 respuestas

Lea otras preguntas en las etiquetas