Shop OBEX P1 Docs P2 Docs Learn Events
Booting from secondary EEPROM (non SD bootloader) — Parallax Forums

Booting from secondary EEPROM (non SD bootloader)

WBA ConsultingWBA Consulting Posts: 2,935
edited 2011-12-23 06:40 in Propeller 1
This is for the Thermistor Cable Tester I am currently making. A "key" that contains an EEPROM will be used to select the configuration program to run. I would like the main program to initialize the LCD and prompt for a key to be inserted if one is not there. If I just use the "key" EEPROM as the main EEPROM, then nothing will prompt the operator top insert a key if one is not inserted.

I have been scouring the forums looking for bootloader code examples that load a program from a secondary EEPROM, but can only find ones that grab programs from SD Cards. I'll have a secondary EEPROM addressed differently than the onboard EEPROM to use. I found a few threads discussing using "sdspiFemto.spin" from Mike Green's FemtoBasic, but I can't find any examples to help me understand the command usage for EEPROMs because they all discuss using SD Cards. The docs for sdspiFemto are a bit above my head for explaining some commands (I think I should somehow make use of the "spin" command, but can't understand the explanation.

Anyone know of any examples that boot from a main EEPROM, check for a secondary EEPROM, then load a program from the secondary EEPROM?

Comments

  • Nick McClickNick McClick Posts: 1,003
    edited 2011-02-18 01:13
    How about the bootloader code for the Propeller Platform SD? That loads from the upper half of eeprom - you can grab the bootloader here. Not exactly what you're looking for, but it looks pretty easy to convert.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-02-18 12:22
    mctrivia also did one for loading and updating the second half of an eeprom. Remember that if you use a 32KB eeprom then a second 32KB eeprom can be external with the sequential address selected by the pins.
  • WBA ConsultingWBA Consulting Posts: 2,935
    edited 2011-02-27 02:34
    Nick and Cluso, thanks for the responses. I have been digging and trying to wrap my head around the steps for reading EEPROMs and I think I may be starting to shed some light on where I need to go. I am really struggling deciphering this complex code, but some things are making sense.
    From "loader.spin", "srwFemto.spin", and "sdspiFemto.spin" (from Nick's link), I have narrowed down my focus to the following sections:

    In loader.spin, the lines 120-147 that drives reading from the SD card and writing that data to EEPROM
    PRI loadEEPROM (fname, eeAdr) | a, c, d
    
      eeAdr += sdspi#bootAddr     ' always use boot EEPROM
    
      if \SD.popen(fname,"r")
         abort string("Can't open file")
      if SD.pread(@buffer,PAGESIZE) <> PAGESIZE
         abort string("Can't read program")
      if SD.writeEEPROM(eeAdr,@buffer,PAGESIZE)
         abort string("Copy EEPROM write error")
      if SD.writeWait(eeAdr)
         abort string("Copy EEPROM wait error")
    
      a := word[@buffer+SD#vbase]   'use actual size of program
    
      repeat c from PAGESIZE to a - 1 step PAGESIZE
        d := (a - c) <# PAGESIZE
        if SD.pread(@buffer,d) <> d
          abort string("Can't read program")
        if SD.writeEEPROM(eeAdr+c,@buffer,d)
          abort string("Copy EEPROM write error")
        if SD.writeWait(eeAdr+c)
          abort string("Copy EEPROM wait error")
    
      if \SD.pclose < 0
         abort string("Error closing file")
      if \sd.popen(@NoDelete, "r") <> 0
        \sd.popen(fname, "d")
    
    At first, I was getting confused at the calls to the SD object for writing to the EEPROM, but after looking at the object in detail, I see that it is just passing those calls right to sdspiFemto, lines 160-174.
    PUB readEEPROM(addr,buffer,count) | t                  '' Read a block from EEPROM to RAM
      t := ioReadCmd
      repeat while long[control][0] & ioTestRdy            ' Wait for previous I/O to finish
      long[control][1] := (count << 16) | (buffer & $FFFF)
      long[control][0] := (t << 24) | (addr & $FFFFFF)
      repeat while long[control][0] & ioTestRdy            ' Wait for this to finish
      return (long[control][0] & ioTestErr) <> 0           ' Return any error code
    
    PUB writeEEPROM(addr,buffer,count) | t                 '' Write a block to EEPROM from RAM
      t := ioWriteCmd
      repeat while long[control][0] & ioTestRdy            ' Wait for previous I/O to finish
      long[control][1] := (count << 16) | (buffer & $FFFF)
      long[control][0] := (t << 24) | (addr & $FFFFFF)
      repeat while long[control][0] & ioTestRdy            ' Wait for this to finish
      return (long[control][0] & ioTestErr) <> 0           ' Return any error code
    
    So, my thoughts are that I need to look at how to utilize the readEEPROM PUB from sdspiFemto to load the secondary EEPROM contents into hub ram and run it as the main program. Messing with hub ram is way over my head, so I am walking blindly now.

    Any thoughts on whether or not I am on the right track?
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-02-27 05:52
    Hi Andrew , the following link at post #18 has a zip file that contains a spin file that takes serial input and writes to the boot EEPROM. This could be modified to use two pins to read an external EEPROM as an alternative to the serial input.

    The spin file in the zip uses Mike Greens I2C object and uses both the EEPROM read and EEPROM write routines.

    If I remember correctly it writes the whole 32K but this would probably not be neccessary , bytes 8 and 9 of the binary determine the program size.

    http://forums.parallax.com/showthread.php?122891-Help-with-a-EEPROM-boot-loader

    Jeff T.
  • RobotWorkshopRobotWorkshop Posts: 2,307
    edited 2011-02-27 06:02
    If you can connect part of the key to a switch you could do it in hardware with the adapter below:

    http://forums.parallax.com/showthread.php?126798-NEW-EEPROM-expansion-%28bank-switch-adapter%29

    Robert
  • Mike GreenMike Green Posts: 23,101
    edited 2011-02-27 07:31
    In sdspiFemto.spin there is a method called bootEEPROM which will run a Spin program from any EEPROM address from any EEPROM attached to any pair of I/O pins. It takes one parameter, a 23 bit "address". As described in the comments at the beginning of the file, Bits 15-0 are the address within the EEPROM (0-65535). Bits 18-16 are the select code of the EEPROM (0-7). Bits 22-19 are the I/O pin pair number (0-15 corresponds to I/O pins 0/1, 2/3, ... , 30/31). To boot from the 2nd 32K of the EEPROM on I/O pins 28/29, you'd call "sdspi.bootEEPROM(sdspi#bootAddr + $8000)".

    All cogs are eventually stopped except the one with the PASM routines for the loader (started by bootEEPROM) and that is the one used to do the COGINIT for the loaded program. This is done because the new program might overwrite the entire hub RAM.

    bootEEPROM assumes that you want to load a full 32K like the Prop ROM's bootloader. It's possible to change the routine to read less than that.
  • WBA ConsultingWBA Consulting Posts: 2,935
    edited 2011-02-27 21:33
    Thanks for the additional info guys. Mike Green intercepted my train of thought and gave it another push so I think I have a handle on it now. I can't set it up to try it right now, but here is what I came up with.

    Using the bootEEPROM PUB in sdspiFemto.spin, I can pass it an address of $71000 (for the 23 bit address will be 11100010000000000000000) and it will boot from a secondary EEPROM with the A0 pin pulled high that it is on the same i2C bus as the onboard EEPROM. Attached is the Excel "brainstorming" that I had to do to have the 23 bit addressing make complete sense, because in sdspiFemto, you only have this:
    i2cBootSCL  = 28                             ' Boot EEPROM SCL pin
    bootAddr    = i2cBootSCL << 18        ' Address of boot EEPROM
    

    To give you the address of the boot EEPROM which had me lost. But, I broke it down using Mike's post and the comments in the file and used Excel to track my thinking. It seems to make sense now and hopefully I can try it out tomorrow. thanks Mike!
  • WBA ConsultingWBA Consulting Posts: 2,935
    edited 2011-03-04 02:52
    I was finally able to work on my bootloader and figure out most of the tricks. I am still stumped on getting it to work with an EEPROM on a different pin pair, because all logical efforts have failed. I modified my setup to use an EEPROM on the boot EEprom bus and pulled A0 high. It works great.
    However, I then tried to utilize the checkPresence routine and calling that routine just puts the chip into lala land and never recovers. I cannot figure out why, because it's so simple. I simply want the main program to check for the secondary EEPROM and if it is present, boot from it. If not, the main program will run an "idle" loop that will check for a secondary EEPROM every few seconds while displaying a message on screen that states such.
    {{------------------------------------------------------------------------------
      Secondary EEPROM Loader
      WBA Consulting
      Andrew Williams
      3/3/11
    
    
    Version History
    001: Converted from Loader.spin by Brian Riley
    002: Minimized code for A0 booting on boot EEPROM i2c bus
    003: Added checkpresence routine
    
    
    }}
    
    CON _clkmode = xtal1 + pll16x
        _xinfreq = 5_000_000       '80 MHz
    
    
        cfgEEaddr      = 113 << 16  '113 = 1110001 where:
                                    '1110... is Pin Pair 28/29
                                    '....001 is select code for A0 EEPROM
                                    ' shift left 16 bits for EEProm start address($0000)
                                    '23 bit address complete: 11100010000000000000000
    
    '------------------------------------------------------------------------------
    
    OBJ
        EEP : "sdspiFemto"       ' EEProm SPIN program loader 
    
    '------------------------------------------------------------------------------
    
    PUB start | EEprsnt
    
    EEprsnt := EEP.checkPresence(cfgEEaddr) 'If EEPROM is present, EEprsnt = 1
    'EEprsnt := 1
    
      If  EEprsnt == 1
        EEP.bootEEPROM(cfgEEaddr) ' load from 001 EEPROM on boot bus
    
    NoEEPROM
    
    '------------------------------------------------------------------------------
    
    PUB NoEEPROM         ' If no A0 EEPROM found, cycle bi-color LED
    
    dira[10..11]~~
    
      repeat
           outa[10] := 1
           outa[11] := 0
           waitcnt(20_000_000 + cnt)
           outa[10] := 0
           outa[11] := 1
           waitcnt(20_000_000 + cnt)
    
    Anyone see why the checkpresence routine is not working? If I comment out the "EEprsnt := EEP.checkPresence(cfgEEaddr)" line and manually set the state of EEprsnt in the code, I get the desired results.
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-03-05 06:27
    Andrew , I thought the idea of an EEPROM key was an interesting concept and started thinking about the different possibilities.

    I came to the conclusion that for me the simplest and most versatile method would be to use a copy of the Propellers own bootloader. Chip made the ROM executable open source at this thread http://forums.parallax.com/showthread.php?101483-Propeller-ROM-source-code-HERE&highlight=bootloader

    The assembly is well documented and not too hard to follow. By modifying mask_sda and mask_scl any pin pair can be selected for your EEPROM(s). The ee_wait routine checks for EEPROM presence and goes to a shutdown routine if not found , the shutdown routine could be replaced with a message routine if prefered.

    If expanded to take parameters this bootloader would give many options of memory size , external memory addresses and different media by which a program could be loaded.

    I have attached a version of the original source that has the serial routine stripped out , as is it will boot the standard EEPROM of a Propeller when loaded into RAM from the Prop Tool IDE. The byte code is less than 500 bytes.

    Something to consider , if not this time maybe in the future

    Jeff T.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-03-05 06:53
    WBA Consulting,
    The bootEEPROM is the only routine in sdspiFemto that initializes the assembly cog before it does its own work. checkPresence is just a read without doing any reading and, like all the other public methods in sdspiFemto, requires you to have initialized the assembly cog by calling the start method first.
  • WBA ConsultingWBA Consulting Posts: 2,935
    edited 2011-03-05 22:37
    Mike, thanks! I missed tthe start routine because it wasn't the first pub. I just automatically assumed that there wasn't a start routine necessary. After looking at it again, I see that I should be able to make use of the error that would come back from the bootEEPROM routine since it contains code to check for EEPROM presence. Anyhow, tomorrow I will take another whack at it.

    Jeff, that looks really promising. PASM is way over my head, but some of that code is making sense to me, so I may dig into it further since I have another project that will need on the fly configuring and a "key" is a good solution so that the box can remain sealed shut.
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-03-06 06:39
    Andrew , I'm glad your making progress . I didn't want to distract you from your original path but wanted to bring to light something I admit I had overlooked in the past.

    I'm not PASM fluent either but Chip's "Pnut" source was easy for me to modify and use as a standalone routine. I'm sure it's been used by others but for me it was a discovery that opened up a bunch of possibilities.

    I have tested it on a development board with a secondary EEPROM on P0 and P1 and so far I can flip flop between launching EEPROM #1 and EEPROM #2 , if I get time later today I would like to attach two EEPROMs to P0 and P1 and see if I can pass address's and pin numbers to the pasm routine (easy for some but like I said I am not an asm guru ).

    The "key" concept is smart I hope the completed project is posted.

    Jeff T.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-03-06 07:46
    WBA Consulting,
    There's a bug in the bootEEPROM routine for the situation where it returns with an error code. It starts up the assembly cog using a control block in a local (stack) variable. This is fine if it's successful since the assembly cog won't use the control block once it starts loading the program. bootEEPROM needs to call stop on an error return like this:
    PUB bootEEPROM(addr) | t, c0, c1                       '' Load and run a new SPIN program
      if not start(@c0)                                    ' Start up the I/O routines using a
        abort                                              '  local control block
      long[control][1] := 0                                ' Check for the presence of EEPROM
      long[control][0] := ioReadCmd << 24 | (addr & $FFFFFF)
      repeat while long[control][0] & ioTestRdy            ' Wait for check to complete and
      if long[control][0] & ioTestErr                      '  abort if there's an error
        abort
      repeat t from 0 to 7                                 ' Stop all COGs except this one and
        if (t <> cogid) and (t <> (cog-1))                 '  the one with the I2C driver in it
          cogstop(t)
      t := ioBootCmd | ioStopLdr | cogid                   ' Tell the I2C driver to load 32K
      long[control][1] := $80000000                        '  into HUB RAM after stopping
      long[control][0] := (t << 24) | (addr & $FFFFFF)     '   this calling cog
      repeat while long[control][0] & ioTestRdy            ' Wait for this to finish
      stop                                                 ' If program not started, stop cog
      return (long[control][0] & ioTestErr) <> 0           ' Return any error code
    
    The SD card boot routine doesn't have this problem since it assumes that there will need to be some additional cleanup if the program fails to load, like turning off the SD card, and your program will furnish the control block area rather than the boot routine creating one on the stack.
  • WBA ConsultingWBA Consulting Posts: 2,935
    edited 2011-03-07 00:27
    Mike, I was able to get things working by simply adding the start routine. Took me a bit to get the code correct, but it works now. This code boots from an A0 select EEPROM on 28/29 if present (A0 line pulled high). If no secondary EEPROM is present, it will flash a bi-color LED tied to P10/P11 back and forth. (quickest way for me to see when things worked)
    {{------------------------------------------------------------------------------
      Secondary EEPROM Loader
      WBA Consulting
      Andrew Williams
      3/3/11
    
    
    Version History
    001: Based upon usage of Mike Green's sdspiFemto.spin
    002: Minimized code for A0 booting on boot EEPROM i2c bus
    003: Added checkpresence routine
    004: Added start sequence for checkpresence and error IF
    
    
    }}
    
    CON _clkmode = xtal1 + pll16x
        _xinfreq = 5_000_000       '80 MHz
    
    
        cfgEEaddr      = 113 << 16  '113 = 1110001 where:
                                    '1110... is Pin Pair 28/29
                                    '....001 is select code for A0 EEPROM
                                    ' shift left 16 bits for EEProm start address($0000)
                                    '23 bit address complete: 11100010000000000000000
    OBJ
        EEP : "sdspiFemto"       ' EEProm SPIN program loader
    
    VAR
       long ioControl[2]    
    
    PUB start | EEprsnt
    
    EEprsnt := 0
    EEP.start(@ioControl)
    EEprsnt := EEP.checkPresence(cfgEEaddr) 'If EEPROM is present, EEprsnt = 1
    
      If EEprsnt <> 0
         EEP.bootEEPROM(cfgEEaddr)   ' load from 001 EEPROM on boot bus
    
      NoEEPROM
    
     
    PUB NoEEPROM         ' If no A0 EEPROM found, cycle bi-color LED
    
    dira[10..11]~~
    
      repeat
           outa[10] := 1
           outa[11] := 0
           waitcnt(20_000_000 + cnt)
           outa[10] := 0
           outa[11] := 1
           waitcnt(20_000_000 + cnt)
    
  • WBA ConsultingWBA Consulting Posts: 2,935
    edited 2011-03-07 13:01
    I changed the thread to solved, because this is working the way I need. When I clean up the code for my project, I will include a snippet to reference this thread and using the bootEEPROM routine. I think others may want to use this in some other ways.
  • Don MDon M Posts: 1,653
    edited 2011-12-21 09:09
    Andrew- wondered if you ever cleaned up your code as you mentioned and would be able to post some completed code?

    I have an idea I may want to try this. What I would like to be able to do is serially transmit the new code to an upper portion of EEPROM. Then have it set a flag and reboot. Is this possible?
  • WBA ConsultingWBA Consulting Posts: 2,935
    edited 2011-12-22 01:37
    Don, I just realized I never posted my final code on this or my other tester thread. Here is the bootloader code for my testers. It doesn't use the upper portion of an EEPROM, but a second EEPROM. The original code I started with from Mike Green does boot from the upper portion, so once new data is stored into the upper portion, you can boot from it like you stated. You may want to search the forums for or start a new thread for code to load data through a serial connection to the upper portion of an EEPROM. I know it has been asked before.
    {{------------------------------------------------------------------------------
      Secondary EEPROM Loader
      WBA Consulting
      Andrew Williams
      3/3/11
    
    
    Version History
    001: Based upon usage of Mike Green's sdspiFemto.spin
    002: Minimized code for A0 booting on boot EEPROM i2c bus
    003: Added checkpresence routine
    004: Added start sequence for checkpresence and error IF
    005: Modified for use with LCD and LEDs on Thermistor Tester
    
    
    }}
    
    CON _clkmode = xtal1 + pll16x
        _xinfreq = 5_000_000       '80 MHz
    
    
        cfgEEaddr      = 113 << 16  '113 = 1110001 where:
                                    '1110... is Pin Pair 28/29
                                    '....001 is select code for A0 EEPROM
                                    ' shift left 16 bits for EEProm start address($0000)
                                    '23 bit address complete: 11100010000000000000000
    
      LCD_PIN   = 8                 ' for Parallax 2x16 serial LCD on P8
      LCD_BAUD  = 9_600
      LCD_LINES = 2
                                      
    OBJ
        EEP : "sdspiFemto"       ' EEProm SPIN program loader
        lcd : "Serial_lcd"                         '2x16 Serial LCD        
    
    VAR
       long ioControl[2]    
    
    PUB start | EEprsnt
    
    if lcd.init(LCD_PIN, LCD_BAUD, LCD_LINES)         ' start lcd
          lcd.cursor(0)                               ' cursor off
          lcd.backLight(false)                         ' backlight on (if available)
          lcd.cls                                     ' clear the lcd
          lcd.str(string("Searching", 13))            ' Show that unit is looking for an EEPROM key
          lcd.str(string("    for Key...", 13))       '  
          waitcnt(clkfreq + cnt)                      ' Pause 1 second
    
    EEprsnt := 0
    EEP.start(@ioControl)
    EEprsnt := EEP.checkPresence(cfgEEaddr) 'If EEPROM is present, EEprsnt = 1
    
      If EEprsnt <> 0
         EEP.bootEEPROM(cfgEEaddr)   ' load from 001 EEPROM on boot bus
    
      NoEEPROM
    
     
    PUB NoEEPROM  |  thermpin         ' If no A0 EEPROM found, cycle bi-color LEDs
    
    dira[11..27]~~
    
          lcd.cls                                     ' clear the lcd
          lcd.str(string("KEY NOT FOUND", 13))        ' Alert key not found
          lcd.str(string("   restarting...", 13))     ' and will restart
    
      repeat thermpin from 1 to 7
           outa[10 + thermpin] := 0                   ' set thermpin LED for Red cathode
           outa[20 + thermpin] := 1                   ' set thermpin LED for Red anode
           waitcnt(clkfreq/4 + cnt)
    
      outa[11..17] := 00000                      ' Turn Off red LEDs
      outa[21..27] := 00000
    
      start
    
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-12-22 11:03
    Hi, the Prop is always going to try and load and boot from pins 30, 31 and 28, 29 respectively so there has to be an intermediate program.

    Assuming there is just the one 64K EEPROM attached and you want to independently load the upper or lower 32K without affecting the other and you also want to use the Prop tool as the interface then as far as I can see you are going to need a second serial connection and a modified boot loader

    On reset the Props boot loader will check the serial port for a “handshake” from the Prop tool, if there is no activity on the serial line the lower 32K is loaded and launched from EEPROM.

    To extend this behavior so as to load a program into a different area of EEPROM ( or into RAM if desired ) from a different rx/tx pin pair a modified copy of the Props boot loader can be loaded to RAM first.

    The modifications to the boot loader include a change in EEPROM address, a change in rx,tx pair and the removal of the time out. The secondary serial connection is just the rx and tx there is no dtr because there is no need to do a reset.

    There is a procedure
    1./ In the IDE Port management implicitly set the port to the default programming port
    2./ Download the modified boot loader to RAM (F10)
    3./ Switch to the program you want in the upper 32K
    4./ In the IDE Port management implicitly set the port to the secondary programming port.
    5./ Download to the upper 32K (F11)

    If you wanted to try this I have attached a modified loader that uses P0 and P1 as rx and tx and has the time out inhibited. I have not adjusted the EEPROM settings so for now it will still load the first 32K or launch to RAM if desired.

    Jeff T.
  • Don MDon M Posts: 1,653
    edited 2011-12-22 15:38
    What I had in mind was to be able to transmit serially via bluetooth through a specific set of rx/tx pins (for example P0 & P1) to the eeprom. Then once that new program has been stored to then send a command via bluetooth to reset or reboot the Prop so that it boots from the new program.

    So am I understanding this correctly that once the Prop is up and running that I could overwrite the lower half of the eeprom with a new program and once the Prop resets it will then load and run the new program? In reality do I even need a boot loader other that what is in the Prop already?
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-12-22 16:24
    Hi, so what you actually want is to be able to program a standard set up via Bluetooth. I seem to recall it being done but I am not absolutely sure.

    Again I think it more feasible using a modified loader, something much simpler than the last example. This modified loader has got to end up in RAM when the time comes to re program the Prop. So it has to be included as a part of each program that is downloaded or stored and loaded from an attached memory source which could be additional EEPROM. Every program would also need a resource to monitor the serial port looking for a command to load the loader.

    I am saying this not knowing whether the Prop tool would be able to synch up via Bluetooth, it would be nice if it were possible, my assumption is that the download would be made using a custom GUI.

    You may get answers regarding the Bluetooth programming, as Andrew suggested it may be best to start another thread with that question. In the mean time I am going to hook up a BT module and do a little experimenting.
    If you knew in advance what the programs were an alternative might be to store several programs to EEPROM (s) and load them as required using a “slot” approach

    E.g.: http://forums.parallax.com/showthread.php?130615-Slot-Programming-the-Propeller

    Jeff T.

    EDIT: to answer the question about programming while up and running. You can read and write at will to the EEPROM while running but you need a means to do that. What I suggested means halting program execution while a new program uses the RAM to load the EEPROM
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-12-22 18:52
    OK, I hooked up a BT module to P0 and P1 and I am able to download a spin file from the Proptool IDE over Bluetooth. I used the previous spin file that I posted, booter_no_timeout.spin. My Bluetooth module does not have a pin I can use as a reset, or at least I have not discovered how to implement it, if it did I feel sure you would be able to use the inbuilt ROM bootloader and the Proptool just as you would a wired connection. Does your Bluetooth module have a pin that you can use as reset.

    Jeff T.
Sign In or Register to comment.