In the 1986VE92U microcontroller, all timers are 16-bit, and this bit depth is not enough to cover the entire range of periods of a rectangular signal that goes to the capture channel. Dividers can not be entered, as this will decrease its resolution. Therefore, I decided to count the overflows of the main timer counter, and based on this, calculate the total pulse length. But this counter is not working properly. Here is the initialization of the timer (hereinafter the temp reduction is the temperature):
void InitTemp() { PORT_InitTypeDef portInitStruct; TIMER_CntInitTypeDef timInitStruct; TIMER_ChnInitTypeDef timChStruct; TIMER_BRGInit(TEMP_TIMER, TIMER_HCLKdiv1); PORT_StructInit(&portInitStruct); portInitStruct.PORT_Pin = TEMP_PORT_PIN; portInitStruct.PORT_OE = PORT_OE_IN; portInitStruct.PORT_FUNC = PORT_FUNC_ALTER; portInitStruct.PORT_SPEED = PORT_SPEED_MAXFAST; portInitStruct.PORT_MODE = PORT_MODE_DIGITAL; PORT_Init(TEMP_PORT, &portInitStruct); TIMER_CntStructInit(&timInitStruct); timInitStruct.TIMER_Period = 0xffff; timInitStruct.TIMER_Prescaler = (SystemCoreClock / (1000000 * TEMP_TIMER_CLK_PRESC)) - 1; TIMER_CntInit(TEMP_TIMER, &timInitStruct); TIMER_ChnStructInit(&timChStruct); timChStruct.TIMER_CH_Mode = TIMER_CH_MODE_CAPTURE; timChStruct.TIMER_CH_Number = TEMP_TIMER_CHANNEL; TIMER_ChnInit(TEMP_TIMER, &timChStruct); TIMER_ITConfig(TEMP_TIMER, TEMP_TIMER_INTERRUPT | TIMER_STATUS_CNT_ZERO, ENABLE); TIMER_Cmd(TEMP_TIMER, ENABLE); } In the interrupt handler, I check what exactly happened: channel lock or overflow:
void Timer1_IRQHandler() { NVIC_ClearPendingIRQ(Timer1_IRQn); if (TIMER_GetITStatus(TEMP_TIMER, TEMP_TIMER_INTERRUPT) == SET) { TIMER_ClearITPendingBit(TEMP_TIMER, TEMP_TIMER_INTERRUPT); HandleTempPeriod(); } else if (TIMER_GetITStatus(TEMP_TIMER, TIMER_STATUS_CNT_ARR) == SET) { HandleTempOverrun(); TIMER_ClearITPendingBit(TEMP_TIMER, TIMER_STATUS_CNT_ARR); } } I count the number of overflows:
volatile uint32_t tempOverrunCount = 0; void HandleTempOverrun() { tempOverrunCount++; } And calculate the pulse length:
void HandleTempPeriod() { static uint32_t rv1, rv2; static uint32_t period = 0; static uint32_t overrun = 0; if (tempsensor.captureState == FirstNotCaptured) { rv1 = TEMP_TIMER->CCR1; tempsensor.captureState = FirstCaptured; tempOverrunCount = 0; } else { overrun = tempOverrunCount; rv2 = TEMP_TIMER->CCR1; if (overrun > 0) { period = TEMP_TIMER->ARR - rv1 + TEMP_TIMER->ARR * (overrun - 1) + rv2; } else { period = rv2 - rv1; } rv1 = rv2; tempOverrunCount = tempOverrunCount - overrun; } } As a result, there are often cases when the variable overrun becomes a unit, when there is no overflow in fact, and also zero when there is an overflow. The errata document for this controller indicates that the capture flag and the CCRx register CCRx separated by one clock cycle, so the register may have an old value at the moment of reading, however, from the moment of interruption to reading the register, enough processor cycles pass to update the timer. Therefore, this error is excluded. I also tried instead of register CCR1 to read CNT , the result is the same. What am I doing wrong?
ps If there are representatives of Milandra here, pay attention: registration does not work on your forum. The activation letter does not come.
HandleTempPeriodandHandleTempOverrunfunctions isHandleTempPeriod: they are called only from one interrupt handler, and an interrupt cannot be put into itself. - maestro