DMA problem solved

What are you developing?
stan
Posts: 70
Joined: Wed Nov 11, 2020 7:40 pm

DMA problem solved

Post 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() {
}
Last edited by stan on Tue Nov 24, 2020 9:19 am, edited 5 times in total.
mlundin
Posts: 94
Joined: Wed Nov 04, 2020 1:20 pm
Answers: 6
Location: Sweden

Re: DMA problem

Post by mlundin »

In your code, what pins are timer_dev *dev1 and dev2 connected to ?
stan
Posts: 70
Joined: Wed Nov 11, 2020 7:40 pm

Re: DMA problem

Post 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********************
stevestrong
Posts: 502
Joined: Fri Dec 27, 2019 4:53 pm
Answers: 8
Location: Munich, Germany
Contact:

Re: DMA problem

Post 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.
mlundin
Posts: 94
Joined: Wed Nov 04, 2020 1:20 pm
Answers: 6
Location: Sweden

Re: DMA problem

Post 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;
stan
Posts: 70
Joined: Wed Nov 11, 2020 7:40 pm

Re: DMA problem

Post 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 ???
stan
Posts: 70
Joined: Wed Nov 11, 2020 7:40 pm

Re: DMA problem

Post 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
mlundin
Posts: 94
Joined: Wed Nov 04, 2020 1:20 pm
Answers: 6
Location: Sweden

Re: DMA problem

Post 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.
stevestrong
Posts: 502
Joined: Fri Dec 27, 2019 4:53 pm
Answers: 8
Location: Munich, Germany
Contact:

Re: DMA problem

Post 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
stan
Posts: 70
Joined: Wed Nov 11, 2020 7:40 pm

Re: DMA problem

Post 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.
Post Reply

Return to “Projects”