Shop OBEX P1 Docs P2 Docs Learn Events
Running Program on Basic Stamp 2 (BS2) from EEPROM — Parallax Forums

Running Program on Basic Stamp 2 (BS2) from EEPROM

-GRIMM--GRIMM- Posts: 56
edited 2013-09-27 09:25 in BASIC Stamp
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
«1

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2013-09-20 12:00
    You cannot do it. The Basic Stamp is limited to 2K bytes of program space. There is no way to change that. Even those Stamps that have larger EEPROMs have 2K "slots" that work somewhat like overlays. You can switch from one slot to another, but the slot program starts from the beginning and you can't call from one slot to another. There's no return between slots either. People have taken large programs and sometimes broken them up into slot modules where one slot does a single or only a few related operations. Typically this will be some kind of initialization or configuration. The main slot keeps track of stuff in a couple of variables, RUNs the 2nd slot passing a parameter in a shared variable. When the 2nd slot is done, it RUNs the main slot. The main slot can tell that the variable has been initialized and skips the RUN of the 2nd slot to continue with the rest of the main program.
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2013-09-21 09:08
    Steven,

    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.
  • davejamesdavejames Posts: 4,047
    edited 2013-09-21 09:22
    ...you can regain space by moving the text to DATa statements and writing a subroutine to pick it out.

    I never thought of that...:innocent:...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:
  • GadgetmanGadgetman Posts: 2,436
    edited 2013-09-21 13:58
    On the P series,you have the option of using entire slots as DATA storage, and read/write it as necessary.
    Check the manual:
    http://parallax.com/sites/default/files/downloads/27218-Web-BASICStampManual-v2.2.pdf
    for the commands STORE, READ and WRITE
  • davejamesdavejames Posts: 4,047
    edited 2013-09-21 16:40
    Gadgetman wrote: »
    On the P series,you have the option of using entire slots as DATA storage, and read/write it as necessary.

    I was under the impression that the DATA directive only worked on slot 0.
  • Mike GreenMike Green Posts: 23,101
    edited 2013-09-21 17:13
    "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).
  • davejamesdavejames Posts: 4,047
    edited 2013-09-21 20:00
    ...ok - I don't know where that's documented. Can you point me?
  • Mike GreenMike Green Posts: 23,101
    edited 2013-09-21 20:07
    Stamp Basic Syntax and Reference Manual ... chapters on the STORE statement and the READ and WRITE statements. The DATA statement just compiles the data into the current slot along with any program. Remember that each slot requires a separate source file and these are listed in the $STAMP directive so the compiler knows what goes where.
  • davejamesdavejames Posts: 4,047
    edited 2013-09-21 21:47
    Thanks Mr. Green - found it.

    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.
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2013-09-22 12:15
    Furthermore, with the BS2pe, you have STORE 8 thru STORE 16, an additional 16kbytes of eeprom for data logging or storage of information, prompts, messages etc. Those higher 8 slots are not for programs, only for data that is put there at run time. For example, suppose you have a BS2pe and a data pointer that runs from 0 to 32767, and you want to store a byte at the pointer location in the continuous 32kbyte address space.
    [SIZE=1][FONT=courier new]slot = pointer/2048   ' which slot?
       STORE slot         ' select it
       WRITE pointer//2048, myByte   ' write to address within slot[/FONT][/SIZE]
    

    The BS2pe is the only one that has 16k for program/data plus an extra 16k for data only.
  • davejamesdavejames Posts: 4,047
    edited 2013-09-22 20:03
    Furthermore, with the BS2pe, you have STORE 8 thru STORE 16...

    ...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?
  • -GRIMM--GRIMM- Posts: 56
    edited 2013-09-23 10:22
    you can regain space by moving the text to DATa statements and writing a subroutine to pick it out
    Can you provide me with a code example (or a place to read it from)

    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
  • Mike GreenMike Green Posts: 23,101
    edited 2013-09-23 10:37
    msg1 data "This is a message",13,0 ' End messages with a zero byte

    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.
  • -GRIMM--GRIMM- Posts: 56
    edited 2013-09-23 11:54
    Thanks.

    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!
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2013-09-23 14:22
    Steven,

    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:
    pntr = msg1   ' set pointer to address of message
    lcdPin = 1  ' a one bit variable to select either p6 or p7
    GOSUB display   ' go display it
    
    and in the Display routine, here is an alternative way to write it, using DO:LOOP syntax, and including the one-bit port selector:
    display:
    DO
       READ pntr,chr  ' get the character at specified address
       pntr = pntr + 1   ' on to next character
       IF chr THEN SEROUT 6+lcdPin, lcdBaud, [ chr] ELSE RETURN
    LOOP
    

    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?
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2013-09-23 14:29
    Dave, I recall that the execution time of the BS2p series STORE command itself is very fast. Less than 100µs on the '2pe. On the other hand, READ and especially WRITE are rather slow. On the original BS2, the READ command takes 550µs, while WRITE takes typically 6000µs, eeprom dependent.
  • davejamesdavejames Posts: 4,047
    edited 2013-09-23 14:55
    Dave, I recall that the execution time of the BS2p series STORE command itself is very fast. Less than 100µs on the '2pe. On the other hand, READ and especially WRITE are rather slow. On the original BS2, the READ command takes 550µs, while WRITE takes typically 6000µs, eeprom dependent.

    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.
  • -GRIMM--GRIMM- Posts: 56
    edited 2013-09-24 08:24
    Steven,

    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:
    pntr = msg1   ' set pointer to address of message
    lcdPin = 1  ' a one bit variable to select either p6 or p7
    GOSUB display   ' go display it
    
    and in the Display routine, here is an alternative way to write it, using DO:LOOP syntax, and including the one-bit port selector:
    display:
    DO
       READ pntr,chr  ' get the character at specified address
       pntr = pntr + 1   ' on to next character
       IF chr THEN SEROUT 6+lcdPin, lcdBaud, [ chr] ELSE RETURN
    LOOP
    

    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?
    Tracy-

    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.
  • Mike GreenMike Green Posts: 23,101
    edited 2013-09-24 08:36
    Make sure you're sending the control codes properly. Display on would be:

    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
  • -GRIMM--GRIMM- Posts: 56
    edited 2013-09-24 10:39
    Mike-

    I'll give that a shot. I believe I may have been sending SEROUT 6, 80, 0$51

    Thanks
  • -GRIMM--GRIMM- Posts: 56
    edited 2013-09-24 12:11
    Well, after reprogramming everything with all the displays as DATA, I have only gained a small amount of extra space to work with.

    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
    .
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2013-09-24 13:55
    -GRIMM- wrote: »
    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.

    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.
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2013-09-24 14:37
    >>Is it possible to combine these and only call Display once?

    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:
    [SIZE=1][FONT=courier new]DO
          READ pntr, chr
          pntr = pntr + 1
          IF chr THEN 
               IF chr <$80 OR chr=$FE THEN SEROUT 6+lcdPin, 84, [ chr ] 
               IF chr = $80 THEN SEROUT 6,84,[REP "."\40]   ' print a string of 40 periods.
               IF chr =>$90 AND chr =<$99 THEN SEROUT LCDScreen+6, 84, [DEC5 Heater(chr-$90)]
          ELSE 
               RETURN
    LOOP[/FONT][/SIZE]
    
  • -GRIMM--GRIMM- Posts: 56
    edited 2013-09-26 07:41
    Thanks for the tip Tracey, that may allow me to reduce some calls.

    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.)
  • Mike GreenMike Green Posts: 23,101
    edited 2013-09-26 08:21
    REP only works for repeating a single character.
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2013-09-26 15:21
    Alternating characters require a loop,
    [FONT=courier new]FOR idx=1 TO 19 : SEROUT 6+LCDpin,84,["."] : NEXT[/FONT]
    


    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!
  • davejamesdavejames Posts: 4,047
    edited 2013-09-26 15:45
    Alternating characters require a loop,
    [FONT=courier new]FOR idx=1 TO 19 : SEROUT 6+LCDpin,84,["."] : NEXT[/FONT]
    


    Mr. Allen,

    Is there any difference between:
    [FONT=courier new]FOR idx=1 TO 19 : SEROUT 6+LCDpin, 84, ["."] : NEXT[/FONT]
    

    and:
    [FONT=courier new]FOR idx=1 to 19
       SEROUT 6+LCDpin, 84, ["."]
    NEXT[/FONT]
    

    in terms of execution speed or memory used?

    I've seen your style in other expert's examples and wondered why it's done.
  • Mike GreenMike Green Posts: 23,101
    edited 2013-09-26 19:05
    No, there's no difference. The compiler treats them identically except that one fits on a single line of text and the other takes 3 lines of text (for identification for compiler error messages).
  • davejamesdavejames Posts: 4,047
    edited 2013-09-26 21:34
    ...ok, thanks.
  • -GRIMM--GRIMM- Posts: 56
    edited 2013-09-27 09:25
    I gave in and bought a BS2sx. I was having to reduce too many functionality items to fit them onto eeprom (such as lower calibration accuracy, condensed diplay). Watch for my questions on using the BS2sx the day after I receive it! Thanks
Sign In or Register to comment.