PDA

View Full Version : Speed of operation of Isopod


hotstepper
05-27-04, 12:23 PM
Hi

Our application requires communicating with another controller using the serial port. The mother board (VIA Mini Etx) is faster. I am using a buad rate of 57600 but still there seems to be data loss. The application code is written using state machines and I doubt that the inherent language implementation of the state machine structure is slowing down the whole process. The mother board has a 1nanosecond sleep betwen each byte of data being sent.

Our idea is to remove the statemachine structure and just use the macro definition style like the one used for sonars might speed-up the operation. What do you think we shud do? Is my thought that a state-machine implementation is slower than a macro style one correct? Also, if you can give me some link to serial communication using assembly language programming that shud be very helpful.

Thanks and in anticipation

Hotstepper

nmitech
05-28-04, 11:19 AM
The possibility is that entire data bytes are being lost because
the application isn't servicing the serial port fast enough. At 57.6
kBaud you have only 173 usec to process a received byte. Does the application use an RXBUFFER? How big?

Even with a receive buffer, if the state machine is designed
incorrectly, it may suffer data overrun. It's possible that the state
machine has been written so that it can only process one received character per state. If so, and the state machine cycle time is slower than 173 usec, it's possible to fill and overrun the receive buffer, because characters are being added faster than they're being removed.

Possible solutions:

