2017-03-01 09:26 AM
I want to refactor this code from Betaflight
/external-link.jspa?url=https%3A%2F%2Fgithub.com%2Fcleanflight%2Fcleanflight%2Fblob%2Ffd1d8d532e8a21fec0b044e984f465b81f4cbed1%2Fsrc%2Fmain%2Fdrivers%2Fpwm_output_stm32f7xx.c
. It is to control brushless motors using a new digital protocol known as Dshot, which replaces PWM for escs for quadcopters etc. I want to use it for my robot for Piwars 2017.
The function that I am having problems understanding is the pwmDigitalMotorHardwareConfig . It is programmed in a generic way but I only need to use the dshot 1200 protocol, for four motors and one Nucleo board(f767zi at the moment)How do I start to understand what is going with regards to the timers, PWM and DMA so that I can modify it for my own needs ?
void
pwmDigitalMotorHardwareConfig
(const
timerHardware_t *timerHardware,uint8_t
motorIndex, motorPwmProtocolTypes_e pwmProtocolType,uint8_t
output){
motorDmaOutput_t *
const
motor = &dmaMotors[motorIndex];motor->timerHardware = timerHardware;
TIM_TypeDef *timer = timerHardware->tim;
const
IO_t motorIO =IOGetByTag
(timerHardware->tag);const
uint8_t
timerIndex =getTimerIndex
(timer);const
bool
configureTimer = (timerIndex == dmaMotorTimerCount-1
);IOInit
(motorIO, OWNER_MOTOR,RESOURCE_INDEX
(motorIndex));IOConfigGPIOAF
(motorIO,IO_CONFIG
(GPIO_MODE_AF_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLUP), timerHardware->alternateFunction);__DMA1_CLK_ENABLE
();if
(configureTimer) {RCC_ClockCmd
(timerRCC
(timer), ENABLE);motor->TimHandle.
Instance
= timerHardware->tim;motor->TimHandle.
Init
.Prescaler
= (SystemCoreClock /timerClockDivisor
(timer) /getDshotHz
(pwmProtocolType)) -1
;;motor->TimHandle.
Init
.Period
= MOTOR_BITLENGTH;motor->TimHandle.
Init
.RepetitionCounter
=0
;motor->TimHandle.
Init
.ClockDivision
= TIM_CLOCKDIVISION_DIV1;motor->TimHandle.
Init
.CounterMode
= TIM_COUNTERMODE_UP;if
(HAL_TIM_PWM_Init
(&motor->TimHandle) != HAL_OK){
/*
Initialization Error*/
return
;}
}
else
{
motor->TimHandle = dmaMotors[timerIndex].
TimHandle
;}
motor->timerDmaSource =
timerDmaSource
(timerHardware->channel);dmaMotorTimers[timerIndex].
timerDmaSources
|= motor->timerDmaSource;/*
Set the parameters to be configured*/
motor->hdma_tim.
Init
.Channel
= timerHardware->dmaChannel;motor->hdma_tim.
Init
.Direction
= DMA_MEMORY_TO_PERIPH;motor->hdma_tim.
Init
.PeriphInc
= DMA_PINC_DISABLE;motor->hdma_tim.
Init
.MemInc
= DMA_MINC_ENABLE;motor->hdma_tim.
Init
.PeriphDataAlignment
= DMA_PDATAALIGN_WORD;motor->hdma_tim.
Init
.MemDataAlignment
= DMA_MDATAALIGN_WORD;motor->hdma_tim.
Init
.Mode
= DMA_NORMAL;motor->hdma_tim.
Init
.Priority
= DMA_PRIORITY_HIGH;motor->hdma_tim.
Init
.FIFOMode
= DMA_FIFOMODE_DISABLE;motor->hdma_tim.
Init
.FIFOThreshold
= DMA_FIFO_THRESHOLD_FULL;motor->hdma_tim.
Init
.MemBurst
= DMA_MBURST_SINGLE;motor->hdma_tim.
Init
.PeriphBurst
= DMA_PBURST_SINGLE;/*
Set hdma_tim instance*/
if
(timerHardware->dmaStream ==NULL
){
/*
Initialization Error*/
return
;}
motor->hdma_tim.
Instance
= timerHardware->dmaStream;/*
Link hdma_tim to hdma[x] (channelx)*/
__HAL_LINKDMA
(&motor->TimHandle, hdma[motor->timerDmaSource], motor->hdma_tim);dmaInit
(timerHardware->dmaIrqHandler, OWNER_MOTOR,RESOURCE_INDEX
(motorIndex));/*
Initialize TIMx DMA handle*/
if
(HAL_DMA_Init
(motor->TimHandle.hdma
[motor->timerDmaSource]) != HAL_OK){
/*
Initialization Error*/
return
;}
TIM_OC_InitTypeDef TIM_OCInitStructure;
/*
PWM1 Mode configuration: Channel1*/
TIM_OCInitStructure.
OCMode
= TIM_OCMODE_PWM1;if
(output & TIMER_OUTPUT_N_CHANNEL) {TIM_OCInitStructure.
OCNPolarity
= (output & TIMER_OUTPUT_INVERTED) ? TIM_OCNPOLARITY_HIGH : TIM_OCNPOLARITY_LOW;TIM_OCInitStructure.
OCNIdleState
= TIM_OCNIDLESTATE_RESET;}
else
{TIM_OCInitStructure.
OCPolarity
= (output & TIMER_OUTPUT_INVERTED) ? TIM_OCPOLARITY_LOW : TIM_OCPOLARITY_HIGH;TIM_OCInitStructure.
OCIdleState
= TIM_OCIDLESTATE_SET;}
TIM_OCInitStructure.
OCFastMode
= TIM_OCFAST_DISABLE;TIM_OCInitStructure.
Pulse
=0
;if
(HAL_TIM_PWM_ConfigChannel
(&motor->TimHandle, &TIM_OCInitStructure, motor->timerHardware->channel) != HAL_OK){
/*
Configuration Error*/
return
;}
}
null2017-03-01 10:33 AM
Seems to be configuring the timer with a defined periodicity(frequency), and then sending 16-bits by modulating the pulse width using DMA to load the new TIM->CCR1 at each Update (Period)
2017-03-02 06:20 AM
Yes, but the pulse width is 0 or a fixed (bit) lenght. The timer outputs are 'abused' for writing digital data using DMA burst function. This is because normal Motor ESCs are driven by a variable pulse length and here the same hardware must be used.
Dieter
2017-03-02 08:05 AM
Ok, but that doesn't appear to be what this code is doing, it has fixed periodicity, and two, non-zero, pulse widths.
♯ define MOTOR_BIT_0 7
♯ define MOTOR_BIT_1 14 ♯ define MOTOR_BITLENGTH 19There may be some intervening idle time, but don't see that in the code.
'
How do I start to understand what is going with regards to the timers, PWM and DMA so that I can modify it for my own needs ?
'I think my answer addresses this question. How it functions systemically, beyond that is another matter.
2017-03-02 08:46 AM
You are right. The 0s are short pulses not missing pulses.