SAM E70 DACC+DMA+TC0

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

Hi everyone. I want to implement the sine wave with DACC+DMA+TC0, but there is no output. Could you please give me a hand.

I can output the sine wave with DACC+DMA with DACC free-running mode, but the frequency is so high(>1Mhz) that cannot meet my need(200Khz).

 

Therefore, I used TC0 to trigger the DACC, but it does not wok.

 

the program is as below.

void Configure_DAC(void)

sysclk_enable_peripheral_clock(ID_DACC);

        printf("sysclk_get_peripheral_hz is %d\n\r",sysclk_get_peripheral_hz());

               

        /* Reset DACC registers */

        dacc_reset(DACC_BASE);

 

        dacc_enable_channel(DACC_BASE,DACC_CHANNEL_0);

        dacc_enable_channel(DACC_BASE,DACC_CHANNEL_1);

        dacc_set_transfer_mode(DACC_BASE, DACC_MR_MAXS0_TRIG_EVENT|DACC_MR_WORD_ENABLED);

       

        g_times = DAC_SAPMLING_POINT / g_frequency;

        float m_amplitude = g_amplitude/2.0;

        float sin_temp = 2*PI/g_times;

        float offset_temp = MAX_AMPLITUDE_IN/VOLT_REF;

        for(int i = 0; i < g_times; i++){

                g_sine_data[i] = (sin(sin_temp*i) *m_amplitude + m_amplitude + 0.2) * offset_temp;

                g_sine_pi_data[i] = (sin(sin_temp*i + PI) *m_amplitude + m_amplitude + 0.2) * offset_temp;

        }

 

        /* Set up analog current */

        dacc_set_analog_control(DACC_BASE, DACC_ANALOG_CONTROL);

       

        configure_tc_trigger();

        dacc_set_trigger(DACC_BASE, DACC_TRIGR_TRGSEL0_TRGSEL1, DACC_CHANNEL_0);

       

        dacc_xdmac_configure(DACC_BASE);       

}

 

static void configure_tc_trigger(void)

{

        uint32_t ul_div = 0;

        uint32_t ul_tc_clks = 0;

        uint32_t ul_sysclk = sysclk_get_cpu_hz();

 

        /* Enable peripheral clock. */

        pmc_enable_periph_clk(ID_TC0);

        ul_tc_clks = 1;

        tc_init(TC0, 0, ul_tc_clks | TC_CMR_CPCTRG | TC_CMR_WAVE |

        TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET);

 

        TC0->TC_CHANNEL[0].TC_RA =180 / 2;

        TC0->TC_CHANNEL[0].TC_RC = 180;

        /* Start the Timer. */

        tc_start(TC0, 0);

 

}

 

static void dacc_xdmac_configure(Dacc *p_dacc)
{
 uint32_t xdmaint;
 /* Initialize and enable DMA controller */
 pmc_enable_periph_clk(ID_XDMAC);

 /* Initialize channel config */
/*
 xdmac_channel_cfg.mbr_ubc = XDMAC_UBC_NVIEW_NDV0 |
 XDMAC_UBC_NDE_FETCH_DIS |
 XDMAC_UBC_NDEN_UPDATED |
 BUFFER_SIZE;
*/
 xdmac_channel_cfg.mbr_ubc = BUFFER_SIZE;

 xdmac_channel_cfg.mbr_sa = (uint32_t)g_sine_data;
 xdmac_channel_cfg.mbr_da = (uint32_t)&(p_dacc->DACC_CDR[0]);
 xdmac_channel_cfg.mbr_cfg = XDMAC_CC_TYPE_PER_TRAN |
 XDMAC_CC_MBSIZE_SINGLE |
 XDMAC_CC_DSYNC_MEM2PER |
 XDMAC_CC_CSIZE_CHK_1 |
 XDMAC_CC_DWIDTH_HALFWORD|
 XDMAC_CC_SIF_AHB_IF0 |
 XDMAC_CC_DIF_AHB_IF1 |
 XDMAC_CC_SAM_INCREMENTED_AM |
 XDMAC_CC_DAM_FIXED_AM  |
 XDMAC_CC_PERID(XDMAC_CHANNEL_HWID_DAC);

 xdmac_channel_cfg.mbr_bc = 0;
 xdmac_channel_cfg.mbr_ds =  0;
 xdmac_channel_cfg.mbr_sus = 0;
 xdmac_channel_cfg.mbr_dus = 0;

 xdmac_configure_transfer(XDMAC, XDMAC_CH, &xdmac_channel_cfg);

 xdmac_channel_set_descriptor_control(XDMAC, XDMAC_CH, 0);
 
 xdmac_enable_interrupt(XDMAC, XDMAC_CH);
 xdmaint =  (XDMAC_CIE_BIE   |
    XDMAC_CIE_DIE   |
    XDMAC_CIE_FIE   |
    XDMAC_CIE_RBIE  |
    XDMAC_CIE_WBIE  |
    XDMAC_CIE_ROIE);
 xdmac_channel_enable_interrupt(XDMAC, XDMAC_CH, xdmaint);
 /*Enable XDMA interrupt */
 NVIC_ClearPendingIRQ(XDMAC_IRQn);
 NVIC_SetPriority( XDMAC_IRQn ,1);
 NVIC_EnableIRQ(XDMAC_IRQn);
  
 xdmac_channel_enable(XDMAC, XDMAC_CH);
}

 

   

thank you

Last Edited: Thu. Dec 26, 2019 - 02:42 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wrong trigger selection?

