Bootloader_non_block.rar

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

Dokonalem malych zmian - jesli urwie sie komunikacja z komputerem (podczas przesylania strony do zapisu nie bedzie transmisji przez 1s), to bootloader sie niejako resetuje, nie ma juz tego efektu zawieszenia, gdy on czeka na kolejne bajty. Oczywiscie nic za darmo - program urosl do 366 bajtow.

  • Bootloader_non_block.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_non_block.rar > main.c

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

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

/* biblioteki avr-libc */
#include & lt; stdbool.h & gt;
#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

/* ustawienia bitów konfiguracyjnych UART */
#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 uint16_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 */
uint16_t Received_Char;

/* wysy?anie znaku '?' do odebrania znaku 'u' lub up?yni?cia czasu
* oczekiwania */
for ( uint8_t Retries_Left = BOOT_WAIT * 10; Retries_Left; --Retries_Left )
{
UART_TX_Byte( '?' );

if ( ( uint8_t )UART_RX_Wait( 100 ) == 'u' )
{
/* definicja zmiennych */
bool Is_Comm_Lost = false;

while ( 1 )
{
/* odebranie znaku */
uint16_t Received_Char = UART_RX_Wait( 1000 );

if ( ( uint8_t )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 " ) );
}
else if ( ( uint8_t )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 */
Received_Char = UART_RX_Wait( 1000 );
if ( !Received_Char || Received_Char & gt; 0xff )
break;

/* zape?nienie bufora strony */
for ( uint16_t Byte_Address = 0;
Byte_Address & lt; SPM_PAGESIZE; Byte_Address += 2 )
{
/* próba odebrania m?odszego bajtu s?owa z pami?ci
* programu */
if ( ( Received_Char = UART_RX_Wait( 1000 ) )
& gt; 0xff )
{
Is_Comm_Lost = true;
break;
}

uint16_t Instruction = Received_Char;

/* próba odebrania starszego bajtu s?owa z pami?ci
* programu */
if ( ( Received_Char = UART_RX_Wait( 1000 ) )
& gt; 0xff )
{
Is_Comm_Lost = true;
break;
}

Instruction += Received_Char & lt; & lt; 8;

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

if ( Is_Comm_Lost )
break;

/* 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
{
/* jeśli odebrano inny znak lub up?yn?? czas oczekiwania na
* odpowiedź, to zako?czenie pracy bootloadera */
break;
}
}

/* jeśli komunikacja z komputerem urwa?a si? podczas przesy?ania
* strony, to bootloader jest uruchamiany ponownie, w przeciwnym
* przypadku zako?czenie pracy bootloadera */
if ( Is_Comm_Lost )
Retries_Left = BOOT_WAIT * 10;
else
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 */
#if defined( __AVR_HAVE_JMP_CALL__ )
asm volatile (
" jmp 0 " " \n\t "
: : );
#elif defined( EIND )
EIND = 0;
asm volatile (
" eijmp " " \n\t "
: : " z " ( 0 ) );
#else
asm volatile (
" ijmp " " \n\t "
: : " z " ( 0 ) );
#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 uint16_t _UART_RX_Wait(
uint16_t Timeout )
{
do
{
if ( UCSRA & 1 & lt; & lt; RXC )
return ( uint16_t )UDR;

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

return 0xffff;
}


Bootloader_non_block.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]).