Page 1 of 3

DMA problem solved

Posted: Fri Nov 20, 2020 5:36 am
by stan
Hi
This program allows to have only one output instead of two.
I can have signal on PB6 or PB7 but not both on one time.
conflict is in this two lines.

Code: Select all

   timer_dma_set_base_addr(dev1, TIMER_DMA_BASE_CCR2); 
   timer_dma_set_base_addr(dev2, TIMER_DMA_BASE_CCR2);

Code: Select all

#define SAMPLES 100
#include <libmaple/dma.h>
 
dma_tube_config dma_cfg, dma_cfg2;
int val1[SAMPLES];
int val2[SAMPLES];                   
int amp = 35;
int cnt = 0;
int time_track = 0;
float stp = 6.2831 / SAMPLES;
int ret = 17;
int out1 = PB7; // TIM4_CH2 DMA_CH4 . 
int out2 = PB6; // TIM4_CH1 DMA_CH3 .                     *************************** 
 
timer_dev *dev1 = PIN_MAP[out2].timer_device;   
timer_dev *dev2 = PIN_MAP[out2].timer_device;
 
void timer_conf()
{
// PB7 TIM4_CH2 DMA_CH4
  timer_dma_set_base_addr(dev1, TIMER_DMA_BASE_CCR2);          // CCR1, CCR1 =  PB6
  timer_dma_set_burst_len(dev1, 1);                            // CCR1, CCR2 =  PB7
  timer_dma_enable_req(dev1, PIN_MAP[out1].timer_channel);     //CCR2, CCR2 = PB7
  timer_set_reload(dev1, 102);                                 //CCR2, CCR1 =  PB6
  timer_set_prescaler(dev1, 0);
 
 
  // PB6 TIM4_CH1 DMA_CH3 .                                  *********************
  timer_dma_set_base_addr(dev2, TIMER_DMA_BASE_CCR2);
  timer_dma_set_burst_len(dev2, 1);
  timer_dma_enable_req(dev2, PIN_MAP[out2].timer_channel);
  timer_set_reload(dev2, 102);
  timer_set_prescaler(dev2, 0);
}
void dma_conf()
{
  dma_init(DMA1);
 // PB7 TIM4_CH2 DMA_CH4
  // PB6 TIM4_CH1 DMA_CH3
  dma_cfg.tube_dst = &(dev1->regs.gen->DMAR);                // PB7
  dma_cfg.tube_dst = &(dev2->regs.gen->DMAR);                // PB6********************
  dma_cfg.tube_src = val1;                                   // PB7
  dma_cfg.tube_src = val2;                                   // PB6********************
  dma_cfg.tube_src_size = DMA_SIZE_32BITS;
  dma_cfg.tube_nr_xfers = SAMPLES;
  dma_cfg.tube_flags = DMA_CFG_SRC_INC | DMA_CFG_CIRC;
  
  dma_cfg.tube_req_src = DMA_REQ_SRC_TIM4_CH2;               //PB7
  dma_cfg.tube_req_src = DMA_REQ_SRC_TIM4_CH1;               //PB6 ********************
  dma_cfg.target_data = 0;
  ret = dma_tube_cfg(DMA1, DMA_CH4, &dma_cfg);
  ret = dma_tube_cfg(DMA1, DMA_CH3, &dma_cfg);
}
void dma_start()
{
  // PB7 TIM4_CH2 DMA_CH4
  dma_enable(DMA1, DMA_CH4);
 timer_resume(dev1);
  dma_enable(DMA1, DMA_CH3);
  timer_resume(dev2);
 
}
void init_wave()
{
  int i;
  for (i = 0; i < SAMPLES; i++)
  {
    val1[i] = 50 + amp * sin(stp * i);
    val2[i] = 50 + amp * sin(stp * i);                     
  }
}
void setup() {
  pinMode(out1, PWM);
  pinMode(out2, PWM);
 
 
  timer_conf();
  dma_conf();
  dma_start();
  init_wave();
}
void loop() {
}

