AFEC with XDMAC

Go To Last Post
2 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi all. There is a problem with cyclic data transmission from AFEC to the clipboard. AFEC is run from the timer and reads the 3 channels. The program given below.

/** The buffer size for transfer  */
#define AFEC0_BUFFER_SIZE          3

/** XDMAC channel HW Interface number for AFEC0. */
#define AFEC0_XDMAC_CH_NUM  35

/** XDMAC channel configuration. */
static xdmac_channel_config_t xdmac_AFEC0_channel_cfg;

static uint32_t ADC_DATA_READYCount=0;
static uint32_t AFEC_END_RXBUF0Count=0;

void InitAFEC(void)
{
 tc_set_writeprotect(afec_tc_ptr,false);
 afec_set_writeprotect(AFEC0,false); 
 uint32_t ul_div;
 uint32_t ul_tcclks;
 uint32_t ul_sysclk;

 /* Get system clock. */
 ul_sysclk = sysclk_get_cpu_hz();
 

 pmc_enable_periph_clk(afec_tc_id);   
 tc_find_mck_divisor(AI_ScanFreq, ul_sysclk, &ul_div, &ul_tcclks, ul_sysclk);
 uint32_t afec_C=ul_sysclk / (ul_div*AI_ScanFreq);
 uint32_t afec_A=afec_C/2;
 tc_init(afec_tc_ptr, afec_tc_channel, ul_tcclks | TC_CMR_WAVE |TC_CMR_WAVSEL_UP_RC |TC_CMR_ACPA_SET|TC_CMR_ACPC_CLEAR);
 
 tc_write_ra(afec_tc_ptr, afec_tc_channel, afec_A);
 tc_write_rc(afec_tc_ptr, afec_tc_channel, afec_C);
 pio_set_peripheral(PIOA,PIO_PERIPH_B,1<<26);
 NVIC_EnableIRQ((IRQn_Type)afec_tc_id); 
 NVIC_SetPriority((IRQn_Type)afec_tc_id, AFEC_Timer_IRQ_level);
 tc_enable_interrupt(afec_tc_ptr, afec_tc_channel, TC_IER_COVFS);
 
 
 afec_enable(AFEC0);
 struct afec_config afec_cfg;
 afec_cfg.resolution = AFEC_16_BITS;  
 afec_cfg.mck = sysclk_get_cpu_hz();
 afec_cfg.afec_clock = 40000000UL;    //40 МГц
 afec_cfg.startup_time = AFEC_STARTUP_TIME_7; 

 
 afec_cfg.tracktim = 15;  //Tracking Time 
 afec_cfg.transfer = 3;  //Transfer Period 
 afec_cfg.anach = true;  //Analog Change 
 afec_cfg.useq = false;  //Use Sequence Enable
 afec_cfg.tag = false;  //16 bit buffer
 afec_cfg.stm = true;  //Single Trigger Mode
 afec_cfg.ibctl = 1;   //AFE Bias Current Control
 
 
 afec_init(AFEC0, &afec_cfg);
 
 struct afec_ch_config afec_ch_cfg;
 afec_ch_cfg.diff=false;     
 afec_ch_cfg.gain = AFEC_GAINVALUE_1; 

 
 afec_ch_set_config(AFEC0, AFEC_CHANNEL_0, &afec_ch_cfg); 
 afec_ch_set_config(AFEC0, AFEC_CHANNEL_6, &afec_ch_cfg); 
 afec_ch_set_config(AFEC0, AFEC_CHANNEL_8, &afec_ch_cfg); 
 
 afec_channel_set_analog_offset(AFEC0, AFEC_CHANNEL_0, 0x200); 
 afec_channel_set_analog_offset(AFEC0, AFEC_CHANNEL_6, 0x200); 
 afec_channel_set_analog_offset(AFEC0, AFEC_CHANNEL_8, 0x200); 

 afec_set_trigger(AFEC0, AFEC_TRIG_TIO_CH_2);
 

 afec_channel_enable(AFEC0, AFEC_CHANNEL_0); 
 afec_channel_enable(AFEC0, AFEC_CHANNEL_6); 
 afec_channel_enable(AFEC0, AFEC_CHANNEL_8); 

 


 /* Initialize channel config */
 uint32_t xdmaint;
 xdmac_AFEC0_channel_cfg.mbr_ubc = XDMAC_UBC_NVIEW_NDV0 |
 XDMAC_UBC_NDE_FETCH_DIS |         //Next Descriptor Enable
 XDMAC_UBC_NDEN_UPDATED |         //Destination parameters are updated when the descriptor is retrieved
 AFEC0_BUFFER_SIZE ;

 xdmac_AFEC0_channel_cfg.mbr_sa = (uint32_t)&(AFEC0->AFEC_LCDR);
 xdmac_AFEC0_channel_cfg.mbr_da = (uint32_t)&DBI_u.DBI_S.AI_int16[0];
 xdmac_AFEC0_channel_cfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN | //(XDMAC_CC) Synchronized mode (Peripheral to Memory or Memory to Peripheral Transfer).
 XDMAC_CC_MEMSET_NORMAL_MODE |        //(XDMAC_CC) Memset is not activated
 XDMAC_CC_MBSIZE_SINGLE |         //(XDMAC_CC) The memory burst size is set to one
 XDMAC_CC_DSYNC_PER2MEM |         //(XDMAC_CC) Peripheral to Memory transfer
 XDMAC_CC_CSIZE_CHK_1 |          //(XDMAC_CC) 1 data transferred
 XDMAC_CC_DWIDTH_HALFWORD|         //(XDMAC_CC) The data size is set to 16 bits
 XDMAC_CC_SIF_AHB_IF1 |          //(XDMAC_CC) The data is read through the system bus interface 1
 XDMAC_CC_DIF_AHB_IF0 |          //(XDMAC_CC) The data is written through the system bus interface 0
 XDMAC_CC_SAM_FIXED_AM |          //(XDMAC_CC) The address remains unchanged.
 XDMAC_CC_DAM_INCREMENTED_AM |        //(XDMAC_CC) The addressing mode is incremented (the increment size is set to the data size).
 XDMAC_CC_PERID(AFEC0_XDMAC_CH_NUM);       //(XDMAC_CC) Channel x Peripheral Identifier

 xdmac_AFEC0_channel_cfg.mbr_bc = 0;       //Block Control Member
 xdmac_AFEC0_channel_cfg.mbr_ds =  0;      //Data Stride Member
 xdmac_AFEC0_channel_cfg.mbr_sus = 0;      //Source Microblock Stride Member.
 xdmac_AFEC0_channel_cfg.mbr_dus = 0;      //Destination Microblock Stride Member.

 xdmac_configure_transfer(XDMAC, XDMA_AFEC0_RX_CH, &xdmac_AFEC0_channel_cfg);

 xdmac_channel_set_descriptor_control(XDMAC, XDMA_AFEC0_RX_CH, 0);

 xdmac_enable_interrupt(XDMAC, XDMA_AFEC0_RX_CH);
 xdmaint =  (XDMAC_CIE_BIE   | //End of Block Interrupt Enable Bit
 XDMAC_CIE_DIE   |    //End of Disable Interrupt Enable Bit 
 XDMAC_CIE_FIE   |    //End of Flush Interrupt Enable Bit
 XDMAC_CIE_RBIE  |    //Read Bus Error Interrupt Enable Bit
 XDMAC_CIE_WBIE  |    //Write Bus Error Interrupt Enable Bit
 XDMAC_CIE_ROIE);    //Request Overflow Error Interrupt Enable Bit

 xdmac_channel_enable_interrupt(XDMAC, XDMA_AFEC0_RX_CH, xdmaint);
 xdmac_channel_enable(XDMAC, XDMA_AFEC0_RX_CH);
 tc_start(afec_tc_ptr, afec_tc_channel);

 afec_set_callback(AFEC0, AFEC_INTERRUPT_OVERRUN_ERROR, AFEC_OVERRUN0, AFEC_IRQ_level); 
 afec_set_callback(AFEC0, AFEC_INTERRUPT_DATA_READY, AFEC_DATA_READY0, AFEC_IRQ_level); 
 
 tc_set_writeprotect(afec_tc_ptr,true);
 afec_set_writeprotect(AFEC0,true); 
 
}

Initialize the DMA controller in the main( )function

 /* Initialize and enable DMA controller */
 pmc_enable_periph_clk(ID_XDMAC);

 /*Enable XDMA interrupt */
 NVIC_ClearPendingIRQ(XDMAC_IRQn);
 NVIC_SetPriority( XDMAC_IRQn ,1);
 NVIC_EnableIRQ(XDMAC_IRQn);


 InitAFEC();

The function of interrupt handling.

void XDMAC_Handler(void)
{
 uint32_t dma_status;

 dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_AFEC0_RX_CH);
 if (dma_status & XDMAC_CIS_BIS) 
 {
  AFEC_END_RXBUF0();
  XDMAC_CIE_BIE_count++;       //End of Block Interrupt Enable Bit
 }

 if (dma_status & XDMAC_CIE_DIE)
 {
  XDMAC_CIE_DIE_count++;    //End of Disable Interrupt Enable Bit 
 }

 if (dma_status & XDMAC_CIE_FIE)
 {
  XDMAC_CIE_FIE_count++;    //End of Disable Interrupt Enable Bit 
 }

 if (dma_status & XDMAC_CIE_RBIE)
 {
  XDMAC_CIE_RBIE_count++;    //End of Disable Interrupt Enable Bit 
 }

 if (dma_status & XDMAC_CIE_WBIE)
 {
  XDMAC_CIE_WBIE_count++;    //End of Disable Interrupt Enable Bit 
 }

 if (dma_status & XDMAC_CIE_ROIE)
 {
  XDMAC_CIE_ROIE_count++;    //End of Disable Interrupt Enable Bit 
 }


}
void AFEC_END_RXBUF0(void)
{
//start_tick_measuring(); 
#ifdef AFEC_TEST
 PIOA->PIO_SODR=Test_Pin_MASK;
#endif // AFEC_TEST
 AFEC_END_RXBUF0Count++;
 xdmac_AFEC0_channel_cfg.mbr_da = (uint32_t)&DBI_u.DBI_S.AI_int16[0];
 xdmac_configure_transfer(XDMAC, XDMA_AFEC0_RX_CH, &xdmac_AFEC0_channel_cfg);

 AI_Processing(); 

#ifdef AFEC_TEST
 PIOA->PIO_CODR=Test_Pin_MASK;
#endif // AFEC_TEST  
//SetTickCount(stop_tick_measuring());
}
//---------------------------------------------------------------------------------------
void AFEC_OVERRUN0(void)
{
 DBC_u.DBC_S.ADC_OverCount++;
}

