…
1) I’ve updated my resume for those of you who care about such things. It’s at http://www.sheer.us/resume/SheerResume-ascii-wa.txt
2) Below please find a bootloader for a Atmel AVR AtMega8 which accepts a binhex file uploaded via windows terminal (or however else you would like). I’m releasing this code to the public domain at this point. Feel free to do whatever you like with it, or not, as appropriate. It could probably easily be modified for any AVR CPU
start_bld:
cli
ldi ZL, LOW(RAMEND)
ldi ZH, HIGH(RAMEND)
out SPL, ZL
out SPH, ZH ; set up the stack
rcall init_bld ; set up some hardware stuff
rcall idle_timer2_bld ; start timer2 ticking
rcall set_system_clock_bld ; setup the system clock for 7.2738Mhz
; check and see if there is a serial console present
sbis RS232_INVALID_IN_PORT, RS232_INVALID
rjmp bld_do_boot ; if no console, boot
ldi uart_char, XON ; send welcome banner
rcall uart_put_char_bld
ldi uart_char, ‘B’
rcall uart_put_char_bld
ldi uart_char, ‘l’
rcall uart_put_char_bld
ldi uart_char, ‘d’
rcall uart_put_char_bld
ldi uart_char, ‘>’
rcall uart_put_char_bld
rcall uart_get_char_bld_to ; get a char, or timeout and fall through
brts bld_do_boot
cpi uart_char, ‘B’ ; if ‘B’, then boot right now
breq bld_do_boot
cpi uart_char, ‘U’ ; if ‘U’, then go into upload mode
breq bld_do_upload ; todo: authentication
bld_do_boot:
jmp ivec_reset
; ‘stubbies’ used to make short relative jumps work okay
bld_do_upload_crc_special1:
rjmp bld_do_upload_crc_special
bld_do_flush1:
rcall bld_do_flush
rjmp bld_do_upload
bld_do_upload_err1:
rjmp bld_do_upload_err
; ******* Upload routine. Decodes lines of Intel Hex, writes them to the flash
; displays a error for bad lines
bld_do_booty:
rcall bld_do_flush
rjmp bld_do_boot
bld_do_upload:
; for now, fetch a line, check its checksum, report back good or bad, wash, rinse, repeat
rcall crlf_bld
ldi ZL, LOW(STRING_SCRATCH)
ldi ZH, HIGH(STRING_SCRATCH)
rcall uart_get_string_bld
ldi uart_char, XOFF ; send XOFF in case this
rcall uart_put_char_t_bld ; takes a while
rcall crlf_bld ; debugging
ldi ZL, LOW(STRING_SCRATCH)
ldi ZH, HIGH(STRING_SCRATCH)
clr XL
clr sample_cnt
ld uart_char, Z
cpi uart_char, ‘:’
breq bld_do_upload_ok
cpi uart_char, ‘F’
breq bld_do_flush1
cpi uart_char, ‘B’
breq bld_do_booty
cpi uart_char, CR
breq bld_do_upload
cpi uart_char, LF
breq bld_do_upload
rjmp bld_do_upload_err1
bld_do_upload_ok:
rcall ascii_to_bin_hex_bld ; convert first 4 bytes of input
; (should be length and high addr)
sts LINE_LEN, TempH ; save length in RAM
mov Temp2, TempH ; store byte count in temp register
sub XL, TempH
sub XL, Temp ; compute checksum
sts LINE_ADDR_H, Temp ; store high byte of address
rcall ascii_to_bin_hex_bld ; convert second 4 bytes of input
sts LINE_ADDR_L, TempH ; store low byte of address
sts LINE_TYPE, Temp ; store line type
sub XL, TempH ; compute checksum
sub XL, Temp
; fetch data, store in line
; hopefully data is even, but no guarentee
ldi YL, LOW(LINE)
ldi YH, HIGH(LINE)
cpi Temp2, 0
breq bld_do_upload ; if zero length record, skip
dec Temp2 ; LENGTH is +1, from dec standpoint
bld_do_upload_loop:
rcall ascii_to_bin_hex_bld ; translate ascii to binary
st Y+, TempH ; store bytes (high)
st Y+, Temp ; store bytes
sub XL, TempH ; compute checksum
sub XL, Temp
dec Temp2 ; LEN was given in bytes
breq bld_do_upload_crc_special1 ; special case: odd number of bytes
dec Temp2 ; but we do words so need 2 decs
brne bld_do_upload_loop ; go around again?
rcall ascii_to_bin_hex_bld ; grab CRC
sts LINE_CHECK, Temp ; store CRC
bld_do_crc_check:
lds TempH, LINE_TYPE
; ldi uart_char, ‘0’
; add uart_char, TempH
; rcall uart_put_char_bld
cpi TempH, LINETYPE_HDR
breq bld_do_upload
cp Temp, XL ; compare CRC to stored
brne bld_do_upload_err1 ; if it doesnt’ match, err
; matches, so program part
ldi YL, LOW(LINE) ; use Y ptr to access
ldi YH, HIGH(LINE) ; stored data for this line
lds Temp2, LINE_LEN ; Temp3 contains countdown
lds ZL, LINE_ADDR_L ; Z ptr is address in flash
lds ZH, LINE_ADDR_H
ldi XL, LOW(BOOTLOAD_START*2) ; X ptr is max flash addr to write
ldi XH, HIGH(BOOTLOAD_START*2) ; keeps us from writing bootloader
; which would put is in NWRW state
; and be bad
bld_do_program_loop:
cp XL, ZL ; check to see if we’re
cpc XH, ZH ; outside of the bootloader
brlo bld_do_program_loop_end ; do not program bootloader
; even if it is in file
mov TempH, ZH ; grab the page
mov Temp, ZL ;
andi Temp, 0xC0 ; skip off the byte address
; leaving only the page address
lds Temp3, LAST_PAGE_L ; compare against
cp Temp, Temp3 ; the last page that
lds Temp3, LAST_PAGE_H ; we used and
cpc TempH, Temp3 ; if it’s different
breq bld_do_program_skip_write ; then we need to write that page
; if we get here, then we must
push ZL ; preserve Z
push ZH
lds ZL, LAST_PAGE_L ; restore previous Z (page we
lds ZH, LAST_PAGE_H ; want to write)
rcall wait_spm_bld ; wait for SPM to clear
ldi Temp, (1<
ascii_to_bin_hex_cont_bld:
adiw ZH:ZL, 1
movw mp16uH:mp16uL, YH:YL
ldi mc16uL, 16 ; load 16
clr mc16uh ; into multiplier
rcall mpy16u_bld ; and multiply
add m16u0, XH ; Add current value to stack
clr XH
adc m16u1, XH ; carry as needed
movw YH:YL, m16u1:m16u0
dec XL ; This keeps us from
brne ascii_to_bin_hex_loop_bld
ascii_to_bin_hex_end_bld:
movw TempH:Temp, YH:YL
pop YH
pop YL
pop Temp2
pop XL
pop XH
ret
uart_put_string_bld:
; put a null-terminated string to the uart
; Z should be pointing to the beginning of the string in RAM
clr uart_char
st Z, uart_char
ldi ZL, LOW(STRING_SCRATCH)
ldi ZH, HIGH(STRING_SCRATCH)
uart_put_string_loop_bld:
ld uart_char, Z+
cpi uart_char, 0
breq uart_put_string_done_bld
rcall uart_put_char_bld
rjmp uart_put_string_loop_bld
uart_put_string_done_bld:
ret
crlf_bld:
ldi uart_char, CR
rcall uart_put_char_bld
ldi uart_char, LF
rcall uart_put_char_bld
ret
uart_put_char_t_bld:
sbis RS232_INVALID_IN_PORT, RS232_INVALID
rjmp uart_put_char_t_done_bld
push Temp
in Temp, UCSRA
sbr Temp, (1<
January 23rd, 2006 at 6:55 pm
I’ve never worked with Atmel stuff: is that an 8051? What do you use for the physical programmer? I’ve only done PIC but there are a number of things that would be better done using 8051.
January 24th, 2006 at 12:12 am
It has some things in common with the 8051 and some things in common with the venerable 8080. You can see the instruction set in the datasheet for the part – just go to digicrime’s web site (http://www.digikey.com) and type in AtMega8, then click on the data sheet. The programmer I use is the $50 STK500, which connects to the serial port of any wintel. There are several other programmers and combination programmer/ICEs, in varying price levels. The AVR is definately the poor man’s microcontroller – it’s got a lot of example code at http://www.avrfreaks.net, it’s a fairly cheap part, the programmer for it is very cheap, and it’s got a free C compiler (Gcc-avr).
On the other hand, it doesn’t have the noise immunity of the PIC parts, and is less hardy in some other ways. But the instruction set is much easier to read, and it’s much less of a PITA to make it do things. It’s very easy to code for, actually.
If you want to learn a new chip, I’d suggest the TI MSP430 – there’s a much larger future for this part – the AVR is more a hobbyist part (although you certainly can do some pretty advanced things with a high end AVR) and it’s ill suited to things like 3 phase motion control.
January 25th, 2006 at 10:21 pm
any three axis motion control I’m going to be doing will be software in teh computer pushing drivers via the parallel port, a la the Enhanced Machine Controller. The AVR-style stuff I’m interested in would be interfacing with hard disc drives to make small, portable data acquisition systems with enormous storage space (so they can stay in the field for six months.) Alas, that relies on available 8051 IDE libraries, so probably the AVR isn’t the right thing for me currently. Still: that’s very cool. Not too many people can write a bootloader.
January 25th, 2006 at 10:28 pm
certainly you will find AtMega IDE libraries.. avrfreaks.net has rather a lot of that kind of thing. Compact flash IO, LCD IO, whatnot.. there’s lots of goodies to pick from.
January 28th, 2006 at 5:27 pm
I was just looking at that, actually. I might get an AVR and play some games.
March 10th, 2006 at 2:44 pm
Your comments in this code read, to my ear, like a kind of avant-garde beat poetry, Gertrude Stein-esq. Witness, semicolon poetry, in five stanzas:
1)
translate ascii to binary / store bytes (high)
store bytes, compute checksum
special case: odd number of bytes
but we do words so need 2 decs
go around again?
2)
grab CRC, store CRC
…
compare CRC to stored —
if it doesnt’ match, err
matches, so program part
…
use Y ptr to access: stored data for this line
(Temp3
contains
countdown)
…
(… max flash addr to write)
keeps us from writing bootloader
which would put
us in NWRW state
and
be
bad
3)
atmel did a binary sweep
but we do a slower
and less
reliable upward rise
because it’s simpler
4)
This is a little more complicated than the straight case
because we need to determine if the digit is 0-9 or A-F
The basic idea here is that for each digit we read,
we subtract ‘0’ from it..
try and see if it is 0-9
… then do your stuff
if not, load again
make uppercase
try with a ‘A’
subtract
add 10 to get correct value
add 10 to get correct value
…
and multiply
Add current value to stack
carry as needed
5)
wait for space
(I’ll be ba-ack)
wait for complete transmissionnn1