2021-11-21 10:03 AM
I have PE9 as an input, and using AF1, PE9 should be connecting to TIM1_CH1 input.
Input is 400Hz square wave, 0 to +3.3V.
This is the code
// Set up TIM1 for ~400Hz waveform period measurement, via PE9
static void KDE_config_TIM1_period_measure(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__GPIOE_CLK_ENABLE(); // already enabled in switch init but never mind
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; // PE9 = TIM1_CH1
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // PE9 = TIM1_CH1 input, not the output!
GPIO_InitStruct.Pull = GPIO_PULLUP; // PE9 = pullup because comparator driving it is open drain o/p
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
// Set up TIM1 to count up and on PE9 +ve edge transfer the count to CCR and reload with 0
__HAL_RCC_TIM1_CLK_ENABLE(); // TIM1EN=1 in RCC2ENR and does a short delay
TIM1->CR1 = 0; // TIM1 upcounter, counter disabled for now
TIM1->ARR = 0xffff; // auto reload value
TIM1->PSC = 3; // prescaler=4, for 10.5MHz counter speed
TIM1->CCMR1 = (1 << 4) // IC1F: input filter = 2
|(0 << 2) // IC1PSC: input prescaler off
|(1 << 0); // CC1S: 01 = channel is input, from TI1
TIM1->CCER = (0 << 3) // CC1NP: CC1 rising edge capture
|(0 << 2) // CC1NE: oc1n not active
|(0 << 1) // CC1P: rising edge capture
|(1 << 0); // CC1E: enable CC1 capture
TIM1->EGR = 0; // CC1G=0
TIM1->CNT = 0;
TIM1->CR2 = 0; // TI1S=0 - TIM1_CH1 pin is connected to TI1 input
TIM1->RCR = 0;
TIM1->SMCR = 0; // slave mode disabled, internal clock source
TIM1->DIER = 0; // interrupts disabled
TIM1->CR1 = (1 << 0); // CEN=1 - enable TIM1
}
and this is the RTOS tack which is reading CCR1
while (1)
{
uint16_t cnt = TIM1->CNT;
// TIM1->EGR = (1<<1); // force capture CNT to CCR1
uint16_t ccr1 = TIM1->CCR1;
uint16_t sr = TIM1->SR;
debug_thread_printf("===== TIM1 = %5u %5u %05x", cnt, ccr1, sr);
osDelay(1000);
}
The output I am getting is
==== TIM1 = 63286 0 0001d
with various values for the CNT, so the counter is running ok. If I uncomment the above force capture line, I get the software-triggered capture taking place (3rd value not shown here)
===== TIM1 = 16491 16493
===== TIM1 = 58404 58406
===== TIM1 = 34750 34753
===== TIM1 = 11067 11069
===== TIM1 = 52958 52961
===== TIM1 = 29275 29277
so it just looks like the PE9 signal is not getting through to IC1PS. I have checked it with a scope on the pin. I al also suspecting that my PE9 config is not right; I cannot find any reference to actual init code for PE9 for the TIM1_CH1 input; all examples I found show PE9 to be the TIM1_CH1 pwm output. Is it correct that selecting AF1 and selecting PE9 as an input is sufficient to select TIM1_CH1 input?
Many thanks for any tips. I've spent 2 days on this so far, and reading the RM, appnots, etc. Page 662/1751 of the RM tells you how to do exactly this, so something must be missing.
2021-11-21 12:17 PM
> GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
This sets the pin in input mode, not AF mode.
To use a pin with a timer, the pin needs to be in AF mode. whether it's being used as an input or an output. You can step through the logic in HAL_GPIO_Init to see how this is done.
2021-11-21 12:42 PM
What mode should I use?
The available modes are:
#define GPIO_MODE_INPUT 0x00000000U /*!< Input Floating Mode */
#define GPIO_MODE_OUTPUT_PP 0x00000001U /*!< Output Push Pull Mode */
#define GPIO_MODE_OUTPUT_OD 0x00000011U /*!< Output Open Drain Mode */
#define GPIO_MODE_AF_PP 0x00000002U /*!< Alternate Function Push Pull Mode */
#define GPIO_MODE_AF_OD 0x00000012U /*!< Alternate Function Open Drain Mode */
#define GPIO_MODE_ANALOG 0x00000003U /*!< Analog Mode */
#define GPIO_MODE_IT_RISING 0x10110000U /*!< External Interrupt Mode with Rising edge trigger detection */
#define GPIO_MODE_IT_FALLING 0x10210000U /*!< External Interrupt Mode with Falling edge trigger detection */
#define GPIO_MODE_IT_RISING_FALLING 0x10310000U /*!< External Interrupt Mode with Rising/Falling edge trigger detection */
#define GPIO_MODE_EVT_RISING 0x10120000U /*!< External Event Mode with Rising edge trigger detection */
#define GPIO_MODE_EVT_FALLING 0x10220000U /*!< External Event Mode with Falling edge trigger detection */
#define GPIO_MODE_EVT_RISING_FALLING 0x10320000U /*!< External Event Mode with Rising/Falling edge trigger detection */
I can see AF_PP or AF_OD but both of those are output structures, not an input pin.
2021-11-21 01:09 PM
> I can see AF_PP or AF_OD but both of those are output structures, not an input pin.
There are neither explicitly input nor output. Rather, the direction is controlled by the peripheral selected.
Use either of GPIO_MODE_AF_PP or GPIO_MODE_AF_OD as the output drive type doesn't matter here.
CubeMX can generate this code for you.
2021-11-21 01:13 PM
The problem is that TIM1_CH1 is the same name for two signals. Page 517/1751 of the RM. One is an input and one is an output. I think PE9 will connect to one or the other, according to whether it is configured as input or output... how else can this work? The problem is that all examples I can find online use PE9 as a PWM output.
You would save me another day of googling around forums and wading through countless posts, if you could tell me what I should use.
I have selected this
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; // PE9 = TIM1_CH1
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // PE9 = TIM1_CH1 input, not the output!
GPIO_InitStruct.Pull = GPIO_PULLUP; // PE9 = pullup because comparator driving it is open drain o/p
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
but I am worried that if PE9 is being driven by the chip, something will be getting hot.
But now I am seeing values in CCR1, plus CC1OF getting set which is as expected. The values are garbage though. Not quite garbage; CCR1 is a smaller value than CNT, with the difference being smaller as the frequency on PE9 increases. It looks like CNT is not getting reset upon the +ve edge arriving on TIM1_CH1.
2021-11-21 01:28 PM
> One is an input and one is an output.
They're the same signal. If it's being used as an input, the internal connections will route it appropriately. If it's an output, the internal connection will drive it.
> You would save me another day of googling around forums and wading through countless posts, if you could tell me what I should use.
I already did.
2021-11-21 01:32 PM
In case it helps, the direction of TIM1_CH1 is chosen when you configure the channel, not the pin. Specifically, the CCxS field in the TIMx->CCMRx register.
2021-11-21 01:46 PM
Great; thank you. I can see what they have done.
Could you help me with the CNT auto-reset setup? Upon +ve edge on PE9, I want CNT to reset to 0 but before it does so, transfer itself to CCR1. I have tried SMS=100 in SMCR but it doesn't do anything
GPIO_InitTypeDef GPIO_InitStruct;
__GPIOE_CLK_ENABLE(); // already enabled in switch init but never mind
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; // PE9 = TIM1_CH1
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // PE9 = AF, and is an input because CH1=input in TIM1 cfg
GPIO_InitStruct.Pull = GPIO_PULLUP; // PE9 = pullup because comparator driving it is open drain o/p
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
// Set up TIM1 to count up and on PE9 +ve edge transfer the count to CCR and reload with 0
__HAL_RCC_TIM1_CLK_ENABLE(); // TIM1EN=1 in RCC2ENR and does a short delay
TIM1->CR1 = 0; // TIM1 upcounter, counter disabled for now with CEN=0
TIM1->ARR = 0xffff; // auto reload value
TIM1->PSC = 3; // prescaler=4, for 10.5MHz counter speed
TIM1->CCMR1 = (1 << 4) // IC1F: input filter = 2
|(0 << 2) // IC1PSC: input prescaler off
|(1 << 0); // CC1S: 01 = channel is input, from TI1
TIM1->CCER = (0 << 3) // CC1NP: CC1 rising edge capture
|(0 << 2) // CC1NE: oc1n not active
|(0 << 1) // CC1P: rising edge capture
|(1 << 0); // CC1E: enable CC1 capture
TIM1->EGR = 0; // CC1G=0
TIM1->CNT = 0;
TIM1->CR2 = 0; // TI1S=0 - TIM1_CH1 pin is connected to TI1 input
TIM1->RCR = 0;
TIM1->SMCR = (1 << 2); // sms=100 (auto reset), internal clock source
TIM1->DIER = 0; // interrupts disabled
TIM1->CR1 = (1 << 0); // CEN=1 - enable TIM1
2021-11-21 02:36 PM
As I've told you, this is described in the PWM input mode subchapter in TIM chapter of RM.
You need to set not only TIMx_SMCR.SMS to Reset mode, but also the source of trigger into the slave-mode controller to TI1FP1, i.e. set TIMx_SMCR.TS to 0b101.
JW
2021-11-21 03:09 PM
Excellent - thank you!
With a 400Hz input I am seeing CCR1=26242 which is right with PCLKx=42MHz and with the TIM1 counter running from 2x that, that works out exactly right. The code, which produces a continuously updated value in CCR, is below in case somebody finds this one day
/*
*
* Set up TIM1 for ~400Hz waveform period measurement, via PE9
* This produces a continuously updated value in TIM1->CCR1. This example code displays it:
* while (1)
* {
* uint16_t ccr1 = TIM1->CCR1;
* debug_thread_printf("CCR1 = %5u", ccr1);
* osDelay(1000);
* }
* TIM1 is clocked at 2xPCLK2 i.e. 84MHz here. The /8 prescaler drops this to 10.5MHz
* which is good for 400Hz and delivers a value around 26240.
*
*/
static void KDE_config_TIM1_period_measure(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
__GPIOE_CLK_ENABLE(); // already enabled in switch init but never mind
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; // PE9 = TIM1_CH1
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // PE9 = AF, and is an input because CH1=input in TIM1 cfg
GPIO_InitStruct.Pull = GPIO_PULLUP; // PE9 = pullup because comparator driving it is open drain o/p
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
// Set up TIM1 to count up and on PE9 +ve edge transfer the count to CCR and reload with 0
__HAL_RCC_TIM1_CLK_ENABLE(); // TIM1EN=1 in RCC2ENR and does a short delay
TIM1->CR1 = 0; // TIM1 upcounter, counter disabled for now with CEN=0
TIM1->ARR = 0xffff; // auto reload value
TIM1->PSC = 7; // prescaler=8, for 10.5MHz counter speed
TIM1->CCMR1 = (1 << 4) // IC1F: input filter = 2
|(0 << 2) // IC1PSC: input prescaler off
|(1 << 0); // CC1S: 01 = channel is input, from TI1
TIM1->CCER = (0 << 3) // CC1NP: CC1 rising edge capture
|(0 << 2) // CC1NE: oc1n not active
|(0 << 1) // CC1P: rising edge capture
|(1 << 0); // CC1E: enable CC1 capture
TIM1->EGR = 0; // CC1G=0
TIM1->CNT = 0;
TIM1->CR2 = 0; // TI1S=0 - TIM1_CH1 pin is connected to TI1 input
TIM1->RCR = 0;
TIM1->SMCR = (1 << 2) // internal clock source, SMS=100 (reset mode)
|(1 << 6) // TS=101 (TI1FP1)
|(1 << 4);
TIM1->DIER = 0; // interrupts disabled
TIM1->CR1 = (1 << 0); // CEN=1 - enable TIM1
}