Using Scratch Pad to store character data X2

matchbox

Senior Member
Hi people.
I had an idea of using the 1024 bytes of scratch pad memory on an X2 chip, to store character data.
I understand this data is volatile. But I required a large volume of character messages (50+, up to 12 average per message) for my current project.
And the X2 Table feature is far too small for this.

My idea was to tell the X2 to load all the character messages into the scratch pad on power up. And do so via #slot 1. Then return to #slot 0 to run the program.
I know It would seem logical to just place all the messages into #slot 1's program memory. Considering is going to use the same amount of program memory to load them into the scratch pad. But this program using heaps of Gosub's, rather than doubling up on code.
I had thought of using #slot 1 for the messages and using Flags and Branches when returning to #slot 0. But It wasn't precise enough, if an interrupt occurred at that time.

This project uses a 5 way switch. Which will be used to toggle though many menu's, with many setting selections. Hence the reason there are so many messages.
From basic explanations and scrolling, through to simple selection choices.

Does this idea seem realistic? And If so.. What would be the simplest way to load all these bytes? To save on typing over 800 @ptr / Put commands:p.

Thanks guys
 
Last edited:

inglewoodpete

Senior Member
I know It would seem logical to just place all the messages into #slot 1's RAM. Considering is going to use the same amount of RAM to load them into the scratch pad. But this program using heaps of Gosub's, rather than doubling up on code.

Does this idea seem realistic? And If so.. What would be the simplest way to load all these bytes? To save on typing over 800 @ptr / Put commands:p.

Thanks guys
First, you use the term "#Slot 1's RAM" . It may just be a misuse of terminology. RAM is global: the same volatile memory is accessed from all slots. Only the programme, stored in flash memory, appears exclusively in separate slots.

It's not clear to me why you need to put all of your text messages into RAM. Surely, having them embedded in the code would be sufficient, since it appears that the text has to be loaded into the scratchpad at startup, presumably from hard code and not via the hSerial or hi2c ports. Scratchpad RAM is best used for backgound character reception.
 

matchbox

Senior Member
Hi Pete. Yep.. it was just a misuse of the terminology. Should have been program memory.
It's not clear to me why you need to put all of your text messages into RAM. Surely, having them embedded in the code would be sufficient, since it appears that the text has to be loaded into the scratchpad at startup, presumably from hard code and not via the hSerial or hi2c ports. Scratchpad RAM is best used for backgound character reception.

The reason I can't embed it into the code. Is due to slot 0's, code being rather large and complex with many dozens of features. Its looking like being around 4kb when finished. That will be minus the messages. And with dozens of Library style (CALL) subroutines to save code also.
Its a shame the X2 didn't have 8Kb in 2 slots or 16Kb in 1 slot.. I can't really see the point of slots, without gosub between them.
 
Last edited:

lbenson

Senior Member
If you don't otherwise need an X2, an M2 (14,18, 20) has 512 bytes of table memory, able to hold your 50*8 characters. In addition, you could use the second slot for additional messages, and also the eeprom.

(Typing as you posted--4k of code would preclude using slot 2 for messages.)
 

matchbox

Senior Member
If you don't otherwise need an X2, an M2 (14,18,20) has 512 bytes of table memory, able to hold your 50*8 characters. In addition, you could use the second slot for additional messages, and also the eeprom.

(Typing as you posted--4k of code would preclude using slot 2 for messages.)
That would be ideal. I did think of how useful an M2 would be with its 1024b of Table memory. But I do require a 28pin for all the IOs on this project.
 
Last edited:

lbenson

Senior Member
But I do require a 28pin for all the IOs on this project.
If digital I/Os, 20M2+MCP23017?

But on the other hand, there's nothing wrong with your original idea if you don't need the scratchpad for background serial receive.

It takes some organization, but you can get a gosub-like function for your extra slots with the use of an idicator byte or two. The biggest problem is figuring out where to return to when you get back to slot 0.

You also might want to consider one-wire eeprom memory.
 

inglewoodpete

Senior Member
Hi Pete. Yep.. it was just a misuse of the terminology. Should have been program memory.

The reason I can't embed it into the code. Is due to slot 0's, code being rather large and complex with many dozens of features. Its looking like being around 4kb when finished. That will be minus the messages. And with dozens of Library style subroutines to save code also.
Its a shame the X2 didn't have 8Kb in 2 slots or 16Kb in 1 slot.. I can't really see the point of slots, without gosub between them.
It's still not clear to me what the problem is. Why do your (apparently fixed) messages have to be stored in Scratchpad or RAM?

Can you dedicate one slot to store and display the required strings? The X2s, unlike the M2s, can only have one program, spread over the four slots.

4k will hold a lot of text, each block with its dedicated print/transmit command or routine. If you really are out of space, look at adding an external i2c EEPROM chip like the 25LC512 (64kbytes) or a smaller one.
 

AllyCat

Senior Member
Hi,
Does this idea seem realistic? And If so.. What would be the simplest way to load all these bytes? To save on typing over 800 @ptr / Put commands:p
Yes, if you happen to need up to about 1000 "EPROM/TABLE" ASCII bytes and don't need the Scratchpad for any other purpose, then your idea seems perfectly sensible. For any more bytes, then an external I2C EEPROM needing only two pins (possibly already allocated/available for the Bus) can give as much EEPROM as you could possibly need, and interestingly is the fastest way to access text strings.

But as you mentioned, PICaxe Basic doesn't generally support "Text Strings", so you need a strategy for loading the Scratchpad. AFAIK, the most efficient method is to use the LOOKUP command; The way I would do it is to use a standard string length of (say) 16 or 32 bytes, but the main (Slot 0) program could calculate the starting address of each message (or use another lookup table of "pointers"). The address of every 4th byte can be coded within a single byte, and/or perhaps each string terminated by a specific character or range (e.g. zero), or, normal ASCII Text characters don't use their MSB for any (other) purpose. Untested, but I'd cut and paste code something like:
Code:
#PICAXE 28x2
#SLOT 1
PTR = 0
SYMBOL EQ = "=" + 128        ; Optional Printing Terminator
  FOR b1 = 0 TO 15 : LOOKUP b1, ("Hello World  123") ,b2 : @PTRINC = b2 : NEXT b1    ; Exact 16 character blocks
  FOR b1 = 0 TO 15 : LOOKUP b1, ("Hello World  456") ,b2 : @PTRINC = b2 : NEXT b1
  FOR b1 = 0 TO 15 : LOOKUP b1, ("Hello World  789") ,b2 : @PTRINC = b2 : NEXT b1
  FOR b1 = 0 TO 15 : LOOKUP b1, ("Message1","Message2") ,b2 : @PTRINC = b2 : NEXT b1
  FOR b1 = 0 TO 15 : LOOKUP b1, ("Item 12", EQ ,"Item 34", EQ) ,b2 : @PTRINC = b2 : NEXT b1
;  Etc for up to 64 rows
RUN 0
Cheers, Alan.
 

matchbox

Senior Member
It's still not clear to me what the problem is. Why do your (apparently fixed) messages have to be stored in Scratchpad?
Because my program has many Call subroutines within slot 0. And the Gosub stack is cleared when changing slots.
Using Flag diverters to return to a specific part slot 0, after accessing the slot 1 text string, is cumbersome in complexity and program memory.
While the 1Kb scratch pad of an X2, is common memory to all 4 slots.
Hi,

Yes, if you happen to need up to about 1000 "EPROM/TABLE" ASCII bytes and don't need the Scratchpad for any other purpose, then your idea seems perfectly sensible.
Thanks Alan(y) That was exactly the sort of thing I was looking for.
 
Last edited:

inglewoodpete

Senior Member
Because my program has many Call subroutines within slot 0. And the Gosub stack is cleared when changing slots.
Using Flag diverters to return to a specific part slot 0, after accessing the slot 1 text string, is cumbersome in complexity and program memory.
While the 1Kb scratch pad of an X2, is common memory to all 4 slots.
I would be structuring my main loop in Slot 0 to have just 1 point in which it passes control to "Slot x", which contains all of the messages and performs the text output. This would then give just one point in Slot 0 to return to from Slot x.

Each time a message is required, a (byte?) variable is assigned a value (Eg a "message pointer" of 1 to 255). When execution in the main loop reaches the message output point (I suggest making it the first or last instruction in the loop), control is transferred to Slot x. A zero in this variable would mean that text output is not required on that loop.

If a value (Eg held in another register) is required to be displayed, the assigned routine is Slot x would be structures to embed the value in its output.

This approach would move all text formatting and output to "Slot x", greatly simplifying your main loop and Slot 0.
 

matchbox

Senior Member
Pete, Your approach is something for me to look more into.
Although I found that I had issues with the special word variables being cleared (as expected) and I also had to restart the Settimer command. Which played havoc with my timer based interrupts.
 

inglewoodpete

Senior Member
Pete, Your approach is something for me to look more into.
Although I found that I had issues with the special word variables being cleared (as expected) and I also had to restart the Settimer command. Which played havoc with my timer based interrupts.
I have written two applications that use multiple slots in 40X2 chips. I just checked their code: both have the timer set to interrupt every 100mS. The interrupt routines just set or clear flags and also increment (my user-) timer variables - 10 interrupts result in a timer period of 1 second. Entry/reentry to each slot requires the timer to be reset and introduces an average error of 50mS (worst case 99mS). This has no negative impact on my particular applications. The introduced error could be reduced by changing the system timer period to 50mS or less.

I use an identical interrupt routine in each slot.
 

matchbox

Senior Member
Hi Guys, me again.
I just got back to doing some more testing. And I have hit a snag that I can't work out.
This bit of code sends the message to the scratch pad, then reads it back out to the display... It then clears a specific segment of the displayed message and leaves the rest.

Code:
#Picaxe 28X2
     #Slot 0                                           ; download into #slot 0
      Setfreq m16                                      ; 8Mhz crystal 4x PLL (PAUSE values are 4x > @8Mhz)
           
     'OLED display
    Symbol OLED_busy = A.1                           ; OLED display in operation (0 = busy 1 = ready)
    Symbol OLED_TX = A.2                             ; OLED display data transmit
    Symbol OLED_baud = N2400_16  
    Symbol index_S  = s_w0                           ; scratch pad character index start byte               
    Symbol index    = s_w1                       
    Symbol Txb      = b0                             ; transmit data byte                         
  
     'Display control
    Symbol line_pos   = b29                          ; print start position on OLED lines
    Symbol flash      = b30                          ; flash OLED setting characters
    Symbol clr_start  = b31                          ; clear character start index
    Symbol clr_finish = b32                          ; clear character finish index 
    Symbol pos_offset = b33
  
  
         Ptr = 0
     For index = 0 to 15 : Lookup index, ("  Test message  "),b52 : @Ptrinc = b52 : Next index

Display_send:   
        
         index_S = 0
         line_pos = 128
        
      Serout OLED_TX, OLED_baud,(254,line_pos)                                      ; display message, line and position
                                                                                      
     If line_pos < 145 then                                                             ; Line start position index calculation
         pos_offset = 144 - line_pos                                                ; convert line position and 1st character location, to start point index line 1
     Else  pos_offset = 208 - line_pos                                                ; start point index line 2
     Endif

           pos_offset = 16 - pos_offset
    
         Ptr = index_S                                                              ; define scratch pad message, index start position
         bPtr = 72       
                      ' 0 to 15
      For index = pos_offset to 15
        @bPtrinc = @Ptr                                                             ; copy characters into bPtr 'display clear variables'
      lookup index,(@Ptrinc,@Ptrinc,@Ptrinc,@Ptrinc,@Ptrinc,@Ptrinc,@Ptrinc,_
                    @Ptrinc,@Ptrinc,@Ptrinc,@Ptrinc,@Ptrinc,@Ptrinc,@Ptrinc,@Ptrinc,@Ptrinc), Txb
              
        Serout OLED_TX, OLED_baud,(Txb)                                               ; transmit message to display
        Sertxd (Txb)
      Next
  

Display_clear_area:
           pause 2000
    
      Serout OLED_TX, OLED_baud,(254,line_pos)                                      ; display message, line and position
         clr_start = 79
         clr_finish = 85 + 1                                                       
           line_pos = 128
    
        'Display character range - bptr 72 to 87
         bptr = clr_start                                                           ; segment of display to be cleared..index start
      Do
           @bptrinc = $20                                                             ; clear display byte pointers
      Loop Until bptr = clr_finish                                                    ; segment of display to be cleared..index finish             
  
            bptr = 72
                     '72 to 87
                     ' 0 to 15
      For index = 0 to 15
      lookup index,(@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,_
                    @bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc), Txb         
      Serout OLED_TX, OLED_baud,(Txb)                                               ; transmit message to display
    Next 

            bptr = clr_start                                                          ; segment of display to be cleared..index start
      Do
           @bptrinc = 0                                                               ; clear display byte pointers
      Loop Until bptr = clr_finish                                                    ; segment of display to be cleared..index finish             
          
         pause 1000
           Goto Display_send

Its work perfectly in the PE6 simulator. i.e. transfers ASCII bytes to the scratch pad and reads them back out to the virtual display.
But it won't work on the 28X2. It only reads back ASCII 0 on the display. Like it won't load the scratch pad.
I tried to debug it... But the simulator doesn't display scratch pad bytes.

I also tried to drive it directly to the display, using the 18M2. With bPtr's instead of Ptr's. It too acted in the same way.
Does anyone have any idea of what the issue may be?

Thanks
 
Last edited:

inglewoodpete

Senior Member
I rarely use the simulator so I'm no expert on it. I'm not sure why you can't see the contents of the simulator's scratchpad. It works for me (Editor/Simulator v6.1.0.0).
 

matchbox

Senior Member
Sorry, I didn't explain that clear enough... I can see the contents of the scratch pad in the simulator. But can't see the scratch pad contents in the memory tool bar, when debugging.
 

inglewoodpete

Senior Member
Sorry, I didn't explain that clear enough... I can see the contents of the scratch pad in the simulator. But can't see the scratch pad contents in the memory tool bar, when debugging.
Hmm, Still a bit cryptic I'm afraid. "When debugging" means debugging in the real chip or the simulator?

I see the following when running your code in the simulator: it updates in "real" (simulator) time.
 

Attachments

AllyCat

Senior Member
Hi,
Code:
      For index = 0 to 15
      lookup index,(@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,_
                    @bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc,@bPtrinc), Txb      
      Serout OLED_TX, OLED_baud,(Txb)                                               ; transmit message to display
    Next
Hmm, Your code is too compex to analyse quickly (which is all the time that I have at the moment) and I'm not sure why you (need to) use both PTR and BPTR, but I suspect that the problem is associated with all those @{b}ptrINCs. What happens to BPTR when that LOOKUP is executed 16 times without BPTR being reloaded with a starting value ?

Cheers, Alan.
 

inglewoodpete

Senior Member
Hi,

Hmm, Your code is too compex to analyse quickly (which is all the time that I have at the moment) and I'm not sure why you (need to) use both PTR and BPTR, but I suspect that the problem is associated with all those @{b}ptrINCs. What happens to BPTR when that LOOKUP is executed 16 times without BPTR being reloaded with a starting value ?

Cheers, Alan.
I have to agree. There are a hundred ways to reference and transfer data but all those @{b}ptrincs are not very efficient.
I suggest the following code and something similar higher up the routine.
Rich (BB code):
   For bPtr = 72 to 87
      Serout OLED_TX, OLED_baud,(@bPtr)                          ; transmit message to display
   Next bptr
 

matchbox

Senior Member
"When debugging" means debugging in the real chip or the simulator?
That's correct. Debugging meaning real time with the chip.
I see the same as you posted, when using the simulator. But when real time debugging. Scratch pad, under the memory tab never gets populated.
I agree this is not totally efficient. Please read my reply to Alan below, of why I am doing it this way.

Taking into account, all requirements that I have stated above.. I'm open to other ways of doing this.
But my understanding of picaxe, is far more limited than your knowledge.

I'm not sure why you (need to) use both PTR and BPTR, but I suspect that the problem is associated with all those @{b}ptrINCs. What happens to BPTR when that LOOKUP is executed 16 times without BPTR being reloaded with a starting value ?
The stored PTR data is taken from the scratch pad and sent to the display. While it is also sent to the character bPtr's so it can be manipulated for sectional erasing of specific characters on either line. Without using the display commands that can only erase both lines all at once.
It is more desirable to only clear one line. Or clear a few character on that line to make certain characters flash.

If I don't enter the bPtr start value, it starts moving down through the RAM on every cycle.
 

AllyCat

Senior Member
Hi,

To clarify: "Under the Hood", the LOOKUP instruction expands to a list of (16) IF ..THEN instructions with just one "true" condition (in this case the index value). It's needed to read "Text Strings" because the compiler/interpreter must work through the list of bytes from the first quote (") symbol of the string. But once the data (bytes) are in (scratchpad) memory, then a simple pointer is sufficient, i.e. the code that I quoted above can be simply pointer = BPTR + index : PEEK pointer , Txb (or GET for the scratchpad), or simply update the BPTR value and use @BPTR{inc}.

Cheers, Alan.
 
Top