Hexload is yet another tool for uploading firmware to small devices, its goals are:
The program is devided into 2 parts, the main executable, which reads command line parameters and the firmware, and the so called loader, a modul that pumps the data into our device.
You can browse the whole folder.
The newest build is also in my local portage, usefull when using gentoo.
Source of the test- loader:
file: http://darcs.erazor-zone.de/hexload/loaders/test.c
/** example loader module @name avr-types.c @version 0.1 @author Alexander 'E-Razor' Krause <admin@erazor-zone.de> 01.03.2005 Alexander 'E-Razor' Krause <admin@erazor-zone.de> -ctags added 15.02.2005 V 0.01 Alexander 'E-Razor' Krause <admin@erazor-zone.de> -initial release */ #include "hexload.h" #include "ihex.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <getopt.h> int do_all; const char *type; const char *default_loader_opts[] = { [0] = "foo", [1] = "bar", [2] = "help", [3] = NULL }; void _init(void) { printf("testlib: init called\n"); } void _fini(void) { printf("testlib: fini called\n"); } void print_help(void) { printf("testlib: help called\n"); } int main (char *opt) { unsigned long int value; char *loader_opts, *opt_value; printf("testlib: verbose==%d,loader-options==%s\n",*pverbose,opt); loader_opts=opt; while (*loader_opts != '\0') { switch (getsubopt (&loader_opts, default_loader_opts, &opt_value)) { case 0: printf("foo=%s",opt_value); break; case 1: printf("bar=%s",opt_value); break; case 2: print_help(); break; default: printf ("Unknown loader option `%s'\n",opt_value); break; } } for (value=0;value<=100;value++) { /*wait 10ms (total time =1sec)*/ usleep(10*1000); (*pprogress_bar)(value,100); } for (value=0;value<=10000;value+=10) { //usleep(10*1000); //wait 10ms (total time =1sec) sleep(1); (*pprogress_bar)(value,10000); } }
Programming of AVR- devices via SPI by using the bit-banging mode of an USB-ftdi-UART chip (USB 2 serial converter).
The programmer isn't that fast (nearly 1kBytes per second) but quite flexible (parallel programming is possible too) and tiny (about 10x15mm).
Thats my first loader, it also provides some header files for implementing SPI- programming for other interfaces.
Look here:
file: http://darcs.erazor-zone.de/hexload/loaders/avr/avr-spi.c
/** AVR-functions for spi @name avr-spi.c @version 0.1 @author Alexander 'E-Razor' Krause <admin@erazor-zone.de> 15.04.2005 Alexander 'E-Razor' Krause <admin@erazor-zone.de> -support for devices without pages (use page-count as flash size) -different adress ranges supportet when checking the flash -error counting added 01.03.2005 Alexander 'E-Razor' Krause <admin@erazor-zone.de> -.h files renamed to .c to fit the convention -ctags added to do: support for different address ranges when checking the flash 15.02.2005 V 0.01 Alexander 'E-Razor' Krause <admin@erazor-zone.de> -initial release */ #include "hexload.h" #include "avr-types.c" /** send the Programming Enable instruction (see page 235) realized via spi_write with data ac:53:OO:XX */ char avr_send_programming_enable(void) { unsigned char data[]={0xac,0x53,0x00,0x00}; if (*pverbose>0) printf(">>Programming Enable "); if ( (spi_echo_buffer(data,4)==4) ){ if (data[2]==0x53) { if (*pverbose>0) printf("done\n"); } else { if (*pverbose>0) printf("failed\n response does not match (0x53!=0x%02x)\n",data[2]); return(-1); } } else { if (*pverbose>0) printf("failed\n"); return(-1); } return(0); } /** get the active devicetype and load the settings, given by avr-types.h send the Read Signature Byte Instruction (see page 235) realized via spi_write with data 30:00:02:00 */ char avr_get_devicetype(void) { unsigned char data[]={0x30,0x00,0x02,0x00}; if (*pverbose>0) printf(">>Device Type "); if ( (spi_echo_buffer(data,4)==4) ){ set_avr_type(data[3]); if (*pverbose>0) printf("%s(%02x)\n",avr_device_str,(unsigned char)data[3]); } else { if (*pverbose>0) printf("failed\n"); return(-1); } return(0); } /** send the Chip Erase instruction (see page 235) realized via spi_write with data ac:80:00:00 */ char avr_send_erase(void) { char data[]={0xac,0x80,0x00,0x00}; if (*pverbose>0) printf(">>Chip Erase "); if ( (spi_echo_buffer(data,4)==4) ){ if (*pverbose>0) printf("done\n"); } else { if (*pverbose>0) printf("failed\n"); return(-1); } usleep(avr_type[INDEX_AVR_WD_ERASE]*1000); return(0); } /** 1. load page 1.1 load low-byte (Load Program Memory Page) 1.2 load high-byte 1.3 do 1.1 and 1.2 until page is full or we've downloaded everything (128pages each 32words, 1 word=2 bytes) (see page 224) 2. write page 2.2 send Write Program Memory Page 2.3 load the next page if required */ char avr_write_flash( void (*pprogress)(unsigned long int, unsigned long int)) { unsigned char data[MAX_SPI_BUFFER_OVER4*4]; unsigned int ac_mrecord_position, ac_page_position, ac_mrecord, available_bytes, ac_page_adress; struct merged_hex_record* pac_mrecord; unsigned int tmp_i,tmp_i2; unsigned long int bytes_now=0; if (*pverbose>0) printf(">>Programming \n\b\r>>Programming "); /*write while merged records are aviable*/ for (ac_mrecord=0;ac_mrecord<(*pmerged_records_count);ac_mrecord++) { /*select ac_mrecord*/ pac_mrecord=(struct merged_hex_record*) (pmerged_records+ac_mrecord); ac_mrecord_position=0; /*calculate a page offset if needed*/ /*btw: we need ac_page_adress later in Write Programm Memory*/ ac_page_adress=pac_mrecord->adress/avr_type[INDEX_AVR_PAGE_SIZE]; ac_page_position=pac_mrecord->adress%avr_type[INDEX_AVR_PAGE_SIZE]; if (*pverbose>1) printf(" Page adress=%04x, offset=%02x\n",ac_page_adress,ac_page_position); /*write ac_mrecord*/ while( (ac_mrecord_position<pac_mrecord->byte_count) ) { /*load a new page and write data until 1. data is aviable and 2. page is not full */ while ( (ac_mrecord_position<pac_mrecord->byte_count) && (ac_page_position<(avr_type[INDEX_AVR_PAGE_SIZE]) )) { /*prepare the data*/ available_bytes=pac_mrecord->byte_count-ac_mrecord_position; if (available_bytes>avr_type[INDEX_AVR_PAGE_SIZE]) available_bytes=avr_type[INDEX_AVR_PAGE_SIZE]; if (*pverbose>2) printf(" %d bytes to write\n",available_bytes); /* use of a spi buffer, that speed's up things a bit and reduces cpu usage */ for (tmp_i=0; tmp_i<((available_bytes>MAX_SPI_BUFFER_OVER4)?MAX_SPI_BUFFER_OVER4:available_bytes); tmp_i++) { /*dump first adress*/ if (tmp_i==0) if (*pverbose>2) printf("%d-",ac_page_position); /*Load Programm Memory Page*/ tmp_i2=tmp_i*4; /* page adress low */ if (avr_type[INDEX_AVR_TYPE]!=5) { data[tmp_i2]=0x40+((0x01&tmp_i)*8); /* page adress high */ data[tmp_i2+1]=0x00; /* position in the page */ data[tmp_i2+2]=ac_page_position/2; } else { data[tmp_i2]=0x40+((0x01&ac_page_adress)*8); /* the attiny12 does not have pages, but here is the MSB of our adress*/ data[tmp_i2+1]=(0x0100&((ac_page_adress)/2))>>8; data[tmp_i2+2]=(0xff&((ac_page_adress)/2)); } ac_page_position++; /* data */ data[tmp_i2+3]=pac_mrecord->data[ac_mrecord_position++]; if (*pverbose>2) printf("%02x.%02x.%02x.%02x|", data[tmp_i2],data[tmp_i2+1],data[tmp_i2+2],data[tmp_i2+3]); } if (*pverbose>2) printf("\n"); if (*pverbose>1) printf(">>(4*%d bytes) ",tmp_i); /*send only*/ if ( (spi_write_buffer(data,4*tmp_i)==4*tmp_i )){ bytes_now+=tmp_i; (*pprogress)(bytes_now,*pmerged_records_bytecount); if (*pverbose>1) printf("done\n"); } else { if (*pverbose>1) printf("failed\n"); return(-1); } } /*write the page*/ if (*pverbose>1) printf(">>Page (size %d/%d) at adress 0x%04x ", ac_page_position, avr_type[INDEX_AVR_PAGE_SIZE], ac_page_adress); if (avr_type[INDEX_AVR_TYPE]!=5) { data[0]=0x4c; data[1]=(0xf8&ac_page_adress)>>3; data[2]=(0x07&ac_page_adress)<<5; data[3]=0; if ( (spi_write_buffer(data,4)==4) ){ if (*pverbose>1) printf("done\n"); } else { if (*pverbose>1) printf("failed\n"); return(-1); } } usleep(avr_type[INDEX_AVR_WD_FLASH]*1000); ac_page_adress++; ac_page_position=0; } } if (*pverbose>0) printf("done\n"); return(0); } /** read out the full adress range, given by merged_hex_record */ char avr_check( void (*pprogress)(unsigned long int, unsigned long int)) { /* read out the data */ unsigned char data[MAX_SPI_BUFFER_OVER4*4]; unsigned int tmp_i, tmp_i2,errors=0; struct merged_hex_record* pac_mrecord; unsigned int ac_mrecord_position, available_bytes, ac_adress,ac_mrecord; unsigned long int bytes_now=0; if (*pverbose>0) printf(">>Checking \n\b\r>>Checking "); if (*pverbose>1) printf("\n"); for (ac_mrecord=0;ac_mrecord < (*pmerged_records_count); ac_mrecord++) { /*select active mrecord*/ pac_mrecord=(struct merged_hex_record*) (pmerged_records+ac_mrecord); ac_mrecord_position=0; while ( (ac_mrecord_position<pac_mrecord->byte_count) ) { available_bytes=pac_mrecord->byte_count-ac_mrecord_position; /*generate packet*/ for (tmp_i=0; tmp_i<((available_bytes>MAX_SPI_BUFFER_OVER4)?MAX_SPI_BUFFER_OVER4:available_bytes); tmp_i++ ) { /*Read Programm Memory*/ tmp_i2=tmp_i*4; data[tmp_i2 ]=0x20+((0x01&tmp_i)*8); ac_adress=(pac_mrecord->adress/2)+ac_mrecord_position++/2; data[tmp_i2+1]=(0x0f00&ac_adress)>>8; data[tmp_i2+2]=(0x00ff&ac_adress); data[tmp_i2+3]=0x00; bytes_now++; //printf("%02x\n",ac_adress); } (*pprogress)(bytes_now,*pmerged_records_bytecount); /*send & receive*/ if (spi_echo_buffer(data,tmp_i*4)>0 ){ } else { if (*pverbose>0) printf("failed\n"); return(-1); } if (*pverbose>1) { /*check read data*/ for (tmp_i=0; tmp_i<((available_bytes>MAX_SPI_BUFFER_OVER4)?MAX_SPI_BUFFER_OVER4:available_bytes); tmp_i++) { if (data[tmp_i*4+3]==pac_mrecord->data[(ac_mrecord_position- (available_bytes>MAX_SPI_BUFFER_OVER4?MAX_SPI_BUFFER_OVER4:available_bytes)) +tmp_i]) { printf("."); } else { printf("!"); errors++; } } printf("\n"); } if (*pverbose>2) { /*dump read data*/ for (tmp_i=0; tmp_i<((available_bytes>MAX_SPI_BUFFER_OVER4)?MAX_SPI_BUFFER_OVER4:available_bytes); tmp_i++) { printf("%02x:",data[tmp_i*4+3]); } printf("\n"); } } } if (errors>0) { if (*pverbose>0) printf("failed\n"); printf("errors in flash found: %d\n",errors); } else { if (*pverbose>0) printf("done\n"); } return(0); }
darcs get http://darcs.erazor-zone.de/hexload/
2004-2005 © Alexander 'E-Razor' Krause