mirror of
https://gitee.com/Lyon1998/pikapython.git
synced 2025-01-15 17:02:53 +08:00
457 lines
13 KiB
C
457 lines
13 KiB
C
/*
|
|
* Copyright 2021 MindMotion Microelectronics Co., Ltd.
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "hal_tim.h"
|
|
|
|
bool TIM_Init(TIM_Type * TIMx, TIM_Init_Type * init)
|
|
{
|
|
uint32_t cr1 = TIMx->CR1 &~ ( TIM_CR1_OPM_MASK
|
|
| TIM_CR1_ARPE_MASK
|
|
| TIM_CR1_CMS_MASK
|
|
| TIM_CR1_DIR_MASK
|
|
);
|
|
cr1 |= TIM_CR1_OPM(init->PeriodMode);
|
|
cr1 |= ((init->EnablePreloadPeriod) ? TIM_CR1_ARPE_MASK: 0u);
|
|
TIMx->CR1 = cr1;
|
|
|
|
/* Check the vadility of StepFreqHz. */
|
|
if ( (init->StepFreqHz == 0u) || (init->StepFreqHz > init->ClockFreqHz) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
switch (init->CountMode)
|
|
{
|
|
case TIM_CountMode_Increasing:
|
|
break;
|
|
case TIM_CountMode_Decreasing:
|
|
cr1 |= TIM_CR1_DIR_MASK;
|
|
break;
|
|
case TIM_CountMode_CenterAligned1:
|
|
cr1 |= TIM_CR1_CMS(1u);
|
|
break;
|
|
case TIM_CountMode_CenterAligned2:
|
|
cr1 |= TIM_CR1_CMS(2u);
|
|
break;
|
|
case TIM_CountMode_CenterAligned3:
|
|
cr1 |= TIM_CR1_CMS(3u);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Calculate the prescaler. */
|
|
TIMx->PSC = init->ClockFreqHz / init->StepFreqHz - 1u;
|
|
TIMx->ARR = init->Period;
|
|
return true;
|
|
}
|
|
|
|
void TIM_Start(TIM_Type * TIMx)
|
|
{
|
|
TIMx->CR1 |= TIM_CR1_CEN_MASK;
|
|
}
|
|
|
|
void TIM_Stop(TIM_Type * TIMx)
|
|
{
|
|
TIMx->CR1 &= ~TIM_CR1_CEN_MASK;
|
|
}
|
|
|
|
uint32_t TIM_GetCounterValue(TIM_Type * TIMx)
|
|
{
|
|
return TIMx->CNT;
|
|
}
|
|
|
|
void TIM_ClearCounterValue(TIM_Type * TIMx)
|
|
{
|
|
TIMx->CNT = 0u;
|
|
}
|
|
|
|
void TIM_EnableInterrupts(TIM_Type * TIMx, uint32_t interrupts, bool enable)
|
|
{
|
|
if (enable)
|
|
{
|
|
TIMx->DIER |= interrupts;
|
|
}
|
|
else
|
|
{
|
|
TIMx->DIER &= ~interrupts;
|
|
}
|
|
}
|
|
|
|
void TIM_EnableDMA(TIM_Type * TIMx, uint32_t dmas, bool enable)
|
|
{
|
|
if (enable)
|
|
{
|
|
TIMx->DIER |= dmas;
|
|
}
|
|
else
|
|
{
|
|
TIMx->DIER &= ~dmas;
|
|
}
|
|
}
|
|
|
|
void TIM_DoSwTrigger(TIM_Type * TIMx, uint32_t swtrgs)
|
|
{
|
|
TIMx->EGR = swtrgs;
|
|
}
|
|
|
|
uint32_t TIM_GetInterruptStatus(TIM_Type * TIMx)
|
|
{
|
|
return TIMx->SR;
|
|
}
|
|
|
|
void TIM_ClearInterruptStatus(TIM_Type * TIMx, uint32_t status)
|
|
{
|
|
TIMx->SR &= ~status;
|
|
}
|
|
|
|
/*******************************/
|
|
static void _TIM_WriteChannelCtrlReg(TIM_Type * TIMx, uint32_t channel, uint32_t regval)
|
|
{
|
|
switch (channel)
|
|
{
|
|
case TIM_CHN_1:
|
|
TIMx->CCMR1 = (TIMx->CCMR1 & ~(0xFF)) | (regval & 0xFF);
|
|
break;
|
|
case TIM_CHN_2:
|
|
TIMx->CCMR1 = (TIMx->CCMR1 & ~(0xFF00)) | ((regval & 0xFF) << 8u);
|
|
break;
|
|
case TIM_CHN_3:
|
|
TIMx->CCMR2 = (TIMx->CCMR2 & ~(0xFF)) | (regval & 0xFF);
|
|
break;
|
|
case TIM_CHN_4:
|
|
TIMx->CCMR2 = (TIMx->CCMR2 & ~(0xFF00)) | ((regval & 0xFF) << 8u);
|
|
break;
|
|
case TIM_CHN_5:
|
|
TIMx->CCMR3 = (TIMx->CCMR2 & ~(0xFF)) | (regval & 0xFF);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void TIM_EnableOutputCompare(TIM_Type * TIMx, uint32_t channel, TIM_OutputCompareConf_Type * conf)
|
|
{
|
|
uint32_t regval = TIM_CCMR1_CC1S(TIM_ChannelIOMode_Out) /* output compare mode. */
|
|
| ( (conf->EnableFastOutput) ? TIM_CCMR1_OC1FE_MASK : 0u ) /* fast output. */
|
|
| ( (conf->EnablePreLoadChannelValue) ? TIM_CCMR1_OC1PE_MASK : 0u) /* preload of channel value. */
|
|
| TIM_CCMR1_OC1M(conf->RefOutMode) /* output compare comparison mode. */
|
|
| ( (conf->ClearRefOutOnExtTrigger) ? TIM_CCMR1_OC1CE_MASK : 0u) /* external trigger clear ref. */
|
|
;
|
|
|
|
_TIM_WriteChannelCtrlReg(TIMx, channel, regval);
|
|
|
|
TIM_PutChannelValue(TIMx, channel, conf->ChannelValue);
|
|
|
|
switch (conf->PinPolarity)
|
|
{
|
|
case TIM_PinPolarity_Disabled:
|
|
TIMx->CCER &= ~( ( TIM_CCER_CC1E_MASK
|
|
| TIM_CCER_CC1NE_MASK
|
|
) << (channel<<2u) ); /* Disable both channel. */
|
|
break;
|
|
|
|
case TIM_PinPolarity_Rising:
|
|
TIMx->CCER = ( ( TIMx->CCER & ~(0xF << (channel<<2u)) )
|
|
| ( ( TIM_CCER_CC1E_MASK ) /* Enable the pin output / input. */
|
|
) << (channel<<2u));
|
|
break;
|
|
|
|
case TIM_PinPolarity_Falling:
|
|
TIMx->CCER = ( TIMx->CCER & ~(0xF << (channel<<2u)) )
|
|
| (( TIM_CCER_CC1E_MASK /* Enable the pin output / input. */
|
|
| TIM_CCER_CC1P_MASK /* Set output active polarity. */
|
|
) << (channel<<2u));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
void TIM_EnableCompOutput(TIM_Type * TIMx, uint32_t channel, bool enable)
|
|
{
|
|
if (enable)
|
|
{
|
|
switch (channel)
|
|
{
|
|
case TIM_CHN_1:
|
|
TIMx->CCER |= TIM_CCER_CC1NE_MASK;
|
|
break;
|
|
case TIM_CHN_2:
|
|
TIMx->CCER |= TIM_CCER_CC2NE_MASK;
|
|
break;
|
|
case TIM_CHN_3:
|
|
TIMx->CCER |= TIM_CCER_CC3NE_MASK;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (channel)
|
|
{
|
|
case TIM_CHN_1:
|
|
TIMx->CCER &= ~ TIM_CCER_CC1NE_MASK;
|
|
break;
|
|
case TIM_CHN_2:
|
|
TIMx->CCER &= ~ TIM_CCER_CC2NE_MASK;
|
|
break;
|
|
case TIM_CHN_3:
|
|
TIMx->CCER &= ~ TIM_CCER_CC3NE_MASK;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* for some TIM instance, there is an additional switch to let the output signal go.
|
|
* in this case, the output is disabled by default. then, only the switch is enabled, the output signal can go.
|
|
*/
|
|
void TIM_EnableOutputCompareSwitch(TIM_Type * TIMx, bool enable)
|
|
{
|
|
if (enable)
|
|
{
|
|
TIMx->BDTR |= TIM_BDTR_MOE_MASK;
|
|
}
|
|
else
|
|
{
|
|
TIMx->BDTR &= ~ TIM_BDTR_MOE_MASK;
|
|
}
|
|
}
|
|
|
|
void TIM_EnableInputCapture(TIM_Type * TIMx, uint32_t channel, TIM_InputCaptureConf_Type * conf)
|
|
{
|
|
uint32_t regval = TIM_CCMR1_CC1S(TIM_ChannelIOMode_In) /* input capture mode. */
|
|
| TIM_CCMR1_IC1PSC(conf->InDiv)
|
|
| TIM_CCMR1_IC1F(conf->InFilter)
|
|
;
|
|
|
|
_TIM_WriteChannelCtrlReg(TIMx, channel, regval);
|
|
|
|
switch (conf->PinPolarity)
|
|
{
|
|
case TIM_PinPolarity_Disabled:
|
|
TIMx->CCER &= ~(TIM_CCER_CC1E_MASK << (channel<<2u));
|
|
break;
|
|
case TIM_PinPolarity_Rising:
|
|
TIMx->CCER = (TIMx->CCER & ~(0xF << (channel<<2u)) )
|
|
| (( TIM_CCER_CC1E_MASK /* Enable the pin output / input */
|
|
) << (channel<<2u) );
|
|
break;
|
|
case TIM_PinPolarity_Falling:
|
|
TIMx->CCER = ( TIMx->CCER & ~(0xF << (channel<<2u)) )
|
|
| (( TIM_CCER_CC1E_MASK /* Enable the pin output / input */
|
|
| TIM_CCER_CC1P_MASK /* Set active input edge. */
|
|
) << (channel<<2u) );
|
|
break;
|
|
case TIM_PinPolarity_RisingOrFalling:
|
|
TIMx->CCER = ( TIMx->CCER & ~(0xF << (channel<<2u)) )
|
|
| (( TIM_CCER_CC1E_MASK /* Enable the pin output / input */
|
|
| TIM_CCER_CC1P_MASK /* Set active input edge. */
|
|
| TIM_CCER_CC1NP_MASK
|
|
) << (channel<<2u) );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint32_t TIM_GetChannelValue(TIM_Type * TIMx, uint32_t channel)
|
|
{
|
|
return TIMx->CCR[channel];
|
|
}
|
|
|
|
void TIM_PutChannelValue(TIM_Type * TIMx, uint32_t channel, uint32_t value)
|
|
{
|
|
if ( channel == TIM_CHN_5 )
|
|
{
|
|
TIMx->CCR5 = value;
|
|
}
|
|
else
|
|
{
|
|
TIMx->CCR[channel] = value;
|
|
}
|
|
}
|
|
|
|
void TIM_SetClockDiv(TIM_Type * TIMx, TIM_ClockDiv_Type div)
|
|
{
|
|
TIMx->CR1 = ( TIMx->CR1 &~ TIM_CR1_CKD_MASK )
|
|
| ( TIM_CR1_CKD(div) ); /* set the frequncy ratio. */
|
|
}
|
|
|
|
void TIM_EnableDeadPeriod(TIM_Type * TIMx, TIM_DeadPeriodConf_Type * conf)
|
|
{
|
|
TIMx->BDTR = ( TIMx->BDTR &~ TIM_BDTR_DTG_MASK )
|
|
| ( TIM_BDTR_DTG(conf->DeadPeriodCoef) ); /* set the coefficient. */
|
|
}
|
|
|
|
void TIM_EnableMasterMode(TIM_Type * TIMx, TIM_MasterModeConf_Type * conf)
|
|
{
|
|
TIMx->CR2 = ( TIMx->CR2 &~ TIM_CR2_MMS_MASK )
|
|
| ( TIM_CR2_MMS(conf->Out) ); /* Set master mode output. */
|
|
|
|
uint32_t smcr = TIMx->SMCR &~ TIM_SMCR_MSM_MASK;
|
|
if (conf->EnableSync) /* synchronize with slave timers. */
|
|
{
|
|
smcr |= TIM_SMCR_MSM_MASK;
|
|
}
|
|
TIMx->SMCR = smcr;
|
|
}
|
|
|
|
void TIM_EnableSlaveMode(TIM_Type * TIMx, TIM_SlaveModeConf_Type * conf)
|
|
{
|
|
if ( conf->Resp != TIM_SlaveResp_Disabled )
|
|
{
|
|
TIMx->SMCR = ( TIMx->SMCR &~ ( TIM_SMCR_TS_MASK
|
|
| TIM_SMCR_SMS_MASK
|
|
) )
|
|
| TIM_SMCR_TS(conf->In) /* set input trigger source. */
|
|
| TIM_SMCR_SMS(conf->Resp); /* set response to the source */
|
|
}
|
|
else
|
|
{
|
|
TIMx->SMCR &= ~ TIM_SMCR_SMS_MASK;
|
|
}
|
|
}
|
|
|
|
void TIM_EnableExtTriggerIn(TIM_Type * TIMx, TIM_ExtTriggerInConf_Type * conf)
|
|
{
|
|
uint32_t smcr = TIMx->SMCR &~ ( TIM_SMCR_ETPS_MASK
|
|
| TIM_SMCR_ETF_MASK
|
|
| TIM_SMCR_ECE_MASK
|
|
| TIM_SMCR_ETP_MASK
|
|
);
|
|
switch (conf->PinPolarity)
|
|
{
|
|
case TIM_PinPolarity_Disabled:
|
|
break;
|
|
case TIM_PinPolarity_Rising:
|
|
smcr |= TIM_SMCR_ECE_MASK; /* enable external trigger input. */
|
|
break;
|
|
case TIM_PinPolarity_Falling:
|
|
smcr |= TIM_SMCR_ETP_MASK; /* falling edge active. */
|
|
smcr |= TIM_SMCR_ECE_MASK; /* enable external trigger input. */
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
smcr |= TIM_SMCR_ETPS( conf->InDiv ); /* division to the input external trigger. */
|
|
smcr |= TIM_SMCR_ETF( conf->InFilter ); /* set filter. */
|
|
TIMx->SMCR = smcr;
|
|
}
|
|
|
|
uint32_t TIM_EnableDMABurst(TIM_Type * TIMx, TIM_DMABurstConf_Type * conf)
|
|
{
|
|
TIMx->DCR = TIM_DCR_DBA(conf->BaseAddr) | TIM_DCR_DBL(conf->Length);
|
|
return (uint32_t)(&(TIMx->DMAR));
|
|
}
|
|
|
|
TIM_EncoderDirection_Type TIM_GetEncoder(TIM_Type * TIMx, uint32_t * value)
|
|
{
|
|
if (value)
|
|
{
|
|
* value = TIM_GetCounterValue(TIMx);
|
|
}
|
|
|
|
if ( (TIMx->CR1 & TIM_CR1_DIR_MASK) != 0u )
|
|
{
|
|
return TIM_EncoderDirection_Backward;
|
|
}
|
|
else
|
|
{
|
|
return TIM_EncoderDirection_Forward;
|
|
}
|
|
}
|
|
|
|
void TIM_SetRepCounter(TIM_Type * TIMx, uint8_t value)
|
|
{
|
|
TIMx->RCR = TIM_RCR_REP(value);
|
|
}
|
|
|
|
uint8_t TIM_GetRepCounterValue(TIM_Type * TIMx)
|
|
{
|
|
return TIMx->RCR >> TIM_RCR_REPCNT_SHIFT;
|
|
}
|
|
|
|
void TIM_EnableIdleOut(TIM_Type * TIMx, uint32_t channel, TIM_IdleOut_Type * conf)
|
|
{
|
|
uint32_t cr2 = TIMx->CR2 & ~ ( ( TIM_CR2_OIS1_MASK
|
|
| TIM_CR2_OIS1N_MASK
|
|
) << ( channel << 1u )
|
|
);
|
|
if ( conf->PinPolarity == TIM_PinPolarity_Rising )
|
|
{
|
|
cr2 |= ( TIM_CR2_OIS1_MASK << ( channel << 1u ) );
|
|
}
|
|
if ( conf->CompPinPolarity == TIM_PinPolarity_Rising )
|
|
{
|
|
cr2 |= ( TIM_CR2_OIS1N_MASK << ( channel << 1u ) );
|
|
}
|
|
TIMx->CR2 = cr2;
|
|
}
|
|
|
|
void TIM_EnableLock(TIM_Type * TIMx, TIM_LockLevel_Type lock)
|
|
{
|
|
TIMx->BDTR = ( TIMx->BDTR & ~ TIM_BDTR_LOCK_MASK )
|
|
| TIM_BDTR_LOCK(lock);
|
|
}
|
|
|
|
void TIM_EnableBreakIn(TIM_Type * TIMx, TIM_BreakIn_Type * conf)
|
|
{
|
|
uint32_t bdtr = TIMx->BDTR &~ ( TIM_BDTR_BKE_MASK
|
|
| TIM_BDTR_BKP_MASK
|
|
| TIM_BDTR_AOE_MASK
|
|
| TIM_BDTR_DOE_MASK
|
|
);
|
|
uint32_t bkinf = 0u;
|
|
switch (conf->PinPolarity)
|
|
{
|
|
case TIM_PinPolarity_Disabled:
|
|
break;
|
|
case TIM_PinPolarity_Rising:
|
|
bdtr |= ( TIM_BDTR_BKE_MASK
|
|
| TIM_BDTR_BKP_MASK
|
|
| ( conf->AutoSwitchOutput ? TIM_BDTR_AOE_MASK : 0u )
|
|
| ( conf->DirectIdleOutput ? TIM_BDTR_DOE_MASK : 0u )
|
|
);
|
|
break;
|
|
case TIM_PinPolarity_Falling:
|
|
bdtr |= ( TIM_BDTR_BKE_MASK
|
|
| ( conf->AutoSwitchOutput ? TIM_BDTR_AOE_MASK : 0u )
|
|
| ( conf->DirectIdleOutput ? TIM_BDTR_DOE_MASK : 0u )
|
|
);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if ( conf->Filter != TIM_BreakInFilter_Disabled )
|
|
{
|
|
bkinf |= ( TIM_BKINF_BKINFE_MASK | TIM_BKINF_BKINF(conf->Filter) );
|
|
}
|
|
bkinf |= conf->Source;
|
|
TIMx->BKINF = bkinf;
|
|
}
|
|
|
|
void TIM_EnablePWMShift(TIM_Type * TIMx, uint32_t channel, uint16_t value)
|
|
{
|
|
if ( value == TIM_GetChannelValue(TIMx, channel) )
|
|
{
|
|
TIMx->PDER &= ~( TIM_PDER_CCR1SHIFTEN_MASK << channel );
|
|
}
|
|
else
|
|
{
|
|
TIMx->PDER |= ( TIM_PDER_CCR1SHIFTEN_MASK << channel );
|
|
TIMx->CCRFALL[channel] = value;
|
|
}
|
|
}
|
|
|
|
/* EOF. */
|