soft PWM via DMA

Post your cool example code here.
Post Reply
arpruss
Posts: 97
Joined: Sat Sep 30, 2017 3:34 am

soft PWM via DMA

Post by arpruss » Thu Oct 26, 2017 3:05 pm

I wanted to do PWM on a pin that had no PWM support, specifically the PB12 pin of the LED on the black pill. Solution: circular DMA transfer to BSRR. The PWM frequency is 7.2MHz (the scope picture shows 3.6, but that's for both the low and the high together), which is kind of crazy. Memory use is 4*DMA_PWM_MAX_DUTY.

To turn off, just call setDMAPWM with duty cycle at 0 or at the maximum.

Is there any way to lower the DMA speed, by the way?

Code: Select all

#include <dma_private.h>

#define PIN_TO_PULSE PB12

#define DMA_PWM_MAX_DUTY 32
uint32_t data[DMA_PWM_MAX_DUTY];

void setDMAPWM(uint32_t pin, uint32_t duty_cycle) {
  gpio_dev *dev = digitalPinToPort(pin);
  uint32_t maskOn = digitalPinToBitMask(pin);
  uint32_t maskOff = digitalPinToBitMask(pin) << 16;
  if (duty_cycle == 0 || duty_cycle >= DMA_PWM_MAX_DUTY) {
    dma_disable(DMA1, DMA_CH1);
    gpio_write_bit(dev, PIN_MAP[pin].gpio_bit, duty_cycle != 0);
    return;
  }
  for (uint32_t i=0; i<duty_cycle; i++) 
    data[i] = maskOn;
  for (uint32_t i=duty_cycle; i<DMA_PWM_MAX_DUTY; i++)
    data[i] = maskOff;
  dma_init(DMA1);
  dma_setup_transfer(DMA1, DMA_CH1, data, DMA_SIZE_32BITS, &(dev->regs->BSRR), 
    DMA_SIZE_32BITS, DMA_PINC_MODE |  DMA_MEM_2_MEM | DMA_CIRC_MODE);
  dma_set_num_transfers(DMA1, DMA_CH1, DMA_PWM_MAX_DUTY);
  dma_enable(DMA1, DMA_CH1);
}

void setup() 
{
  pinMode(PIN_TO_PULSE, OUTPUT);
  setDMAPWM(PIN_TO_PULSE, 1);  
}

void loop() 
{
  for(int i=0;i<DMA_PWM_MAX_DUTY;i++) {
    setDMAPWM(PIN_TO_PULSE, i);  
    delay(50);
  }
  for(int i=0;i<DMA_PWM_MAX_DUTY;i++) {
    setDMAPWM(PIN_TO_PULSE, DMA_PWM_MAX_DUTY-1-i);  
    delay(50);
  } 
}
Attachments
3_6.jpg
3_6.jpg (53.81 KiB) Viewed 269 times

racemaniac
Posts: 621
Joined: Sat Nov 07, 2015 9:09 am

Re: PWM via DMA

Post by racemaniac » Thu Oct 26, 2017 3:21 pm

i don't think there's a way to throttle mem2mem DMA.
in a thread where we did benchmarks on the effect of DMA on the performance of the MCU, someone also mentioned that the datasheet mentions you shouldn't put mem2mem in circular mode (but as you can guess, that's what i did for the benchmark)
Once you do that, you really see how much it affects other dma's running, as the poor dma controller is used at full capacity :).
so use at your own risk :)

stevestrong
Posts: 1819
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany

Re: PWM via DMA

Post by stevestrong » Thu Oct 26, 2017 7:35 pm

Normally you should trigger the DMA by a timer trigger or compare output, so that you can control the frequency.
In this case you should use memory to peripheral mode (DMA_MINC_MODE | DMA_MEM_2_PER | DMA_CIRC_MODE).

Or you use a larger buffer (256 bytes), and thus also increase the PWM resolution.

arpruss
Posts: 97
Joined: Sat Sep 30, 2017 3:34 am

Re: PWM via DMA

Post by arpruss » Thu Oct 26, 2017 9:01 pm

racemaniac wrote:
Thu Oct 26, 2017 3:21 pm
i don't think there's a way to throttle mem2mem DMA.
in a thread where we did benchmarks on the effect of DMA on the performance of the MCU, someone also mentioned that the datasheet mentions you shouldn't put mem2mem in circular mode (but as you can guess, that's what i did for the benchmark)
Once you do that, you really see how much it affects other dma's running, as the poor dma controller is used at full capacity :).
so use at your own risk :)
But does it affect performance when one isn't using other DMAs?
... Nevermind, I found the thread.
Answer: not much.

arpruss
Posts: 97
Joined: Sat Sep 30, 2017 3:34 am

Re: PWM via DMA

Post by arpruss » Thu Oct 26, 2017 10:33 pm

My own benchmarking shows a 10% decrease in speed for memory dominated tasks.

victor_pv
Posts: 1745
Joined: Mon Apr 27, 2015 12:12 pm

Re: PWM via DMA

Post by victor_pv » Fri Oct 27, 2017 4:21 am

As Steve said, instead of doing mem2mem, configure the DMA as mem2per, and use a dma channel that can be triggered by a timer event (either the time update, or one of the channel compares), enable DMA requests for that timer (or timer channel), and the timer will trigger the transfers at the rate you set the timer to.

arpruss
Posts: 97
Joined: Sat Sep 30, 2017 3:34 am

Re: PWM via DMA

Post by arpruss » Fri Oct 27, 2017 3:34 pm

Thanks! In fact, I see a thread on this.

stevestrong
Posts: 1819
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany

Re: soft PWM via DMA

Post by stevestrong » Sun Oct 29, 2017 9:27 am

I changed the title to reflect that the PWM generated here is a software solution.

similar project: viewtopic.php?f=18&t=2305

Post Reply