allankliu 发表于 2019-3-1 17:05:31

STM8L TIMx ETR并不能够实现完全的外部时钟计数

在工程中,原来利用GPIO外部中断实现脉冲计数,因为是低功耗设计,所以MCU平时都是Halt状态。觉得如果利用ETR的输入,配合TIM的计数溢出中断可以减少从低功耗模式中恢复的次数,以降低系统占空比。但是发现TIMx的设计必须依赖于内部sysclk的存在,如果halt模式下停止sysclk,则TIMx的CNTL/CNTH完全不更新。
#include "stm8l15x.h"
#include <stdbool.h>

uint32_t ul2;
uint32_t ul3;

INTERRUPT_HANDLER(TIM2_UPD_OVF_TRG_BRK_USART2_TX_IRQHandler,19)
{
if(TIM2_GetITStatus(TIM2_IT_Update) != RESET)
{
    ul2++;
    TIM2_ClearITPendingBit(TIM2_IT_Update);
}
}

INTERRUPT_HANDLER(TIM3_UPD_OVF_TRG_BRK_USART3_TX_IRQHandler,21)
{
if(TIM3_GetITStatus(TIM3_IT_Update) != RESET)
{
    ul3++;
    TIM3_ClearITPendingBit(TIM3_IT_Update);
}
}

void setup( void )
{
CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1);

CLK->ICKCR |= 0x40;
// enable CCKO 38kHz
CLK->CCOR = CLK_CCOSource_LSI;

GPIO_Init(GPIOC, GPIO_Pin_4, GPIO_Mode_Out_PP_Low_Slow);
GPIO_Init(GPIOB, GPIO_Pin_3, GPIO_Mode_In_PU_No_IT);
GPIO_Init(GPIOD, GPIO_Pin_1, GPIO_Mode_In_PU_No_IT);

GPIO_Init(GPIOE, GPIO_Pin_2, GPIO_Mode_Out_PP_Low_Slow);
GPIO_Init(GPIOA, GPIO_Pin_4, GPIO_Mode_In_PU_No_IT);
GPIO_Init(GPIOA, GPIO_Pin_5, GPIO_Mode_In_PU_No_IT);

SYSCFG->RMPCR3 |= SYSCFG_RMPCR3_CCO_REMAP;
SYSCFG->RMPCR2 |= SYSCFG_RMPCR2_TIM2TRIG_REMAP;
SYSCFG->RMPCR2 |= SYSCFG_RMPCR2_TIM3TRIG_REMAP1;


// short cut PC4/PB3 or PC4/PD1 without changing SYSCFG_Remap.
// SYSCFG_RMPCR3, CCO_REMAP = 0:1 = PC4:PE2
// SYSCFG_RMPCR2, TIM2_TRG_REMAP = 0:1 = PB3:PA4
// SYSCFG_RMPCR2, TIM3_TRG_REMAP = 0:1 = PD1:PA5

TIM2_DeInit();
CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);

//TIM2_ETRClockMode2Config(TIM2_ExtTRGPSC_DIV2, TIM2_ExtTRGPolarity_NonInverted,0x00);
TIM2_ETRClockMode2Config(TIM2_ExtTRGPSC_OFF, TIM2_ExtTRGPolarity_Inverted,0x00);
//TIM2_TimeBaseInit(TIM2_Prescaler_1,TIM2_CounterMode_Up,9999);
TIM2_TimeBaseInit(TIM2_Prescaler_1,TIM2_CounterMode_Up,100);
TIM2_ITConfig(TIM2_IT_Update,ENABLE);
TIM2_SetCounter(0x0);
TIM2_ClearITPendingBit(TIM2_IT_Update);
TIM2_Cmd(ENABLE);

TIM3_DeInit();
CLK_PeripheralClockConfig(CLK_Peripheral_TIM3, ENABLE);

//TIM3_ETRClockMode2Config(TIM3_ExtTRGPSC_DIV2, TIM3_ExtTRGPolarity_NonInverted,0x00);
TIM3_ETRClockMode2Config(TIM3_ExtTRGPSC_OFF, TIM3_ExtTRGPolarity_Inverted,0x00);
//TIM3_TimeBaseInit(TIM3_Prescaler_1,TIM3_CounterMode_Up,9999);
TIM3_TimeBaseInit(TIM3_Prescaler_1,TIM3_CounterMode_Up,100);
TIM3_ITConfig(TIM3_IT_Update,ENABLE);
TIM3_SetCounter(0x0);
TIM3_ClearITPendingBit(TIM3_IT_Update);
TIM3_Cmd(ENABLE);

enableInterrupts();
}

void Halt_Init(void)
{

/* Set STM8 in low power */
PWR->CSR2 = 0x2;

/* Stop RTC Source clock */
CLK_RTCClockConfig(CLK_RTCCLKSource_Off, CLK_RTCCLKDiv_1);

#ifdef USE_LSE
    CLK_LSEConfig(CLK_LSE_OFF);
    while ((CLK->ECKCR & 0x04) != 0x00);
#else
    CLK_LSICmd(DISABLE);
    while ((CLK->ICKCR & 0x04) != 0x00);
#endif

/* Stop clock RTC and LCD */        
CLK_PeripheralClockConfig(CLK_Peripheral_RTC, DISABLE);
CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, DISABLE);
CLK_PeripheralClockConfig(CLK_Peripheral_TIM3, DISABLE);

}

int main( void )
{
setup();
while(true){
    Halt_Init();
    asm("nop");
    halt();
}
//return 0;
}
在Halt_Init中,如果把TIM2/TIM3 DISABLE掉,TIMx_CNTL/TIMx_CNTH一直保持初始值,无法进入中断服务程序。从RM0031.pdf中看到的图也发现,fsysclk一直存在于所谓的外部时钟源模式2(ETR)。也就是说所谓外部时钟源模式,其内部时钟必须始终存在。

我现在有两个选择:

1. 把LSI 38KHz作为sysclk赋给TIM2/TIM3,但是我TIM4的sysclk必须是HSI,因为我需要1ms的系统定时中断;
2. 恢复EXTI中断服务。

就是不清楚那种功耗更低些。

STM32L外设与STM8L外设类似,也欢迎纠错和讨论。

allankliu 发表于 2019-3-1 17:09:50

如果有其他的模式,请指教一二。

butterflyspring 发表于 2019-3-20 10:46:44

STM8L的外设工作需要系统时钟支持,而低功耗模式下(HALT),系统时钟停止,降低功耗。相应的定时器TIMX也没有了时钟,所以整个外设就不能工作了。 而部分STM32L系列产品是有低功耗定时器的外设,可以在STOP模式下利用低速时钟工作。所以可以根据你的需求平衡一下功耗或者选择:)
页: [1]
查看完整版本: STM8L TIMx ETR并不能够实现完全的外部时钟计数