Running Program on Basic Stamp 2 (BS2) from EEPROM
-GRIMM-
Posts: 56
Hello
I am currently using all the onboard EEPROM on my BS2 module due to a large amount of program functions (no, there is nothing wasteful in the program)
I need to add even more functionality now, and I require a little bit more memory.
I could not find any help by searching, so I have to ask (and make it easily searchable for others):
Is there an easy way to store program code on an external EEPROM and have the BS2 boot from the external?
Or possibly store subroutines on the external EEPROM and have the main function calls on the BS2 EEPROM?
I have done this with the propeller, but not the stamp.
I will be ordering the 24LC128 (although I'm thinking about a 24LC1026 from digikey)
Thanks
-Steven
I am currently using all the onboard EEPROM on my BS2 module due to a large amount of program functions (no, there is nothing wasteful in the program)
I need to add even more functionality now, and I require a little bit more memory.
I could not find any help by searching, so I have to ask (and make it easily searchable for others):
Is there an easy way to store program code on an external EEPROM and have the BS2 boot from the external?
Or possibly store subroutines on the external EEPROM and have the main function calls on the BS2 EEPROM?
I have done this with the propeller, but not the stamp.
I will be ordering the 24LC128 (although I'm thinking about a 24LC1026 from digikey)
Thanks
-Steven
Comments
I'll echo Mike's comments, and ask if you have considered moving from the standard BS2 to one in the BS2p series? You will have a lot more space to work with, and to my way of thinking the individual slots are not that hard to work with. Apart from the fact that there is only one active at a time, they are kind of like the cogs in a propeller. You can pass data back and forth via the scratchpad RAM or eeprom. With the 'p series, any slot has access to the eeprom in the other slots. Well, it is long ways to the propeller, but definitely a step in that direction.
There are often ways to save space in a program slot. One of the biggest space hogs is text that is written as part of a DEBUG or SEROUT statement. Prompts, messages. If there is a lot of that, you can regain space by moving the text to DATa statements and writing a subroutine to pick it out. Each byte in a DEBUG takes up 14 bits, but only 8 bits as DATa.
I never thought of that......duh...
So, common text that's used menu-to-menu on an LCD could be pulled from DATA and not embedded into each slots' code?
Thank you Mr. Allen!
:thumb:
Check the manual:
http://parallax.com/sites/default/files/downloads/27218-Web-BASICStampManual-v2.2.pdf
for the commands STORE, READ and WRITE
I was under the impression that the DATA directive only worked on slot 0.
Not true. I believe that, on the BS2sx and BS2e, the slot used for data is the same one as the active program is in. On the BS2p series, the data slot and program slot can be different (using the STORE statement).
Although the chapter descriptions of DATA and STORE aren't very clear on the ability to "flatten" the slot memory, the example code for STORE in the on-line version of help was rather detailed.
I did not know about this capability of the BS2pe. This opens some new doors for me with my current multi-slot project.
The BS2pe is the only one that has 16k for program/data plus an extra 16k for data only.
...darn! Another "duh!"
That means I can off-load all the text for messages into upper slots making room for more code in slots 1 - 8.
Any idea of the hit on execution-time redirecting from slot-to-slot?
One main problem I am encountering is the LCD's ability to understand code as the parallax 4x20 would (i.e. I am not able to use commands such as [LCDLine1] with the hex value, for some reason the LCD panels I have (two of them) from DigiKey are less user-friendly.)
Here is an example of my LCD outputs:
ClearLCD:
FOR i = 1 TO 4
SEROUT 6, 80, [" ... ... "]
SEROUT 7, 80, [" ... ... "]
NEXT
RETURN
Where 6 and 7 are (obviously) the serial pins on my two LCD screens.
I think reducing the size of this would be the best way to attack this problem, as I have several display outputs.
Here is an overview of my program/circuit, without the actual code:
Main program:
GOSUB Discovery (activates one transistor, reads 8 channels of an MCP3208, detects input type from 6 possible circuits)
GOSUB StoreADC (based on circuit type detected, activates x# of 5 transistors [power conservation], reads 8 channels of the ADC and stores them in an 8x1 word array [values range from 0-25000])
GOSUB Calc (calculates characteristics from a calibrated linearized log curve)
GOSUB Display (based on circuit type detected, calls one of 3 display types, displaying circuit characteristics)
I have had to cut down the range from 0-50000 to 0-25000 to reduce the size of the 'calculate' function
StoreADC:
FOR i = 1 TO 8
Varx(i) = 0
NEXT
FOR j = 1 TO 15 'along with onboard capacitors, dampens variation of circuit
PAUSE 50
FOR i = 0 TO 7
LOW CS
SHIFTOUT DataIO, Clock, MSBFIRST, [ Offset | i ]
SHIFTIN DataIO, Clock, MSBPOST, [results\13]
HIGH CS
Varx(i+1) = Varx(i+1) + results
NEXT
NEXT
RETURN
pntr var word
chr var byte
display:
read pntr,chr ' get the character at specified address
if chr = 0 then return ' zero marks end of message
serout lcdPin, lcdBaud, [chr]
pntr = pntr + 1 ' on to next character
goto display
' to call the above routine:
pntr = msg1 ' set pointer to address of message
gosub display ' go display it
By default, the data comes from slot 0. You can use the STORE statement to change which slot is accessed by the READ statement.
This technique is used for text message and text fragments of messages. You'd still use a SEROUT statement directly for inserting
numeric information into your messages.
There's another example of this technique at the end of the Stamp Manual chapter on the DATA statement.
So to go from my previous:
ClearLCD:
FOR i = 1 TO 4
SEROUT 6, 80, [" ... ... "]
SEROUT 7, 80, [" ... ... "]
NEXT
RETURN
I have modified to:
(Header)
ClearLCDData DATA " .... ", 13,0
(Variables)
pntr VAR word
chr VAR byte
(Subroutine)
ClearLCD:
FOR i = 1 TO 4
READ pntr,chr
IF chr = 0 THEN return
SEROUT 6, 80, [chr]
pntr = pntr + 1
GOTO ClearLCD
NEXT
This has cleared up one line on the EEPROM memory map. I will keep reformatting all of my outputs and see how much I can clear up, and see if I can group some output calls in order to conserve space.
THanks!
The LCD port number can be a variable, so as not to duplicate the subroutine for each screen. Mike included "lcdPin" as a variable in his suggested routine, but I see you did not pick up on that. A one-bit variable will do considering that the LCDs are on p6 and p7.
To call the display routine, set the relevant variables & pointers: and in the Display routine, here is an alternative way to write it, using DO:LOOP syntax, and including the one-bit port selector:
Often LCDs do have a special command set that you can find by digging into the manual, things like ClearScreen. I don't understand what your ClearLCD routine is supposed to be doing. It appears to be placing groups of 3 dots on the screen. Is it working okay?
Thank you Mr. Allen. That 100us will not be a problem for my application.
To get around the longer READ times, I'll be moving the pertinent data into SPRAM for faster access.
I actually did just that (6+LCDScreen) after posting that follow up. Yes the LCD displays the dots and characters fine (I put the dots there to at least show it was still responding). For some reason I am not able to send it the hex commands, so every display I have is in groups of 80 characters (to fill the 4x20 display and return to beginning position)
The LCD in use is a Newhaven Display LCD (PN NHD-0420D3Z-NSW-BBW-V3). Manual can be found at http://www.newhavendisplay.com/specs/NHD-0420D3Z-NSW-BBW-V3.pdf
It lists commands such as:
Display On: (0xFE) 0x41
Display Off: (0xFE) 0x42
Clear Screen: (0xFE) 0x51
Column 1 Line 1: 0x00
However I could not get them to cooperate by sending them the hex code. Also, I created a Baud test program and it would only respond with a Baud rate of 75-80, which seems extremely low. But that's what I'm working with.
I will continue grouping commands and just might have enough room (or repeats) to fit everything in here. Although I am purchasing a BS2Psx just in case.
SEROUT lcdPin, lcdBaud, [ $FE, $41]
If this were in a DATA string, you'd use:
turnOn data $FE, $41, 0
Remember that a zero byte marks the end of the string and can't be used as a character. If you need to use zero bytes for data, use $FF as the string terminator instead. The display subroutine would look like:
display:
DO
READ pntr, chr
pntr = pntr + 1
IF chr <> $FF THEN SEROUT 6+lcdPin, lcdBaud, [ chr ] ELSE RETURN
LOOP
I'll give that a shot. I believe I may have been sending SEROUT 6, 80, 0$51
Thanks
Let me ask another follow up question; Is it possible with the 'pntr' calls to combine DATA strings?
i.e. if I have 80 characters to work with (4x20 LCD) and I store them in groups of 10 (to display/hide accordingly)...
Currently I am rewriting pntr and calling Display every 10 characters
DisplayPJJ:
LCDScreen = 0
pntr = DispRes
GOSUB Display
pntr = DispPJJ
GOSUB Display
pntr = J1P1
GOSUB Display
SEROUT LCDScreen+6, 80, [DEC5 Heater(3)]
pntr = Ohms
GOSUB Display
pntr = BlankLine
GOSUB Display
GOSUB Display
...
Is it possible to combine these and only call Display once?
Thanks
.
The default baud rate for that LCD is 9600 bps, and the proper baudmode setting for that is 84:
SEROUT 6,84,[...]
That is a calculated value (baudmode = INT(1000000 / baudrate) - 20), or you can look it up for common baud rates like 9600 in the Stamp manual. The value you are using, 80, computes to 10000 baud. Maybe close enough, but give 84 a try.
The command set for the LCD should really work. It has a PIC micro on board that acts as the protocol and command interpreter.
The compression is far better if the Data strings are long. It is not efficient at all with strings of only one or a few bytes, quite the opposite, it takes more code to set it up than it would to include it in a straight SEROUT. I forget what the breakeven string length is, but it might be around 8 characters.
The REP modifier can be a big space saver,
SEROUT 6,84,[REP "."\40] ' print a string of 40 periods.
The Display routine can be elaborated to match your needs. It can include the display's native control codes (once you figure them out!). It could with some planning also include your own special control codes, which the PBASIC display routine would interpret to mean things like, insert blank line, or print decimal value for Heater(3) here. The codes from $80 to $FD are available for special meanings, unless you happen to want to use the LCD's extended character set. Random snippet:
Do you know if it would work repeating a pattern?
i.e. SEROUT 6,84,[REP " ."\20]
Ill give it a try when I get this taken back apart and hooked up (thinking I should add an external connection for programming.)
If you can shift user expectations so that a whole line of dots will serve, you will save considerable code space by using REP instead. You get used to focusing in on the essentials when working with limited resources!
Mr. Allen,
Is there any difference between:
and:
in terms of execution speed or memory used?
I've seen your style in other expert's examples and wondered why it's done.