Sunday, February 10, 2008

Bit Shifting in PBasic

This project requires sending luminance information for 64 motors from the video to the program and the program needing to parse this information and send out 64 message out to the appropriate motors in the linear PBasic style. Straightforward like this, things were very slow and memory intensive to say the least. I soon realized packing information as efficiently as possible to streamline the original message would improve performance I just didn't know how. I was finally introduced to the concept of bitwise operations and I've been racking my brain over the concept ever since.

Intuitively, I knew with only 3 motor positions, I could use single digits as values to coordinate motor rotation instead of memory intensive numbers (which the motors need) such as 1000, 850, and 700. A "0", "1" and "2" would substitute and these translate into binary very nicely.

PBasic has functions to save nibbles and a single bit, but not crumbs. So, my first experiments were sending a 32-byte message, sorting this into memory and breaking apart the byte into its nibbles, which would translate into either the "0", "1" or "2". Two motors could be controlled by one byte of information respectively. This was still slow, both to transmit the message over the serial cable and to send the messages to the motors sequentially. My experiments had the last motor in only a 16 motor string delay its movement anywhere between 5 -10 seconds. This would only get exponentially worse by adding 48 more motors.

So, to try and make this short, I finally figured out how to send a message that once extracted, will produce 4 distinct numbers. Here is some code to show this abstracted to control 1 motor, but could control 32 in this instance.

DECLARED VALUES
mask(0) = 3
mask(1) = 12
mask(2) = 48
mask(3) = 192

shift(0) = 0
shift(1) = 2
shift(2) = 4
shift(3) = 6


INTRO:
SERIN 16, 16780, [SPSTR 16]
   
//serial in a 16-byte message and write each byte to an address in scratchpad ram starting at index 0
FOR index = 0 TO 7
GET (index), Sdata(index)    
//Loop structure to retrieve the first 8 bytes of data from the scratchpad ram and load into an 8-byte array Sdata
NEXT

MAIN1:
FOR index = 0 TO 3
temp(index) = Sdata(0) & mask(index) >> shift(index)    
 //load the first byte in the Sdata array, parse into the 4 crumbs with the mask and shift arrays and save in a temp array.
NEXT
GOTO MOTOR1

MOTOR1:
Branch temp(0), [A1_1, A1_2, A1_3]         //switch to a subroutine based upon the byte value in temp(0) to control motor position

A1_1:
pw = 850             //sets the position value for the motor
SEROUT 15, Baud+$8000, ["!SC", 15, 0, pw.lowbyte, pw.highbyte, CR] //send the position message to the appropriate motor, in this case the motor control board on line 15 and the motor on line 15.
GOTO MOTOR2


This has improved performance substantially and is very responsive, but I feel that there may still be room for improvement toward circumventing the linear logic.