I try to do some bare-metal programming on Beaglebone Black using StarterWare. All modifications to run with the Black are already done and I'm running the DMTimer-example which works well.
In next step I have changed this example, the ISR just toggles a GPIO (which should need some dozens of clock cycles only). And I changed the timer and timer reload count of the example to 0xFFFFFF0F which is equal to 10 usec period - so my ISR should be called every 10 usec.
Amazingly this seems o be the limit, when I use bigger timer values which should result in more frequent calls of ISR it still stays at these 10 usec, even 5 usec are not possible with the DMTimer-example. As timer clock source CLK_M_OSC is already used so this shouldn be fine.
So...any idea how ISR can be called faster?
Have you tried adjusting (or disabling) the timer prescaler? I found that the DMTimer example uses the prescaler and I didn't get the behaviour that it suggested (interrupts every 700ms) until I added the line
DMTimerPreScalerClkDisable(SOC_DMTIMER_2_REGS);
After that, it appeared to work correctly.
With the prescaler disabled, you should get 10ms with a reload counter of 0xFFFFFF06 or 5ms with a reload counter of 0xFFFFFF83.
Related
I've got an issue with STM32F0 timers. I'm doing everything register level and am disabling a timer and zeroing the count. After this I re-enable external interrupts and restart the timer on receipt of an edge.
It seems though that it the interrupt happens very soon after the count has been written, the zeroing does not take place.
I'm wondering if there is a delay when writing to the counter. I wonder if there would have to be at least one pre-scaled clock cycle?
My processor is an STM32F437ZGT6 and I wish to count two different pulse trains (RPM). The range is quite wide, I may have an engine that idles at 150 rpm and we get a pulse from the cam, so 0.5 pulses per revolution, or 1.25 pulses per second. At the other extreme I may need to count 460 flywheel teeth at 3000 rpm, 23000 pulses per second. I have a prescaler available so I can divide the external event by up to 8 but even so this become too intense at higher speeds because every event or eight event causes an interrupt.
One alternative I am considering would be to have one timer use the external event as the clock and it would just count events within a time window. My difficulty comes from determining how to use another timer to control the window by setting and clearing CEN or some similar action.
In RM0090, section 18.3.15 Timer synchronization the example shows one timer controlling another, timer 1 controlling timer two. I thought that may be useable but althought I did not read otherwise I don't see that any two timers could be paired. The signal I am interested in actually feeds two timers. TIM1 ch1 and TIM9 ch1.
Any suggestions would be appreciated as I don't want to cobble up some Rube Goldberg scheme where one timer fires off an ISR and then the ISR opens and closes the time window.
I should have noted that a lookup table is provided that provides the expected engine speed and the number of pulses per revolution.
Thanks,
jh
If you want to just count external events, you can select external clock source for timer. (Point "Clock selection" of reference manual). SPL should have an example.
And read count from Tim CNT register every time you need.
The problem here is to read counts often enough.
Usually auto-reload register is 2 bytes so you have up to 2 ^ 16 counts before overflow, and loosing counted value.
Timers 2 and 5 have 4 bytes auto-reload registers so you have up to 2 ^ 32 counts.
If you need more then 2 ^ 32 counts you have at least two ways:
- Timer cascade, by setting one timer event as a clock for another.
You can find this in the reference manual as "Using one timer as prescaler for another timer".
Cascading offers you up to 2 ^ 64 timer.
There is an example for SPL in "TIM_CascadeSynchro" folder.
- Less beautiful, but more easy way is to create a counter variable and, increment it in timer irq handler.
Number of counts may be found as cnt_variable * TIMx-> ARR.
Several cascaded variables give the unlimited counter).
Thanks for the post. I will try to add a little detail. RPM 1 is fed into TIM3 ch2 and TIM4 ch1. RPM 2 is fed into TIM1 ch1 and Tim9 ch1. Both have a range of 1.25 pulses per second up to 30000 pulses per second. I am given the number of pulses per revolution which can range from 0.5 to 460 and the expected engine rpm, 150 - 3000 rpm so I can scale things a bit. The reason for feeding two different timers is to be able to use different counting techniques based on speed (pulses per second). For low speed I can capture events (pulses) and grab the timer count using an ISR. But when the pulse count gets high I want to use a different method so as not to incur more than 1000 interrupts per second per channel. So my idea there is to have one timer control another. One timer would simply count events without generating interrupts. The second counter would control the period of time that the first timer would be allowed to collect events.
Thanks,
jh
Seems like you need: timer synchronization with enabling/disabling slave timer according to the trigger output of master timer.
Description can be found in the following sections of RM0090:
18.3.14 Timers and external trigger synchronization in paragraph Slave mode: Gated mode
18.3.15 Timer synchronization in paragraph Using one timer to enable another timer
Also good explanation can be found in TIMx register section for registers TIMx_SMCR: bits TS and SMS; TIMx_CR2: bits MMS.
TIMx internal trigger connection (tables 93, 97 and 100) сontains possible connections of the trigger output of one timer with the input of another. Timers that you can use as master are marked in the picture below:
TIM_ExtTriggerSynchro example from SPL library can be used for code copy-paste.
I think the best way is:
Set RPM pins as external clock source for slave timer.
Set enabling/disabling of slave timer from the output compare of master timer. So changing TIMx_CCRx register value you can change duration of measurement.
Set master timer interrupts on update event (maybe on few events TIMx_RCR register).
Do all the calculations in master timer interrupt handler
Also it seems to me that you can just use 16 bit timer as RPM counter. Even on 30000 pulses you will have overflow every 2^16/30000 = 2,18 seconds which is rarely rare for STM32F4 clock frequencies. And use other timer, with, for example, 2 second period, interrupt for calculations.
Good luck!
I am working with a STM8 timer (not my code, but maintaining it) and in it it uses a timer. Apparently the clock is set at 16MHz erfo 0.0625uS. The settings of the timer are ARRH=0x03 ARRL=0x20 therefore (0x0320=800) it resets at 800 (ergo 50us)
PSCR is set at 0 so the timer has the same freq as the micro.
Anyway, when checking this with an oscilloscope, it does not give good readings.
The timer interrupt is called at:
56us , 54uS, 54uS, 52uS, 52uS, 52us, 38us(!!!), 42us(?), 50us, 50us....
curiosly summed up it gives 500uS so it does count as 10 times 50uS
The first 8 times at the timer interrupt some AD conversion is happening so there is the possibility that an AD interrupt is being called in between too.
1) Do you think this is affecting the frequency of the timer?
2) why does it "correct" itself by firing an interrupt at 38uS??
I would appreciate any comment based on your embedded or STM8 experience, since I know precise answers would need to examine the code...
I'm not sure if you still need an answer. I once had the same and searched for a long time... simple solution in my case:
I had an ADC ISR with high jitter. That came from my main loop. In some sub-sub-sub routine the ADC interrupt was temporarily deactivated for a critical section (data transfer between interrupt and main loop context). The effect is exactly what you discribe:
Sometimes the time between two interrupts is longer, because the interupt is pending and waiting for execution until the interrupt is enabled again. The timer is still continuing to run. Timing example:
interrupt is disabled in main loop (or sub routine)
interrupt flag is set by timer -> interrupt pending
interrupt is enabled again -> ISR is executed too late
interrupt is disabled in main loop
interrupt flag is set by timer -> pending
interrupt is enabled again -> ISR is executed much too late
main loop does NOT disable interrupt for some case (maybe by control flow, maybe timing issue)
The next interrupt is executed at the right time which is 50 us after raising the last interrupt, NOT 50 us after calling the last ISR. --> time between ISR calling is shortened.
I hope I could help.
I am writing an preemptive kernel in C and assembly. I've been looking at and setting up timer interrupts through the PIT and the PIC but one thing I am utterly unable to find an answer on.
We have initilized the 8254 chip to be counting on counter 0 in mode 2. We set it to fire an interrupt on IR0 on the PIC every 10 ms. After that we enable the IR0 on the PIC and things work as intended.
However lets say at certain conditions we want to alter the time that the PIT fires at by feeding it a new value. Or just restart the counter midcounting.
The intel manual for the chip has some detail on the gate and using it to restart the counter by getting a rising edge on the gate.
THe manual also says that if we give the counter a new value it doesn't reset the counter until after the current counting sequence is finished unless a trigger (rising edge on the gate) happens before the counting is over.
The manual also says that sending a new CW to the chip would reset the counter, however I don't believe this is the optimal way of restarting or altering the counter.
So the question is, how would this be done in either c or assembly? (We got full write access whenever we want).
To not leave a question unanswered and as I've somewhat of an answer I'll answer it myself.
As far as I've understood the chip has 3 counters but only counter 2 (we start counting at 0) has the gate pin connected (and this one has it connected to the speaker). As a result counter 0 which is the real timer counter doesn't have a connection on the gate which means we can't cause a trigger on it after sending it a new value.
This means that sending a value to it and then restarting it on the value before the timer is up is impossible without sending it new ICW.
In case we want to reset the timer when we get out of an interrupt caused by the 8259 chip which the 8254 is connected to at the end of the handling of that interrupt (that is we don't want the time to be running during the actual interrupt) we would be best of changing the mode to mode 0 which doesn't restart the timer on terminal count and then just manually restart it with the time we want to use for it each time we are about to end and interrupt.
I'm using a PIC18 with Fosc = 10MHz. So if I use Delay10KTCYx(250), I get 10,000 x 250 x 4 x (1/10e6) = 1 second.
How do I use the delay functions in the C18 for very long delays, say 20 seconds? I was thinking of just using twenty lines of Delay10KTCYx(250). Is there another more efficient and elegant way?
Thanks in advance!
It is strongly recommended that you avoid using the built-in delay functions such as Delay10KTCYx()
Why you might ask?
These delay functions are very inaccurate, and they may cause your code to be compiled in unexpected ways. Here's one such example where using the Delay10KTCYx() function can cause problems.
Let's say that you have a PIC18 microprocessor that has only two hardware timer interrupts. (Usually they have more but let's just say there are only two).
Now let's say you manually set up the first hardware timer interrupt to blink once per second exactly, to drive a heartbeat monitor LED. And let's say you set up the second hardware timer interrupt to interrupt every 50 milliseconds because you want to take some sort of digital or analog reading at exactly 50 milliseconds.
Now, lastly, let's say that in your main program you want to delay 100,000 clock cycles. So you put a call to Delay10KTCYx(10) in your main program. What happenes do you suppose? How does the PIC18 magically count off 100,000 clock cycles?
One of two things will happen. It may "hijack" one of your other hardware timer interrupts to get exactly 100,000 clock cycles. This would either cause your heartbeat sensor to not clock at exactly 1 second, or, cause your digital or analog readings to happen at some time other than every 50 milliseconds.
Or, the delay function will just call a bunch of Nop() and claim that 1 Nop() = 1 clock cycle. What isn't accounted for is "overheads" within the Delay10KTCYx(10) function itself. It has to increment a counter to keep track of things, and surely it takes more than 1 clock cycle to increment the timer. As the Delay10KTCYx(10) loops around and around it is just not capable of giving you exactly 100,000 clock cycles. Depending on a lot of factors you may get way more, or way less, clock cycles than you expected.
The Delay10KTCYx(10) should only be used if you need an "approximate" amount of time. And pre-canned delay functions shouldn't be used if you are already using the hardware timer interrupts for other purposes. The compiler may not even successfully compile when using Delay10KTCYx(10) for very long delays.
I would highly recommend that you set up one of your timer interrupts to interrupt your hardware at a known interval. Say 50,000 clock cycles. Then, each time the hardware interrupts, within your ISR code for that timer interrupt, increment a counter and reset the timer over again to 0 cycles. When enough 50,000 clock cycles have expired to equal 20 seconds (or in other words in your example, 200 timer interrupts at 50,000 cycles per interrupt), reset your counter. Basically my advice is that you should always manually handle time in a PIC and not rely on pre-canned Delay functions - rather build your own delay functions that integrate into the hardware timer of the chip. Yes, it's going to be extra work - "but why can't I just use this easy and nifty built-in delay function, why would they even put it there if it's gonna muck up my program?" - but this should become second nature. Just like you should be manually configuring EVERY SINGLE REGISTER in your PIC18 upon boot-up, whether you are using it or not, to prevent unexpected things from happening.
You'll get way more accurate timing - and way more predictable behavior from your PIC18. Using pre-canned Delay functions is a recipe for disaster... it may work... it may work on several projects... but sooner or later your code will go all buggy on you and you'll be left wondering why and I guarantee the culprit will be the pre-canned delay function.
To create very long time use an internal timer. This can helpful to avoid block in your application and you can check the running time. Please refer to PIC data sheet on how to setup a timer and its interrupt.
If you want a very high precision 1S time I suggest also to consider an external RTC device or an internal RTC if the micro has one.