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.

  • Your interrupt handler is poorly written. What immediately catches the eye: a) at first we do something, then we clear the bits, and not vice versa; b) and you did not think that the status can be not only or-or ? It is necessary to read the status in a temporary variable and process accordingly (no else!). And above all this, there is no synchronization of write-read global variable (must be atomic). - 0andriy
  • @ 0andriy, of course, can be not only either or , but this should not be the cause of the problem: if at least one interrupt flag remains raised, the program will return to the handler after its completion. Why do I need to reset the interrupt flags at the end of the handler? And which flags do you mean: NVIC or peripherals? I am not sure about atomic either, since the simultaneous calling of the HandleTempPeriod and HandleTempOverrun functions is HandleTempPeriod : they are called only from one interrupt handler, and an interrupt cannot be put into itself. - maestro
  • I tried to transfer the reset of flags to the end, removed the else in the interrupt handler. Did not help. - maestro

0