Bootloader.rar

AVR Boot Loader - który ładnie i szybko działa / USB

master_pablo -> oczywi¶cie dałem return 0; na końcu tej funkcji oczekuj±cej na znak. Hmmm ale do jakich¶ innych celów to fajny pomysł aby używać w tym przypadku jako parametru zwrotnego uint16_t - bo wtedy rozumiem, że można byłoby wpisywać zamiast return -1; to return 0xFFFF; Dzięki czemu je¶li zwrócona warto¶ć będzie większa od 255 to znaczy że TimeOut. No ja myslalem, ze wlasnie takie bylo Twoje pierwotne zamierzenie w tej funkcji. A czy bedziesz zwracal -1 czy 0xFFFF, to w zasadzie bez roznicy, bo -1 to wlasnie 0xFFFF :). Tak czy siak, w programie to nigdzie nie jest wykorzystywane, wiec rownie dobrze mozna zwracac uint8_t. Hmmm ale jak to było, że parametr wyj¶ciowy funkcji był uint16_t a było wpisane return -1; i to działało? czy nie powinien on być typu int ? Tak nigdy nie bylo. Pierwotnie bylo int, potem int16_t, a teraz uint8_t. Zreszta nawet jakby byl zly typ, to program by sie kompilowal, ale z ostrzezeniem. ... odno¶nie UCSRB = 0; i TXEN - to racja, ale na szczę¶cie w przypadku naszego bootloadera nie musimy się martwić tak± kwesti± jak opisałe¶ na końcu proponuj±c: UCSRB = 0; _delay_us( UART_BYTE_TIME ); ponieważ wysyłane znaki nie s± istotne z punktu widzenia poprawnego działania bootloadera a szczególnie te '+' plusiki - to tylko sygnał dla PC że może dalej nadawać, a i tak zawsze po wysłaniu znaku '+' czeka na odpowiedĽ z PC - więc taki przypadek błędu nie powinien nigdy zaj¶ć. Ostatecznie więc chyba się zgodzisz, że możemy zostawić samo UCSRB =0; ???Oczywiscie masz racje. Ja to w wersji z poprzedniego posta dopisalem, bo czemu nie, jak jeszcze ponad 150 bajtow wolnych sie marnuje. A w razie czego jest co usunac, zeby zaoszczedzic te 8 bajtow :). Przeniesione z poprzedniego posta: w zalaczniku jest najnowsza wersja bootloader, korzystajaca juz z biblioteki boot.h z avr-libc zamiast kodu BoskiegoDialera. Zajmuje 350 bajtow, tak wiec mniej niz pierwotna wersja :). Mam nadzieje, ze jest w pelni uniwersalna, w kazdym razie da sie ja bezblednie skompilowac dla chyba kazdego mikrokontrolera. Do dalszych testow nie mam sprzetu.

  • Bootloader.rar
    • Bootloader.elf
    • main.o
    • Array
    • Bootloader.sym
    • main.c
    • Bootloader.pnproj
    • Bootloader.map
    • main.lst
    • Makefile
    • Instrukcja.txt
    • Bootloader.lss
    • Bootloader.hex
    • Bootloader.pnps


Download file - link to post

Bootloader.rar > main.c

////////////////////////////////////////////////////////////////////////////////
/* Bootloader
* Autor: Miros?aw Kardaś (2009-06-16)
* Modyfikacje: Pawe? Szramowski (2009-06-30) */
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/* Do??czenie bibliotek */
////////////////////////////////////////////////////////////////////////////////

/* biblioteki avr-libc */
#include & lt; stdint.h & gt;
#include & lt; avr/boot.h & gt;
#include & lt; avr/io.h & gt;
#include & lt; avr/pgmspace.h & gt;
#include & lt; avr/wdt.h & gt;
#include & lt; util/delay.h & gt;
#include & lt; util/setbaud.h & gt;

////////////////////////////////////////////////////////////////////////////////
/* Definicje sta?ych programowych i makr */
////////////////////////////////////////////////////////////////////////////////

/* wersja bootloadera */
#define BOOTLOADER_VERSION 1

/* ustawienia UART */
#define UART_DATA_BITS 8
#define UART_PARITY 'n'
#define UART_STOP_BITS 1

/* czas przesy?ania jednego znaku przez UART [us] */
#if UART_PARITY == 'n'
#define UART_BYTE_TIME \
( 1000000UL / ( BAUD / ( 1 + UART_DATA_BITS + UART_STOP_BITS ) ) )
#elif ( UART_PARITY == 'e' ) || ( UART_PARITY == 'o' )
#define UART_BYTE_TIME \
( 1000000UL / ( BAUD / ( 1 + UART_DATA_BITS + 1 + UART_STOP_BITS ) ) )
#endif