1. We have a feature in the state machine (THIS-TIME) which, if
carefully used, can allow more than one character of received data to be processed per state machine cycle. (It's possible to introduce an infinite loop with THIS-TIME, which is why it must be used with care.)

2. A high-level definition (the "macro definition style") might be able to process received data faster than the state machine. (Normally these run in the "idle" time between state cycles, so it depends on how heavily loaded the state machine is.)

3. A combination of 1 & 2 would be to write a high-level definition to process multiple characters during one state.

4. You could write some assembly language code, but this should not be necessary. All of the IsoMax serial I/O code is already written in assembler and is quite fast. (And because this code is
interrupt-driven, the serial receive interrupt is not available to the
user.) In our experience, the usual limitation is not the kernel code which fills the receive buffer, but the application code which empties the receive buffer. It is possible that some judicious use of assembly language in your application code would make the difference...but that should be a last resort.

hotstepper
05-28-04, 12:15 PM
Hi

Thanks for the elaborate reply. We have been trying this for sometime now. Please go thru the following code and let me know where it can be made more efficient. Moreover, we had added a new macro "MOTORTHREAD" today into the same and the code doesnt seem to be downloading. It is getting stuck everytime at the first line of the macro. What cud be the reason for this to occur? The program is not complete and many more details and macros are to be added, but i just want to confirm that we are doing it the correct way. I also wanted to know if something like "arrays" cud be implemented in isomax. Even a userdefined stack wud do for me. I have 8 sonars and want to store their values at specific time intervals and transmit them over the serial port after accumulating 18 such readings.

Awaiting ur reply

Hotstepper

: SETBAUD DECIMAL 57600 SCI0 BAUD ;

DECIMAL 70 CONSTANT TRANSTART EEWORD
DECIMAL 126 CONSTANT TRANSEND EEWORD

DECIMAL 51 CONSTANT MOTORHEADER EEWORD
DECIMAL 53 CONSTANT STATUSHEADER EEWORD
DECIMAL 83 CONSTANT SERVOHEADER EEWORD
DECIMAL 99 CONSTANT SONARHEADER EEWORD
DECIMAL 153 CONSTANT INITHEADER EEWORD
DECIMAL 65 CONSTANT PANHEADER EEWORD
DECIMAL 7100 CONSTANT SERVOCNTR EEWORD

VARIABLE MOTOVEL EEWORD
VARIABLE MOTOTIME EEWORD

VARIABLE SERVOPOWER EEWORD
VARIABLE PANFLAG EEWORD
VARIABLE PANRESOLUTION EEWORD
VARIABLE DEGREE EEWORD
VARIABLE MOVEDEGREE EEWORD

VARIABLE SONAR1 EEWORD
VARIABLE SONAR2 EEWORD
VARIABLE SONAR3 EEWORD
VARIABLE SONAR4 EEWORD
VARIABLE SONAR5 EEWORD
VARIABLE SONAR6 EEWORD
VARIABLE SONAR7 EEWORD
VARIABLE SONAR8 EEWORD

VARIABLE SERVOID EEWORD
VARIABLE SERVODEG EEWORD

VARIABLE DATASTART EEWORD
VARIABLE HEADER EEWORD
VARIABLE DATAEND EEWORD

DECIMAL 0 PANFLAG !

: DLY 15000 0 DO LOOP ; EEWORD

: DDLY 10 0 DO DLY LOOP ; EEWORD

: IOTHREAD
REDLED OFF
GRNLED OFF
YELLED OFF
SCI0 RX DATASTART !
DATASTART @ TRANSTART = IF
SCI0 RX HEADER !
HEADER @ MOTORHEADER = IF
REDLED ON YELLED OFF GRNLED OFF
SCI0 RX MOTOVEL !
SCI0 RX MOTOTIME !
SCI0 RX DATAEND !
DATAEND @ TRANSEND = IF
THEN
THEN
HEADER @ STATUSHEADER = IF
REDLED OFF YELLED ON GRNLED OFF
SCI0 RX DATAEND !
DATAEND @ TRANSEND = IF
THEN

TRANSTART SCI0 TX
STATUSHEADER SCI0 TX
SONAR1 @ SCI0 TX
SONAR2 @ SCI0 TX
SONAR3 @ SCI0 TX
SONAR4 @ SCI0 TX
SONAR5 @ SCI0 TX
SONAR6 @ SCI0 TX
SONAR7 @ SCI0 TX
SONAR8 @ SCI0 TX
TRANSEND SCI0 TX
THEN

HEADER @ SERVOHEADER = IF
REDLED OFF YELLED OFF GRNLED ON
SCI0 RX SERVOID !
SCI0 RX SERVODEG !
SCI0 RX DATAEND !
DATAEND @ TRANSEND = IF
THEN
THEN

HEADER @ PANHEADER = IF
REDLED OFF YELLED ON GRNLED OFF
SCI0 RX PANRESOLUTION !
SCI0 RX DATAEND !
1 PANFLAG !
DATAEND @ TRANSEND = IF
THEN

THEN

HEADER @ INITHEADER = IF
REDLED ON YELLED ON GRNLED ON
SCI0 RX DATAEND !
DATAEND @ TRANSEND = IF
THEN
SETBAUD
32767 PWMA0 PWM-PERIOD
SERVOCNTR PWMA0 PWM-OUT
SERVOCNTR PWMA1 PWM-OUT
SERVOCNTR PWMA2 PWM-OUT
SERVOCNTR PWMA3 PWM-OUT
0 PANFLAG !
THEN
THEN
; EEWORD

: SONARPANTHREAD
PANFLAG @ 1 = IF
32767 PWMA0 PWM-PERIOD
1800 SERVOPOWER !
SERVOPOWER PWMA3 PWM-OUT
DDLY
18 0 DO
PANRESOLUTION @ 59 * SERVOPOWER @ + SERVOPOWER !
DLY
32767 PWMA0 PWM-PERIOD
SERVOPOWER @ PWMA3 PWM-OUT
DLY
GRNLED OFF
LOOP
THEN
32767 PWMA0 PWM-PERIOD
SERVOCNTR PWMA3 PWM-OUT
0 PANFLAG !
; EEWORD

: SERVOTHREAD

REDLED OFF YELLED OFF GRNLED ON

SERVODEG @ 128 SWAP U< IF
256 SERVODEG @ - 59 * 1800 + SERVODEG !
ELSE
SERVODEG @ 59 * 7100 + SERVODEG !
THEN

SERVOID @ 1 = IF
32767 PWMA0 PWM-PERIOD
SERVODEG @ PWMA0 PWM-OUT
THEN

SERVOID @ 2 = IF
32767 PWMA0 PWM-PERIOD
SERVODEG @ PWMA1 PWM-OUT
THEN

SERVOID @ 3 = IF
32767 PWMA0 PWM-PERIOD
SERVODEG @ PWMA2 PWM-OUT
THEN

SERVOID @ 4 = IF
32767 PWMA0 PWM-PERIOD
SERVODEG @ PWMA3 PWM-OUT
THEN
; EEWORD

: MOTORTHREAD
MOTOVEL @ 128 SWAP U< IF
256 MOTOVEL @ - 9 * 6000 + MOTOVEL !
ELSE
MOTOVEL @ 9 * 7100 + MOTOVEL !
THEN

32767 PWMA5 PWM-PERIOD
MOTOVEL @ PWMA5 PWM-OUT ( TIMEOUT FUNDA CLEAR
; EEWORD
( MACHINE 1

MACHINE IO EEWORD
ON-MACHINE IO
APPEND-STATE CALL_IO EEWORD

IN-STATE CALL_IO
CONDITION
CAUSES IOTHREAD
THEN-STATE CALL_IO TO-HAPPEN IN-EE

CALL_IO SET-STATE


( MACHINE 2

MACHINE PAN EEWORD
ON-MACHINE PAN
APPEND-STATE CALL_SONARPAN EEWORD

IN-STATE CALL_SONARPAN
CONDITION
CAUSES SONARPANTHREAD
THEN-STATE CALL_SONARPAN TO-HAPPEN IN-EE

CALL_SONARPAN SET-STATE

( MACHINE 3

MACHINE SERVO EEWORD
ON-MACHINE SERVO
APPEND-STATE CALL_SERVO EEWORD

IN-STATE CALL_SERVO
CONDITION
CAUSES SERVOTHREAD
THEN-STATE CALL_SERVO TO-HAPPEN IN-EE

CALL_SERVO SET-STATE

( MACHINE 4

MACHINE MOTOR EEWORD
ON-MACHINE MOTOR
APPEND-STATE CALL_MOTOR EEWORD

IN-STATE CALL_MOTOR
CONDITION
CAUSES MOTORTHREAD
THEN-STATE CALL_MOTOR TO-HAPPEN IN-EE

CALL_MOTOR SET-STATE


( CHAINING MACHINES

MACHINE-CHAIN CHN
IO
PAN
SERVO
MOTOR
END-MACHINE-CHAIN

: HANG BEGIN PB5 OFF? UNTIL ; EEWORD

: STARTUP
ISOMAX-START
CHN
; EEWORD

HEX 3C00 AUTOSTART STARTUP
SAVE-RAM

RMDumse
05-28-04, 02:41 PM
I see a number of things in your program that concern me. (Of course it is hard to take in a large program in a glance, so not all these observations may apply, but wanted to give you some feed back as soon as possible, and LC has left for the weekend.)

First off, I see a DLY and a DDLY word. These words just spin and do nothing but waste processor time. These are exactly the sort of things that are called Program Counter Capture Loops, and break the "IsoStructure" concept, and could be responsible for characters being lost.

Another thing I saw, as I took your code and "pretty printed" it, was none of your state machines have any booleans between the CONDITION ... CAUSES constructs. That means they will steal a boolean from the stack, and cause unbalance, and depending on what they find in that non-existant boolean's value, the CAUSE ... phrase will or won't run.

Also I notice all your machines are really single state machines which never change state, so are better off as threads than machines anyway.

Now, RX can also be a Program Counter Capture Loop. So you only want to call RX when you know it will find a character and not just loop there waiting for one. If you call it, and there is no character there, program execution will stop until a character arrives. That's why there's an RX? word. You call it to see if there's a character (like in a CONDITION clause) and only then call RX if there's a character ready (like in a CAUSES clause).

Finally, I don't see that you've used interrupts for your serial input. Assigning buffers to the serial channel give you much better capture of the incoming data, and allows the machines time then to get around to processing the captured, buffered data.

RMDumse
05-28-04, 03:22 PM
Another thing I noticed. You have your initialization strings for the state machines in the source, and not in the start up word. It would be a good idea to have the states initialized in the start up word, because when you power down, then back up, the state information will be lost, but must be re-established before the machines are run. So consider putting these lines in the STARTUP word.

Also, PWM-PERIOD only needs to be set up once. You could put this in the STARTUP word, and then not have to say it so often else were. There's nothing wrong with saying it often, but it isn't necessary, and makes the program longer than necessary.

: STARTUP

CALL_IO SET-STATE
CALL_SONARPAN SET-STATE
CALL_SERVO SET-STATE
CALL_MOTOR SET-STATE

32767 PWMA0 PWM-PERIOD

ISOMAX-START
CHN
; EEWORD

RMDumse
05-28-04, 03:55 PM
Originally posted by hotstepper
I also wanted to know if something like "arrays" cud be implemented in isomax.

Arrays are easily accomplished in the underlying Forth language. Arrays amount to alloting space, then computing indexes. This can be done explicitly, or fancier methods of making new defining words that do this implicitly are possible. It depends on the level of sophiscitication you wish to go to. Forth is very very flexible.

Pls tell me a little more about your program. You want to save 18 reading on 8 sonars. Is this data to be averaged? or otherwise massaged? before sending? or do you mean you need to send 8x18 readings at once?

RMDumse
05-28-04, 04:07 PM
Can you use the second serial channel to talk to the Via Mini Etx? I notice you are trying to develop and communicate on SCI0. If you can use SCI1 (Don't know if you are using IsoPod(TM) with two serials or MiniPod(TM), TiniPod(TM) etc. with only one serial.)

In any case, here is an example of what I have done on a project to make the incoming and outgoing serial interrupt driven.

HERE 50 4 + ALLOT CONSTANT RBUFF0 EEWORD
RBUFF0 50 4 + SCI0 RXBUFFER

HERE 50 4 + ALLOT CONSTANT TBUFF0 EEWORD
TBUFF0 50 4 + SCI0 TXBUFFER

HERE 10 4 + ALLOT CONSTANT RBUFF EEWORD
RBUFF 10 4 + SCI1 RXBUFFER

HERE 20 4 + ALLOT CONSTANT TBUFF EEWORD
TBUFF 20 4 + SCI1 TXBUFFER

HERE 10 ALLOT CONSTANT MBUFF EEWORD

I made both SCI0 and SCI1 have serial buffers. SCI0 I used full size character buffers of 80 decimal (50 hex). For SCI1 I used short buffers. My messages on SCI1 was only 16 decimal (10 hex) characters long, so for input I made the buffer 16 characters, and for output, I made that double to give me room to be sending one message and buffering up another at the same time.

I also created a small buffer to be used as an array buffer for my working on the message.

Regarding your high baud rate, I think using these buffers would improve your situation considerably.

Here's the state machine I used to sync up with the host's message.

MACHINE RECEIVER EEWORD
ON-MACHINE RECEIVER
APPEND-STATE AWAIT-SYNC EEWORD
APPEND-STATE CHECK-SYNC EEWORD
APPEND-STATE AWAIT-DATA EEWORD
APPEND-STATE STORE-DATA EEWORD

0A7 CONSTANT SYNCCHAR EEWORD
VARIABLE MOFFSET EEWORD ( offset into message buffer
VARIABLE RXCHAR EEWORD ( last character received, for state tests
: GET-CHAR SCI1 RX RXCHAR C! ; EEWORD

( wait for valid 0A7 sync character

IN-STATE
AWAIT-SYNC
CONDITION
SCI1 RX?
CAUSES
GET-CHAR
THEN-STATE
CHECK-SYNC
THIS-TIME IN-EE

IN-STATE
CHECK-SYNC
CONDITION
RXCHAR C@ SYNCCHAR = NOT
CAUSES
(
THEN-STATE
AWAIT-SYNC
THIS-TIME IN-EE

IN-STATE
CHECK-SYNC
CONDITION
RXCHAR C@ SYNCCHAR =
CAUSES
SYNCCHAR MBUFF C!
1 MOFFSET !
GRNLED ON ( DEBUG - INDICATES SYNC RECEIVED
THEN-STATE
AWAIT-DATA
THIS-TIME IN-EE

( receive 15 bytes of data

IN-STATE
AWAIT-DATA
CONDITION
SCI1 RX?
CAUSES
GET-CHAR
THEN-STATE
STORE-DATA
THIS-TIME IN-EE

IN-STATE
STORE-DATA
CONDITION
MOFFSET @ 0F <
CAUSES
RXCHAR C@
MBUFF MOFFSET @ + C!
1 MOFFSET +!
THEN-STATE
AWAIT-DATA
THIS-TIME IN-EE

IN-STATE
STORE-DATA
CONDITION
MOFFSET @ 0F < NOT
CAUSES
RXCHAR C@ MBUFF 0F + C!
( PROCESS PACKET )
CHKSUMCHK
IF ( CHKSUM OKAY TAKE DATA
( REDLED ON
MESSAGEPROCESS
THEN
GRNLED OFF
THEN-STATE
AWAIT-SYNC
NEXT-TIME IN-EE

hotstepper
05-29-04, 06:46 AM
HI

Thanks for the prompt replies. The sonar usage for our application is as follows: we have 8 sonars placed at 45degree angle w.r.t. each other and then take in readings from them. When asked for values, the isopod will have to transmit the echo readings from all of them thru the serial port. What we have on mind is to keep the sonars fired all the while, i.e. run the sonar code as a seperate thread wherein we are continuously reading the echo pulses and dynamically calculating the average of the readings for each sonar seperately. The average values is stored in 8 different variables and they will be updated dynamically. That is one application.

In one more we are rotating 2 sonars(mounted on two servos), by 180degrees each and scanning the area. Now, the problem here is at varied resolution i.e. at a shift of say 5/10degrees each in the servo position, we will have to decide how many values will we get say 36 readings at 10deg. resolution for both the sonars and 72 readings at 5deg. resolution. Based in that we have to know how many locations/variables we need to store all these values as they are to be transmitted at once on the serial port. I have no idea if dynamic memory allocation is a solution. The array implementation I had asked about was for the same. Please suggest a solution to this....

cwkoehler
04-08-06, 07:28 PM
Randy,

A while back you posted this example of how to sync a serial connection. I'm comprehending all but a few lines. I was hoping you could shed some light. Here is the code with the lines of interes in bold. Thanks in advance


IN-STATE
STORE-DATA
CONDITION
MOFFSET @ 0F<
CAUSES
RXCHAR C@
MBUFF MOFFSET @ + C!
1 MOFFSET +!
THEN-STATE
AWAIT-DATA
THIS-TIME IN-EE

IN-STATE
STORE-DATA
CONDITION
MOFFSET @ 0F < NOT
CAUSES
RXCHAR C@ MBUFF 0F + C!
( PROCESS PACKET
CHKSUMCHK
( CHKSUM OKAY TAKE DATA
MESSAGEPROCESS
THEN
THEN-STATE
AWAIT-SYNC
NEXT-TIME IN-EE

your full source code ABOVE

Regards
Chris



Follow UP

After looking at this for some time let me give this a guess. The first BOLD

RXCHAR C@ places the last received character on top of the stack

MBUFF MOFFSET @ + sets the address location within MBUFF to the value of the MOFFSET variable

and finally the C! stores the last received character at this location in MBUFF



The Second Bold RXCHAR C@ MBUFF 0F + C!

does essentially the same thing except instead of using MOFFSET to establish where in MBUFF the syntax places the last received character to the last address of MBUFF




Does this about explain what is going on here? Any insight would be greatly appreciated.

Regards
Chris

Pacetech
04-20-06, 01:33 PM
This works on a fixed packet length transmission of 0F bytes, each byte is fetched and stored in the MBUFF array, the MOFFSET is the array index, gets incremented after it receives each byte.


IN-STATE
STORE-DATA
CONDITION ( Are we at the end of the packet?
MOFFSET @ 0F < ( Check MBUFF Index is not at end
CAUSES
RXCHAR C@ ( Fetch the next serial character
MBUFF MOFFSET @ + C! ( Store it in the MBUFF array
1 MOFFSET +! ( Increase the MBUFF Index
THEN-STATE
AWAIT-DATA
THIS-TIME IN-EE

IN-STATE
STORE-DATA
CONDITION ( Are we at the end of the packet?
MOFFSET @ 0F < NOT ( Check Index is >= 0F
CAUSES
RXCHAR C@ ( Fetch the next serial character
MBUFF 0F + C! ( Store it in the MBUFF array
CHKSUMCHK ( CHKSUM OKAY TAKE DATA
IF ( If CHKSUM return TRUE = Data is OK
PROCESS PACKET ( Process the packet
THEN
THEN-STATE
AWAIT-SYNC
NEXT-TIME IN-EE