/** * @brief Deactivates the PWM peripheral. * * @param[in] pwmp pointer to the @p PWMDriver object * * @notapi */ void pwm_lld_stop(PWMDriver *pwmp) { //{&TCCR1A, &TCCR1B, &OCR1AH,&OCR1AL,&OCR1BH,&OCR1BL,&OCR1CH,&OCR1CL,&TCNT1H,&TCNT1L,&TIFR1,&TIMSK1}, uint8_t index = getTimerIndex(pwmp); *timer_registers_table[index][1] &= ~((1<<CS12) |(1<<CS11) | (1<<CS10)); *timer_registers_table[index][11] = 0; }
/** * @brief Configures and activates the GPT peripheral. * * @param[in] gptp pointer to the @p GPTDriver object * * @notapi */ void gpt_lld_start(GPTDriver *gptp) { uint8_t psc; if (gptp->state == GPT_STOP) { /* Clock activation.*/ } /* Configuration.*/ #if AVR_GPT_USE_TIM2 || defined(__DOXYGEN__) if (gptp == &GPTD2) { psc = prescaler(gptp->config->frequency, ratio_extended, PRESCALER_SIZE_EXTENDED); gptp->clock_source = clock_source_extended[psc] & 0x07; TCCR2A = (1 << WGM21) | (0 << WGM20); TCCR2B = (0 << WGM22); OCR2A = F_CPU / ratio_extended[psc] /gptp->config->frequency - 1; return; } #endif uint8_t i = getTimerIndex(gptp); psc = prescaler(gptp->config->frequency, ratio_base, PRESCALER_SIZE_BASE); gptp->clock_source = clock_source_base[psc] & 0x07; *regs_table[i].tccra = (0 << WGM11) | (0 << WGM10) | (0 << COM1A1) | (0 << COM1A0) | (0 << COM1B1) | (0 << COM1B0); *regs_table[i].tccrb = (1 << WGM12); *regs_table[i].ocr1 = 0; *regs_table[i].ocr2 = F_CPU / ratio_base[psc] / gptp->config->frequency - 1; }
/** * @brief Stops the timer. * * @param[in] gptp pointer to the @p GPTDriver object * * @notapi */ void gpt_lld_stop_timer(GPTDriver *gptp) { uint8_t i = getTimerIndex(gptp); *regs_table[i].tccrb &= ~((7 << CS10) | (1 << OCIE1A)); *regs_table[i].tifr = (1 << OCF1A); }
/** * @brief Configures and activates the PWM peripheral. * * @param[in] pwmp pointer to the @p PWMDriver object * * @notapi */ void pwm_lld_start(PWMDriver *pwmp) { if ( pwmp->state == PWM_STOP) { /* Clock activation.*/ #if USE_AVR_PWM2 || defined(__DOXYGEN__) if(pwmp == &PWMD2) { TCCR2B |= (0<<CS22) |(0<<CS21) | (1<<CS20); //parti col no prescaling if(pwmp->config->callback != NULL) TIMSK2 = (1<<TOIE2); return; } #endif //{&TCCR1A, &TCCR1B, &OCR1AH,&OCR1AL,&OCR1BH,&OCR1BL,&OCR1CH,&OCR1CL,&TCNT1H,&TCNT1L,&TIFR1,&TIMSK1}, uint8_t index = getTimerIndex(pwmp); *timer_registers_table[index][1] |= (1<<CS12) |(0<<CS11) | (1<<CS10); *timer_registers_table[index][10] = (1<<TOIE1); } /* Configuration.*/ }
/** * @brief Starts the timer in continuous mode. * * @param[in] gptp pointer to the @p GPTDriver object * @param[in] period period in ticks * * @notapi */ void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t period) { gptp->callback = gptp->config->callback; gptp->period = period; gptp->counter = 0; uint8_t i = getTimerIndex(gptp); *regs_table[i].tcnt1 = 0; *regs_table[i].tcnt2 = 0; *regs_table[i].tifr = (1 << OCF1A); *regs_table[i].timsk = (1 << OCIE1A); *regs_table[i].tccrb |= (gptp->clock_source << CS10); }
/** * @brief Enables a PWM channel. * @pre The PWM unit must have been activated using @p pwmStart(). * @post The channel is active using the specified configuration. * @note Depending on the hardware implementation this function has * effect starting on the next cycle (recommended implementation) * or immediately (fallback implementation). * * @param[in] pwmp pointer to a @p PWMDriver object * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) * @param[in] width PWM pulse width as clock pulses number * * @notapi */ void pwm_lld_enable_channel(PWMDriver *pwmp, pwmchannel_t channel, pwmcnt_t width) { uint32_t val = width; val *= 256; val /= (uint32_t)pwmp->period; if(val > 0x00FF) val = 0xFF; #if USE_AVR_PWM2 || defined(__DOXYGEN__) if(pwmp == &PWMD2) { pwm_configure_hw_channel(&TCCR2A,7-2*channel,6-2*channel,pwmp->config->channels[channel].mode); TIMSK2 |= (1<< (channel + 1)); if(pwmp->config->channels[channel].callback != NULL) switch(channel) { case 0: OCR2A = val; break; case 1: OCR2B = val; break; } return; } #endif //{&TCCR1A, &TCCR1B, &OCR1AH,&OCR1AL,&OCR1BH,&OCR1BL,&OCR1CH,&OCR1CL,&TCNT1H,&TCNT1L,&TIFR1,&TIMSK1}, uint8_t index = getTimerIndex(pwmp); pwm_configure_hw_channel(timer_registers_table[index][0],7-2*channel,6-2*channel,pwmp->config->channels[channel].mode); *timer_registers_table[index][2*channel+2] = 0; *timer_registers_table[index][2*channel+3] = val; *timer_registers_table[index][10] |= (1<< (channel + 1)); if(pwmp->config->channels[channel].callback != NULL) { *timer_registers_table[index][11] |= (1<< (channel + 1)); } }
void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, motorPwmProtocolTypes_e pwmProtocolType) { 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); uint32_t hz; switch (pwmProtocolType) { case(PWM_TYPE_DSHOT600): hz = MOTOR_DSHOT600_MHZ * 1000000; break; case(PWM_TYPE_DSHOT300): hz = MOTOR_DSHOT300_MHZ * 1000000; break; default: case(PWM_TYPE_DSHOT150): hz = MOTOR_DSHOT150_MHZ * 1000000; } motor->TimHandle.Instance = timerHardware->tim; motor->TimHandle.Init.Prescaler = (SystemCoreClock / timerClockDivisor(timer) / hz) - 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; } switch (timerHardware->channel) { case TIM_CHANNEL_1: motor->timerDmaSource = TIM_DMA_ID_CC1; break; case TIM_CHANNEL_2: motor->timerDmaSource = TIM_DMA_ID_CC2; break; case TIM_CHANNEL_3: motor->timerDmaSource = TIM_DMA_ID_CC3; break; case TIM_CHANNEL_4: motor->timerDmaSource = TIM_DMA_ID_CC4; break; } 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)); dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), 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; TIM_OCInitStructure.OCPolarity = TIM_OCPOLARITY_HIGH; TIM_OCInitStructure.OCIdleState = TIM_OCIDLESTATE_RESET; TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET; 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; } }
void pwmDshotMotorHardwareConfig(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); 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(); RCC_ClockCmd(timerRCC(timer), ENABLE); motor->TimHandle.Instance = timerHardware->tim; motor->TimHandle.Init.Prescaler = (timerClock(timer) / getDshotHz(pwmProtocolType)) - 1; motor->TimHandle.Init.Period = pwmProtocolType == PWM_TYPE_PROSHOT1000 ? MOTOR_NIBBLE_LENGTH_PROSHOT : MOTOR_BITLENGTH; motor->TimHandle.Init.RepetitionCounter = 0; motor->TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; motor->TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; motor->TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_PWM_Init(&motor->TimHandle) != HAL_OK) { /* Initialization Error */ return; } 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->dmaRef == NULL) { /* Initialization Error */ return; } motor->hdma_tim.Instance = timerHardware->dmaRef; /* 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)); dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), 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.OCIdleState = TIM_OCIDLESTATE_RESET; TIM_OCInitStructure.OCPolarity = (output & TIMER_OUTPUT_INVERTED) ? TIM_OCPOLARITY_HIGH : TIM_OCPOLARITY_LOW; TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET; TIM_OCInitStructure.OCNPolarity = (output & TIMER_OUTPUT_INVERTED) ? TIM_OCNPOLARITY_HIGH : TIM_OCNPOLARITY_LOW; } else { TIM_OCInitStructure.OCIdleState = TIM_OCIDLESTATE_SET; TIM_OCInitStructure.OCPolarity = (output & TIMER_OUTPUT_INVERTED) ? TIM_OCPOLARITY_LOW : TIM_OCPOLARITY_HIGH; TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_SET; TIM_OCInitStructure.OCNPolarity = (output & TIMER_OUTPUT_INVERTED) ? TIM_OCNPOLARITY_LOW : TIM_OCNPOLARITY_HIGH; } 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; } }
void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, motorPwmProtocolTypes_e pwmProtocolType) { TIM_OCInitTypeDef TIM_OCInitStructure; DMA_InitTypeDef DMA_InitStructure; 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, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_UP), timerHardware->alternateFunction); if (configureTimer) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); RCC_ClockCmd(timerRCC(timer), ENABLE); TIM_Cmd(timer, DISABLE); uint32_t hz; switch (pwmProtocolType) { case(PWM_TYPE_DSHOT600): hz = MOTOR_DSHOT600_MHZ * 1000000; break; case(PWM_TYPE_DSHOT300): hz = MOTOR_DSHOT300_MHZ * 1000000; break; default: case(PWM_TYPE_DSHOT150): hz = MOTOR_DSHOT150_MHZ * 1000000; } TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)((SystemCoreClock / timerClockDivisor(timer) / hz) - 1); TIM_TimeBaseStructure.TIM_Period = MOTOR_BITLENGTH; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure); } TIM_OCStructInit(&TIM_OCInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) { TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; TIM_OCInitStructure.TIM_OCNPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCNPolarity_Low : TIM_OCNPolarity_High; } else { TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCPolarity_Low : TIM_OCPolarity_High; } TIM_OCInitStructure.TIM_Pulse = 0; timerOCInit(timer, timerHardware->channel, &TIM_OCInitStructure); timerOCPreloadConfig(timer, timerHardware->channel, TIM_OCPreload_Enable); motor->timerDmaSource = timerDmaSource(timerHardware->channel); dmaMotorTimers[timerIndex].timerDmaSources |= motor->timerDmaSource; TIM_CCxCmd(timer, timerHardware->channel, TIM_CCx_Enable); if (configureTimer) { TIM_CtrlPWMOutputs(timer, ENABLE); TIM_ARRPreloadConfig(timer, ENABLE); TIM_Cmd(timer, ENABLE); } DMA_Channel_TypeDef *channel = timerHardware->dmaChannel; if (channel == NULL) { /* trying to use a non valid channel */ return; } dmaInit(timerHardware->dmaIrqHandler, OWNER_MOTOR, RESOURCE_INDEX(motorIndex)); dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex); DMA_Cmd(channel, DISABLE); DMA_DeInit(channel); DMA_StructInit(&DMA_InitStructure); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)timerChCCR(timerHardware); DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)motor->dmaBuffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = MOTOR_DMA_BUFFER_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(channel, &DMA_InitStructure); DMA_ITConfig(channel, DMA_IT_TC, ENABLE); }
/** * @brief Disables a PWM channel. * @pre The PWM unit must have been activated using @p pwmStart(). * @post The channel is disabled and its output line returned to the * idle state. * @note Depending on the hardware implementation this function has * effect starting on the next cycle (recommended implementation) * or immediately (fallback implementation). * * @param[in] pwmp pointer to a @p PWMDriver object * @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1) * * @notapi */ void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) { uint8_t index = getTimerIndex(pwmp); pwm_configure_hw_channel(timer_registers_table[index][0],7-2*channel,6-2*channel,PWM_OUTPUT_DISABLED); *timer_registers_table[index][11] &= ~(1<< (channel + 1)); }