/* podstawienie nazwa rejestrów UART */
#ifndef UCSRA
#define UCSRA UCSR0A
#endif
#ifndef UCSRB
#define UCSRB UCSR0B
#endif
#ifndef UCSRC
#define UCSRC UCSR0C
#endif
#ifndef UBRRL
#define UBRRL UBRR0L
#endif
#ifndef UBRRH
#define UBRRH UBRR0H
#endif
#ifndef UDR
#define UDR UDR0
#endif

/* podstawienie nazw bitów w rejestrze UCSRA */
#ifndef RXC
#define RXC RXC0
#endif
#ifndef TXC
#define TXC TXC0
#endif
#ifndef UDRE
#define UDRE UDRE0
#endif
#ifndef FE
#define FE FE0
#endif
#ifndef DOR
#define DOR DOR0
#endif
#ifndef UPE
#define UPE UPE0
#endif
#ifndef U2X
#define U2X U2X0
#endif
#ifndef MPCM
#define MPCM MPCM0
#endif

/* podstawienie nazw bitów w rejestrze UCSRB */
#ifndef RXCIE
#define RXCIE RXCIE0
#endif
#ifndef TXCIE
#define TXCIE TXCIE0
#endif
#ifndef UDRIE
#define UDRIE UDRIE0
#endif
#ifndef RXEN
#define RXEN RXEN0
#endif
#ifndef TXEN
#define TXEN TXEN0
#endif
#ifndef UCSZ2
#define UCSZ2 UCSZ02
#endif
#ifndef RXB8
#define RXB8 RXB80
#endif
#ifndef TXB8
#define TXB8 TXB80
#endif

/* podstawienie nazw bitów w rejestrze UCSRC */
#ifndef UMSEL
#ifdef UMSEL0
#define UMSEL UMSEL0
#else
#define UMSEL UMSEL00
#define UMSEL0 UMSEL00
#define UMSEL1 UMSEL01
#endif
#endif
#ifndef UPM1
#define UPM1 UPM01
#endif
#ifndef UPM0
#define UPM0 UPM00
#endif
#ifndef USBS
#define USBS USBS0
#endif
#ifndef UCSZ1
#define UCSZ1 UCSZ01
#endif
#ifndef UCSZ0
#define UCSZ0 UCSZ00
#endif
#ifndef UCPOL
#define UCPOL UCPOL0
#endif

#if UART_DATA_BITS == 5
#define UCSRB_DATA_BITS ( 0 & lt; & lt; UCSZ2 )
#define UCSRC_DATA_BITS ( 0 & lt; & lt; UCSZ1 | 0 & lt; & lt; UCSZ0 )
#elif UART_DATA_BITS == 6
#define UCSRB_DATA_BITS ( 0 & lt; & lt; UCSZ2 )
#define UCSRC_DATA_BITS ( 0 & lt; & lt; UCSZ1 | 1 & lt; & lt; UCSZ0 )
#elif UART_DATA_BITS == 7
#define UCSRB_DATA_BITS ( 0 & lt; & lt; UCSZ2 )
#define UCSRC_DATA_BITS ( 1 & lt; & lt; UCSZ1 | 0 & lt; & lt; UCSZ0 )
#elif UART_DATA_BITS == 8
#define UCSRB_DATA_BITS ( 0 & lt; & lt; UCSZ2 )
#define UCSRC_DATA_BITS ( 1 & lt; & lt; UCSZ1 | 1 & lt; & lt; UCSZ0 )
#elif UART_DATA_BITS == 9
#define UCSRB_DATA_BITS ( 1 & lt; & lt; UCSZ2 )
#define UCSRC_DATA_BITS ( 1 & lt; & lt; UCSZ1 | 1 & lt; & lt; UCSZ0 )
#endif

#if UART_PARITY == 'n'
#define UCSRC_PARITY ( 0 & lt; & lt; UPM1 | 0 & lt; & lt; UPM0 )
#elif UART_PARITY == 'e'
#define UCSRC_PARITY ( 1 & lt; & lt; UPM1 | 0 & lt; & lt; UPM0 )
#elif UART_PARITY == 'o'
#define UCSRC_PARITY ( 1 & lt; & lt; UPM1 | 1 & lt; & lt; UPM0 )
#endif

