need help with K20 DMA ADC config emulating flexible scan mode

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

need help with K20 DMA ADC config emulating flexible scan mode

1,882 Views
brintonengineer
Contributor III

I'm referencing Application Note AN4590 to add high speed sampling and hardware channel scan on a K20 (specifically MK20DX128VLH5 on the FRDM-K20D50M dev board). However, I also need PDB hardware triggering of the ADC for my low-jitter DSP application.

I can get the PDB to trigger the ADC and, provided I disable ADC DMA and enable ADC INT, I can read analog data. But when I disable ADC INT and enable ADC DMA I get a PDB sequence error interrupt (PDB0_CH0S = 0x10001). The reference manual says:

When one conversion, which is triggered by one of the pre-triggers from PDB channel n, is in progress, new trigger from PDB channel's corresponding pre-trigger m cannot be accepted by ADCn, and ERR[m] is set.

So, it sounds like the COCO flag is not getting cleared. In my DMA configuration, I cannot see why DMA is not clearing the ADC after copy. Any help is appreciated!

DMA Initialization:

void dma_adc_init(uint8_t *chan_list, uint32_t num_chan, uint16_t *results, uint32_t results_size)

{

  printf("Initializing DMA\r\n");

  /* Enable Error Interrupts on Ch0 and Ch1. */

  DMA_CERR = 0x40;

  DMA_EEI |= DMA_EEI_EEI0_MASK | DMA_EEI_EEI1_MASK;

  /****************************************************************************

  * Setup Transfer Control Descriptor #0 (Channel List to ADC)

  ***************************************************************************/

  

  DMAMUX0_CHCFG0 = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(54); // DMA

  /* Source and data destination both 8-bits long. */

  DMA_TCD0_ATTR = DMA_ATTR_SSIZE(0x00) | DMA_ATTR_DSIZE(0x00);

  /* DMA_TCD0_SADDR = chan_list */

  DMA_TCD0_SADDR = (uint32_t)&chan_list[0];                            

  DMA_TCD0_NBYTES_MLNO = 1;

  DMA_TCD0_SOFF = 1;

  DMA_TCD0_SLAST = (uint32_t)-((int32_t)(num_chan));

  /* DMA_TCD0_DADDR = adc_buffer */

  DMA_TCD0_DADDR = (uint32_t) &ADC0_SC1A;

  DMA_TCD0_DOFF = 0;

  DMA_TCD0_DLASTSGA = 0;

  /* Ch0 Major iteration count. */

  DMA_TCD0_BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(num_chan);

  DMA_TCD0_CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(num_chan);

  /* Don't link to another channel. Don't generate interrupt. This DMA gets

    called when Ch1 finishes indicating that the ADC results have been

  copied to memory. This DMA copies the next ADC settings to the ADC

  status-control register. */

  DMA_TCD0_CSR = 0;

  

  /****************************************************************************

  * Setup Transfer Control Descriptor #1 (ADC -> Memory)

  ***************************************************************************/

  

  DMAMUX0_CHCFG1 = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(40); // ADC0

  /* Source and data destination both 16-bits long. */

  DMA_TCD1_ATTR = DMA_ATTR_SSIZE(0x01) |

                  DMA_ATTR_DSIZE(0x01);

  /* DMA_TCD0_SADDR = adc_buffer2 */

  DMA_TCD1_SADDR = (uint32_t) &ADC0_RA;

  DMA_TCD1_NBYTES_MLNO = 2;

  DMA_TCD1_SOFF = 0;

  DMA_TCD1_SLAST = 0;

  /* DMA_TCD0_DADDR = adc_buffer */

  DMA_TCD1_DADDR = (uint32_t) &results[0];

  DMA_TCD1_DOFF = 2;

  DMA_TCD1_DLASTSGA = (uint32_t)-((int32_t)(results_size));

  /* Link to Ch0 on major iteration. */

  DMA_TCD1_BITER_ELINKYES = DMA_BITER_ELINKYES_ELINK_MASK |

                           DMA_BITER_ELINKYES_LINKCH(0x0) |

  DMA_BITER_ELINKNO_BITER(results_size/sizeof(uint16_t));

  DMA_TCD1_CITER_ELINKYES = DMA_CITER_ELINKYES_ELINK_MASK |

   DMA_CITER_ELINKNO_CITER(results_size/sizeof(uint16_t));

  /* Don't link to another channel. Don't generate interrupt. This DMA gets

    called when Ch1 finishes indicating that the ADC results have been

  copied to memory. This DMA copies the next ADC settings to the ADC

  status-control register. */

  DMA_TCD1_CSR = DMA_CSR_MAJORELINK_MASK |

  DMA_CSR_MAJORLINKCH(0) |

  DMA_CSR_INTHALF_MASK |

  DMA_CSR_INTMAJOR_MASK;

  /* Enable DMA Ch1. */

  DMA_ERQ |= DMA_ERQ_ERQ1_MASK;

}

and the main() function:

int main(void)

{

  cpu_init();

  pta_init();

  ptc_init();

  ptd_init();

  uart0_init();

  printf("\r\n\n\n" "Digital Signal Processor Firmware Version " FW_VERSION_ "\r\n");

  print_uuid();

  print_reset_status();

  SysTick_Init();

  ftfl_init();

  ftm0_init();

  pit_init();

  vref_init();

  pdb_init(50000); /// totally slow for debugging

  printf("Initializing RAM...\r\n");

  memset(adc_buffer, 0, sizeof(adc_buffer));

  memset(res_buffer, 0, sizeof(res_buffer));

  memset(out_buffer, 0, sizeof(out_buffer));

  adc_init();

  dma_adc_init(uc_adc_mux, sizeof(uc_adc_mux)/sizeof(uc_adc_mux[0]), adc_buffer, sizeof(adc_buffer));

  printf("Starting ADC sampling (sample rate 100kHz)\r\n");

  pdb_trigger();

  while(1) { delay_ms(1000); print_time(); }

}

ADC Initialization:

void adc_init(void)

{

  printf("Initializing ADC\r\n");

  /* Use PDB for hardware trigger. */

  SIM_SOPT7 = 0;

  /* Set ADC clocks. */

  ADC0_CFG1 = ADC_CFG1_ADIV(0x01) | ADC_CFG1_MODE(0x03) | ADC_CFG1_ADICLK(0x02);

  ADC0_CFG2 = ADC_CFG2_ADHSC_MASK | ADC_CFG2_ADLSTS(0x03);                      

  /* No compare nor offset values. */

  ADC0_CV1 = ADC_CV1_CV(0x00);                                  

  ADC0_CV2 = ADC_CV2_CV(0x00);                                  

  ADC0_OFS = ADC_OFS_OFS(0x00);

  /* Set to software trigger for now. After calibration we'll change it back

    to hardware and trigger on PDB. Enable DMA. */

  ADC0_SC2 = ADC_SC2_DMAEN_MASK | ADC_SC2_REFSEL(0x00);

  ADC0_SC2 = ADC_SC2_REFSEL(0x00);

 

  /* Disable hardware averaging. Disable ADC continuous conversion - multiple

    triggers from PDB. */

  ADC0_SC3 = ADC_SC3_AVGS(0x00);

  // Start Calibration

  printf("Calibrating ADC...\r\n");

  ADC0_SC3 |= ADC_SC3_CAL_MASK;

  // Wait for calibration to finish

  while( (ADC0_SC1A & ADC_SC1_COCO_MASK ) == ADC_SC1_COCO_MASK );

  

  if ((ADC0_SC3 & ADC_SC3_CALF_MASK) == ADC_SC3_CALF_MASK )

  {

  printf("Calibration failed!\r\n");

  }

  // switch to hardware trigger

  ADC0_SC2 |= ADC_SC2_ADTRG_MASK;

  /* Set the channel mux for A trigger. */

  ADC0_SC1A = ADC_SC1_ADCH(0x00);

}

Programmable Delay Block Initialization:

void pdb_init(uint16_t period)

{

  printf("Initializing Programmable Delay Block (PDB)\r\n");

  /* Software trigger, error interrupts enabled, continuous mode. */

  PDB0_SC = PDB_SC_LDMOD(0x00) |

           PDB_SC_PDBEIE_MASK |

            PDB_SC_PRESCALER(0x8) |

            PDB_SC_TRGSEL(0xF) |

           PDB_SC_PDBIE_MASK |

            PDB_SC_MULT(0x3) |

           PDB_SC_CONT_MASK;

  /* Set the PDB modulus. */

  PDB0_MOD = period;

  /* Disable PDB Interrupt Delay (i.e. don't generate interrupt). */

  PDB0_IDLY = PDB_IDLY_IDLY(0xFFFF);

  /* Pretriggers 0 and 1 are both enabled. */

  PDB0_CH0C1 = PDB_C1_BB(0x00) | PDB_C1_TOS(0x03) | PDB_C1_EN(0x03);             

  /* Clear channel flags. Clear channel sequence error flags. */

  PDB0_CH0S = PDB_S_CF(0x00) | PDB_S_ERR(0xFF);  

  /* Channel 0 delay. */

  PDB0_CH0DLY0 = PDB_DLY_DLY(period/2);

  PDB0_CH0DLY1 = PDB_DLY_DLY(0xFFFF);

  /* Start module. */

  PDB0_SC |= PDB_SC_PDBEN_MASK | PDB_SC_LDOK_MASK;

  // NOTE: We're not using the Pulse-Out module.

}

0 Kudos
3 Replies

551 Views
Kan_Li
NXP TechSupport
NXP TechSupport

Hi JD,

The coco flag would be clear when the respective SC1n register is written or when the respective Rn register is read. so there is only one DMA channel needed to copy the Rn register to memory, and the coco flag would be cleared automatically after the DMA transfer.

Hope that helps,

B.R

Kan

0 Kudos

551 Views
brintonengineer
Contributor III

Found a typo in code:

  ADC0_SC2 = ADC_SC2_DMAEN_MASK | ADC_SC2_REFSEL(0x00);

  ADC0_SC2 = ADC_SC2_REFSEL(0x00);

DMA interrupt is now being called. However, I can't seem to get more than 512 bytes to copy in a single Major Loop. When setting the iteration to 512 and DLASTSGA to -1024 I get DMA errors:

  DMA_TCD1_DLASTSGA = (uint32_t)-1024;

  /* Link to Ch0 on major iteration. */

  DMA_TCD1_BITER_ELINKYES = DMA_BITER_ELINKYES_ELINK_MASK | DMA_BITER_ELINKYES_LINKCH(0x0) | DMA_BITER_ELINKNO_BITER(512);

  DMA_TCD1_CITER_ELINKYES = DMA_CITER_ELINKYES_ELINK_MASK | DMA_CITER_ELINKNO_CITER(512);

Is there a fundamental limit to how much memory can be copied? I see in the K20 family reference manual "Crossbar-Light switch integration" figure that there are TWO SRAM controllers (controller_L and controller_U). How are these configured? Can I take advantage of this to improve system bandwidth? Is this what is limiting the Major Loop size?

Thank you,

JD

0 Kudos

551 Views
Kan_Li
NXP TechSupport
NXP TechSupport

Hi JD,

For a channel link enabled configuration, the BITER and CITER only have 9 bit field, so the max allowable count is 0x1FF(511).

Hope that helps,

B.R

Kan

0 Kudos