ADVERTISEMENT

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.


Download file - link to post
  • Bootloader_non_block.rar
    • Bootloader.sym
    • Bootloader.pnps
    • Makefile
    • Bootloader.elf
    • Instrukcja.txt
    • .dep
      • main.o.d
    • main.o
    • main.lst
    • Bootloader.pnproj
    • Bootloader.map
    • Bootloader.hex
    • main.c
    • Bootloader.lss


Bootloader_non_block.rar > Instrukcja.txt

W wykorzystywanym mikrokontrolerze nale¿y zaprogramowaæ (wartoœæ 0) bit BOOTRST i ustawiæ 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¿yæ przez dwa, by uzyskaæ adres bajtu startowego, który nale¿y przypisaæ do zmiennej BLS_START w makefile. Nale¿y równie¿ zmieniæ nazwê (MCU) i czêstotliwoœæ pracy (F_CPU [Hz]) mikrokontrolera, a w razie potrzeby szybkoœæ portu szeregowego (BAUD_RATE [bps]) i czas oczekiwania przed uruchomieniem za³adowanego programu (BOOT_WAIT [s]).


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œæ 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œæ 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;
}