Author Topic: Gigadevice GD32VF103 DMA and the DAC  (Read 2037 times)

0 Members and 1 Guest are viewing this topic.

Offline ale500Topic starter

  • Frequent Contributor
  • **
  • Posts: 415
Gigadevice GD32VF103 DMA and the DAC
« on: November 18, 2021, 07:12:33 pm »
After wasting several hours trying to get this to work: The DAC0 gets its DATA from memory using DMA triggered by a timer.

The DAC gets triggered by a timer (5) and then initiates a DMA transfer (DMA1, CH2), after 1024 transfers an interrupt occurs and the buffer where the data resides changes, so far so good, this works but...

The symptom ? 0 V on PIN A4.

Before you ask, if I trigger the DAC per software and write the data manually, I get a signal at PIN A4 (see code below). It just does not output anything when the data comes from the DMA. The timer works, triggers DMA, interrupts work, the DAC0_R12DH gets written, but nothing gets through :(

Any ideas ?

Notes:

- I'm using segger's embedded studio for RISCV 5.66 and segger's jlink too. And Gigadevice's gd32vf103_xx.c/h. I could use platformio, I do not see that something will change.
- Something I observed is that the DAC0_DO register remains at 0 regardless of what the DAC0_R12DH gets written with. Something contrary to the manual approach where the DAC0_DO register mirrors what I write manually.


The code:
Code: [Select]
void dac_init( void )
{
    dma_parameter_struct dma_init_struct;
    timer_parameter_struct timer5_init_struct;

    // PIN
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_DAC);
    rcu_periph_clock_enable(RCU_DMA1);
    rcu_periph_clock_enable(RCU_AF);

    gpio_init(GPIOA, GPIO_MODE_AIN, 0U, \
              GPIO_PIN_4 );

    // timer
    rcu_periph_clock_enable(RCU_TIMER5);
    timer_deinit(TIMER5);
    timer_struct_para_init(&timer5_init_struct);

    timer5_init_struct.prescaler         = 0U;
    timer5_init_struct.alignedmode       = TIMER_COUNTER_EDGE;
    timer5_init_struct.counterdirection  = TIMER_COUNTER_UP;
    timer5_init_struct.period            = 65535U;
    timer5_init_struct.clockdivision     = TIMER_CKDIV_DIV1;
    timer5_init_struct.repetitioncounter = 0U;
   
    timer_init(TIMER5, &timer5_init_struct);

    timer_update_event_enable(TIMER5);
    timer_dma_enable(TIMER5, TIMER_DMA_UPD);

    // DMA

    dma_deinit(DMA1, DMA_CH2);
    dma_struct_para_init(&dma_init_struct);

    dma_init_struct.periph_addr  = &DAC0_R12DH;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_32BIT;
    dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory_addr  = &dac_buf_0;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
    dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.number       = 1024U;
    dma_init_struct.direction    = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.priority     = DMA_PRIORITY_MEDIUM;


    dma_init(DMA1, DMA_CH2, &dma_init_struct);
    // interrupt on the full channel
    dma_interrupt_enable(DMA1, DMA_CH2, DMA_INT_FTF);

    eclic_irq_enable(DMA1_Channel2_IRQn, 1, 1);
    // DAC

    dac_deinit();

    dac_trigger_source_config(DAC0, DAC_TRIGGER_T5_TRGO);
    dac_trigger_enable(DAC0);
    dac_wave_mode_config(DAC0, DAC_WAVE_DISABLE);
    dac_dma_enable(DAC0);
    dac_output_buffer_enable(DAC0);
    dac_enable(DAC0);
    dma_channel_enable(DMA1, DMA_CH2);
    timer_enable(TIMER5);

}

// the interrupt to switch buffers
void DMA1_Channel2_IRQHandler(void)
{
    // Clear the interrupt flag to avoid retriggering.
    dma_interrupt_flag_clear(DMA1, DMA_CH2, DMA_INT_FLAG_G);

    dma_channel_disable(DMA1, DMA_CH2);

    if (dac_buff_current == 0U)
    {
        dma_memory_address_config(DMA1, DMA_CH2, &dac_buf_1);
        GPIO_BC(GPIOC) = GPIO_PIN_13;
    }
    else
    {
        dma_memory_address_config(DMA1, DMA_CH2, &dac_buf_0);
        GPIO_BOP(GPIOC) = GPIO_PIN_13;
    }
    dma_transfer_number_config(DMA1, DMA_CH2, 1024U);
    dac_buff_current = dac_buff_current ^ 1;

    dma_channel_enable(DMA1, DMA_CH2);
}


And the manual version:

Code: [Select]
    rcu_periph_clock_enable(RCU_GPIOA);
   
    gpio_init(GPIOA, GPIO_MODE_AIN, 0U, \
              GPIO_PIN_4 );
   
    rcu_periph_clock_enable(RCU_DAC);
    dac_trigger_source_config(DAC0, DAC_TRIGGER_SOFTWARE);
    dac_trigger_enable(DAC0);
    dac_wave_mode_config(DAC0, DAC_WAVE_DISABLE);
   
    dac_output_buffer_enable(DAC0);
    dac_enable(DAC0);


    for (;;)
    {
        dac_data_set(DAC0, DAC_ALIGN_12B_R, value);
        dac_software_trigger_enable(DAC0);
        delay_us(50)

        value = (value + 1) & 4095;
    }


« Last Edit: November 18, 2021, 07:14:33 pm by ale500 »
 

Offline bson

  • Supporter
  • ****
  • Posts: 2270
  • Country: us
Re: Gigadevice GD32VF103 DMA and the DAC
« Reply #1 on: November 18, 2021, 09:22:02 pm »
R12DH sounds like a 12-bit dual conversion holding register.  Note "dual" - it's used when driving both DAC channels using a single DMA stream.  You probably want to use the appropriate single-conversion data register.  If you haven't set up both DAC channels, with one slaving off the other (I forget the details, but the F4xx has common registers for this) I'm not surprised if a DMA transfer simply stalls.
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 495
  • Country: sk
Re: Gigadevice GD32VF103 DMA and the DAC
« Reply #2 on: November 18, 2021, 09:47:23 pm »
I don't use the GD32, but IMO you should select Update as TRGO in TIMERx_CTL1.MMC (I don't know what's the incantation for that in the "library" you are using); and you should not enable DMA from TIM5 (which presumably sets TIMERx_DMAINTEN.UPDEN) as DMA should be triggered from DAC itself (where you did enable it, too).

If this won't work, read out and check/post content of relevant DAC, DMA and TIMER5 registers.

JW
 

Offline bson

  • Supporter
  • ****
  • Posts: 2270
  • Country: us
Re: Gigadevice GD32VF103 DMA and the DAC
« Reply #3 on: November 18, 2021, 10:12:33 pm »
Also, the peripheral width should be 16-bit unless you in fact intend to write to a 32-bit dual holding register.  Otherwise if you feed 16 bit memory into 32 bit peripheral regs the DMA will collect two 16 bit samples into a 32 bit peripheral write.

I also think you need to enable master mode on the timer by setting MMS = 0b010 in CR2.  But again, this is based on STM32F4xx (no idea if the RISC-V GD32 is still the same).  STM32F4xx timers won't output TRGO to the DAC (or anything else) unless in master mode.
« Last Edit: November 18, 2021, 10:14:08 pm by bson »
 

Offline ale500Topic starter

  • Frequent Contributor
  • **
  • Posts: 415
Re: Gigadevice GD32VF103 DMA and the DAC
« Reply #4 on: November 20, 2021, 08:59:25 am »
Thanks for the comments, and tips, sadly mostly do not apply.
DAC0_R12DH is the register for the DAC0, the common register is named DACC_R12DH, DH stands for Data Hold (register), according  to the manual.
Reading 16 bits and writing them to a 32 bit port is possible and pads the upper 16 bits with zeroes (DACx_R12DH have to be read/write using 32 bit accesses), as described page 133 of the user manual.

Now to the tricky part regarding the timer and DMA. If I do not set DMA request update (UPDEN Update DMA request enable), nothing happens. There are no transfers.
If I disable the DMA feature in the DAC the same. Maybe there is a conflict between the two, it is not clear to me. Maybe I should use the timer5 and the DMA to try to copy a block and see if that works, then.
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 495
  • Country: sk
Re: Gigadevice GD32VF103 DMA and the DAC
« Reply #5 on: November 20, 2021, 09:18:56 am »
I said:

- select Update as TRGO in TIMERx_CTL1.MMC
- don't enable DMA from TIM5
- if this won't work, read out and check/post content of relevant DAC, DMA and TIMER5 registers

JW
 

Offline ale500Topic starter

  • Frequent Contributor
  • **
  • Posts: 415
Re: Gigadevice GD32VF103 DMA and the DAC
« Reply #6 on: November 20, 2021, 03:34:20 pm »
I said:

- select Update as TRGO in TIMERx_CTL1.MMC
- don't enable DMA from TIM5
- if this won't work, read out and check/post content of relevant DAC, DMA and TIMER5 registers

JW

I know what you said, but all 3 possible modes make (some) pulses on TRGO, that's why I did not see that this made a difference (according to the manual). But it does, then it works.
There is another issue, it has to do with the debugging, when I download the code to the chip it triggers the DMA once and then the interrupts does not get triggered and that's it :(

Thanks
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 495
  • Country: sk
Re: Gigadevice GD32VF103 DMA and the DAC
« Reply #7 on: November 20, 2021, 05:16:49 pm »
There is another issue, it has to do with the debugging, when I download the code to the chip it triggers the DMA once and then the interrupts does not get triggered and that's it :(
Read out and check/post TIM/DAC and mainly DMA registers content, including flags.

This writeup is for STM32 but maybe helps. Sorry, I have no easy solutions to offer, just blood, toil, tears and sweat.

JW
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf