I2C custom loader (propeller soft reset)
byrtolet
Posts: 22
in Propeller 1
Hello!
I want to implement custom i2c loader.
My main problem is that I am memory constrained.
My current app uses propellergcc with 6 cogs running in cog mode and other two in lmm.
I want to do something like:
1. Boot propeller in nomral lmm mode
2. Start i2c communication cog.
3. receive (via i2c) up to six cog programs and star them (they would have to wait for some event to start their function, not to mess up anything in the hub)
4. start another cog which would overwrite the entire hub memory (or most of it)
5. Restart the propeller (restart the cog from step 4) as it was started after loading from the i2c eeprom. (but with all the extra cogs previously started running)
I don't know how to perform step 5 at all, can anybody help
I would probably need to reserve some of the hub ram for the communication with the already started cogs, any ideal how to do that (without complicated linker scripts if possible).
I want to implement custom i2c loader.
My main problem is that I am memory constrained.
My current app uses propellergcc with 6 cogs running in cog mode and other two in lmm.
I want to do something like:
1. Boot propeller in nomral lmm mode
2. Start i2c communication cog.
3. receive (via i2c) up to six cog programs and star them (they would have to wait for some event to start their function, not to mess up anything in the hub)
4. start another cog which would overwrite the entire hub memory (or most of it)
5. Restart the propeller (restart the cog from step 4) as it was started after loading from the i2c eeprom. (but with all the extra cogs previously started running)
I don't know how to perform step 5 at all, can anybody help
I would probably need to reserve some of the hub ram for the communication with the already started cogs, any ideal how to do that (without complicated linker scripts if possible).
Comments
Each cog program would be read or copied into the buffer, then started in a cog using a COGINIT instruction. Once the cog starts up, the buffer could be reused for another program.
Yes, i know about that buffer. I will use propeller as i2c slave. I have a working i2c slave code. I just don't know how to restart the propeller, after loading its hub memory. What i can do right now is to have only one cog initially loaded (the i2c slave one) reuse its memory for starting other cogs.
What I actually need is a way of loading different programs in the propeller at different times (there is an external mcu (esp32) which will decide what to load).
I know one could load the propeller via the async serial, but I use the i2c to communicate anyway so I thought to do the loading on i2c.
The idea of cog loading is to spare the memory, which is left unused (and not easy usable) after starting the cogs.
LMM programs must reside in the hub. You can't overwrite the entire hub.
What if you added the i2c functions to one of the LMM cogs? There would be no need to restart it. It would start its application code after loading the other cogs.
Another possibility may be to override the heap address so that malloc will reuse the cog program memory. I don't use propellergcc so I don't know if organizes the program memory so this would work efficiently.
LMM is too slow for 400khz i2c unfortunately.
One can even write a linker scripts with some fixed addresses for the required buffers for the i2c, which can be made the same across all images we throw at the hub.
I don't know how to start a LMM cog from cog mode one. That would do as well.
Just to be clear: step 5 is not a restart of the propeller, since you want the other COGs to keep running, it's just restarting one particular COG. That's pretty straightforward in assembly language, you just have to do a "coginit" giving that COG's ID as the cog to initialize.
If the new program you want to start is an LMM program it's slightly trickier. In that case it depends on what's been put into HUB memory in step 4. If what you're writing into HUB is the new LMM program, then doing a "coginit" with a parameter of 0 and an address of the ".lmmkernel" section should do the trick. (I think .lmmkernel should always start at address 32, but you might want to double check that).
The easiest would probably be to reserve some space at the top of HUB. The C stack pointer (sp) is initialized to the top of HUB memory. If, very early in your program, you set it to something like 0x7f00 then the space from 0x7f00 to approximately 0x7fe0 will be available for communication. Note that I say "approximately" because the startup code probably does use some stack so the very top of HUB memory will be corrupted, and the exact values used will depend upon the GCC version and on how early you change the stack pointer in your main() function.
I'm sure there's a way to set the initial stack pointer value using a linker script, which would be even easier (and safer), but I don't know off-hand what exactly that would be. It probably depends on the version of PropGCC that you're using.
Yes, definitely. PropGCC supports FCACHE, so a well written I2C driver should run at almost the same speed in LMM as in COG (the inner loop should be put in COG memory via FCACHE). I suspect @DavidZemon 's propware has I2C drivers that will do this, his code is usually very efficient.
Can confirm. PropWare's I2CMaster class uses FCache to send and receive bytes: https://github.com/parallaxinc/PropWare/blob/develop/PropWare/serial/i2c/i2cmaster.h#L141
You'll get the same max clock rate with XMM, CMM, LMM, and COG modes.
Thank you for the replays.
I know about the fcache, but its size is limited. I've implemented i2c slave in the propeller, which is a bit trickier than implementing a master.
The main reason I use propeller as an i2c slave is that the other controller's (esp32) ability for being slave is limited - it cant do register like accesses (as far as I could understand).
Also, i2c's rate using passive pull-ups is pretty much limited to 400khz and one can't do clock stretching if needed with an active clock. Of course if you don't use ridiculously low value resistors.
Whatever the propeller c mode it is running in (lmm, cmm or cog) you'll still need to dedicate a cog for i2c slave communication