#if UART_STOP_BITS == 1
#define UCSRC_STOP_BITS ( 0 & lt; & lt; USBS )
#elif UART_STOP_BITS == 2
#define UCSRC_STOP_BITS ( 1 & lt; & lt; USBS )
#endif

/* makro zamieniaj?ce podany argument na ?a?cuch znaków */
#define TOSTRING( x ) STRINGIFY( x )
#define STRINGIFY( x ) #x

////////////////////////////////////////////////////////////////////////////////
/* Deklaracje funkcji statycznych */
////////////////////////////////////////////////////////////////////////////////

static void UART_TX_Byte(
const uint8_t Data );

static void UART_TX_String_P(
const prog_char *String_Ptr );

static uint8_t _UART_RX_Wait(
uint16_t Timeout );

/* Makro przeliczaj?ce argument w milisekundach na przyjmowan? przez funkcj?
* _UART_RX_Wait wielokrotnośae czasu przesy?ania jednego znaku. */
#define UART_RX_Wait( x ) _UART_RX_Wait( ( x * 1000UL ) / UART_BYTE_TIME )

////////////////////////////////////////////////////////////////////////////////
/* Definicje funkcji */
////////////////////////////////////////////////////////////////////////////////

static void __vectors(
void )
__attribute__ (( section( " .vectors " ), naked, used ));
static void __vectors(
void )
{
/* skok do sekcji .init2 (konieczny ze wzgl?du na umieszczanie sta?ych z
* pami?ci programu pomi?dzy sekcjami .vectors a .init0, a wi?c na samym
* pocz?tku programu w przypadku wykorzystania opcji -nostartfiles */
asm (
" rjmp __init2 " " \n\t "
: : );
}

static void __init2(
void )
__attribute__ (( section( " .init2 " ), naked, used ));
static void __init2(
void )
{
/* inicjalizacja wskaźnika stosu, rejestru z zerem i rejestru flag */
asm volatile (
" out __SP_L__, %A0 " " \n\t "
" out __SP_H__, %B0 " " \n\t "
" clr __zero_reg__ " " \n\t "
" out __SREG__, __zero_reg__ " " \n\t "
: : " r " ( ( uint16_t )( RAMEND ) ) );
}

#ifdef WDIF
static void __init3(
void )
__attribute__ (( section( " .init3 " ), naked, used ));
static void __init3(
void )
{
/* wy??czenie watchdoga (w tych mikrokontrolerach, w których watchdog
* ma mo?liwośae generowania przerwania pozostaje on te? aktywny po
* resecie) */
MCUSR = 0;
_WD_CONTROL_REG = 1 & lt; & lt; _WD_CHANGE_BIT | 1 & lt; & lt; WDE;
_WD_CONTROL_REG = 0;
}
#endif

static void __init9(
void )
__attribute__ (( section( " .init9 " ), naked, used ));
static void __init9(
void )
{
/* skok do funkcji main */
asm (
" rjmp main " " \n\t "
: : );
}