//---------------------------------------------------------------------------------------
void AFEC_DATA_READY0(void)
{
 ADC_DATA_READYCount++;
}

 

The interrupt "End of Block" occurs only once, although the "AFEC_INTERRUPT_DATA_READY" occurs periodically.

How to ensure the periodicity of the transfer by DMA channel?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found a bug in my program: In the interrupt handler it is necessary 1) to disable the channel, 2) to configure the transmission, 3) to enable the channel.

void AFEC_END_RXBUF0(void)
{
#ifdef AFEC_TEST
 PIOA->PIO_SODR=Test_Pin_MASK;
#endif // AFEC_TEST
 AFEC_END_RXBUF0Count++;
 xdmac_channel_disable(XDMAC, XDMA_AFEC0_RX_CH);
 xdmac_AFEC0_channel_cfg.mbr_da = (uint32_t)&DBI_u.DBI_S.AI_int16[0];
 xdmac_configure_transfer(XDMAC, XDMA_AFEC0_RX_CH, &xdmac_AFEC0_channel_cfg);
 xdmac_channel_enable(XDMAC, XDMA_AFEC0_RX_CH);
 AI_Processing(); 

#ifdef AFEC_TEST
 PIOA->PIO_CODR=Test_Pin_MASK;
#endif // AFEC_TEST  
}