Mise en oeuvre d'un DMA

Présentation du DMA RX62N

L'utilisation d'un DMA lors d'un projet de développement sur microcontroleur est parfois fastidieuse et longue. Cependant, ce périphérique permet d'exploiter toute la puissance du microcontroleur. Dans le cas précis du RX62N, un DMA Controller est disponible, possédant lui même 4 canaux. Ces canaux permettent le transfert de données de manières bien différentes:
  • Le mode bloc (1 activation = transfert de X octets)
  • Le mode répété
  • Le mode simple

Exemple de démonstration proposé

Il est proposé ici de développer un code de démarrage simple, utilisant le DMA en mode répétition, sur source de déclenchement de type interruption. Concrètement, il s'agit d'effectuer l'acquisition de données analogique, via le convertisseur analogique/numérique, à cadence fixée par un timer. Un transfert est effectué automatiquement vers une zone de données en RAM, contenant 640 points. Cela illustre l'utilisation faite dans l'oscilloscope.

Code source associé


// The destination of the data acquired
unsigned short dma_data[640];

// DMA channel 0 interrupt - activated when 640 x 16bits have been transfered
#pragma interrupt (ISR_DMAC0 (vect=198, enable))
void ISR_DMAC0()
{
  DMAC0.DMCNT.BIT.DTE = 1; //Enable channel    
}

// Entry point
void main()
{
  Config_ADC();
  Config_TMR();
  Config_DMA();

  while (true);
}

// Configuration of analog to digital converter
void Config_ADC()
{
  SYSTEM.MSTPCRA.BIT.MSTPA22 = 0;        // Enable AD1 module
  AD1.ADCSR.BIT.ADIE = 0;             // No interrupts
  AD1.ADCSR.BIT.CH = 0;             // AN4 in continuous scan mode 
  AD1.ADCR.BIT.MODE = 2;             // Continuous scan mode
  AD1.ADCR.BIT.CKS = 3;             // Clock Select PCLK
  AD1.ADCR.BIT.TRGS = 0;            // Conversion starts by software
  AD1.ADDPR.BIT.DPSEL = 0;            // LSB padding
  AD1.ADCSR.BIT.ADST = 1;             // Start AD1    
}

// Configuration of timer (CMT2 module)
void Config_TMR()
{
  MSTP(CMT2) = 0;
  CMT2.CMCOR = 18750/2; // Sampling frequency : 640Hz 
  CMT2.CMCR.BIT.CKS = 0; // Divide PCLK by 8 - 6MHz
  CMT.CMSTR1.BIT.STR2 = 1;
}

// Configuration of the DMA
void Config_DMA()
{
  // Power on DMA module
  MSTP(DMACA) = 0;

  // Timer CMT2 will enable a transfert    
  ICU.DMRSR0 = 30;

  // Transfert from ADC - AN4    
  DMAC0.DMSAR = (void*)&AD1.ADDRA;

  // Transfert to RAM data - an array
  DMAC0.DMDAR = (void*)dma_data;

  // Transfert 640 x 16bits    
  DMAC0.DMCRA = (640<<16) + 640;

  DMAC0.DMCRB = 0;

  DMAC0.DMTMD.BIT.MD = 1; //Repeat mode
  DMAC0.DMTMD.BIT.DTS = 0; //Destination is the repeat area
  DMAC0.DMTMD.BIT.SZ = 1; //16 bits transfert
  DMAC0.DMTMD.BIT.DCTG = 1; //Interrupts are the transfert clock

  DMAC0.DMAMD.BIT.SM = 0; //Source is fixed - AN4
  DMAC0.DMAMD.BIT.SARA = 0;
  DMAC0.DMAMD.BIT.DM = 2; //Destination is incremented
  DMAC0.DMAMD.BIT.DARA = 0;

  DMAC0.DMCSL.BIT.DISEL = 0;

  DMAC0.DMINT.BIT.RPTIE = 1; // Repeat end interrupt enabled
  DMAC0.DMINT.BIT.ESIE = 1; // Repeat end interrupt enabled
  _IEN(_DMACA_DMAC0I) = 1; // Enable interrupt
  _IPR( _DMACA_DMAC0I ) = 6; // Priority

  DMAC.DMAST.BIT.DMST = 1; //DMA Module Enabled    
  DMAC0.DMCNT.BIT.DTE = 1; //Enable channel

  // Enable TMR interrupt
  CMT2.CMCR.BIT.CMIE = 1;    
  _IEN( _CMT2_CMI2 ) = 1; // Enable interrupt    
}