ADVERTISEMENT

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


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


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êæ flash
*/
void erase_flash(void);

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

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

#endif

#endif


bootloader_ver_200.rar > Instrukcja.txt

W wykorzystywanym mikrokontrolerze nale¿y zaprogramowaæ (wartoœæ 0) bit BOOTRST i ustawiæ bity BOOTSZ tak, by sekcja bootloadera mia³a 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_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œæ 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œæ 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;
}