Hi all wonder if you could give me a hand.
Before anything = I know I should/could use the input compare mode but I can't for my application.
I'm generating an interrupt from the rising edge of a grey code output from a motor feedback system. I initially stop the timer with:
// Start of ISR
// Halt the timer
HAL_TIM_Base_Stop();
// Read the value of the count
value = TIMx->CNT;
// Reset the value
TIMx->CNT = 0;
// Start the timer with interrupts
HAL_TIM_Base_Start_IT();
If the timer reaches it's period value then an interrupt is generated and it's assumed the motor isn't turning.
However what is strange is that I get different readings depending on the code I insert AFTER the the timer has been started.
So:
// Start the timer
HAL_TIM_Base_Start_IT();
// Print value
UART_Write_Num(value);
// Deal with the rising edge interrupt
Clear_INT_FLAG();
// End of ISR
would give me different values for value than the following:
// Start the timer
HAL_TIM_Base_Start_IT();
// Print value
UART_Write_String("\nMeasured value = ");
UART_Write_Num(value);
// Deal with the rising edge interrupt
Clear_INT_FLAG();
// End of ISR
I just don't understand why this happens. The interrupt is triggered at a maximum frequency of 1.7kHz which seems low to me. Surely once the timer has been started the code after it should have no affect on it?
Thanks for any advice.
second everything from previous two posts. You want your ISR to execute as fast as possible. You could make up an array and store the values you want to dump there. When that is full, you let the code run into a breakpoint, and you can inspect the array.
what is strange is that I get different readings depending on the code I insert AFTER the the timer has been started.
Why would you expect it to always be the same? Different code takes different amounts of time to execute, and interrupts have code-dependent latency.
Since your program is written in C/C++, you have no control over what machine code instructions are produced. The compiler will produce whatever machine code it thinks is best, and any change to the source - no matter how irrelevant it may seem - could change the compiler's output in ways that affect execution timing. Put simply, code written in C (and most other high level languages) is not guaranteed to have any particular execution speed. You can only hope the compiler will try to make it go as fast as possible.
If you want exact timing then either use hardware-only methods (eg. timer capture/compare registers), or program in assembler!
All of the above are pointing at the same issue: get the UART code out of the ISR. Put the value in a 'most recent reading' variable or, if necessary, put it in a queue (I would hesitate to add this much code to the ISR but I have done it before). Using a queue to synchronize the data is kind of an advanced topic because the queue reader is probably running with interrupts enabled and the queue writer is an interrupt routine that could be writing in the middle of the reader code. It takes a bit of care to get this right.
Given only a fragment of the code, I can't see if there are other interrupts of higher priority that may interrupt this ISR. That can be an issue.
I would look at the library code and see how it is written. In general, I don't use any provided code, especially for interrupt handlers. Every function I call has overhead getting in and out. I would want to know if reading/writing the timer was atomic (happens in one cycle) and, if so, I wouldn't bother to start and stop it. I would just grab the reading and set the counter to 0. No start, no stop, just grab and run. I want in and out of that ISR as fast as possible.
Thank you all for your replies - sorry I have not acknowledged them earlier I'm very busy at the minute.
The part that I find strange though is this. (I read what you all said and I take it in but this issue isn't really to do with the interrupt per se it just happens to be in an interrupt) The timer is started and then the code after it affects the value that I read next time. Are we just saying writing to the UART takes too long and because I don't re enable the interrupt until I've written to the UART the interrupt is just serviced as soon as the previous code has finished then I enable the interrupt and it instantly fires as the flag has been set in the GPIO hardware?
Thanks
you are stopping and restarting the timer. That itself already gives you execution time dependency for the code inbetween and before (ISR entry).
Thank you all for your replies - sorry I have not acknowledged them earlier I'm very busy at the minute.
The part that I find strange though is this. (I read what you all said and I take it in but this issue isn't really to do with the interrupt per se it just happens to be in an interrupt) The timer is started and then the code after it affects the value that I read next time. Are we just saying writing to the UART takes too long and because I don't re enable the interrupt until I've written to the UART the interrupt is just serviced as soon as the previous code has finished then I enable the interrupt and it instantly fires as the flag has been set in the GPIO hardware?
Thanks
That's pretty much it, the UART_Write_Num() seems simple until you realize that it has a lot of work to do in converting the values to ASCII. You even noted that there was a difference if you just tried to print a string with UART_Write_String()
At 115k baud, the string alone will take 1.5 ms to print and at 9600 baud will take about 18 ms. Actual values may vary a bit, I assumed 10 bits per char, it could be 9.
Turn on an LED, or set a pin, when you enter the ISR and turn it off just before you leave. You can look at the ISR time on a scope. The time will be exaggerated by the time it takes to turn off the LED or pin. Don't forget to remove the code!
You didn't give any info about the expected timing of the inputs, but it's pretty simple. Given you don't clear the interrupt straight away in your interrupt routine (read: as soon as you're actually able to accept a new pulse, i.e. after storing the value and clearing the timer) no input edge will trigger an interrupt until your comparatively loooooooong UART code has finished executing.
I.e. you're missing input pulses, so on your next read the counter will hold the sum of the times between a random, unknown number of pulses.
And yes, you really need input capture.
You shouldn't be sending output to a UART within an unrelated ISR, especially if you're using a black box like the ST HAL and don't know what it's doing internally. If you need to inspect things like the value of counters read within an ISR, then defer the write to the UART to after you exit the ISR.
The interrupt is triggered at a maximum frequency of 1.7kHz which seems low to me.
You need to transmit about 200bits (assuming 3 digits for the value, 1 start and 1 stop bit) with the longer string.
The interrupt period is then:
1/1700Hz = 588µsSo, the absolute maximum time per bit if you don't want to have overruns (disregarding IRQ latency and all the other code!) is:
588µs/200 = 3µsthat is to say, a baud rate higher than 300 000.
IIRC, the F4 UART supports up to 2Mb/s, but how is it set up in your case?
In any case, spending that much time in an ISR is not (generally speaking) good programming practice.