bootloader_ver_200.rar

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

master_pablo ---> jeszcze raz odnośnie tego kodu: if( uart_waitchar(500) < 1 ) goto CallApp; a w tej chwili: /* czy są jeszcze dane do zaprogramowania? jeśli brak to zakończ */ if ( !UART_RX_Wait( 500 ) ) break; chodzi o to, że jeśli wsad jest krótszy niż cała wolna pamięć do zaprogramowania to ma się zakończyć ta główna pętla programująca. Czyli jeśli PC ma coś do nadania to wysyła tam bajt większy niż 0, a jeśli już nie ma nic do nadania to albo nic nie wysyła albo wysyła 0. (inaczej w przypadku krótkiego wsadu wydawałoby się, że procek się zawiesił a on w tym czasie próbuje dokończyć pętlę programującą czekając ileś tam razy 500ms (tyle ile wolnych bajtów pozostaje poza wsadem) W związku z powyższym dokonałem też w kodzie lekkiej zmiany procedury: static uint8_t _UART_RX_Wait( uint16_t Timeout ) teraz może ona zwracać w tym przypadku uint8_t - a dzięki temu niechcąco kod się odchudził o 10bajtów - odnośnie moich wprowadzonych zmian w makefile i kodzie związanych z ramką - to uznałem pod naporem racjonalnych argumentów, że kolega ma w pełni rację i można to zostawić w kodzie - nawet tak jest lepiej - jak kolega zauważył ;) --------------- a teraz moje pytanko - bo obejrzałem dokładnie kodzik w main.c i proszę o wyjaśnienie - chociaż tak ogólnie - po co to przeliczanie??? #define UART_BYTE_TIME \ ( 1000000UL / ( BAUD / ( 1 + UART_DATA_BITS + UART_STOP_BITS ) ) ) żeby potem tego użyć tutaj: /* 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 ) jakie ma znaczenie przeliczanie na us - na razie zupełnie nie czaję o co w tym chodzi - chociaż widzę, że ładnie działa ;) ---------- aha i widzę że wyjąłeś z procedury wysyłającej znak - czekanie na zakończenie jego wysyłania i dopisałeś pod koniec /* wyłączenie interfejsu UART (stanie się to dopiero po zakończeniu * wysyłania) * tuż przedz UCSRB = 0; skąd ta pewność że nastąpi dopiero po ? .... na wszelki wypadek przesyłam źródła z moimi poprawkami

  • bootloader_ver_200.rar
    • prog.bat
    • Bootloader.elf
    • main.o
    • Bootloader_mirekk36.pnps
    • Bootloader.sym
    • appspace.S
    • main.c
    • Bootloader.map
    • main.lst
    • Bootloader_mirekk36.pnproj
    • Makefile
    • Instrukcja.txt
    • Bootloader.lss
    • Bootloader.hex
    • appspace.lst
    • appspace.h
    • appspace.o


Download file - link to post

bootloader_ver_200.rar > main.c

////////////////////////////////////////////////////////////////////////////////
/* Bootloader
* ( w oparciu o kod Ÿród?owy kolegi BoskiDialer /elektroda.pl/ )
* Autor: Miros?aw Kardaœ (2009-06-16)
* Modyfikacje: Pawe? Szramowski (2009-06-30) */
////////////////////////////////////////////////////////////////////////////////

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

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

/* biblioteki w?asne */
#include &quot; appspace.h &quot;

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

#define BOOTLOADER_VERSION &quot; 2 &quot;

#define UART_DATA_BITS 8
#define UART_PARITY 'n'
#define UART_STOP_BITS 1

#define UART_BYTE_TIME \
( 1000000UL / ( BAUD / ( 1 + UART_DATA_BITS + UART_STOP_BITS ) ) )

#define TOSTRING( x ) STRINGIFY( x )
#define STRINGIFY( x ) #x

////////////////////////////////////////////////////////////////////////////////
/* Deklaracje zmiennych globalnych i statycznych */
////////////////////////////////////////////////////////////////////////////////

static uint8_t g_Page_Buffer[ SPM_PAGESIZE ]
__attribute__ (( section( &quot; .noinit &quot; ) ));

