The serial AVR109 bootloader is implemented as an integral part of weAutSys / weAut_01. It is designed to be (by fuse setting) the entry point for all reset or restart.
Hence the board should always come with this bootloader in its (upper flash) place and be fused to enter it on reset. All the basic (weAut_01) initialisations are then done anyway by the bootloader. On an external or power on reset this bootloader will after a quite short time without receiving ESC jump to the system/application software start, see Bootloader operation for details and Bootloader support for an overview and further references.
There the initialisation tasks already done may (and will) be omitted from the "normal" system software (according to the value of USE_BOOTLOADER). Additionally functions and constants provided by the integrated bootloader (see file boot109.h) may be linked to and used by system or application software. About building and linking the bootloader see the descriptive part of file boot109.c and download and read
Albrecht Weinert
A serial bootloader for weAut_01, ArduinoMega and akin
for more information on re-using bootloader functions in the application software.
Defines | |
#define | FAR_ADD(varHF) |
Generate a far address for high flash memory items. | |
#define | getSerByte() |
Basic function: UART(0) get one byte already received. | |
#define | isSerByteRec() |
Basic function: UART(0) has one byte received. | |
#define | LOW_ADD(varLF) |
Generate a far address for low flash memory items. | |
Functions | |
void | appMain (uint8_t init) __attribute__((noreturn)) |
Jump to application program. | |
void | basicSystemInit (void) |
Initialise system resources. | |
void | bootMain (void) __attribute__((noreturn)) |
Jump to the bootloader. | |
char * | copyChars_P (char *dst, ADDR_T src, uint8_t mxLen) |
Copy a string from flash memory to RAM. | |
void | initUART0 (uint32_t baudRate, uint8_t x2, uint8_t parity, uint8_t stopBits, uint8_t useInt) |
Initialise the serial input (UART0) | |
uint8_t | recvErrorState (void) |
Get UART receive error status and flush receiver on error. | |
uint8_t | recvSerByte (void) |
Basic UART receive one byte. | |
ADDR_T | resetCauseText_P (uint8_t resetCauses) |
The reset cause text. | |
void | sendSerByte (uint8_t c) |
Basic UART send one byte (guarded) | |
void | sendSerBytes (char *src) |
Basic UART0 send multiple bytes from RAM. | |
void | sendSerBytes_P (ADDR_T src) |
Basic UART send multiple bytes from flash. | |
void | toHMI8LEDchain (uint8_t val) |
Output to a chain of eight HMI/visible LEDs. | |
void | wait25 (void) |
A very basic delay function keeping the CPU busy for about 25µs. | |
uint8_t | waitSerByte (uint8_t tOut) |
Basic UART wait for a byte received. | |
Variables | |
char const | bootloaderPlatf [] |
Bootloader's platform name and CPU frequency. | |
char const | bootloaderWlc [] |
Bootloader's welcome greeting and copyright notice. | |
char const | bootResetCause0 [] |
no reset cause: exit from from active bootloader or by command | |
char const | bootResetCause1 [] |
reset cause: power on | |
char const | bootResetCause2 [] |
reset cause: external | |
char const | bootResetCause4 [] |
reset cause: brown out | |
char const | bootResetCause8 [] |
reset cause: watchdog | |
char const | bootResetCauseG [] |
reset cause: JTAG | |
char const | bootResetCauseN [] |
reset cause: not known | |
char const | bootTextReset [] |
The text "Reset by:". | |
char const | bootTextRevis [] |
The text "Revision:". | |
char const | greetEmptFlash [] |
Greeting for empty application flash. |
#define FAR_ADD | ( | varHF | ) |
Generate a far address for high flash memory items.
avr-gcc is restricted (may say dumb) enough always to deliver 16 bit addresses respectively pointers for variables even if they reside by INFLASH or PROGMEM in higher addresses. Note that the ATmega1284P e.g. has 128K flash memory and the ATmega2560 e.g. has 256Kbyte.
Hence if for example the boatloader flash array timOutCountPatr is finally at address 0x01e20c &timOutCountPatr[1] will (with avr-gcc) be 0x0e20d instead of 0x1e20d.
Using FAR_ADD(timOutCountPatr[1])
supplies both the &-operator and the missing 0x10000 respectively 0x30000, correcting the error described.
For devices with less than 64KByte = 32KWords flash memory this macro's value is just &
(varHF).
To get a 32 bit address for an item in the lowest 64kbyte of use the macro LOW_ADD instead.
Note that both macros FAR_ADD and LOW_ADD cover all flash of an ATmega1284P but only half of the ATmega2560's flash.
Note: Hopefully in future, avg-gcc will automatically switch to 24bit pointers on larger devices and automatically handle them correctly. What, in the end, we have higher level languages and their compilers for? But, alas, as of end 2015 this is still not the case.
varHF | a variable in the highest 64Kbyte flash memory block. This covers any bootloader space. Do not supply a pointer; the & (i.e. the address operator) will be applied to the parameter. |
#define LOW_ADD | ( | varLF | ) |
Generate a far address for low flash memory items.
This macro provides a 16 or 32 bit address (ADDR_T) for an item (a variable) in lowest 64Kbate segment of the memory. The upper 16 bits of the address provided this way are 0.
Use this macro to make a 16 or 32 bit address (ADDR_T) parameter for e.g. sendSerBytes_P. Giving a (16 bit) pointer here would work by the (correct) automatic cast, also — but with a compiler warning.
varLF | a variable in the lowest 64Kbyte flash memory block. This covers the (start of) application space. Do not supply a pointer; the & (i.e. the address operator) will be applied to the parameter. |
#define isSerByteRec | ( | ) |
Basic function: UART(0) has one byte received.
This expression is non-zero if the UART(0) has one received byte ready
#define getSerByte | ( | ) |
Basic function: UART(0) get one byte already received.
This is essentially the unguarded version of recvSerByte(void). In other words it has to be guarded by waitSerByte(uint8_t tOut) or by isSerByteRec().
void basicSystemInit | ( | void | ) |
Initialise system resources.
This function does the basic initialisations for the target hardware and runtime. It essentially disables all interrupts and initialises the ports and other resources except the UART (for that see initUART0).
The situations to use are
that is
void toHMI8LEDchain | ( | uint8_t | val | ) |
Output to a chain of eight HMI/visible LEDs.
If the target hardware has a line of eight LEDs this function sets them according to parameter val
. Otherwise nothing is done.
The pre-condition is these eight LEDs being independently controllable by software without any side-effects on I/O to an external process controlled by the target hardware.
With weAut_01 these are the eight green digital input (DI) display LEDs.
With ArduinoMega and easyAVR — assuming above conditions to be met — it might be just one eight bit output port named by the macro CHAIN8LED_PORT. If no setting is made for a chain of 8 independent LEDs and the macro NO_CHAIN8LED is defined an implementation may just do nothing (without compile time warning).
void appMain | ( | uint8_t | init | ) |
Jump to application program.
First of all this function disables all interrupts and the watchdog and does a basicSystemInit() if init
is not 0. Parameter init
should only be OFF if a ref basicSystemInit "basic initialisation" has been done and those settings haven't been spoiled.
This function then initialises the UART (0) with or without interrupt usage depending on the platform.
With freshly set zeroReg and stackpointer this function will then go to the normal program's start in the flash memory. Hence it will never return to the caller.
init | ON: do full basicSystemInit() also |
void bootMain | ( | void | ) |
Jump to the bootloader.
At first this function disables all interrupts and the watchdog.
With freshly set zeroReg and stackpointer this function will then go to the bootloader's start in the flash memory. Hence this function will never return to the caller.
void initUART0 | ( | uint32_t | baudRate, |
uint8_t | x2, | ||
uint8_t | parity, | ||
uint8_t | stopBits, | ||
uint8_t | useInt | ||
) |
Initialise the serial input (UART0)
UART 0 is initialised in asynchronous mode for receiving and transmitting (full duplex). A recommended baudRate is 38400; it's fast enough for communication and even boot loading and still robust enough for critical or long lines.
If in doubt x2 should be OFF. It is needed only for very high baudRates with respect to the CPU clock frequency (F_CPU). And some exotic baudrate F_CPU combinations get higher accuracy with x2 ON.
baudRate | the rate desired (usually 38400) |
x2 | true: double speed (half receive samples) |
parity | 0=false: none; odd , even value: odd, even |
stopBits | 2: 2 stop bits, 1 [default]: 1 stop bit |
useInt | true: use UART interrupts |
ADDR_T resetCauseText_P | ( | uint8_t | resetCauses | ) |
The reset cause text.
According to the bits defined for the MCUSR register this function returns a (flash memory) pointer to
" power on ", " external reset ", " power (brown) out ", " watchdog reset ", " jtag reset ", " no reset (by command?) " or " unknown cause ".
resetCauses | The µC's reset info as by MCUSR |
void wait25 | ( | void | ) |
A very basic delay function keeping the CPU busy for about 25µs.
Calling this function will keep the CPU busy for 500 cycles (two less for small flash devices) on a 20 MHz platform (weAut_01). That will take 25µs. On slower platforms with e.g. 16 MHz (Arduino) the number of cycles is, of course, proportionally reduced.
char* copyChars_P | ( | char * | dst, |
ADDR_T | src, | ||
uint8_t | mxLen | ||
) |
Copy a string from flash memory to RAM.
This function copies a String
src
dst
.The function copies up to mxLen-1
characters from src
to dst
and appends a trailing 0. Returned is the address of the last character in dst
modified (i.e. the 0's address).
Rationale: Besides a variety of functions to handle and output strings in RAM weAutSys features a second (sub-) set of functions to handle / output strings in flash memory, their names usually ending in P
or _P
. Insofar these functions usually save the trouble of copying strings form flash to RAM (prior to output e.g.). But due to avr-gcc C pointer limitations the standard flash variable handling won't work above 64K byte, as is the case with bootloader variables on large flash devices. A third set of functions for those use cases can hardly be justified. Here the workaround is "copy to an intermediate RAM buffer and
use RAM handling functions". That workaround is support by this function.
dst | the destination to modify (in RAM, not null!) |
src | the source (string) to copy from (in flash memory, not null!) |
mxLen | the maximum number of characters to modify in dst including the trailing 0 appended. The maximum advance of the return value to parameter dest |
dst
is NULL void sendSerByte | ( | uint8_t | c | ) |
Basic UART send one byte (guarded)
This is a very basic send function for the initialised UART(0). It will wait for the UART being ready to accept the next byte to be transmitted. If the UART is not initialised or handled correctly it may wait endlessly.
This functions uses spin waiting and hence the respective remarks for recvSerByte apply.
c | the character or byte to be sent |
void sendSerBytes_P | ( | ADDR_T | src | ) |
Basic UART send multiple bytes from flash.
This is a very basic send function for the initialised UART. It uses spin waiting and hence the remarks for sendSerByte apply.
src | pointer to the first character or byte to be sent in of the 0-terminated string. Must not be null. |
void sendSerBytes | ( | char * | src | ) |
Basic UART0 send multiple bytes from RAM.
This is a very basic send function for the initialised UART. It uses spin waiting and hence is meant for situations without any threading support (or interrupt), as e.g. early initialisation phases or bootloaders.
src | pointer to the first character or byte to be sent in of the 0-terminated string, must not be null |
uint8_t waitSerByte | ( | uint8_t | tOut | ) |
Basic UART wait for a byte received.
This is a very basic receive function for the initialised UART. It uses spin waiting for a received byte timeout of tOut/10 seconds.
Cause of this spin waiting this function is meant for situations without any threading support (or interrupt), as e.g. early initialisation phases or bootloaders.
tOut | a time out in 100 ms (1..254) |
uint8_t recvSerByte | ( | void | ) |
Basic UART receive one byte.
This is a very basic receive function for the initialised UART. If no received byte is ready it will endlessly wait for it. To avoid this it may be guarded by waitSerByte — in which case the (unguarded) macro getSerByte() may also be used.
This function uses spin waiting and would hence be blocking all other activities. It is meant for situations without any threading support (or interrupts), as e.g. early initialisation phases or in bootloaders. And it is, of course, never to be used with an armed watchdog.
uint8_t recvErrorState | ( | void | ) |
Get UART receive error status and flush receiver on error.
This function retrieves and returns the error status of an initialised UART(0). If no error occurred 0 is returned and nothing else done.
Otherwise the initialised UART's receiver is flushed.
char const bootloaderWlc[] |
Bootloader's welcome greeting and copyright notice.
This is a four line text in (high!) flash memory plus three starting and two trailing empty lines. It is meant for display as well as embedded copyright notice.
char const greetEmptFlash[] |
Greeting for empty application flash.
This is a one line text in (high!) flash memory plus two starting and one trailing empty lines. It says:
remain in bootloader: application flash empty
char const bootloaderPlatf[] |
Bootloader's platform name and CPU frequency.
This is a one line text in (high!) flash memory ending in a linefeed.
char const bootTextRevis[] |
The text "Revision:".
This is a text block in (high!) flash memory (0-terminated).
char const bootTextReset[] |
The text "Reset by:".
This is a text block in (high!) flash memory (0-terminated).