PDA

View Full Version : Running continuously using a state machine


ai4presidente
08-03-06, 04:24 PM
Hi,
I am writing a program that allows the user to communicate with the Plugapod using the terminal (NMI term). My original program was quite simple and just used a DO loop in the main program. However, I have implemented the program using state-machines, and it appears that simply using a do-loop will not work. I looked at some of the applications, and I found that a common design is to write a function like main or startup and then use a EVERY 50000 CYCLES SCHEDULE-RUNS on the machine chain. I tried one of these programs and they do appear to run continuously. However, when I attempted to implement my code in a similar manner, the main function stops running after 1 iteration. The code is

DECIMAL
: MAIN
EVERY 50000 CYCLES SCHEDULE-RUNS FISHCHAIN

?KEY IF
KEY CMDCHAR C!
GRNLED ON
ELSE
NULLCHAR CMDCHAR C!
GRNLED OFF
THEN
CMDCHAR C@ .
CR



; EEWORD

I do not really understand how the EVERY 50000 CYCLES SCHEDULE-RUNS command works, so I am also concerned that if it only runs the FISHCHAIN every 50,000 cycles, it will miss commands that are sent.

Any help would be greatly appreciated.

Thank you.

RMDumse
08-04-06, 04:38 PM
I looked at some of the applications, and I found that a common design is to write a function like main or startup and then use a EVERY 50000 CYCLES SCHEDULE-RUNS on the machine chain. I tried one of these programs and they do appear to run continuously.

You bring up a number of very deep overlapped concepts. Let's see if I can help. First things first.

Yes, it is common to use

EVERY 50000 CYCLES SCHEDULE-RUNS <nameofmachinechain>

This installs the chain into the background. The named machine chain runs periodically. The 50000 cycles of a 5 MHz reference clock works out to run 100 times a second.

Since the number passed to CYCLES is a 16-bit value, this is about as slow as you can run the background task. (65535 is the absolute highest unsigned number you can have in 16-bits, but 76.2951... is not a nice clean value, like 100 times a second the 50000 gives you.)

So as far as mechanical things go, 100 times a second is pretty good. It's twice as fast as most servos were intended to be updated. It's fairly fast compared to the human eye and ear, it's difficult to see the flicker in an LED modulated 100 times a second. So for mechanical and human interfaces, 100 times a second is a very nice rate to use, not so fast that the processor is unnecessarily loaded, but fast enough that humans and many mechanical systems can't tell the difference between that and continuous.

BTW, if you use INSTALL, without specifying a period, it will choose 50000, or 100 times a second, for you.

Now you could run the background faster. For instance, if you ran every 5000 cycles you'd be interrupting at 1000 times a second. Ever millisecond your background task would run. What if your background task is very short, can you run faster? Sure. Let's say your background task takes 50 cycles. Then you could run every 500 cycles, or 10,000 times a second, and you'd still have half the processor time available to chit chat in the foreground.

However, if you only are sending signals to RC Servos, why in the world would you run 100s of times faster than they can even update themselves?

Well, everything in the world is not mechanical and slow like humans and mechanical systems. With electronic systems, such as communications, characters can come in very often. For instance, with a 9600 baud serial link, you can have a character every millisecond. So if you were tracking a serial link, and wanted to catch every character, you'd need your background to run every 5000 cycles, or 1000 times a second!

Now think of a serial link at 115200, that's 100 times faster. Wow. You'd really have to run the background fast, and it would have to be very short to complete so it could run that many times a second. Hummm...

Maybe there's a better way.

Yes, there is. Usually you need to catch characters that come in fast, but since it takes several characters to make a message, if you buffer the characters up, then you can read them at a much slower rate than that of the individual character rate.

So you can buffer serial inputs.

Here is an example of creating two buffers:

HERE 80 4 + ALLOT CONSTANT RBUFF EEWORD
HERE 80 4 + ALLOT CONSTANT TBUFF EEWORD

Basically, they are just big variables. There's a 4 byte overhead associated with using buffers, so we add 4 to the length of circular buffer we want. And here is an example of enabling the buffers.

RBUFF 80 4 + SCI0 RXBUFFER
TBUFF 80 4 + SCI0 TXBUFFER

The word RXBUFFER uses an object descriptor, a length and an address (reverse order show) to assign a machine code interrupt routine to gather the characters and put them in the circular buffer named.

The word TX is about the same, but gives an outgoing buffer that will take a series of characters and transmit them as soon as possible, without having to wait for each individual character to pass.

So you can use buffers to make sure you get all the "fast" characters coming in, even if your background task runs slower than the character rate. In the background task, you can get as many characters as you wish, or as are available, and process them, so to speak, at your leisure.

However, when I attempted to implement my code in a similar manner, the main function stops running after 1 iteration.

Yes the code you show will only run the ?KEY... once and exit to the OS after the one run. Here's another way to look at it. Make FISHCHAIN a routine with your communications in it. Install FISHCHAIN with MAIN. Since this will run 100 times a second, I moved the printing of CMDCHAR up to where it only runs when a new key is there. Otherwise you'd have about 100 NULLCHARs run out to the screen, with whatever else you had typed in between.


I do not really understand how the EVERY 50000 CYCLES SCHEDULE-RUNS command works, so I am also concerned that if it only runs the FISHCHAIN every 50,000 cycles, it will miss commands that are sent.

With the example I've modified, you will catch any characters that come in no faster than 100 per second. But to keep the slow background rate, and allow a faster incoming rate, I'll add buffers to the example:


DECIMAL
HERE 80 4 + ALLOT CONSTANT RBUFF EEWORD
HERE 80 4 + ALLOT CONSTANT TBUFF EEWORD

RBUFF 80 4 + SCI0 RXBUFFER
TBUFF 80 4 + SCI0 TXBUFFER

: FISHCHAIN
BEGIN
SCIO RX?
WHILE
SCIO RX CMDCHAR C!
GRNLED ON
CMDCHAR C@ .
CR
REPEAT
; EEWORD

: MAIN
RBUFF 80 4 + SCI0 RXBUFFER
TBUFF 80 4 + SCI0 TXBUFFER
EVERY 50000 CYCLES SCHEDULE-RUNS FISHCHAIN
; EEWORD


It was a pretty deep question. So, I hope that helps. If not ask further questions.