View Full Version : ISOMax Timing
Hi,
my first question related to when in time you can assume things are ran. From the docco, it says that the default rate that the state machines are ran is 100Hz.
I wanted to double check that this means that state transitions will occur at 100Hz. For example if you had a state that was checking if a char was available on SCI0 (SCI0 RX?) and if so transitioned to a state that read the character, the actual rate that you would be reading the character would be at 50Hz (as one cycle is wasted in checking if a char is available).
the second question I had was whether there was some information on how long different instructions take, or how many instructions on average you can fit in a certain time window.
I'm trying to run some motor controllers, gyro filtering, etc... and need to run it as quick as possible, so I'm trying to determine how long each of my states may take to run, so that I can try and get as much running as possible. This requires knowing how long the different instructions take, etc.
Any help appreciated.
thanks
Daniel
RMDumse
08-07-07, 02:04 PM
100Hz. I wanted to double check that this means that state transitions will occur at 100Hz.
Yes, by default, once every 50,000 cycles, the scheduled interrupt runs the background task. All the machines are given a time slice, and vector to their active state, and the chain of transitions attached to that state are evaluated. So if you are looking for a character, and upon receiving it, you process it and return back to the same state, then you will take characters 100 per second.[/QUOTE]
For example if you had a state that was checking if a char was available on SCI0 (SCI0 RX?) and if so transitioned to a state that read the character, the actual rate that you would be reading the character would be at 50Hz (as one cycle is wasted in checking if a char is available).
Well, yes, but I don't think you are thinking of this situation correctly. A state is a waiting period. The idea of doing something active in a state (as you suggest "read the character") is not consistent with good state machine design.
Instead, the character should be taken in a transition, going from one state to another. So if you leave a state that is waiting for a character to go to another state to take the character, what is the waiting component of the next state? Doesn't it just take the character and return to the character waiting state every time? Why add a state for that? Isn't it better to take the character in the transition, and then return to the waiting state?
the second question I had was whether there was some information on how long different instructions take, or how many instructions on average you can fit in a certain time window.
Not surprizingly, the answer is widely varied. The short machine coded primatives, like DUP and + and - are very fast. If you roughly allot a few microseconds, maybe average 5, you would be close. More complicated words, like the multiply, *, which uses primatives, but also calculates the sign of the result, will take longer because many primatives are called in sequence of finding the answer. Other words, like the words list itself, WORDS, will run a long list and take many seconds, depending on how many words are in the dictionary, the baud rate, the amount of overhead the background task is taking, etc. The same with printing a number. It depends on the number itself, how many characters are generated, the baud rate, and so on. So your question is not easily answered.
The good news is, you can measure them for yourself if you like. Here's a short program that uses the system timers to read just before and just after a word runs, to give you the "ticks" it takes to complete.
HEX
0C00 CONSTANT SYS_BASE EEWORD ( use 0C00 for '803,'805 )
SYS_BASE 158 + CONSTANT TMRD3_BASE EEWORD ( tD 178 older isomax,TC 158 newer
TMRD3_BASE CONSTANT TMR_CMP1 EEWORD
TMRD3_BASE 5 + CONSTANT TMR_CNTR EEWORD
DECIMAL 28 CONSTANT T0 EEWORD
: T' ( i*x -- j*x n ) ' CFA
TMR_CNTR @ >R EXECUTE TMR_CNTR @ R> ( end start )
2DUP U< IF - TMR_CMP1 @ + ELSE - THEN T0 -
; EEWORD
Thanks very much for that detailed answer.
Excellent service :)
Daniel
cwkoehler
08-09-07, 10:58 AM
I'm a little confused. How exactly would you use this short program to test a word? Encapsulate the program in the word? Reempt the word 'call' with the program? Suppose I had a word defined as such
: INIT-TIMERB
\ Init CTRL Register
7600 TB0.CTRL !
\ Init SCR Register
0080 TB0.SCR !
\ Init CAP - Zero Capture registers
0000 TB0.CNTR !
; EEWORD
how would I use the code segment provided to measure the time of instruction?
Code:
HEX
0C00 CONSTANT SYS_BASE EEWORD ( use 0C00 for '803,'805 )
SYS_BASE 158 + CONSTANT TMRD3_BASE EEWORD ( tD 178 older isomax,TC 158 newer
TMRD3_BASE CONSTANT TMR_CMP1 EEWORD
TMRD3_BASE 5 + CONSTANT TMR_CNTR EEWORD
DECIMAL 28 CONSTANT T0 EEWORD
: T' ( i*x -- j*x n ) ' CFA
TMR_CNTR @ >R EXECUTE TMR_CNTR @ R> ( end start )
2DUP U< IF - TMR_CMP1 @ + ELSE - THEN T0 -
; EEWORD
thanks
Chris
nmitech
08-09-07, 02:32 PM
You could do,
T' INIT-TIMERB .
Here is the example,
http://www.newmicros.com/isopod/appnotes/TTick.txt
Hi,
I experimented with that tick timing function to work out how long each of my functions were taking to execute. That seemed to work and i got a bunch of numbers which I then used to check whether all the functions i had running should be able to fit into 1 second at their different rates - this will probably make more sense in the text to follow...
The problem is is that when i run some checks (for example counters incrementing each time into the function and printing to the console when count = say 10,000), is that my functions aren't running as fast as they're supposed to. For example a 400 Hz loop is maybe running at 50 Hz.
So, what I've done now is done some tests where i run each function (nothing else running) in a loop until a counter reaches say 50000 and then stop the program. I time how long this takes to run then divide by 50,000 and I have the time each function takes to run (minus the overhead for the condition checking and counter incrementing... but i can live with this inaccuracy - i think,...). An example of this code is below - but I don't have a problem with this bit... i think this works okay for me and should give me an indicative idea of how fast each function runs.
VARIABLE my_count EEWORD
0 my_count !
LOOPINDEX PRT_ANG_CONTROL EEWORD
5000 PRT_ANG_CONTROL END
: GO
0 my_count !
BEGIN
OUTPUT_ANG_INFO \ FUNCTION TO TIME
\ print count value once in awhile
\ for feedback to user
PRT_ANG_CONTROL COUNT
IF
CR my_count @ DUP .
1 + my_count !
THEN
my_count @ 10 =
UNTIL
; EEWORD
\ start stop watch and run 'GO'
\ stop stop watch when above loop exits (it will display 1 2 3 ... 9)
\ divide time by (in this case 50,000 - but you could increase to increase accuracy)
Anyway, what I now have is a bunch of functions with approximate running times and I then work out how fast I should be able to run each one in the whole SYSTEM.
This is where I would like some input, because i feel this should work but the functions aren't running as fast as they should so there's obviously something flawed in my thinking into how this all should work.
Basically what I'm trying to do is optimise the scheduling for these functions in my system.
For example, some functions I have are:
-> reading encoder and calculating a pan velocity
-> reading encoder and calculating a tilt velocity
-> a vel controller demmanding pan motor through pwm / h-bridge
-> a vel controller demmanding tilt motor through pwm / h-bridge
-> serial decoding function reading from SCI0 and updating pan / tilt demmands
-> etc...
My methodology to work out timing is:
-> for each of the functions I have the MET (max execution time) for each function as timed above.
-> i set a nominal rate for each function - for example 5 hz, 40 hz, or 80 hz, etc. I have these numbers set to a number of LOOPINDEX vars which I have on each of the conditions on several state machines, and when the counter's reached it runs the function (supposidly at the rate I set)
-> i change the rates that functions above run at, so that the total time (MEC for each function * rate the function is running at) for all functions doesn't exceed a certain max time.
Here I am under the assumption that everything has to fit into 1 second. THEREFORE i leave some margin for the interpretor/OS overhead and make sure the total of the functions executed in one second through the state machine doesn't exceed say 0.8secs
I'm hoping there's some flaw in my thinking here that's obvious to you guys and you can point it out.... but i'm not sure atm.
Some other info which might be useful is, i've increased the system frequency to 800Hz, with:
SYS-FREQ 20 / CONSTANT Ang-Output-Rate EEWORD
5.0E6 SYS-FREQ S>F F/ F>D DROP
PERIOD
I have about 10 state machines running too.... perhaps comments on time it takes / overheads to switch between machines or functions?
okay thanks,
Hopefully this makes some sort of sense.
cheers
Daniel
Hi,
No-ones seemed to decifer my longer message above, so i'll try a shorter one.
refering to the following code, I run this and then run an app on my desktop to just receive the "#" character and time the rate at which it's receiving.
The program below simply runs one state machine continuously and should be executing the "LogData" and hence "SendPacket" at the system frequency.
Over a long period of time it spits out consistantly at 400 Hz.
From what I understand about the code I've written below, it should be spitting out at 800 Hz.
Any help appreciated.
SCRUB
ISOMAX-START
DECIMAL
\ +++++++++++++++++++++++++++++++
\ Use these next vars to alter the
\ output logging rate over serial
800 CONSTANT SYS_FREQ EEWORD
LOOPINDEX log_freq_count EEWORD
1 log_freq_count END
115200 CONSTANT BAUD_RATE EEWORD
\ +++++++++++++++++++++++++++++++
\ serial buffer
\ helps get all data through at a consistent rate
HERE 10 ALLOT CONSTANT BUFFER1 EEWORD
BUFFER1 10 SCI0 TXBUFFER
\ +++++++++++++++++++++++++++++++
\ Functions
\ Serial init
: SetupSerial
SCI0 BAUD_RATE BAUD
; EEWORD
\ individual byte tx
: TX-BYTE
BEGIN \ Ensure previous character has been transmitted
SCI0 TX?
UNTIL
SCI0 TX \ Transmit
; EEWORD
\ Send packet
: SendPacket \ sends the top 4 numbers on the stack over serial
35 TX-BYTE
; EEWORD
\ main log data function
: LogData
\ this function puts the data on the stack and
\ then sends the packet with the SendPacket
\ function
\ get data to tx
\ finally , we send the packet
SendPacket
; EEWORD
\ +++++++++++++++++++++++++++++++
\ Machine stuff
MACHINE MACHINE_Log EEWORD
ON-MACHINE MACHINE_Log
APPEND-STATE STATE_LogNow EEWORD
IN-STATE STATE_LogNow \ Get gyro data with moving 3 average
CONDITION
log_freq_count COUNT
CAUSES
LogData
THEN-STATE
STATE_LogNow
TO-HAPPEN
IN-EE
\ +++++++++++++++++++++++++++++++
\ START
: MAIN
\ set system frequency
5.0E6 SYS_FREQ S>F F/ F>D DROP
PERIOD
SetupSerial
STATE_LogNow SET-STATE
INSTALL MACHINE_Log
; EEWORD
SAVE-RAM
additionally to the post just submitted, if I increase the system frequecy to 1600 Hz, the characters spit out at 800 Hz.
Exactly half like before.
thanks.
Daniel
nmitech
01-08-08, 02:28 PM
I think the problem is the BAUD value. It probably got chop off since it only hold 16-bit value. Where 115200 is a double. What IsoMax version do you have? From V0.65 to current V0.82 the default baud rate is 115200.
If you have V0.61 or older, you can use this,
HEX
: SetupSerial
16 F00 ! ( set SCI baudrate to 115200
; EEWORD
to replace your code below,
...
...
115200 CONSTANT BAUD_RATE EEWORD
...
...
\ Serial init
: SetupSerial
SCI0 BAUD_RATE BAUD
; EEWORD
...
...
RMDumse
01-08-08, 03:52 PM
I'm looking at how the LOOPINDEX is written, thinking, won't that divide by 2? So I tested it.
SCRUB
IsoMax V0.82
LOOPINDEX X OK
1 X END OK
X COUNT . 0 OK
X COUNT . -1 OK
X COUNT . 0 OK
X COUNT . -1 OK
Yes, it takes two passes of COUNT to reset X. So I am not surprized your machine runs every other time.
If you wanted the LOOPINDEX to fire every time, there are a couple ways of doing that. One would be to set the START and END to the same value
COLD
IsoMax V0.82
LOOPINDEX X OK
1 X START OK
1 X END OK
X COUNT . 0 OK
X COUNT . -1 OK
X COUNT . -1 OK
X COUNT . -1 OK
X COUNT . -1 OK
But as you can see, the first time, the initialized LOOPINDEX will run with a 0 value, and so fail the top limit test. On the other hand if you set the END at 0, it will give a boolean true and reset every time.
COLD
IsoMax V0.82
LOOPINDEX X OK
0 X END OK
COUNT . -1 OK
COUNT . -1 OK
COUNT . -1 OK
COUNT . -1 OK
So the short example above is an issue of how LOOPVARs work. Do you suppose the longer one has the same problem? I've really not been able to grok the whole idea of the longer post as you suspected.
RMDumse
01-08-08, 04:29 PM
The problem is is that when i run some checks (for example counters incrementing each time into the function and printing to the console when count = say 10,000), is that my functions aren't running as fast as they're supposed to. For example a 400 Hz loop is maybe running at 50 Hz.
800Hz is pretty fast, but I've even run short programs up at 10,000 Hz so it isnt' out of the question.
So, what I've done now is done some tests where i run each function (nothing else running) in a loop until a counter reaches say 50000 and then stop the program.
This method should give the same result (within reasonable tolerance) to the single pass timing we described above with T'
CR my_count @ DUP .
Since the . function really works hard, formating in decimal, waiting for the CR and following LF to go out first, then streaming the decimal characters, it can hold up your timing. It only runs 10 times, but it will add several character times to each pass. Maybe you want to turn on the serial buffers so the serial part doesn't slow the rest of your timing loop down that mcuh.
This is where I would like some input, because i feel this should work but the functions aren't running as fast as they should so there's obviously something flawed in my thinking into how this all should work.
You're thinking is okay. I'm not sure of your implementation however.
Here I am under the assumption that everything has to fit into 1 second. THEREFORE i leave some margin for the interpretor/OS overhead and make sure the total of the functions executed in one second through the state machine doesn't exceed say 0.8secs
Basic assumptions seem just fine.
Personally I'd time the words strung together, see how long it took, then multiple by how often I ran it, and see if there was still time left over worst case, and it should work.
I have about 10 state machines running too.... perhaps comments on time it takes / overheads to switch between machines or functions?
I think the overhead is low, comparable to a word call, or like I suggested maybe 5uS or so.
Answered the short question, but really don't have enough to go on to help more.
Just a quick note to say thanks for you detailed responses. You answered everything i needed.
The loop index thing is obvious now you point it out :) and explains why it was executing half the speed.
I don't think there was an issue with the baud rate (well it might not have been interpretted correctly, but obviously defaulted back to 115200 else I wouldn't have been able to decode the packets on the other end).
again thanks,
daniel
vBulletin v3.0.7, Copyright ©2000-2012, Jelsoft Enterprises Ltd.