简体   繁体   English

STM32F7 两个定时器通道共用一个 DMA 通道

[英]STM32F7 Two Timer Channels Share One DMA Channel

I am trying to write a driver that sends DShot commands to an ESC.我正在尝试编写一个将DShot 命令发送到 ESC 的驱动程序。 I am using an STM32F722 MCU.我正在使用 STM32F722 MCU。 The DShot protocol is similar to addressable LEDs where 1/3 duty cycle represents a 0 and a 2/3 duty cycle represents a 1. The frequency is 600kHz for DShot600. DShot 协议类似于可寻址 LED,其中 1/3 占空比代表 0,2/3 占空比代表 1。DShot600 的频率为 600kHz。

All of my PWM channels are on TIM2.我所有的 PWM 通道都在 TIM2 上。 The problem is that TIM2_CH2 and TIM2_CH4 both share DMA1_Stream6_CH3.问题是 TIM2_CH2 和 TIM2_CH4 都共享 DMA1_Stream6_CH3。 TIM2_CH4 also exists on DMA1_Stream7_CH3. TIM2_CH4 也存在于 DMA1_Stream7_CH3 上。
DMA1 映射 However, when I try to enable outputs on both TIM2_CH2 and TIM2_CH4, the outputs start looking weird (see pic below).但是,当我尝试在 TIM2_CH2 和 TIM2_CH4 上启用输出时,输出开始看起来很奇怪(见下图)。 If I disable TIM2_CH2, the outputs on the 3 remaining channels look perfect (see pic below).如果我禁用 TIM2_CH2,其余 3 个通道的输出看起来很完美(见下图)。 不良数据 好数据

I think I might have to enable or disable the channels in a certain fashion to ensure they don't run at the same time.我想我可能必须以某种方式启用或禁用通道,以确保它们不会同时运行。 However, I need them to both output at the same time.但是,我需要它们同时使用 output。 Is this possible?这可能吗?

All relevant code is here.所有相关代码都在这里。 Fair warning, I don't use any HAL or LL libraries so it's a bit lengthy.公平的警告,我不使用任何 HAL 或 LL 库,所以它有点冗长。 main.c

#include "stm32f7xx.h"
#include "pwm.h"
#include "rcc.h"
#include "dwt.h"
#include "usart.h"
#include "drv_dshot.h"

uint16_t motor_value[4] = {2000, 2000, 2000, 2000};

int main(void){
    RCC_216MHz_Init();
    DWT_Init();

    dshot_init();


    while(1){
        dshot_write(motor_value);
        delay(1);

    }
}

void DMA1_Stream5_IRQHandler(void){
    if(DMA1->HISR & DMA_HISR_TCIF5){
        DMA1_Stream5->CR    &= ~DMA_SxCR_EN;
        while(DMA1_Stream5->CR & DMA_SxCR_EN){}
        TIM2->DIER          &= ~TIM_DIER_CC1DE;
        DMA1->HIFCR         |= DMA_HIFCR_CTCIF5;
        DMA1_Stream5->NDTR  = DSHOT_DMA_BUFFER_SIZE;
    }
}
void DMA1_Stream6_IRQHandler(void){
    if(DMA1->HISR & DMA_HISR_TCIF6){
        DMA1_Stream6->CR    &= ~DMA_SxCR_EN;
        while(DMA1_Stream6->CR & DMA_SxCR_EN){}
        TIM2->DIER          &= ~TIM_DIER_CC2DE;
        DMA1->HIFCR         |= DMA_HIFCR_CTCIF6;
        DMA1_Stream6->NDTR  = DSHOT_DMA_BUFFER_SIZE;
    }
}
void DMA1_Stream1_IRQHandler(void){
    if(DMA1->LISR & DMA_LISR_TCIF1){
        DMA1_Stream1->CR    &= ~DMA_SxCR_EN;
        while(DMA1_Stream1->CR & DMA_SxCR_EN){}
        TIM2->DIER          &= ~TIM_DIER_CC3DE;
        DMA1->LIFCR         |= DMA_LIFCR_CTCIF1;
        DMA1_Stream1->NDTR  = DSHOT_DMA_BUFFER_SIZE;
    }
}
void DMA1_Stream7_IRQHandler(void){
    if(DMA1->HISR & DMA_HISR_TCIF7){
        DMA1_Stream7->CR    &= ~DMA_SxCR_EN;
        while(DMA1_Stream7->CR & DMA_SxCR_EN){}
        TIM2->DIER          &= ~TIM_DIER_CC4DE;
        DMA1->HIFCR         |= DMA_HIFCR_CTCIF7;
        DMA1_Stream7->NDTR  = DSHOT_DMA_BUFFER_SIZE;
    }
}