////////////////////////////////////////////////////////////////////////////////
/* 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( &quot; .vectors &quot; ), 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 (
&quot; rjmp __init2 &quot; &quot; \n\t &quot;
: : );
}

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

#ifdef WDIF
static void __init3(
void )
__attribute__ (( section( &quot; .init3 &quot; ), 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 &amp; lt; &amp; lt; _WD_CHANGE_BIT | 1 &amp; lt; &amp; lt; WDE;
_WD_CONTROL_REG = 0;
}
#endif

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

int main(
void )
__attribute__ (( noreturn ));
int main(
void )
{
/* konfiguracja i w??czenie interfejsu UART */
#if UART_DATA_BITS == 5
#define UCSRB_DATA_BITS ( 0 &amp; lt; &amp; lt; UCSZ2 )
#define UCSRC_DATA_BITS ( 0 &amp; lt; &amp; lt; UCSZ1 | 0 &amp; lt; &amp; lt; UCSZ0 )
#elif UART_DATA_BITS == 6
#define UCSRB_DATA_BITS ( 0 &amp; lt; &amp; lt; UCSZ2 )
#define UCSRC_DATA_BITS ( 0 &amp; lt; &amp; lt; UCSZ1 | 1 &amp; lt; &amp; lt; UCSZ0 )
#elif UART_DATA_BITS == 7
#define UCSRB_DATA_BITS ( 0 &amp; lt; &amp; lt; UCSZ2 )
#define UCSRC_DATA_BITS ( 1 &amp; lt; &amp; lt; UCSZ1 | 0 &amp; lt; &amp; lt; UCSZ0 )
#elif UART_DATA_BITS == 8
#define UCSRB_DATA_BITS ( 0 &amp; lt; &amp; lt; UCSZ2 )
#define UCSRC_DATA_BITS ( 1 &amp; lt; &amp; lt; UCSZ1 | 1 &amp; lt; &amp; lt; UCSZ0 )
#elif UART_DATA_BITS == 9
#define UCSRB_DATA_BITS ( 1 &amp; lt; &amp; lt; UCSZ2 )
#define UCSRC_DATA_BITS ( 1 &amp; lt; &amp; lt; UCSZ1 | 1 &amp; lt; &amp; lt; UCSZ0 )
#endif

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

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

#include &amp; lt; util/setbaud.h &amp; gt;

UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA = 1 &amp; lt; &amp; lt; U2X;
#endif
UCSRC = 1 &amp; lt; &amp; lt; URSEL | UCSRC_DATA_BITS | UCSRC_PARITY | UCSRC_STOP_BITS;
UCSRB = 1 &amp; lt; &amp; lt; RXEN | 1 &amp; lt; &amp; 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 &amp; gt; 0;
--Retries_Left )
{
if ( ( Received_Char = ( uint8_t )UART_RX_Wait( 100 ) ) == 'u' )
break;

UART_TX_Byte( '?' );
}

if ( Received_Char == 'u' )
{
Retries_Left = 10;
while ( 1 )
{
/* odebranie znaku */
Received_Char = ( uint8_t )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( &quot; \r\n &quot; &quot; &amp; &quot;
TOSTRING( SPM_PAGESIZE ) &quot; , &quot;
TOSTRING( BLS_START ) &quot; , &quot;
TOSTRING( MCU ) &quot; , &quot;
TOSTRING( XTAL ) &quot; , &quot;
BOOTLOADER_VERSION
&quot; * &quot; &quot; \r\n &quot; ) );

/* odmierzanie czasu rozpoczyna si? od nowa */
Retries_Left = 10;
}
else if ( Received_Char == 'w' )
{
/* wyczyszczenie pami?ci programu */
erase_flash();

for ( uint16_t Page_Address = 0; Page_Address &amp; lt; BLS_START;
Page_Address += SPM_PAGESIZE )
{
/* wys?anie znaku '+' */
UART_TX_Byte( '+' );

/* czy s? jeszcze dane do zaprogramowania? jeœli brak to zako?cz */
if ( !UART_RX_Wait( 500 ) ) break;


/* zape?nienie bufora strony */
for ( uint16_t Byte_Address = 0;
Byte_Address &amp; lt; SPM_PAGESIZE; ++Byte_Address )
g_Page_Buffer[ Byte_Address ] =
( uint8_t )UART_RX_Wait( 500 );

/* zaprogramowanie strony */
write_page( Page_Address, &amp; g_Page_Buffer );
}

/* odblokowanie sekcji RWW i zako?czenie pracy bootloadera */
reenable_rww();
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 (stanie si? to dopiero po zako?czeniu
* wysy?ania) */
UCSRB = 0;

/* skok do w?aœciwego programu */
#ifdef __AVR_HAVE_JMP_CALL__
asm volatile (
&quot; jmp 0 &quot; &quot; \n\t &quot;
: : );
#else
asm volatile (
&quot; clr r30 &quot; &quot; \n\t &quot;
&quot; clr r31 &quot; &quot; \n\t &quot;
&quot; ijmp &quot; &quot; \n\t &quot;
: : );
#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 &amp; 1 &amp; lt; &amp; 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 &amp; 1 &amp; lt; &amp; lt; RXC )
return ( uint8_t )UDR;

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

return 0;
}


bootloader_ver_200.rar > Instrukcja.txt

W wykorzystywanym mikrokontrolerze nale?y zaprogramowaae (wartoœae 0) bit BOOTRST i ustawiae bity BOOTSZ tak, by sekcja bootloadera mia?a 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]).


bootloader_ver_200.rar > appspace.h

/**
* \brief Nag?ówek sterownika do niskopoziomowych operacji na sekcji RWW - pami?ci flash.
* \file appspace.h
*/
#ifndef __appspace_h__
#define __appspace_h__

#ifndef __ASSEMBLER__

/**
* Czyœci pami?ae flash
*/
void erase_flash(void);

/**
* Odblokowanie sekcji RWW
*/
void reenable_rww(void);

/**
* Programuje pami?ae flash danymi.
* \param pgm_addr Adres w pami?ci programu, pod którym ma by?a zapisana strona. Musi byae wyrównane do granicy stron
* \param data WskaŸnik na dane do zapisania
*/
void write_page(uint16_t pgm_addr, void* data);

#endif

#endif