Shop OBEX P1 Docs P2 Docs Learn Events
Can a Prop program Another Prop Using Serial I/O on Pins Other Than P30/31? — Parallax Forums

Can a Prop program Another Prop Using Serial I/O on Pins Other Than P30/31?

JRetSapDoogJRetSapDoog Posts: 954
edited 2015-02-10 12:22 in Propeller 1
Hi, all. I'm just at the musing stage, but am wondering if a first Propeller can load a program image (such as from an SD card or the high part of a 64KB EEPROM) into a second Propeller (on the same board) over a serial connection between them on pins other than P30/31, providing that the second Propeller already has code on it to know how to receive the image and what to do with it (start it)? Sounds a bit like asking if water is wet, but I'm just checking. If doable, may I ask some ways that this could be done? For example, would a PASM program running on (or started in) a COG of the second Propeller receive the image and load the image into RAM (and perhaps optionally write it to EEPROM if updating the firmware, so to speak)? By the way, in this scenario, only the first Propeller is connected with an SD card.

Presently, this inquiry is just for reference, but I did build a dual-prop board with a serial connection between two Props on pins other than P30/31, so the capability might come in handy someday (or maybe I should redesign the board, though I don't guess that the two Props could directly share their P30/31 lines without major problems unless one was held in reset, maybe (which is another connection between them)). Currently, I'm fine with programming each Prop separately over separate 4-pin headers using a Prop Plug that I manually switch back and forth as necessary (depending on which Prop I need to program). But someday, it might be nice (or even necessary) to have the first Prop program the second one (at least its RAM and maybe its EEPROM). Any comments would be appreciated or pointers to existing code or similar efforts. Thanks and good day.

Comments

  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-06 00:07
    Yes, water is wet, and slave Prop loader is doable, certainly when the slave Prop has it's own preloaded booter. I would just use a single I/O, there is no need for full-duplex. However, you can just control the reset and EEPROM of the slave directly so that there is no need for any preloaed booter etc. This is nice and simple although it does use up 3 I/O on the master but is very flexible.
  • Cluso99Cluso99 Posts: 18,069
    edited 2015-02-06 01:02
    Yes, water is wet, and slave Prop loader is doable, certainly when the slave Prop has it's own preloaded booter. I would just use a single I/O, there is no need for full-duplex. However, you can just control the reset and EEPROM of the slave directly so that there is no need for any preloaed booter etc. This is nice and simple although it does use up 3 I/O on the master but is very flexible.
    You could get away with just P28/P29 SCL & SDA when, after loading the EEPROM boot code, it looked for data on a single P28 or P29 (ie SDA or SCL) provided the other pin (SCL or SDA) is kept constant. ie you are sharing one of the SDA & SCL pins.
  • JRetSapDoogJRetSapDoog Posts: 954
    edited 2015-02-06 14:03
    Thanks for those comments, Peter and Ray. I get part of that, but not all of it. Guess I'm that guy who said, "[Could you] Explain this to me like I'm a four/six year old."

    The design of the dual-Prop board I'm currently using has 8 possible communication lines between the 2 Props (1 or 2 may be enough, but I designed it with 8, just in case). However, I didn't arrange things to connect a line from the master to the slave Prop's reset (or EEPROM). If I redesign the board, I wonder if you'd recommend having a line from the master Prop connect to the slave's reset line (and/or EEPROM lines). Although the current board doesn't have that, I was thinking that the master could pass a message to the slave for which the slave was pre-programmed to act upon to call REBOOT (on itself, of course) if the master needed to reset the slave. Or, if the slave reprogrammed its own EEPROM, then it could call REBOOT (with or without prodding from the master). All that presumes that the slave's EEPROM code always retains such capability, otherwise future EEPROM reprogramming or rebooting based on a message would be lost.

    Changing gears, although I mentioned possibly reprogramming the slave's EEPROM above, perhaps we could set that aside for a moment and consider just reprogramming the slave's RAM. I'm currently in the dark about how to do that. Even if I had a connection to the slave's reset line and I suspended COG 0 to reload the RAM, I believe that would just cause it to load from its EEPROM (assuming no host communication on P30/31). And I believe having the slave call REBOOT on itself would do the same thing.

    I guess I'm looking for a mechanism that would allow the RAM to be reloaded without botching things up, since I presume that any running SPIN interpreters aren't going to like having the RAM reloaded while they are still running and clobbering their original/current code. Therefore, I'm wondering if only a PASM cog could reload the RAM. If so, then how would a SPIN interpreter be launched? Could the PASM COGINIT instruction be used? The Propeller Manual says that it can "tart or restart a cog, optionally by ID, to run Propeller Assembly or Spin code." But it later states, "It is not practical to launch Spin code from a user’s Propeller Assembly code; we recommend launching only assembly code with this instruction." But I'm not sure what all that means.

    I'm wondering if reprogramming the RAM could be accomplished by [1] having a PASM (or SPIN) cog call STOP on COG 0 to suspend COG 0's SPIN interpreter, [2] using a PASM cog to load the RAM with a new image downloaded from the master Prop (say off of an SD card), and [3] calling COGINIT on COG 0 to bring it out of "suspension" (the dormant state) and get it up-and-running at the main/first method of the image that was just loaded in? But when the manual says that COGINIT can "restart" a cog, I don't know if that includes restarting a stopped cog with its current code. Perhaps it can only restart a cog by reloading the cog, clobbering what's already in there, the SPIN interpreter in this case. Anyway, the manual says that bits 17:4 of the COGINIT instruction point to the assembly code to load into the cog, so that does NOT sound like restarting the cog with the code that's already in it. So, at this point,I have no idea how to launch the new code that was loaded into RAM. Would one have to give COGINIT the address of the SPIN interpreter located at the bottom of ROM? Wonder what that address is (perhaps F002 or F800 or thereabouts). Oh, wait, I seem to recall something about the interpreter code being scrambled (maybe) so that idea is probably out (unless one knows how to unscramble it). Or maybe there's an unscrambled version of the SPIN interpreter floating around. Or maybe one can call the booter to load the interpreter to get around any scrambling. Gee, I'm confused!

    Hmm...thinking further about this, I recall that Mike Green has code that can cause a single Propeller to reload its RAM from an SD card and have a SPIN interpreter in COG 0 run that code somehow, so it follows that it must be possible to reload and run with the code image coming from another Prop (providing the slave already has the communication and reload code in RAM and probably EEPROM).

    But getting back to the suggestions on going directly to the slave's EEPROM, that would require writing the EEPROM every time one wanted to run new code in the slave. Well, of course rewriting the EEPROM would be necessary if updating the firmware of the slave. But one might not always want to lose the original. I was also concerned about wearing out the EEPROM, but I guess you'd have to erase it a few times a day for years to run into that problem. But, for now, I would still be interested in having a way to reload the RAM (and run that) without having to necessarily reprogram the EEPROM. However, I'm currently fairly clueless about how to do that. Anyway, as mentioned, I'm just musing at this point and don't have an immediate need for this technique. However, if I do redesign the board I'm using, the answers could affect the design. At any rate, thanks again for your comments.
  • average joeaverage joe Posts: 795
    edited 2015-02-06 15:50
    From what I understand...

    There are many ways to do what you want, although it's much easier to do using the programming pins. First, you'd need to signal the slave telling it to load a new image. This would cause the slave to stop ALL other cogs and then start a new PASM cog that will reload the HubRam. Then, kill the thread that STARTED that cog. This leaves one remaining cog (probably 90% full duplex serial with a mechanism to increment through the hub addresses and perhaps checksum) that will fill the hub. Once hub is full, it should be as simple as starting the SPIN interpreter pointing to the new entry. (Pbase, Dbase and ??)

    I've actually looked at doing this several times but instead, my multi-prop boards handle loading using the programming pins. It's just way easier for me since it's an "out of the box" solution.
  • msrobotsmsrobots Posts: 3,709
    edited 2015-02-06 16:06
    Well there is a PropellerLoader Object in spin written by Chip. It is in the PropellerTool Library. You need to connect RX,TX and Reset. of the propeller you want to load. To three pins of the propeller you want to program from. 1M pulldown on reset.

    There is a thread about it somewhere on this forum. The version Chip wrote included the to be loaded binary as file into the spin code.

    Mike G adapted this source for the Spinerette Webserver. His Version can load a binary from SD to be programmed into another Propeller. Also somewhere on this forum.

    Peter J. idea is cool also. As long as you hold the target prop in reset state you can take over the I2C lines of that prop from another one and simply write the EEPROM.

    here original from Chip
    ''***************************************
    ''*  Propeller Loader v1.0              *
    ''*  Author: Chip Gracey                *
    ''*  Copyright (c) 2006 Parallax, Inc.  *
    ''*  See end of file for terms of use.  *
    ''***************************************
    
    ' v1.0 - 13 June 2006 - original version
    
    ''_____________________________________________________________________________
    ''
    ''This object lets a Propeller chip load up another Propeller chip in the same
    ''way the PC normally does.
    ''
    ''To do this, the program to be loaded into the other Propeller chip must be
    ''compiled using "F8" (be sure to enable "Show Hex") and then a "Save Binary
    ''File" must be done. This binary file must then be included so that it will be
    ''resident and its address can be conveyed to this object for loading.
    ''
    ''Say that the file was saved as "loadme.binary". Also, say that the Propeller
    ''which will be performing the load/program operation has its pins 0..2 tied to
    ''the other Propeller's pins RESn, P31, and P30, respectively. And we'll say
    ''we're working with Version 1 chips and you just want to load and execute the
    ''program. Your code would look something like this:
    ''
    ''
    ''OBJ loader : "PropellerLoader"
    ''
    ''DAT loadme file "loadme.binary"
    ''
    ''PUB LoadPropeller
    ''
    ''  loader.Connect(0, 1, 2, 1, loader#LoadRun, @loadme)
    ''
    ''
    ''This object drives the other Propeller's RESn line, so it is recommended that
    ''the other Propeller's BOEn pin be tied high and that its RESn pin be pulled
    ''to VSS with a 1M resistor to keep it on ice until showtime.
    ''_____________________________________________________________________________
    ''
    
    
    CON
    
      #1, ErrorConnect, ErrorVersion, ErrorChecksum, ErrorProgram, ErrorVerify
      #0, Shutdown, LoadRun, ProgramShutdown, ProgramRun
      
    
    VAR
    
      long P31, P30, LFSR, Ver, Echo
      
    
    PUB Connect(PinRESn, PinP31, PinP30, Version, Command, CodePtr) : Error
    
      'set P31 and P30
      P31 := PinP31
      P30 := PinP30
    
      'RESn low
      outa[PinRESn] := 0            
      dira[PinRESn] := 1
      
      'P31 high (our TX)
      outa[PinP31] := 1             
      dira[PinP31] := 1
      
      'P30 input (our RX)
      dira[PinP30] := 0             
    
      'RESn high
      outa[PinRESn] := 1            
    
      'wait 100ms
      waitcnt(clkfreq / 10 + cnt)
    
      'Communicate (may abort with error code)
      if Error := \Communicate(Version, Command, CodePtr)
        dira[PinRESn] := 0
    
      'P31 float
      dira[PinP31] := 0
      
    
    PRI Communicate(Version, Command, CodePtr) | ByteCount
    
      'output calibration pulses
      BitsOut(%01, 2)               
    
      'send LFSR pattern
      LFSR := "P"                   
      repeat 250
        BitsOut(IterateLFSR, 1)
    
      'receive and verify LFSR pattern
      repeat 250                   
        if WaitBit(1) <> IterateLFSR
          abort ErrorConnect
    
      'receive chip version      
      repeat 8
        Ver := WaitBit(1) << 7 + Ver >> 1
    
      'if version mismatch, shutdown and abort
      if Ver <> Version
        BitsOut(Shutdown, 32)
        abort ErrorVersion
    
      'send command
      BitsOut(Command, 32)
    
      'handle command details
      if Command          
    
        'send long count
        ByteCount := byte[CodePtr][8] | byte[CodePtr][9] << 8
        BitsOut(ByteCount >> 2, 32)
    
        'send bytes
        repeat ByteCount
          BitsOut(byte[CodePtr++], 8)
    
        'allow 250ms for positive checksum response
        if WaitBit(25)
          abort ErrorChecksum
    
        'eeprom program command
        if Command > 1
        
          'allow 5s for positive program response
          if WaitBit(500)
            abort ErrorProgram
            
          'allow 2s for positive verify response
          if WaitBit(200)
            abort ErrorVerify
                    
    
    PRI IterateLFSR : Bit
    
      'get return bit
      Bit := LFSR & 1
      
      'iterate LFSR (8-bit, $B2 taps)
      LFSR := LFSR << 1 | (LFSR >> 7 ^ LFSR >> 5 ^ LFSR >> 4 ^ LFSR >> 1) & 1
      
    
    PRI WaitBit(Hundredths) : Bit | PriorEcho
    
      repeat Hundredths
      
        'output 1t pulse                        
        BitsOut(1, 1)
        
        'sample bit and echo
        Bit := ina[P30]
        PriorEcho := Echo
        
        'output 2t pulse
        BitsOut(0, 1)
        
        'if echo was low, got bit                                      
        if not PriorEcho
          return
          
        'wait 10ms
        waitcnt(clkfreq / 100 + cnt)
    
      'timeout, abort
      abort ErrorConnect
    
      
    PRI BitsOut(Value, Bits)
    
      repeat Bits
    
        if Value & 1
        
          'output '1' (1t pulse)
          outa[P31] := 0                        
          Echo := ina[P30]
          outa[P31] := 1
          
        else
        
          'output '0' (2t pulse)
          outa[P31] := 0
          outa[P31] := 0
          Echo := ina[P30]
          Echo := ina[P30]
          outa[P31] := 1
    
        Value >>= 1
    
    {{
    
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474;                                                   TERMS OF USE: MIT License                                                  &#9474;                                                            
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
    &#9474;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation    &#9474; 
    &#9474;files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,    &#9474;
    &#9474;modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software&#9474;
    &#9474;is furnished to do so, subject to the following conditions:                                                                   &#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&#9474;
    &#9474;                                                                                                                              &#9474;
    &#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE          &#9474;
    &#9474;WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR         &#9474;
    &#9474;COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,   &#9474;
    &#9474;ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                         &#9474;
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    }}    
    

    Enjoy!

    Mike
  • JRetSapDoogJRetSapDoog Posts: 954
    edited 2015-02-07 22:51
    Thanks for the additional comments.

    @Average Joe: Thanks for that summary/list. I think the part I would struggle with the most is:
    Once hub is full, it should be as simple as starting the SPIN interpreter pointing to the new entry. (Pbase, Dbase and ??)

    For Pasm COGINIT, the manual gives the following bit usage:

    31..18: 14-bit Long address for PAR Register; 17..4: 14-bit Long address of code to load; 3: new (indicator); 2..0: Cog ID.

    But I'm not clear on what address to use (or even if the COGINIT instruction will work).

    @msrobots: Thanks for pointing out Chip's loader and Mike's server and for your comments.

    On my master prop, I actually have some pins free (how often can one say that!), so, if I do a redesign, I'll likely connect some free ones to the slave's serial, EEPROM, or both, as well as its reset pin..
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2015-02-07 22:56
    Assuming your master has EEPROM routines loaded then you can reassign the I2C pins to the ones connected to the slave and just access it from the master as you would normally. This is all I do in Tachyon and I can load files directly from upper 64K EEPROM or SD into the slave. I mainly use this for reading a board and then cloning it onto other boards as an easy means to upgrade firmware in the field and so it does not depend upon any software in the slave/target at all or having to have additional software just to work with the Prop serial bootloader, which btw would still require 3 I/O from the master anyway.
  • average joeaverage joe Posts: 795
    edited 2015-02-08 01:17
    I do believe that CogInit should work.

    I believe that the 14 bit PAR address (31..18) would be the pointer to ?Pbase?
    The 14 bit address for code (17..4) would point to the Spin interpreter in ROM.
    3 should be 0? (I think)
    2..0 CogID, I'd try to load into the cog that's calling the coginit.

    If you are interested I'm sure I could dig the info out for you. As I said, I've looked at doing this before just never had the time.

    Here's one way I have loaded an image without using propeller pins, it would require some modification but might be a good starting point.
    http://www.parallax.com/sites/default/files/downloads/AN007-SoftLoadXBee-v1.0.pdf
  • JRetSapDoogJRetSapDoog Posts: 954
    edited 2015-02-10 12:22
    Hey, thanks for the additional comments, guys! Sorry for the delayed reply.

    @Peter: That does sound like a slick way to upgrade units in the field.

    @AJ: Thanks for your thoughts on Coginit and those details. And thanks for the pdf link. I've just glossed over it so far (I had to remind myself (via a search) what Propellant is and got distracted). As for digging into it further, thanks for the kind offer. In that I don't have an immediate need to try this (and am still contemplating a board redesign), I wouldn't want to put you out. However, if, down the road, you do come up with additional information or end up trying this, I'd be all ears .
Sign In or Register to comment.