drv_dshot.c

#include "stm32f7xx.h"
#include "stdbool.h"

#include "drv_dshot.h"

static uint32_t motor1_dmabuffer[DSHOT_DMA_BUFFER_SIZE];
static uint32_t motor2_dmabuffer[DSHOT_DMA_BUFFER_SIZE];
static uint32_t motor3_dmabuffer[DSHOT_DMA_BUFFER_SIZE];
static uint32_t motor4_dmabuffer[DSHOT_DMA_BUFFER_SIZE];

static uint16_t dshot_prepare_packet(uint16_t value);
static void dshot_prepare_dmabuffer_all(uint16_t *motor_value);
static void dshot_prepare_dmabuffer(uint32_t *motor_dmabuffer, uint16_t value);
static uint16_t dshot_prepare_packet(uint16_t value);
static void dshot_dma_start(void);
static void dshot_enable_dma_request(void);

void dshot_write(uint16_t *motor_value){
    dshot_prepare_dmabuffer_all(motor_value);
    dshot_enable_dma_request();
    dshot_dma_start();
}

static void dshot_prepare_dmabuffer_all(uint16_t *motor_value){
    dshot_prepare_dmabuffer(motor1_dmabuffer, motor_value[0]);
    dshot_prepare_dmabuffer(motor2_dmabuffer, motor_value[1]);
    DMA1_Stream1->NDTR  |= DSHOT_DMA_BUFFER_SIZE;
    dshot_prepare_dmabuffer(motor3_dmabuffer, motor_value[2]);
    DMA1_Stream6->NDTR  |= DSHOT_DMA_BUFFER_SIZE;
    dshot_prepare_dmabuffer(motor4_dmabuffer, motor_value[3]);
    DMA1_Stream5->NDTR  |= DSHOT_DMA_BUFFER_SIZE;
}

static void dshot_prepare_dmabuffer(uint32_t *motor_dmabuffer, uint16_t value)
{
    uint16_t packet;
    packet = dshot_prepare_packet(value);

    for(int i = 0; i < 16; i++)
    {
        motor_dmabuffer[i] = (packet & 0x8000) ? MOTOR_BIT_1 : MOTOR_BIT_0;
        packet <<= 1;
    }

    motor_dmabuffer[16] = 0;
    motor_dmabuffer[17] = 0;

}

static uint16_t dshot_prepare_packet(uint16_t value){
    uint16_t packet;
    bool dshot_telemetry = false;

    packet = (value << 1) | (dshot_telemetry ? 1 : 0);

    // compute checksum
    unsigned csum = 0;
    unsigned csum_data = packet;

    for(int i = 0; i < 3; i++)
    {
        csum ^=  csum_data; // xor data by nibbles
        csum_data >>= 4;
    }

    csum &= 0xf;
    packet = (packet << 4) | csum;

    return packet;
}

static void dshot_dma_start(void){
    TIM2->CNT           = 0;

    TIM2->DIER          |= TIM_DIER_CC1DE;
    TIM2->DIER          |= TIM_DIER_CC2DE;
    TIM2->DIER          |= TIM_DIER_CC3DE;
    TIM2->DIER          |= TIM_DIER_CC4DE;
}

static void dshot_enable_dma_request(void){


    DMA1_Stream5->CR    |= DMA_SxCR_EN;
    DMA1_Stream6->CR    |= DMA_SxCR_EN;
    DMA1_Stream1->CR    |= DMA_SxCR_EN;
    DMA1_Stream7->CR    |= DMA_SxCR_EN;
}

