Forums » Software Development »
ClockPeriod
Added by Rob Gillis about 13 years ago
Hello,
I am having problems changing the system clock period using the QNX BSP. When I try to change it using the ClockPeriod function, it sets a value that confuses QNX as to the correct time. For example, if I try to change the period from 1 millisecond to 50 microseconds, QNX will run 20x slower, tested using the sleep utility from the command line.
I've attached the test program that I used. I ran this same program on an x86 system with no issues.
Thanks,
Rob Gillis
clock_period.cpp (899 Bytes) clock_period.cpp |
Replies (11)
RE: ClockPeriod - Added by John Pruitt about 13 years ago
Rob,
I don't have experience trying to change the clock period. The documentation does seem to indicate that making the period very small can result in significant overhead in the system from all the interrupts. (see clock_setres() and http://www.qnx.com/developers/docs/6.3.2/neutrino/sys_arch/kernel.html)
I have usually used the ClockCycles() function in order to do more precise timing.
John
RE: ClockPeriod - Added by Rob Gillis about 13 years ago
John,
Actually, the point I was trying to make is that changing the system tick using ClockPeriod confuses the OS concept of time, which shouldn't happen. Using the attached program this is what happens:
- ./clock_period
ClockPeriod: 999999 nsecs <- 1 millisecond tick - sleep 5 <- sleeps for 5 seconds (observed)
- ./clock_period 10000000 <- 10 millisecond tick
- ./clock_period
ClockPeriod: 9999999 nsecs - sleep 5 <- sleeps for < 1 second (observed)
- ./clock_period 200000 <- 200 usec tick
- sleep 5 <- sleeps for 25 seconds (observed)
As you can see, changing the system tick period to anything other than 1 millisecond causes the sleep utility to malfunction. If I just rebuild this program for my x86 CPU/BSP, sleep functions correctly no matter what the system tick is running at.
So, to me this means the problem is either with the MityDSP BSP or the ARM-specific part of QNX. All I was asking is if you could help me either confirm or eliminate the BSP as a problem. Or if you have any other theories I'd certainly be willing to listen.
Thanks,
Rob
RE: ClockPeriod - Added by John Pruitt about 13 years ago
Rob,
I see your point.
We have not provided the arm clock handling routines so in that sense, this would seem to be the arm-specific part of QNX. My understanding though, is that the kernel gets things like device specific handling routines from the bsp, so in that sense, the fix to the problem would probably require a change to the MityDSP BSP. This is good news since you can build the BSP but right now it is not real helpful since it is not clear what the needed changes are.
If we knew what snippets of code from the BSP are used when the ClockPeriod function is called, then a change might be possible. I checked on Foundry27 for a reference to a problem like this and found the following:
http://community.qnx.com/sf/discussion/do/listPosts/projects.bsp/discussion.bsp.topc8003
The code attached to the posting changed the invert_timer_freq() function in bsp-mitydsp-omap-l138-src/src/hardware/startup/lib/invert_timer_freq.c as follows:
Old:
unsigned long rate; unsigned long rem; unsigned long div; unsigned long quot;
New:
unsigned long rate; unsigned long long rem; unsigned long div; unsigned long long quot;
This apparently prevents some overflows that may contribute to the problem. It doesn't really sound like this would fix all the problems you are seeing, but it might help. Could you please try this and let me know how it goes? It would also be interesting to print out the syspage to see how calling ClockPeriod changes the system values related to time. (e.g. use the command pidin syspage
)
Hope this helps.
John
RE: ClockPeriod - Added by Rob Gillis about 13 years ago
John,
I just tried the above mentioned change, and as you suspected it did not fix the problem but was worth a try.
Regarding the pidin info, could you let me know what section of the syspage you would like to see. I did capture the qtime section:- pidin syspage=qtime
Header size=0x0000009c, Total Size=0x00000de0, #Cpu=1, Type=4
Section:qtime offset:0x00000190 size:0x00000060
boot:38962200 CPS:00000000016e3600 rate/scale:41666666/-15 intr:21
This stays constant no matter what the ClockPeriod() is set for, which is what I would expect. My x86 board has the same behavior.
Let me know what to try next. Also, are you able to replicate this problem at your office?
Thanks,
Rob
RE: ClockPeriod - Added by John Pruitt about 13 years ago
Rob,
With regards to the syspage, I was hoping to see values change after changing the ClockPeriod. Sections relating to time and clocks seemed like good candidates. If the x86 shows changes in one way and the omap shows changes in a different way, then this could help isolate the problem.
Right now, I am not in a position to replicate this problem. I have never tried this and have no reason to doubt that it is happening as you say.
Hope this helps.
John
RE: ClockPeriod - Added by Rob Gillis about 13 years ago
Hi John,
The pidin program does not display the info we're interested in, so I modified my clock_period program to display the timer_load value (not to be confused with the timer_load callout) from the syspage. Here are the results:
- ./clock_period <-- 1 millisecond
ClockPeriod: 999999 nsecs
timer_load: 24000
- ./clock_period 2000000 <-- 2 milliseconds
- ./clock_period
ClockPeriod: 1999999 nsecs
timer_load: 48000
- ./clock_period 5000000 <-- 5 milliseconds
- ./clock_period
ClockPeriod: 4999999 nsecs
timer_load: 120000
- ./clock_period 200000 <-- 200 microseconds
- ./clock_period
ClockPeriod: 199999 nsecs
timer_load: 4800
Looks like QNX is putting the correct values into the syspage. I don't know whether they are not getting loaded into the timer register (except for initial boot up), or if there is some other issue that causes sleep to malfunction.
Any ideas?
Thanks,
Rob
RE: ClockPeriod - Added by John Pruitt about 13 years ago
Rob,
It looks like there is a callout function that does not really do what it is supposed to. I suspect the kernel is expecting the timer to change but nothing is happening at the lower level. The timer_load values you show seem consistent with a 24MHz clock.
The function in question is timer_reload_omapl1xx in src/hardware/startup/lib/arm/callout_timer_omapl1xx.S. The function just returns.
In callout_timer_pxa250.S, the timer_reload function actually does something. It looks like it is supposed to reload the #QT_TIMER_LOAD value into the timer registers, or it is just supposed to disable the timer interrupt and presumably another call to timer_load will be done with the new value.
On the omap, (http://www.ti.com/lit/ug/spruh77/spruh77.pdf) it looks like there is a way to do what we want but I think a couple of things need to change. I don't currently a board set up so this is just a guess.
Current way of doing things:
timer_load_omapl1xx():- loads the QT_TIMER_LOAD value into the TMR_PRD12 register
- The QT_TIMER_LOAD value is defined in src/hardware/startup/lib/arm/a.le/asmoff.def as 0x30.
- sets the ENA12 register to 2.
- The ENA12 value of 2 says that the timer will continuously reload with PRD12 value.
- does nothing, just returns
Current code:
CALLOUT_START(timer_load_omapl1xx, 0, patch_timer) /* * Get the address of the timer registers (patched) */ mov ip, #0x000000ff orr ip, ip, #0x0000ff00 orr ip, ip, #0x00ff0000 orr ip, ip, #0xff000000 /* * Get the load value */ ldr r0, [r1, #QT_TIMER_LOAD] /* * load counter value */ str r0, [ip, #OMAPL1xx_TMR_PRD12] /* * start the timer running */ ldr r0, [ip, #OMAPL1xx_TMR_TCR] orr r0, r0, #OMAPL1xx_TCR_ENA12 str r0, [ip, #OMAPL1xx_TMR_TCR] mov pc, lr CALLOUT_END(timer_load_omapl1xx)
CALLOUT_START(timer_reload_omapl1xx, 0, patch_timer) /* * Get the address of the timer registers (patched) */ mov ip, #0x000000ff orr ip, ip, #0x0000ff00 orr ip, ip, #0x00ff0000 orr ip, ip, #0xff000000 mov pc, lr CALLOUT_END(timer_reload_omapl1xx)
Possible way of fixing things:
timer_load_omapl1xx():- load the QT_TIMER_LOAD value into both the TMR_PRD12 and the TMR_REL12 registers
- set the ENA12 register to 3
- load the QT_TIMER_LOAD value into the TMR_REL12 register.
CALLOUT_START(timer_load_omapl1xx, 0, patch_timer) /* * Get the address of the timer registers (patched) */ mov ip, #0x000000ff orr ip, ip, #0x0000ff00 orr ip, ip, #0x00ff0000 orr ip, ip, #0xff000000 /* * Get the load value */ ldr r0, [r1, #QT_TIMER_LOAD] /* * load counter value */ str r0, [ip, #OMAPL1xx_TMR_PRD12] str r0, [ip, #OMAPL1xx_TMR_REL12] /* * start the timer running */ ldr r0, [ip, #OMAPL1xx_TMR_TCR] /*orr r0, r0, #OMAPL1xx_TCR_ENA12*/ orr r0, r0, #(0x3 <<6) str r0, [ip, #OMAPL1xx_TMR_TCR] mov pc, lr CALLOUT_END(timer_load_omapl1xx)
CALLOUT_START(timer_reload_omapl1xx, 0, patch_timer) /* * Get the address of the timer registers (patched) */ mov ip, #0x000000ff orr ip, ip, #0x0000ff00 orr ip, ip, #0x00ff0000 orr ip, ip, #0xff000000 /* * Get the load value */ ldr r0, [r1, #QT_TIMER_LOAD] /* * load counter value */ str r0, [ip, #OMAPL1xx_TMR_REL12] mov pc, lr CALLOUT_END(timer_reload_omapl1xx)
Can you try making these changes?
Thanks.
RE: ClockPeriod - Added by John Pruitt about 13 years ago
The QT_TIMER_LOAD value of 0x30 is just an offset into the system page or some structure. It is not the actual load value.
RE: ClockPeriod - Added by Rob Gillis about 13 years ago
Hi John,
I need to do more testing, but it looks like I have a fix. You cannot change the timer's period while it is running, so I modified the timer_load callout to stop the timer first and zero the counter before changing the period:
In omapl1xx.h:
#define OMAPL1xx_TCR_ENA12_OFF (0xFFFFFF3F)
In callout_timer_omapl1xx.S:
CALLOUT_START(timer_load_omapl1xx, 0, patch_timer)
/*
* Get the address of the timer registers (patched)
*/
mov ip, #0x000000ff
orr ip, ip, #0x0000ff00
orr ip, ip, #0x00ff0000
orr ip, ip, #0xff000000
/*
* stop the timer
*/
ldr r0, [ip, #OMAPL1xx_TMR_TCR]
and r0, r0, #OMAPL1xx_TCR_ENA12_OFF
str r0, [ip, #OMAPL1xx_TMR_TCR]
/*
* reset the timer count
*/
mov r0, #0x00000000
str r0, [ip, #OMAPL1xx_TMR_TIM12]
/*
* Get the load value
*/
ldr r0, [r1, #QT_TIMER_LOAD]
/*
* load counter value
*/
str r0, [ip, #OMAPL1xx_TMR_PRD12]
/*
* start the timer running
*/
ldr r0, [ip, #OMAPL1xx_TMR_TCR]
orr r0, r0, #OMAPL1xx_TCR_ENA12
str r0, [ip, #OMAPL1xx_TMR_TCR]
mov pc, lr
CALLOUT_END(timer_load_omapl1xx)
Thanks for your help with this problem. I didn't get to try your solution, it may also have worked. Could you please test out this fix when you have a setup you can use, and incorporate the fix into the next BSP release?
Thanks,
Rob
RE: ClockPeriod - Added by John Pruitt about 13 years ago
Rob,
I think the method I described was a way of giving the timer control over the reload so it could be done gracefully.
Your method sounds like it would be fine for a situation where you have some setup changes to do and don't really care if the timer interrupts are a little bit off. I think that by stopping the timer, doing a reload, and then restarting, there will be a time between interrupts that is indeterminate. Using the other method probably keeps these times to either the old counter value or the new one. Not sure what advantage this is, but it might matter in other situations. After the setup period, everything should be fine.
I am not sure when the next BSP release will be, but these changes will be included.
Glad we found the right area for you.
John
RE: ClockPeriod - Added by Rob Gillis about 13 years ago
John,
The timer_load callout only gets called when you change the system tick period, so it will only be indeterminate (and expected to behave that way) for a single tick. And with either fix you need to reset the timer count otherwise you will have problems when going from a larger tick period to a smaller tick period.
Thanks,
Rob