0
\$\begingroup\$

I'm playing with the blue pill.

Here I run TIM2 and enable the DMA on its update event, according to Table 78 of RM0008, the DMA channel I should use is channel 2 on DMA1. Then I want the DMA to update TIM1.CCR1.

But I cannot get it working around DMA part. Here is the code:

#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/timer.h>
#include <libopencm3/stm32/dma.h>

#define PHASE_SIZE  10

const unsigned short PWM_phase[PHASE_SIZE] = {
  1, 11, 21, 31, 41, 51, 61, 71, 81, 91
};

int main(void) {
  // setup TIM1 as the main output
  rcc_periph_clock_enable(RCC_TIM1);
  rcc_periph_clock_enable(RCC_GPIOA);
  rcc_periph_clock_enable(RCC_AFIO);
  gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO8);
  timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
  timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1);
  timer_enable_oc_output(TIM1, TIM_OC1);
  timer_enable_oc_preload(TIM1, TIM_OC1);
  timer_enable_break_main_output(TIM1);
  timer_set_oc_value(TIM1, TIM_OC1, 30);
  timer_set_period(TIM1, 120);
  timer_enable_counter(TIM1);

  // setup DMA
  rcc_periph_clock_enable(RCC_DMA1);
  dma_set_peripheral_address(DMA1, DMA_CHANNEL2, (uint32_t)TIM1_CCR1);
  dma_set_memory_address(DMA1, DMA_CHANNEL2, (uint32_t)&PWM_phase[0]);
  dma_set_number_of_data(DMA1, DMA_CHANNEL2, PHASE_SIZE);
  dma_set_priority(DMA1, DMA_CHANNEL2, DMA_CCR_PL_MEDIUM);
  dma_set_read_from_memory(DMA1, DMA_CHANNEL2);
  dma_set_memory_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_16BIT);
  dma_set_peripheral_size(DMA1, DMA_CHANNEL2, DMA_CCR_MSIZE_16BIT);
  dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL2);
  dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL2);
  dma_enable_circular_mode(DMA1, DMA_CHANNEL2);
  dma_enable_channel(DMA1, DMA_CHANNEL2);

  // setup TIM2 
  rcc_periph_clock_enable(RCC_TIM2);
  timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
  timer_set_period(TIM2, 100);
  timer_set_dma_on_update_event(TIM2);
  timer_enable_counter(TIM2);

  while(1) {
    //__asm("nop");
  }
}

I can read through openocd that the TIM2 is ticking. But when the RCC_DMA is enabled, I cannot read DMA registers anymore (may be they are busy?).

Is there something wrong with DMA setup? Thank you!

And there is no libopencm3 tag yet?

\$\endgroup\$
0
\$\begingroup\$

you have 2 issues. First, You must give TIM1_CCR1 address, I recommend to use the macro TIM_CCR1() for this task:

dma_set_peripheral_address(DMA1, DMA_CHANNEL2, (uint32_t)&TIM_CCR1(TIM1));

Second, You are forgetting to enable the update event in the TIM2 config:

timer_enable_irq(TIM2, TIM_DIER_UDE);

Good luck!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.