Re: DMA problem

Posted: Fri Nov 20, 2020 7:38 am
by mlundin
In your code, what pins are timer_dev *dev1 and dev2 connected to ?

Re: DMA problem

Posted: Fri Nov 20, 2020 9:36 am
by stan
dev1 = PB7 = timer 4 CH2
dev2 = PB6 = timer 4 CH1

Code: Select all

dma_cfg.tube_dst = &(dev1->regs.gen->DMAR);                // PB7
  dma_cfg.tube_dst = &(dev2->regs.gen->DMAR);                // PB6********************

Re: DMA problem

Posted: Fri Nov 20, 2020 10:58 am
by stevestrong
Well, you actually recognized the limitation: one timer device can use only one channel as DMA base address.

What is the purpose of this code snippet?
I suppose you are using bluepill.

Re: DMA problem

Posted: Fri Nov 20, 2020 1:15 pm
by mlundin
It was more a hint than a question really, your code has

Code: Select all

timer_dev *dev1 = PIN_MAP[out2].timer_device;   
timer_dev *dev2 = PIN_MAP[out2].timer_device;
I think that should be

Code: Select all

timer_dev *dev1 = PIN_MAP[out1].timer_device;   
timer_dev *dev2 = PIN_MAP[out2].timer_device;

Re: DMA problem

Posted: Fri Nov 20, 2020 1:58 pm
by stan
Yes it is a bluepill, that should be quadrature generator for quadrature detector after changing
val2 = 50 + amp * sin(stp * i);
to
val2 = 50 + amp * cos(stp * i);

May be it is posible to that differently such as ;
val2 = val1 + 90 degree ???

Re: DMA problem

Posted: Fri Nov 20, 2020 2:01 pm
by stan
mlundin wrote: Fri Nov 20, 2020 1:15 pm It was more a hint than a question really, your code has

Code: Select all

timer_dev *dev1 = PIN_MAP[out2].timer_device;   
timer_dev *dev2 = PIN_MAP[out2].timer_device;
I think that should be

Code: Select all

timer_dev *dev1 = PIN_MAP[out1].timer_device;   
timer_dev *dev2 = PIN_MAP[out2].timer_device;
I corrected it = no difference

Re: DMA problem

Posted: Fri Nov 20, 2020 3:00 pm
by mlundin
You have declared both dma_cfg and dma_cfg2. In dma_conf() you only use dma_cfg, and sets the values for both channels to the same config structure overwriting the first value, then you call

Code: Select all

  ret = dma_tube_cfg(DMA1, DMA_CH4, &dma_cfg);
  ret = dma_tube_cfg(DMA1, DMA_CH3, &dma_cfg);
with the same dma_cfg for both channels, you have to be careful and make sure to apply all the changes needed in the right oreder when going from one to two channels.

Re: DMA problem

Posted: Fri Nov 20, 2020 3:11 pm
by stevestrong
stan wrote: Fri Nov 20, 2020 1:58 pm Yes it is a bluepill, that should be quadrature generator for quadrature detector
Ok, but for that you don't need DMA with timers. At least not for the same timer.
You can generate synchronized pulses using two timers in several ways, please study RM0008 chapter. 15.3.15

Is this the theory?
https://www.rs-online.com/designspark/q ... t-1-theory

There are some alternatives how to implement it in a simple way:
- interrupt based: you generate an IRQ in periodic time intervals and set "manually" the GPIO pins within the ISR (you can use look up tables).
- similar as above, but instead of IRQ you use timer based-triggered DMA to output IO values to GPIO ouput port register -this will avoid the fluctuations of the first method.
https://www.youtube.com/watch?v=3JFBkdbeSXA

Re: DMA problem

Posted: Fri Nov 20, 2020 5:08 pm
by stan
mlundin wrote: Fri Nov 20, 2020 3:00 pm You have declared both dma_cfg and dma_cfg2. In dma_conf()
dma_cfg2. = that is left over from another attempt, I removed it.