int main(
void )
__attribute__ (( noreturn ));
int main(
void )
{
/* konfiguracja i w??czenie interfejsu UART */
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA = 1 & lt; & lt; U2X;
#else
UCSRA = 0;
#endif
#ifdef URSEL
UCSRC = 1 & lt; & lt; URSEL | UCSRC_DATA_BITS | UCSRC_PARITY | UCSRC_STOP_BITS;
#else
UCSRC = UCSRC_DATA_BITS | UCSRC_PARITY | UCSRC_STOP_BITS;
#endif
UCSRB = 1 & lt; & lt; RXEN | 1 & lt; & lt; TXEN | UCSRB_DATA_BITS;

/* deklaracja zmiennych */
uint8_t Retries_Left, Received_Char;

/* wysy?anie znaku '?' do odebrania znaku 'u' lub up?yni?cia czasu
* oczekiwania */
for ( Retries_Left = BOOT_WAIT * 10; Retries_Left & gt; 0;
--Retries_Left )
{
if ( ( Received_Char = UART_RX_Wait( 100 ) ) == 'u' )
break;

UART_TX_Byte( '?' );
}

if ( Received_Char == 'u' )
{
Retries_Left = 10;
while ( 1 )
{
/* odebranie znaku */
Received_Char = UART_RX_Wait( 100 );

if ( Received_Char == 'i' )
{
/* jeśli odebrano znak 'i', to wys?anie ci?gu znaków
* identyfikuj?cych mikrokontroler i bootloader */
UART_TX_String_P( PSTR( " \r\n " " & "
TOSTRING( SPM_PAGESIZE ) " , "
TOSTRING( BLS_START ) " , "
TOSTRING( MCU ) " , "
TOSTRING( XTAL ) " , "
TOSTRING( BOOTLOADER_VERSION )
" * " " \r\n " ) );

/* odmierzanie czasu rozpoczyna si? od nowa */
Retries_Left = 10;
}
else if ( Received_Char == 'w' )
{
/* odczekanie do zako?czenia operacji na pami?ci EEPROM
* i Flash */
eeprom_busy_wait();
boot_spm_busy_wait();

/* kasowanie ca?ej pami?ci programu */
for ( uint32_t Page_Address = 0; Page_Address & lt; BLS_START;
Page_Address += SPM_PAGESIZE )
{
/* skasowanie strony pami?ci */
boot_page_erase( Page_Address );
boot_spm_busy_wait();
}

/* programowanie pami?ci programu */
for ( uint32_t Page_Address = 0; Page_Address & lt; BLS_START;
Page_Address += SPM_PAGESIZE )
{
/* wys?anie znaku '+' */
UART_TX_Byte( '+' );

/* jeśli odebrano zero lub up?yn?? czas oczekiwania na
* odpowiedź, to zako?czenie pracy bootloadera */
if ( !UART_RX_Wait( 500 ) )
break;

/* zape?nienie bufora strony */
for ( uint16_t Byte_Address = 0;
Byte_Address & lt; SPM_PAGESIZE; Byte_Address += 2 )
{
/* przygotowanie instrukcji */
uint16_t Instruction = ( uint16_t )UART_RX_Wait( 500 );
Instruction += UART_RX_Wait( 500 ) & lt; & lt; 8;

/* zapisanie instrukcji do bufora */
boot_page_fill( Byte_Address, Instruction );
}

/* zapisanie strony pami?ci */
boot_page_write( Page_Address );
boot_spm_busy_wait();
}

/* odblokowanie sekcji Read-While-Write */
boot_rww_enable();

/* zako?czenie pracy bootloadera */
break;
}
else if ( Received_Char == 'q' || !Retries_Left-- )
{
/* jeśli odebrano znak 'q' lub up?yn?? czas oczekiwania na
* odpowiedź, to zako?czenie pracy bootloadera */
break;
}
}
}

/* wy??czenie interfejsu UART (dzieje si? to dopiero po zako?czeniu
* wysy?ania) i odczekanie do ko?ca ewentualnej transmisji */
UCSRB = 0;
_delay_us( UART_BYTE_TIME );

/* skok do w?aściwego programu */
#ifdef __AVR_HAVE_JMP_CALL__
asm volatile (
" jmp 0 " " \n\t "
: : );
#else
asm volatile (
" clr r30 " " \n\t "
" clr r31 " " \n\t "
" ijmp " " \n\t "
: : );
#endif

/* niesko?czona p?tla (konieczna, by kompilator nie wygenerowa?
* niepotrzebnego kodu) */
while ( 1 )
{}
}

static void UART_TX_Byte(
const uint8_t Data )
{
while ( !( UCSRA & 1 & lt; & lt; UDRE ) )
{}

UDR = Data;
}

static void UART_TX_String_P(
const prog_char *String_Ptr )
{
uint8_t Single_Char;

while ( ( Single_Char = pgm_read_byte( String_Ptr++ ) ) )
UART_TX_Byte( Single_Char );
}

static uint8_t _UART_RX_Wait(
uint16_t Timeout )
{
do
{
if ( UCSRA & 1 & lt; & lt; RXC )
return UDR;

_delay_us( UART_BYTE_TIME );
} while ( Timeout-- );

return 0;
}


Bootloader.rar > Instrukcja.txt

W wykorzystywanym mikrokontrolerze nale?y zaprogramowaae (wartośae 0) bit BOOTRST i ustawiae bity BOOTSZ tak, by sekcja bootloadera mia?a co najmniej 256 s?ów.
Adres s?owa startowego bootloadera podany przy opisie fusebitów nale?y pomno?yae przez dwa, by uzyskaae adres bajtu startowego, który nale?y przypisaae do zmiennej BLS_START w makefile. Nale?y równie? zmieniae nazw? (MCU) i cz?stotliwośae pracy (F_CPU [Hz]) mikrokontrolera, a w razie potrzeby szybkośae portu szeregowego (BAUD_RATE [bps]) i czas oczekiwania przed uruchomieniem za?adowanego programu (BOOT_WAIT [s]).