Inexplicable extra pulses when using PWM + DMA
I'm try to generate some pulses to PB0 using STM32F103C8T6 with the following code
#include <stdint.h>
// STM32F103C8 is a medium density device, hence we use the xB header
#include <stm32f103xb.h>
#if !defined(__SOFT_FP__) && defined(__ARM_FP)
#warning \
"FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif
void enable_clock() {
RCC->CR |= RCC_CR_HSION;
while ((RCC->CR & RCC_CR_HSIRDY) == 0);
}
// @formatter:off
#define HI 6
#define LO 3
uint16_t buffer[] = {
0, LO, HI, LO
};
// @formatter:on
void blink_dma_to_gpio() {
enable_clock();
// GPIO B configuration
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Enable IO port B
GPIOB->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_MODE0); // GPIO B: Clear pin 6 configuration
GPIOB->CRL |= GPIO_CRL_CNF0_1 | GPIO_CRL_MODE0_0; // GPIO B: Set pin 6 to alternate function push-pull 10MHz output
// TIM3 configuration
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // Enable TIM3
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; // Enable alternate function
TIM3->PSC = 1 - 1;
TIM3->ARR = 10 - 1;
TIM3->CR1 |= TIM_CR1_ARPE;
TIM3->BDTR |= TIM_BDTR_MOE;
TIM3->CCMR2 |= TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 // PWM mode 1
| TIM_CCMR2_OC3PE // Enable preload
;
TIM3->CCER |= TIM_CCER_CC3E; // Enable capture compare 3
TIM3->CCMR2 |= TIM_CCMR2_OC4M_0; // Active on match
TIM3->CCER |= TIM_CCER_CC4E; // Enable capture compare 4
TIM3->DIER |= TIM_DIER_CC4DE; // Enable DMA1 request
TIM3->CCR4 = 7;
// DMA1 configuration
RCC->AHBENR |= RCC_AHBENR_DMA1EN; // Enable DMA1
DMA1_Channel3->CPAR = (uint32_t) &TIM3->CCR3;
DMA1_Channel3->CMAR = (uint32_t) &buffer;
DMA1_Channel3->CNDTR = sizeof(buffer) / sizeof(buffer[0]);
DMA1_Channel3->CCR = DMA_CCR_PL // Very high priority
| DMA_CCR_MSIZE_0 // 16 bit peripheral
| DMA_CCR_PSIZE_0 // 16 bit peripheral
| DMA_CCR_MINC // Increment memory
| DMA_CCR_CIRC // Circular memory
| DMA_CCR_DIR // Memory to peripheral
| DMA_CCR_HTIE // Half transfer interrupt
| DMA_CCR_TCIE // Transfer complete interrupt
;
NVIC_EnableIRQ(DMA1_Channel3_IRQn);
// Enable peripherals
DMA1_Channel3->CCR |= DMA_CCR_EN;
TIM3->CR1 |= TIM_CR1_CEN;
}
int main() {
blink_dma_to_gpio();
for (;;);
}
void DMA1_Channel3_IRQHandler() {
if (DMA1->ISR & DMA_ISR_HTIF3) {
DMA1->IFCR = DMA_IFCR_CHTIF3;
}
if (DMA1->ISR & DMA_ISR_TCIF3) {
DMA1->IFCR = DMA_IFCR_CTCIF3;
}
}I expect there to be only 3 pulses from the beginning to the end of the DMA buffer. However, when hooking to an oscilloscope, the pulses output are inconsistent.
Some pulses are right with short, long, and short pulses, but some pulses just have random long or short pulse in them. I can't see what's wrong with my code. Please let me know if there is anything potentially wrong with my code.
