2014-08-19 04:45 AM
Hi,
We're using STM32F Trying to get Timer3/Ch 4 to count edges from a 24VDC fan tachometer to get Rpm. Done research through Reference manual and forum posts. Obviously I'm missing something. We also tried Input Capture and can see that clock is counting real fast between edges, but this is not what we want. At full speed fan pulses are 100Hz. Think we need to use TIM_ETRClockMode2 since we need to use Ch 4 of the timer. Here is the code, of course we've tried a lot of other Firmware with no luck:/* TIM3/4 count Tachometer edges using ADC1 Ch 4 terminal as input */
void ConfigTach(void) Beg
/* TIM3 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* GPIOB clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
/* GPIOB Configuration: TIM3/4 (PB1) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Connect TIM3/4 pin (PB1) to AF (Alternate Function) */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource1,GPIO_AF_TIM3);
/* Configure TIM3/4 to capture rising edges */
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_Period = 0xFFFF; // TIM3 is 16-bit counter
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
/* Timer is triggered by external clock (Fan Tachometer) */
TIM_ETRClockMode2Config(TIM3,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x0);
/* TIM3 enable counter */
TIM_Cmd(TIM3,ENABLE); // start Timer
End
#external-clock-timer3 #rpm
2014-08-19 07:50 AM
Not sure how this associates with CH4? For TIM3_ETR consider PD2
2014-08-19 08:35 AM
Thanks for your reply, Clive.
Made me realize my stupid mistake. Did not understand that ETR for a timer was an alternate function. Thought that the same pin the timer used for OC was used as its ETR-pin. Duhh. Since we need to use terminals on our card normally connected to AD we're left with PA5, pin 41 that have TIM2 Ch2 ETR as AF. Is there anything missing or too much in the code I've provided. (After doing alterations to TIM2 Ch1). /Richard2014-08-19 09:56 AM
End of [DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/STM32F3%20new%20project&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=531]this thread
2014-08-19 10:04 AM
PA5 TIM2_CH1_ETR, here using CH1 connectivity, quick blind port
// STM32 External Clock Input STM32F3-Discovery - sourcer32@gmail.com
// Keil SWV Semi-Hosting - STM32F3-DISCO needs SB10 Solder Bridge made
/**************************************************************************************/
#include <
stdio.h
>
#include ''stm32f3_discovery.h''
#include ''stm32f30x.h''
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOA Peripheral clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Connect TIM2_CH1_ETR pin to AF1 on pin PA5 (Conflicts with L3GD20 on STM32F3-DISCO)
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_1);
// Connect TIM3_CH2 pin to AF2 on pin PA4 (Free on STM32F3-DISCO)
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_2);
}
/**************************************************************************************/
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Enable TIM2 Peripheral clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF; // 32-bit Maximal
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_TIxExternalClockConfig(TIM2, TIM_TIxExternalCLK1Source_TI1, TIM_ICPolarity_Rising, 0); // TIM2_CH1_(ETR)
TIM_Cmd(TIM2, ENABLE);
}
/**************************************************************************************/
void TIM3_Configuration(void)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Enable TIM3 Peripheral clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1 MHz
TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // 50 Hz
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* Enable TIM3 Preload register on ARR */
TIM_ARRPreloadConfig(TIM3, ENABLE);
/* TIM PWM1 Mode configuration: Channel */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 10000; // 50%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
/* Output Compare PWM1 Mode configuration: Channel2 PA.4 */
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_Cmd(TIM3, ENABLE);
}
/**************************************************************************************/
int main(void)
{
uint32_t CurrentTick, LastTick;
GPIO_Configuration();
TIM2_Configuration();
TIM3_Configuration(); // 50 Hz Source, clip PA4 to PA5
// Print a tick everytime the counter changes
LastTick = TIM_GetCounter(TIM2) - 1;
while(1)
{
CurrentTick = TIM_GetCounter(TIM2);
if (CurrentTick != LastTick)
{
printf(''Tick:%5u Delta:%5u
'', CurrentTick, (uint16_t)(CurrentTick - LastTick));
LastTick = CurrentTick;
}
}
}
/**************************************************************************************/
#include <
rt_misc.h
>
#pragma import(__use_no_semihosting_swi)
struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f)
{
ITM_SendChar(ch);
return(ch);
}
int fgetc(FILE *f)
{
char ch;
ch = 1;
return((int)ch);
}
int ferror(FILE *f)
{
/* Your implementation of ferror */
return EOF;
}
void _ttywrch(int ch)
{
ITM_SendChar(ch);
}
void _sys_exit(int return_code)
{
label: goto label; /* endless loop */
}
/**************************************************************************************/
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d
'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
2014-08-19 12:44 PM
Thank you for your support.
Need to do some hardware changes to our card tomorrow before code can be tested, but I'm confident that all will work well now when the mystery of ETR has been revealed to me. /Richard