I am trying to set up a timer for input capture, and have been pouring over the STM reference manual and examples, following the steps listed in stm32f2xx_tim.c
, but still can’t get it to work.
I have stripped my example down to just trying to count input captures on a pin (A4) connected to a 1kHz source. I suspect the issue is in how I am setting the pin for input. I log values in loop() after a delay(1000)
. Reading the pin, I get random values as I would expect with a 1kHz input. I have verified the input with a scope.
There is a commented out TIM_GenerateEvent(TIM3, TIM_EventSource_CC1);
line inside loop. If I uncomment that, I do receive capture interrupts on channel 1. I also get capture interrupts for the unconfigured channels 2-4, and for the update event, so I expect the interrupts are all configured properly.
I have gone through the capture diagrams Figure 125 & 126 of the reference manual, and everything seems to be configured properly. The only things I can think of is the input pin is not configured properly (just a normal input, correct?), or there is TIM3 alternate function remapping, but I can not figure out how to read AFIO_MAPR to rule this out.
Thanks,
-Michael
captureCount: 0 captureIncreasedCount: 0 updateCount: 62 discardCount: 183 pin: low timer value: 0xE322 TIM3_SR: 0x0 TIM3_CCMR1: 0x1 TIM3_CCER: 0x3
captureCount: 0 captureIncreasedCount: 0 updateCount: 78 discardCount: 231 pin: high timer value: 0x60EF TIM3_SR: 0x0 TIM3_CCMR1: 0x1 TIM3_CCER: 0x3
captureCount: 0 captureIncreasedCount: 0 updateCount: 93 discardCount: 276 pin: low timer value: 0xE148 TIM3_SR: 0x0 TIM3_CCMR1: 0x1 TIM3_CCER: 0x3
captureCount: 0 captureIncreasedCount: 0 updateCount: 109 discardCount: 324 pin: high timer value: 0x62D6 TIM3_SR: 0x0 TIM3_CCMR1: 0x1 TIM3_CCER: 0x3
captureCount: 0 captureIncreasedCount: 0 updateCount: 124 discardCount: 369 pin: low timer value: 0xE32F TIM3_SR: 0x0 TIM3_CCMR1: 0x1 TIM3_CCER: 0x3
captureCount: 0 captureIncreasedCount: 0 updateCount: 140 discardCount: 417 pin: low timer value: 0x63F4 TIM3_SR: 0x0 TIM3_CCMR1: 0x1 TIM3_CCER: 0x3
#define SYSCORECLOCK 60000000UL // Timer clock tree uses core clock / 2
volatile uint16_t updateCount = 0;
volatile uint16_t discardCount = 0;
volatile uint16_t captureCount = 0;
volatile uint16_t captureIncreasedCount = 0;
volatile uint32_t lastCapture = 0;
void TIM3_Update_Interrupt_Handler(void);
void TIM3_Capture_Interrupt_Handler(void);
void TIM3_Capture_Discard_2_Interrupt_Handler(void);
void TIM3_Capture_Discard_3_Interrupt_Handler(void);
void TIM3_Capture_Discard_4_Interrupt_Handler(void);
void setup() {
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/*
1. Enable TIM clock using RCC_APBxPeriphClockCmd(RCC_APBxPeriph_TIMx, ENABLE) function
*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/*
2. Configure the TIM pins by configuring the corresponding GPIO pins
*/
GPIO_InitTypeDef gpioInitStructure;
gpioInitStructure.GPIO_Pin = GPIO_Pin_6;
gpioInitStructure.GPIO_Mode = GPIO_Mode_IN;
gpioInitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpioInitStructure);
/*
2. Configure the Time base unit as described in the first part of this driver,
if needed, else the Timer will run with the default configuration:
- Autoreload value = 0xFFFF
- Prescaler value = 0x0000
- Counter mode = Up counting
- Clock Division = TIM_CKD_DIV1
*/
TIM_TimeBaseInitTypeDef timerInitStructure;
TIM_TimeBaseStructInit(&timerInitStructure);
timerInitStructure.TIM_Prescaler = (uint16_t)(SYSCORECLOCK / 1000000UL) - 1;
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &timerInitStructure);
/*
3. Fill the TIM_ICInitStruct with the desired parameters including:
- TIM Channel: TIM_Channel
- TIM Input Capture polarity: TIM_ICPolarity
- TIM Input Capture selection: TIM_ICSelection
- TIM Input Capture Prescaler: TIM_ICPrescaler
- TIM Input CApture filter value: TIM_ICFilter
*/
TIM_ICInitTypeDef inputCaptureInitStructure;
TIM_ICStructInit(&inputCaptureInitStructure);
inputCaptureInitStructure.TIM_Channel = TIM_Channel_1;
inputCaptureInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
inputCaptureInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
inputCaptureInitStructure.TIM_ICFilter = 0;
/*
4. Call TIM_ICInit(TIMx, &TIM_ICInitStruct) to configure the desired channel with the
corresponding configuration and to measure only frequency or duty cycle of the input signal,
or,
Call TIM_PWMIConfig(TIMx, &TIM_ICInitStruct) to configure the desired channels with the
corresponding configuration and to measure the frequency and the duty cycle of the input signal
*/
TIM_ICInit(TIM3, &inputCaptureInitStructure);
/*
5. Enable the NVIC or the DMA to read the measured frequency.
*/
attachSystemInterrupt(SysInterrupt_TIM3_Compare1, TIM3_Capture_Interrupt_Handler);
attachSystemInterrupt(SysInterrupt_TIM3_Compare2, TIM3_Capture_Discard_2_Interrupt_Handler);
attachSystemInterrupt(SysInterrupt_TIM3_Compare3, TIM3_Capture_Discard_3_Interrupt_Handler);
attachSystemInterrupt(SysInterrupt_TIM3_Compare4, TIM3_Capture_Discard_4_Interrupt_Handler);
attachSystemInterrupt(SysInterrupt_TIM3_Update, TIM3_Update_Interrupt_Handler);
NVIC_InitTypeDef nvicStructure;
nvicStructure.NVIC_IRQChannel = TIM3_IRQn;
nvicStructure.NVIC_IRQChannelPreemptionPriority = 14;
nvicStructure.NVIC_IRQChannelSubPriority = 1;
nvicStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvicStructure);
/*
6. Enable the corresponding interrupt (or DMA request) to read the Captured value,
using the function TIM_ITConfig(TIMx, TIM_IT_CCx) (or TIM_DMA_Cmd(TIMx, TIM_DMA_CCx))
*/
TIM_ITConfig(TIM3, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);
/*
7. Call the TIM_Cmd(ENABLE) function to enable the TIM counter.
*/
TIM_Cmd(TIM3, ENABLE);
/*
8. Use TIM_GetCapturex(TIMx); to read the captured value.
*/
}
void loop() {
delay(1000);
Serial.print("captureCount: ");
Serial.print(captureCount);
Serial.print(" captureIncreasedCount: ");
Serial.print(captureIncreasedCount);
Serial.print(" updateCount: ");
Serial.print(updateCount);
Serial.print(" discardCount: ");
Serial.print(discardCount);
Serial.print(" pin: ");
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)) {
Serial.print("high");
} else {
Serial.print("low");
}
Serial.print(" timer value: 0x");
//Serial.print(TIM_GetCapture1(TIM3));
Serial.print(TIM3->CNT, HEX);
Serial.print(" TIM3_SR: 0x");
Serial.print(TIM3->SR, HEX);
Serial.print(" TIM3_CCMR1: 0x");
Serial.print(TIM3->CCMR1, HEX);
Serial.print(" TIM3_CCER: 0x");
Serial.println(TIM3->CCER, HEX);
// TIM_GenerateEvent(TIM3, TIM_EventSource_CC1);
}
void TIM3_Capture_Interrupt_Handler(void) {
captureCount++;
uint32_t capture = TIM_GetCapture1(TIM3);
if ((capture - lastCapture) > 0) captureIncreasedCount++;
lastCapture = capture;
}
void TIM3_Update_Interrupt_Handler(void) {
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
updateCount++;
}
}
void TIM3_Capture_Discard_2_Interrupt_Handler(void) {
TIM_GetCapture2(TIM3);
discardCount++;
}
void TIM3_Capture_Discard_3_Interrupt_Handler(void) {
TIM_GetCapture3(TIM3);
discardCount++;
}
void TIM3_Capture_Discard_4_Interrupt_Handler(void) {
TIM_GetCapture4(TIM3);
discardCount++;
}