void dshot_init(void){
    /////////////////GPIO INIT///////////////////
    // enable clock for GPIOA
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    // set mode, speed, type, pull, AF
    GPIOA->MODER    &= ~GPIO_MODER_MODER0;
    GPIOA->MODER    |= GPIO_MODER_MODER0_1;
    GPIOA->OSPEEDR  &= ~GPIO_OSPEEDR_OSPEEDR0;
    GPIOA->OTYPER   &= ~GPIO_OTYPER_OT0;
    GPIOA->PUPDR    &= ~GPIO_PUPDR_PUPDR0;
    GPIOA->AFR[0]   &= ~GPIO_AFRL_AFRL0;
    GPIOA->AFR[0]   |= (GPIO_AF1_TIM2 << (4U * 0U));

    GPIOA->MODER    &= ~GPIO_MODER_MODER1;
    GPIOA->MODER    |= GPIO_MODER_MODER1_1;
    GPIOA->OSPEEDR  &= ~GPIO_OSPEEDR_OSPEEDR1;
    GPIOA->OTYPER   &= ~GPIO_OTYPER_OT1;
    GPIOA->PUPDR    &= ~GPIO_PUPDR_PUPDR1;
    GPIOA->AFR[0]   &= ~GPIO_AFRL_AFRL1;
    GPIOA->AFR[0]   |= (GPIO_AF1_TIM2 << (4U * 1U));

    GPIOA->MODER    &= ~GPIO_MODER_MODER2;
    GPIOA->MODER    |= GPIO_MODER_MODER2_1;
    GPIOA->OSPEEDR  &= ~GPIO_OSPEEDR_OSPEEDR2;
    GPIOA->OTYPER   &= ~GPIO_OTYPER_OT2;
    GPIOA->PUPDR    &= ~GPIO_PUPDR_PUPDR2;
    GPIOA->AFR[0]   &= ~GPIO_AFRL_AFRL2;
    GPIOA->AFR[0]   |= (GPIO_AF1_TIM2 << (4U * 2U));

    GPIOA->MODER    &= ~GPIO_MODER_MODER3;
    GPIOA->MODER    |= GPIO_MODER_MODER3_1;
    GPIOA->OSPEEDR  &= ~GPIO_OSPEEDR_OSPEEDR3;
    GPIOA->OTYPER   &= ~GPIO_OTYPER_OT3;
    GPIOA->PUPDR    &= ~GPIO_PUPDR_PUPDR3;
    GPIOA->AFR[0]   &= ~GPIO_AFRL_AFRL3;
    GPIOA->AFR[0]   |= (GPIO_AF1_TIM2 << (4U * 3U));

    /////////////////TIMER INIT///////////////////
    // enable clock for TIM2
    RCC->APB1ENR    |= RCC_APB1ENR_TIM2EN;
    TIM2->CR1       &= ~TIM_CR1_CEN;
    // set PSC, AR, clock div, cnt, cnt mode
    TIM2->PSC       = 0;    //(uint16_t)((float) TIMER_CLOCK / 12000000) - 1;
    TIM2->ARR       = MOTOR_BITLENGTH;
    TIM2->CR1       &= ~TIM_CR1_CKD;
    TIM2->CR1       &= ~TIM_CR1_DIR;
    // set output compare mode
    // channel 1
    TIM2->CCER      &= ~TIM_CCER_CC1E;
    TIM2->CCMR1     |= TIM_CCMR1_OC1M_1 |
                       TIM_CCMR1_OC1M_2;
    TIM2->CCER      &= ~TIM_CCER_CC1P;
    TIM2->CCR1      = 0;
    TIM2->CCER      |= TIM_CCER_CC1E;
    // channel 2
    TIM2->CCER      &= ~TIM_CCER_CC2E;
    TIM2->CCMR1     |= TIM_CCMR1_OC2M_1 |
                       TIM_CCMR1_OC2M_2;
    TIM2->CCER      &= ~TIM_CCER_CC2P;
    TIM2->CCR2      = 0;
    TIM2->CCER      |= TIM_CCER_CC2E;
    // channel 3
    TIM2->CCER      &= ~TIM_CCER_CC3E;
    TIM2->CCMR2     |= TIM_CCMR2_OC3M_1 |
                       TIM_CCMR2_OC3M_2;
    TIM2->CCER      &= ~TIM_CCER_CC3P;
    TIM2->CCR3      = 0;
    TIM2->CCER      |= TIM_CCER_CC3E;
    // channel 4
    TIM2->CCER      &= ~TIM_CCER_CC4E;
    TIM2->CCMR2     |= TIM_CCMR2_OC4M_1 |
                       TIM_CCMR2_OC4M_2;
    TIM2->CCER      &= ~TIM_CCER_CC4P;
    TIM2->CCR4      = 0;
    TIM2->CCER      |= TIM_CCER_CC4E;
    // enable preload
    TIM2->CCMR1     |= TIM_CCMR1_OC1PE;
    TIM2->CCMR1     |= TIM_CCMR1_OC2PE;
    TIM2->CCMR2     |= TIM_CCMR2_OC3PE;
    TIM2->CCMR2     |= TIM_CCMR2_OC4PE;
    //
    TIM2->CR1       |= TIM_CR1_ARPE;
    // enable the counter
    TIM2->CR1       |= TIM_CR1_CEN;

    /////////////////DMA INIT///////////////////
    /*
     * TIM2_CH1 on Stream5_CH3
     * TIM2_CH2 on Stream6_CH3
     * TIM2_CH3 on Stream1_CH3
     * TIM2_CH4 on Stream7_CH3
     */

    // reset DMA
    RCC->AHB1RSTR       |= RCC_AHB1RSTR_DMA1RST;
    RCC->AHB1RSTR       &= ~RCC_AHB1RSTR_DMA1RST;
    // disable DMA stream 5
    DMA1_Stream5->CR    &= ~DMA_SxCR_EN;
    while(DMA1_Stream5->CR & DMA_SxCR_EN){}
    DMA1_Stream5->CR    = 0;
    DMA1_Stream5->NDTR  = 0;
    DMA1_Stream5->PAR   = 0;
    DMA1_Stream5->M0AR  = 0;
    DMA1_Stream5->M1AR  = 0;
    DMA1_Stream5->FCR   = 0x00000021U;
    DMA1_Stream5->CR    &= ~DMA_SxCR_CHSEL;
    DMA1->HIFCR         |= 0x00000F40U;
    // disable DMA stream 6
    DMA1_Stream6->CR    &= ~DMA_SxCR_EN;
    while(DMA1_Stream6->CR & DMA_SxCR_EN){}
    DMA1_Stream6->CR    = 0;
    DMA1_Stream6->NDTR  = 0;
    DMA1_Stream6->PAR   = 0;
    DMA1_Stream6->M0AR  = 0;
    DMA1_Stream6->M1AR  = 0;
    DMA1_Stream6->FCR   = 0x00000021U;
    DMA1_Stream6->CR    &= ~DMA_SxCR_CHSEL;
    DMA1->HIFCR         |= 0x003F0000U;
    // disable DMA stream 1
    DMA1_Stream1->CR    &= ~DMA_SxCR_EN;
    while(DMA1_Stream1->CR & DMA_SxCR_EN){}
    DMA1_Stream1->CR    = 0;
    DMA1_Stream1->NDTR  = 0;
    DMA1_Stream1->PAR   = 0;
    DMA1_Stream1->M0AR  = 0;
    DMA1_Stream1->M1AR  = 0;
    DMA1_Stream1->FCR   = 0x00000021U;
    DMA1_Stream1->CR    &= ~DMA_SxCR_CHSEL;
    DMA1->LIFCR         |= 0x00000F40U;
    // disable DMA stream 7
    DMA1_Stream7->CR    &= ~DMA_SxCR_EN;
    while(DMA1_Stream7->CR & DMA_SxCR_EN){}
    DMA1_Stream7->CR    = 0;
    DMA1_Stream7->NDTR  = 0;
    DMA1_Stream7->PAR   = 0;
    DMA1_Stream7->M0AR  = 0;
    DMA1_Stream7->M1AR  = 0;
    DMA1_Stream7->FCR   = 0x00000021U;
    DMA1_Stream7->CR    &= ~DMA_SxCR_CHSEL;
    DMA1->HIFCR         |= 0x0F400000U;
    // enable clock
    RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
    // enable interrupts
    NVIC_SetPriority(DMA1_Stream5_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
    NVIC_EnableIRQ(DMA1_Stream5_IRQn);

    NVIC_SetPriority(DMA1_Stream6_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
    NVIC_EnableIRQ(DMA1_Stream6_IRQn);

    NVIC_SetPriority(DMA1_Stream1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
    NVIC_EnableIRQ(DMA1_Stream1_IRQn);

    NVIC_SetPriority(DMA1_Stream7_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
    NVIC_EnableIRQ(DMA1_Stream7_IRQn);
    // motor 4 DMA settings
    DMA1_Stream5->CR    |= (0x3 << 25U);
    DMA1_Stream5->M0AR  = (uint32_t)motor4_dmabuffer;
    DMA1_Stream5->CR    |= DMA_SxCR_DIR_0;          // mem to per
    DMA1_Stream5->FCR   |= DMA_SxFCR_DMDIS;         // fifo en
    DMA1_Stream5->FCR   &= ~DMA_SxFCR_FTH;          //1/4 full
    DMA1_Stream5->CR    &= ~DMA_SxCR_MBURST;
    DMA1_Stream5->CR    &= ~DMA_SxCR_PBURST;
    DMA1_Stream5->PAR   = (uint32_t)(&(TIM2->CCR1));
    DMA1_Stream5->NDTR  = DSHOT_DMA_BUFFER_SIZE;
    DMA1_Stream5->CR    &= ~DMA_SxCR_PINC;
    DMA1_Stream5->CR    |= DMA_SxCR_MINC;
    DMA1_Stream5->CR    |= DMA_SxCR_MSIZE_1;
    DMA1_Stream5->CR    |= DMA_SxCR_PSIZE_1;
    DMA1_Stream5->CR    &= ~DMA_SxCR_CIRC;
    DMA1_Stream5->CR    |= DMA_SxCR_PL_0;
    // DMA transfer complete interrupt enable
    DMA1_Stream5->CR    |= DMA_SxCR_TCIE;
    // motor 4 DMA settings
    DMA1_Stream6->CR    |= (0x3 << 25U);
    DMA1_Stream6->M0AR  = (uint32_t)motor3_dmabuffer;
    DMA1_Stream6->CR    |= DMA_SxCR_DIR_0;          // mem to per
    DMA1_Stream6->FCR   |= DMA_SxFCR_DMDIS;         // fifo en
    DMA1_Stream6->FCR   &= ~DMA_SxFCR_FTH;          //1/4 full
    DMA1_Stream6->CR    &= ~DMA_SxCR_MBURST;
    DMA1_Stream6->CR    &= ~DMA_SxCR_PBURST;
    DMA1_Stream6->PAR   = (uint32_t)(&(TIM2->CCR2));
    DMA1_Stream6->NDTR  = DSHOT_DMA_BUFFER_SIZE;
    DMA1_Stream6->CR    &= ~DMA_SxCR_PINC;
    DMA1_Stream6->CR    |= DMA_SxCR_MINC;
    DMA1_Stream6->CR    |= DMA_SxCR_MSIZE_1;
    DMA1_Stream6->CR    |= DMA_SxCR_PSIZE_1;
    DMA1_Stream6->CR    &= ~DMA_SxCR_CIRC;
    DMA1_Stream6->CR    |= DMA_SxCR_PL;
    // DMA transfer complete interrupt enable
    DMA1_Stream6->CR    |= DMA_SxCR_TCIE;
    // motor 2 DMA settings
    DMA1_Stream1->CR    |= (0x3 << 25U);
    DMA1_Stream1->M0AR  = (uint32_t)motor2_dmabuffer;
    DMA1_Stream1->CR    |= DMA_SxCR_DIR_0;          // mem to per
    DMA1_Stream1->FCR   |= DMA_SxFCR_DMDIS;         // fifo en
    DMA1_Stream1->FCR   &= ~DMA_SxFCR_FTH;          //1/4 full
    DMA1_Stream1->CR    &= ~DMA_SxCR_MBURST;
    DMA1_Stream1->CR    &= ~DMA_SxCR_PBURST;
    DMA1_Stream1->PAR   = (uint32_t)(&(TIM2->CCR3));
    DMA1_Stream1->NDTR  = DSHOT_DMA_BUFFER_SIZE;
    DMA1_Stream1->CR    &= ~DMA_SxCR_PINC;
    DMA1_Stream1->CR    |= DMA_SxCR_MINC;
    DMA1_Stream1->CR    |= DMA_SxCR_MSIZE_1;
    DMA1_Stream1->CR    |= DMA_SxCR_PSIZE_1;
    DMA1_Stream1->CR    &= ~DMA_SxCR_CIRC;
    DMA1_Stream1->CR    |= DMA_SxCR_PL_0;
    // DMA transfer complete interrupt enable
    DMA1_Stream1->CR    |= DMA_SxCR_TCIE;
    // motor 4 DMA settings
    DMA1_Stream7->CR    |= (0x3 << 25U);
    DMA1_Stream7->M0AR  = (uint32_t)motor1_dmabuffer;
    DMA1_Stream7->CR    |= DMA_SxCR_DIR_0;          // mem to per
    DMA1_Stream7->FCR   |= DMA_SxFCR_DMDIS;         // fifo en
    DMA1_Stream7->FCR   &= ~DMA_SxFCR_FTH;          //1/4 full
    DMA1_Stream7->CR    &= ~DMA_SxCR_MBURST;
    DMA1_Stream7->CR    &= ~DMA_SxCR_PBURST;
    DMA1_Stream7->PAR   = (uint32_t)(&(TIM2->CCR4));
    DMA1_Stream7->NDTR  = DSHOT_DMA_BUFFER_SIZE;
    DMA1_Stream7->CR    &= ~DMA_SxCR_PINC;
    DMA1_Stream7->CR    |= DMA_SxCR_MINC;
    DMA1_Stream7->CR    |= DMA_SxCR_MSIZE_1;
    DMA1_Stream7->CR    |= DMA_SxCR_PSIZE_1;
    DMA1_Stream7->CR    &= ~DMA_SxCR_CIRC;
    DMA1_Stream7->CR    |= DMA_SxCR_PL_0;
    // DMA transfer complete interrupt enable
    DMA1_Stream7->CR    |= DMA_SxCR_TCIE;
}

drv_dshot.h

/*
 * drv_dshot.h
 *
 *  Created on: Dec 29, 2021
 *      Author: jeremywolfe
 */

#ifndef DRV_DRV_DSHOT_H_
#define DRV_DRV_DSHOT_H_

/* User Configuration */
// Timer Clock
#define TIMER_CLOCK             108000000   // 100MHz

// MOTOR 1 (PA3) - TIM5 Channel 4, DMA1 Stream 3
#define MOTOR_1_TIM             (&htim2)
#define MOTOR_1_TIM_CHANNEL     TIM_CHANNEL_4

// MOTOR 2 (PA2) - TIM2 Channel 3, DMA1 Stream 1
#define MOTOR_2_TIM             (&htim2)
#define MOTOR_2_TIM_CHANNEL     TIM_CHANNEL_3

// MOTOR 3 (PA0) - TIM2 Channel 1, DMA1 Stream 5
#define MOTOR_3_TIM             (&htim2)
#define MOTOR_3_TIM_CHANNEL     TIM_CHANNEL_1

// MOTOR 4 (PA1) - TIM5 Channel 2, DMA1 Stream 4
#define MOTOR_4_TIM             (&htim2)
#define MOTOR_4_TIM_CHANNEL     TIM_CHANNEL_2


/* Definition */
#define MHZ_TO_HZ(x)            ((x) * 1000000)

#define DSHOT600_HZ             MHZ_TO_HZ(12)
#define DSHOT300_HZ             MHZ_TO_HZ(6)
#define DSHOT150_HZ             MHZ_TO_HZ(3)

#define MOTOR_BIT_0             60
#define MOTOR_BIT_1             120
#define MOTOR_BITLENGTH         180

#define DSHOT_FRAME_SIZE        16
#define DSHOT_DMA_BUFFER_SIZE   18 /* resolution + frame reset (2us) */

#define DSHOT_MIN_THROTTLE      48
#define DSHOT_MAX_THROTTLE      2047
#define DSHOT_RANGE             (DSHOT_MAX_THROTTLE - DSHOT_MIN_THROTTLE)


/* Functions */
void dshot_init(void);
void dshot_write(uint16_t *motor_value);

#endif /* DRV_DRV_DSHOT_H_ */

I decided to instead use TIM5 because it shares the exact same pins as TIM2.我决定改用 TIM5,因为它与 TIM2 共享完全相同的引脚。 However, TIM5 has no overlaps on the DMA Request Mapping.但是,TIM5 在 DMA 请求映射上没有重叠。 After changing the code, it works just as intended.更改代码后,它按预期工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM