~vdupras/collapseos

5b4917dbe950a89ef434e4af5fa2fda1bf3488f7 — Virgil Dupras 26 days ago 4910b9c
avr: allow writing to flash
5 files changed, 53 insertions(+), 13 deletions(-)

M blk/690
M blk/691
A blk/692
A blk/693
M doc/avr.txt
M blk/690 => blk/690 +1 -1
@@ 4,4 4,4 @@ This program allows you to access AVR chips Flash memory, EEPROM
and fuses using a SPI relay. This requires drivers that imple-
ment the SPI Relay protocol.

Load range: B691-BXXX
Load range: B691-B693

M blk/691 => blk/691 +13 -12
@@ 1,14 1,15 @@
: _cmd ( b4 b3 b2 b1 -- r4 )
    (spix) DROP DUP (spix) DROP SWAP (spix) = ( b4 f )
    SWAP (spix) SWAP ( r4 f ) NOT IF ABORT" AVR err" THEN ;
( page size in words, 64 is default on atmega328P )
CREATE aspfpgsz 64 ,
VARIABLE aspprevx
: _x ( a -- b ) DUP aspprevx ! (spix) ;
: _xc ( a -- b ) DUP (spix) ( a b )
    DUP aspprevx @ = NOT IF ABORT" AVR err" THEN ( a b )
    SWAP aspprevx ! ( b ) ;
: _cmd ( b4 b3 b2 b1 -- r4 ) _xc DROP _x DROP _xc DROP _x ;
: asprdy ( -- ) BEGIN 0 0 0 0xf0 _cmd 1 AND NOT UNTIL ;
: asp$ ( -- )
    ( RESET pulse ) (spie) (spid) (spie)
    ( wait 20ms ) 2000 0 DO LOOP
    ( enable prog ) 0 0 0x53 0xac _cmd DROP ;
: asprdy ( -- f ) 0 0 0 0xf0 _cmd NOT ;
: aspfl@ ( -- lfuse ) 0 0 0 0x50 _cmd ;
: aspfh@ ( -- hfuse ) 0 0 0x08 0x58 _cmd ;
: aspfe@ ( -- efuse ) 0 0 0x00 0x58 _cmd ;
: aspfl! ( lfuse -- ) 0 0xa0 0xac _cmd ;
: aspfh! ( hfuse -- ) 0 0xa8 0xac _cmd ;
: aspfe! ( efuse -- ) 0 0xa4 0xac _cmd ;
    ( wait >20ms ) 5000 0 DO LOOP
    ( enable prog ) 0xac (spix) DROP
    0x53 _x DROP 0 _xc DROP 0 _x DROP ;
: asperase 0 0 0x80 0xac _cmd asprdy ;

A blk/692 => blk/692 +7 -0
@@ 0,0 1,7 @@
( fuse access. read/write one byte at a time )
: aspfl@ ( -- lfuse ) 0 0 0 0x50 _cmd ;
: aspfh@ ( -- hfuse ) 0 0 0x08 0x58 _cmd ;
: aspfe@ ( -- efuse ) 0 0 0x00 0x58 _cmd ;
: aspfl! ( lfuse -- ) 0 0xa0 0xac _cmd ;
: aspfh! ( hfuse -- ) 0 0xa8 0xac _cmd ;
: aspfe! ( efuse -- ) 0 0xa4 0xac _cmd ;

A blk/693 => blk/693 +13 -0
@@ 0,0 1,13 @@
: aspfb! ( n a --, write word n to flash buffer addr a )
    SWAP 256 /MOD ( a lo hi ) SWAP ROT ( hi lo a )
    DUP ROT ( hi a a lo ) SWAP ( hi a lo a )
    0 0x40 ( hi a lo a 0 0x40 ) _cmd DROP ( hi a )
    0 0x48 _cmd DROP ;
: aspfp! ( page --, write buffer to page )
    0 SWAP aspfpgsz @ * 256 /MOD ( 0 lsb msb )
    0x4c _cmd DROP asprdy ;
: aspf@ ( page a -- n, read word from flash )
    SWAP aspfpgsz @ * OR ( addr ) 256 /MOD ( lsb msb )
    2DUP 0 ROT ROT ( lsb msb 0 lsb msb )
    0x20 _cmd ( lsb msb low )
    ROT ROT 0 ROT ROT ( low 0 lsb msb ) 0x28 _cmd 8 LSHIFT OR ;

M doc/avr.txt => doc/avr.txt +19 -0
@@ 48,3 48,22 @@ batch, that is, running your commands right after the "asp$" command, ending
your batch with "(spid)" so that the next batch works. In my tests, interacting
with the chip "live" in a single "asp$" session sometimes resulted in unreliable
data that didn't properly detect sync errors. TODO: investigate further.

# Writing data to Flash

Writing to AVR's flash is done in batch mode, page by page. To this end, the
chip has a buffer which is writable byte-by-byte. To write to the flash, you
begin by writing to that buffer using aspfb! and then write to a page using
aspfp!.

Please note that aspfb! deals with *words*, not bytes. If, for example, you want
to hook it to A!*, make sure you use AMOVEW instead of AMOVE. You will need to
create a wrapper word around aspfb! that divides dst addr by 2 because AMOVEW
use byte-based addresses but aspfb! uses word-based ones. You also have to make
sure that A@* points to @ (or another word-based fetcher) instead of its default
value of C@.

Beware of bootloader sections! By default, AVR chips have a bootloader using the
first few pages (by default, the ATMega328P uses 4 pages for its bootloader).
Check (or modify) the BOOTSZ fuses to confirm where you whould start writing
your program.