#define   DACC_TRIGR_TRGSEL0_TRGSEL0 (0x0u << 4) /**< \brief (DACC_TRIGR) TC0 output */
#define   DACC_TRIGR_TRGSEL0_TRGSEL1 (0x1u << 4) /**< \brief (DACC_TRIGR) TC1 output */
#define   DACC_TRIGR_TRGSEL0_TRGSEL2 (0x2u << 4) /**< \brief (DACC_TRIGR) TC2 output */
#define   DACC_TRIGR_TRGSEL0_TRGSEL3 (0x3u << 4) /**< \brief (DACC_TRIGR) PWM0 event 0 */
#define   DACC_TRIGR_TRGSEL0_TRGSEL4 (0x4u << 4) /**< \brief (DACC_TRIGR) PWM0 event 1 */
#define   DACC_TRIGR_TRGSEL0_TRGSEL5 (0x5u << 4) /**< \brief (DACC_TRIGR) PWM1 event 0 */
#define   DACC_TRIGR_TRGSEL0_TRGSEL6 (0x6u << 4) /**< \brief (DACC_TRIGR) PWM1 event 1 */

/Lars

 

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

Hi Lajon

thank you,

I do not  think it is  wrong.

In the file dacc.h of SAME70, the trigger define is as below.

---------------------------------

#define   DACC_TRIGR_TRGSEL0_TRGSEL0 (0x0u << 4) /**< \brief (DACC_TRIGR) DATRG */
#define   DACC_TRIGR_TRGSEL0_TRGSEL1 (0x1u << 4) /**< \brief (DACC_TRIGR) TC0 output */
#define   DACC_TRIGR_TRGSEL0_TRGSEL2 (0x2u << 4) /**< \brief (DACC_TRIGR) TC1 output */
#define   DACC_TRIGR_TRGSEL0_TRGSEL3 (0x3u << 4) /**< \brief (DACC_TRIGR) TC2 output */
#define   DACC_TRIGR_TRGSEL0_TRGSEL4 (0x4u << 4) /**< \brief (DACC_TRIGR) PWM0 event 0 */
#define   DACC_TRIGR_TRGSEL0_TRGSEL5 (0x5u << 4) /**< \brief (DACC_TRIGR) PWM0 event 1 */
#define   DACC_TRIGR_TRGSEL0_TRGSEL6 (0x6u << 4) /**< \brief (DACC_TRIGR) PWM1 event 0 */
#define   DACC_TRIGR_TRGSEL0_TRGSEL7 (0x7u << 4) /**< \brief (DACC_TRIGR) PWM1 event 1 */

----------------------------------

 

thank you

Last Edited: Fri. Dec 27, 2019 - 01:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey, did you ever figure out the issue? I am facing the same problem now (on the s70, though).

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

In djhoo's code:

dacc_set_trigger(DACC_BASE, DACC_TRIGR_TRGSEL0_TRGSEL1, DACC_CHANNEL_0);

should be:

dacc_set_trigger(DACC_BASE, 1, DACC_CHANNEL_0);

The function does the <<4 to the passed value with the macro: DACC_TRIGR_TRGSEL0().

 

However, I am having the same problem on the S70 as well. Still looking for a solution.

 

mike

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

RE: SAM S70 + DACC + XDMAC +TC0

As it turns out my issue was not with the trigger pacing out the buffer values to the DACC.

 

I am using a circular linked list with lld_view1 type descriptors.

Turns out it is not enough to set the da here:

                xdmac_channel_cfg.mbr_da = (uint32_t)&(DACC->DACC_CDR[0]);

and do:

    xdmac_configure_transfer(XDMAC, xdma_chan, &xdmac_channel_cfg);        // this can be done at the inter-block (inter-descriptor) boundary

 

The da's also have to be set in the lld_view linked list descriptors:

 

    lld1[0].mbr_da = (uint32_t)&(DACC->DACC_CDR[0]);
    lld1[1].mbr_da = (uint32_t)&(DACC->DACC_CDR[0]);

 

even though we have both :

A: XDMAC_UBC_NDEN_UNCHANGED set in the linked list descriptors:

 

            lld1[0].mbr_ubc = lld1[1].mbr_ubc =
                XDMAC_UBC_NVIEW_NDV1 |
                XDMAC_UBC_NDE_FETCH_EN |
                XDMAC_UBC_NSEN_UPDATED |
                XDMAC_UBC_NDEN_UNCHANGED |
                XDMAC_UBC_UBLEN( NUM_DAC_CHAN*DAC_BUFFER_SIZE );

 

 

and B: XDMAC_CNDC_NDDUP_DST_PARAMS_UNCHANGED to start things off in:

 

    xdmac_channel_set_descriptor_control(XDMAC, xdma_chan,
            XDMAC_CNDC_NDVIEW_NDV1 |
        XDMAC_CNDC_NDE_DSCR_FETCH_EN |                                        // fetch *NDA next
        XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED |                                // load CSAx with lld1[0].mbr_sa
        XDMAC_CNDC_NDDUP_DST_PARAMS_UNCHANGED                                // do not load CDAx with lld1[0].mbr_da
        );                                                                                

 

 

I went back to check the sample code references and they all had the destination addresses initialized in the linked list descriptors.

So the problem was with my assumption that the flags not to update the destination addresses (XDMAC_UBC_NDEN_UNCHANGED and XDMAC_CNDC_NDDUP_DST_PARAMS_UNCHANGED) worked.

 

 

mike