Shop OBEX P1 Docs P2 Docs Learn Events
PropBasic: Launch program in ram — Parallax Forums

PropBasic: Launch program in ram

VonSzarvasVonSzarvas Posts: 3,522
edited 2011-04-22 13:18 in Propeller 1
Hello!

Have been experimenting with a self-executing program, but am failing to understand the launch code (chip's code).

There is a valid eeprom image stored in the upper part of a 64kB eeprom at pins 28/29 ($8000 - $FFFF)
I tested the image by launching it with a spin loader from the obex.

The plan is to launch this eeprom image using PropBasic, or inline pasm.

I added the following code at the end of the PropBasic file:
tmpAddr     long
smode           CON     0
time_xtal       CON     100000          ' 20 * 20000 / 4 / 1	'20ms (@20MHz, 1 inst/loop)
interpreter     CON     $43C010         ' $0001 << 18 + $3C01 << 4 + %0000

ASM

                        '
' Launch program in ram
'

launch                  mov     tmpAddr,#0              'set tmpAddr to zero
                        rdword	tmpAddr,#$0004+2	'if pbase address invalid, shutdown
			cmp	tmpAddr,#$0010	wz
	if_nz		jmp	#shutdown

			rdbyte	tmpAddr,#$0004		'if xtal/pll enabled, start up now
			and	tmpAddr,#$F8		'..while remaining in rcfast mode
			clkset	tmpAddr

:delay			djnz	time_xtal,#:delay	'allow 20ms @20MHz for xtal/pll to settle

			rdbyte	tmpAddr,#$0004		'switch to selected clock
			clkset	tmpAddr

			coginit	interpreter		'reboot cog with interpreter
'
'
' Shutdown
'
shutdown		nop ' mov	ee_jmp,#0		'deselect eeprom (replace jmp with nop)
:call			nop ' call	#ee_stop		'(always returns)

	'		cmp	smode,#0	wz	'if serial mode, send error (z=0)
	'if_nz		mov	smode,#0		'(only do once)
	'if_nz		mov	:call,#0		'(replace call with nop)
	'if_nz		call	#tx_bit_align		'(may return to shutdown, no problem)

			mov	dira,#0			'cancel any outputs

			mov	smode,#$02		'stop clock
			clkset	smode			'(suspend until reset)



ENDASM


My code file copies the image from eeprom to ram, then does a "GOTO launch" to run the above code. I tested the image in ram after copying it... It can read it back and write it to PST, and all the bytes seem to match the original code.eeprom file.

-- I suspect the problem is with the copy/pasted launch code. Regrettably I do not really understand it all!!. So my question would be...:

Q: Should this snippet of inline ASM code actually work, or is something seriously wrong with this approach ?


Ultimately I would like to be able to call a simple PropBasic command to restart the propeller running whatever code is in ram. Ie. (A kind of soft reboot!)

(A few months ago Bean told that this might be tough to implement... Some months on I am not ready to admit defeat, but I am feeling he was right!)

:)

Comments

  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-04-19 11:51
    Hi, I played around with the same booter code and came up with some interesting results along the lines of what you seem to be doing. The thread is at this link http://forums.parallax.com/showthread.php?130615-Slot-Programming-the-Propeller

    Jeff T.
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-21 01:23
    Thank you for posting. I had an idea that the bootloader should run in its own task (propbasic wise), so I moved your code into the attached.

    I am a little concerned about:
    mov                     address,taskparam     'retrieve array
    
    Not certain that it actually moves the propbasic defined long array into the asm address- and in the correct format, and not sure yet how to test that in pasm.

    At the moment I call the task like this from the main program (cog0):
    COGINIT BootloaderTask, 0
    

    Cog0 does seem to immediately stop as my status leds driven from the main cog program go off. But then it hangs.

    Maybe I should not be launching a cog into cog0 from cog0? I tried an intermediate cog1 which simply stopped the first cog0 and launched the new cog0, but that did not seem to help.

    If I run the obex bootloader (spin code), it correctly runs the image I have stored in the upper eeprom- so I believe that part is ok.

    ... another day of probing begins !
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-04-21 14:59
    Hi, I don't know how this is managed in Prop Basic so I can't help much. I did observe an error in the three longs passed to the asm.

    taskparam(1) should =0 which is the default EEPROM that comes with the Prop boards
    taskparam(2) should =$8000 which is the location in memory that you want your read to begin

    Jeff T.
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-22 01:38
    Not sure if it makes a difference to the chipaddress = 0 param, but just in case!

    I am using a PPDB and have changed the supplied eeprom to a 64kB version, 24FC512

    So I have the params set as you noted above (pin, chipaddress, eeprommem) = (28, 0, $8000).

    Thanks for your help- I am struggling to debug this! I am currently trying to craft some simple ASM to write bytes to the attached (via usb) onboard PST. I hope that would at least help me discover when the program dies by sending a byte at various points in the code and "seeing" where the code gets to.
  • kuronekokuroneko Posts: 3,623
    edited 2011-04-22 01:54
    Could you compile your PropBASIC program to SPIN/PASM (menu option) and attach the result (or attach the complete BASIC source)? At least then we can see what's going on. It's probably down to some simple parameter mixup.
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-22 02:39
    Thank you... here is the PropBASIC source and also the 2 compiled spin files (Test and Task) which are generated by the bst/propbasic compiler.
  • kuronekokuroneko Posts: 3,623
    edited 2011-04-22 03:54
    I had a quick look. It seems that you're still undecided about chip address and memory start. The former is a logical thing 0..7 while the latter is an offset within the 64K address range. ATM you have the chip address set as $8000 which translates to 0 and the memory start is 0. Which means you read from EEPROM 0 (boot EEPROM) starting at location 0. IIRC you want the upper 32K so that would require chip address being 0 and memory start set to $8000, i.e. the reverse of what you have now.

    This is what Jeff ("Hi!") referred to a few posts up:
    taskparam(1) should =0 which is the default EEPROM that comes with the Prop boards
    taskparam(2) should =$8000 which is the location in memory that you want your read to begin
    taskparam(1) is equivalent to chip address, taskparam(2) is memory start
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-22 04:02
    kuroneko wrote: »
    I had a quick look. It seems that you're still undecided about chip address and memory start........

    Sorry, I had reversed them a couple times whilst testing. I have set them back to the following, but still no joy.
    mem_start               long    $8000
    pin_num                 long    1 << 28
    chip_address            long    0
    


    (I have updated the files attached to post 7.)
  • kuronekokuroneko Posts: 3,623
    edited 2011-04-22 04:17
    OK, I check later (dinner time). Thanks.
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-22 04:41
    OK, good appetite!

    --

    I did notice something which may or maynot be an issue... to do with the timings.
    DEVICE          P8X32A, XTAL1, PLL16X
    XIN             5_000_000
    

    and
    time_xtal               long    20 * 20000 / 4 / 1      '20ms (@20MHz, 1 inst/loop)
    

    I was running the code at 80MHz, not 20 MHz as is assumed by the time_xtal formula
    I tried changing to PLL4X, and also adjusting the time_xtal delay to make it 20ms at 80MHz, but it did not seem to make a difference.

    Not sure if the bootloader operation is timing critical...???
  • kuronekokuroneko Posts: 3,623
    edited 2011-04-22 04:51
    shl     mask_scl,[COLOR="red"]pin_num[/COLOR]            
                            shl     mask_sda,[COLOR="red"]pin_num[/COLOR]            
                            
                            ...                                    
                                                                
    mem_start               long    $8000                       
    [COLOR="red"]pin_num                 long    1 << 28[/COLOR]
    
    Does that seem odd? You really need the pin number here (#28) not a mask.
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-22 04:59
    that was something I took from the way the PropBasic compiler dealt with PIN definitions. I also tried it without the mask/shift but no joy
    pin_num                 long    28
    

    I just checked again the original code from unsoundcode (post #2.)

    the only difference seems to be that he calls the coginit (starts the task) like this
    repeat 2
         waitcnt(clkfreq/100 + cnt)
         
      clkset(0,12000000)
      coginit(0,@Entry,array_ptr)
    

    Could the clkset be vital here? I don't seem to be able to handle that with PropBasic, but maybe there is a PASM alternative?
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-22 05:18
    Actually I just found some code you suggested in a previous post, and added it at the start of the task:
    http://forums.parallax.com/showthread.php?122326-CLKSET-in-ASM&p=905516&viewfull=1#post905516
    clkset  :mode
            wrlong  :freq, #0
            wrbyte  :mode, #4
    
    :mode   long    %0000_0000
    :freq   long    12_000_000
    


    It does not solve the matter, but surely it proves the frequency is now set the same as the original program.

    Also I changed 2 lines thus, to "ensure / hope" the pin_num setting is correct
    shl     mask_scl, #28 'pin_num
    shl     mask_sda, #28 'pin_num
    
  • kuronekokuroneko Posts: 3,623
    edited 2011-04-22 05:49
    Are you able to run your program with Jeff's code?
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-22 06:08
    Yes. Just tried it again to be sure.

    I have added some extra led flashes through the code. The codes executes until this block, but hangs at [ call #ee_read ] - so an led before this line flashes, but not after. It might be a PIN issue yet... Is it possible somewhere between PropBasic and PASM, the PIN is not being defined or init'd correctly? How would I do that in PASM?
    boot                    mov     smode,#0                'clear mode in case error
    
                            call    #ee_read                'send read command
    
    :loop                   call    #ee_receive             'get eeprom byte
                            wrbyte  eedata,address          'write to ram
                            add     address,#1
    
                            cmp count,first_byte  wz         'calculate the file length
                    if_z   mov low_byte,eedata               'from the word value in
                            cmp  count,second_byte  wz       'bytes at address $0008 and $0009
                    if_z   call #getcount
    
                            djnz    count,#:loop            'loop until done
                            call    #ee_stop                'end read (followed by launch)
    
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-22 06:19
    OK, this new "flashled" test really helps!

    I have found the problematic code here
    ee_start                mov     bits,#9                 '1      ready 9 start attempts
    :loop                   andn    outa,mask_scl           '1(!)   ready scl low
    
                            or      dira,mask_scl           '1!     scl low
                            nop                             '1
                            andn    dira,mask_sda           '1!     sda float
                            call    #delay3                 '5
                            or      outa,mask_scl           '1!     scl high
                            nop                             '1
                            test    mask_sda,ina    wc      'h?h    sample sda
            if_nc           djnz    bits,#:loop             '1,2    if sda not high, loop until done
    
            if_nc           jmp     #shutdown               '1      if sda still not high, shutdown
    
                            or      dira,mask_sda           '1!     sda low
    

    It would seem the code loops until it gives-up and does the jmp #shutdown.
  • kuronekokuroneko Posts: 3,623
    edited 2011-04-22 06:23
    Provided that mask_scl and mask_sda are setup correctly there shouldn't be an issue. Not coming back could simply mean that the loader shuts down (no ACK). What happens if you run the program with RCFAST (as Jeff's loader does)?
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-22 06:57
    Indeed, it does appear the ACK fails to arrive. I get 10 flashes (10 loops), then shutdown.

    The RCFAST settings seem to make no difference either.

    I have attached revised version of the code to reflect all the adjustments.

    I have attempted to implement the same parameter loading as Jeff used, and set the clk to RCFAST, so in theory everything "should" be exactly the same (except for the compiler of course).

    time for a little gardening / head recharging!
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-04-22 07:12
    Hi, not sure if I can help here but to just clarify the mask and pin numbers. They were set up as variables initially but looking at your set up these are the constants needed in BootloaderTask.

    mask_sda long $2
    mask_scl long $1
    pin_num long $1C
    mem_start long $8000
    chip_address long 0
    cs_write long $A0
    cs_read long $A1

    you could also try deleting the following lines from the "boot" label they are probably not needed in you app

    cmp count,first_byte wz 'calculate the file length
    if_z mov low_byte,eedata 'from the word value in
    cmp count,second_byte wz 'bytes at address $0008 and $0009
    if_z call #getcount

    Jeff T.
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-22 10:07
    Thanks for both your ideas I could narrow down the "problem".

    When PropBasic creates the spin file, it starts with something like this:
    PUB Init(pv_DataStart)                                      
      Return ((pv_DataStart >> 2) << 18) + ((@__INIT >> 2) << 4)
    

    By manually inserting a clkset, the problem was solved.
    PUB Init(pv_DataStart)      
      clkset(0,12000000)                                
      Return ((pv_DataStart >> 2) << 18) + ((@__INIT >> 2) << 4)
    

    Maybe an advanced option of the PropBasic COGINIT command might allow a parameter for setting the clkspeed of the new cog.

    Or maybe I can work around this somehow... I already tried changing the clk when the new task starts without success., but maybe I just need to twiddle with some delays...

    Will report back!
  • VonSzarvasVonSzarvas Posts: 3,522
    edited 2011-04-22 11:26
    SUCCESS ! (Even better !)

    So here is a work around.... No need for the manual clkset edit of the spin file

    Just ensure this appears at the start of the task. I found that not only should we set the clock speed, but also zero the pin registers. I believe it might be an issue with the PropBasic compiler which could be easily solved, so I will post an explanation on the PropBasic thread.
    mov     dira,#0
            mov     outa,#0
    
            clkset  clkmode12
            wrlong  clkfreq12, #0
            wrbyte  clkmode12, #4
    

    Again, BIG BIG thanks for your persistence - it feels really good to crack this nut !

    Max.
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-04-22 13:18
    Well done Max and thanks for the explanation.

    Jeff T.
Sign In or Register to comment.