📄 atmegaboot.c
字号:
/**********************************************************/
/* Serial Bootloader for Atmel megaAVR Controllers */
/* */
/* tested with ATmega8, ATmega128 and ATmega168 */
/* should work with other mega's, see code for details */
/* */
/* ATmegaBOOT.c */
/* */
/* build: 050815 */
/* date : 15.08.2005 */
/* */
/* Monitor and debug functions were added to the original */
/* code by Dr. Erik Lins, chip45.com. (See below) */
/* */
/* Thanks to Karl Pitrich for fixing a bootloader pin */
/* problem and more informative LED blinking! */
/* */
/* For the latest version see: */
/* http://www.chip45.com/ */
/* */
/* ------------------------------------------------------ */
/* */
/* based on stk500boot.c */
/* Copyright (c) 2003, Jason P. Kyle */
/* All rights reserved. */
/* see avr1.org for original file and information */
/* */
/* This program is free software; you can redistribute it */
/* and/or modify it under the terms of the GNU General */
/* Public License as published by the Free Software */
/* Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will */
/* be useful, but WITHOUT ANY WARRANTY; without even the */
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
/* PARTICULAR PURPOSE. See the GNU General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU General */
/* Public License along with this program; if not, write */
/* to the Free Software Foundation, Inc., */
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* */
/* Licence can be viewed at */
/* http://www.fsf.org/licenses/gpl.txt */
/* */
/* Target = Atmel AVR m128,m64,m32,m16,m8,m162,m163,m169, */
/* m8515,m8535. ATmega161 has a very small boot block so */
/* isn't supported. */
/* */
/* Tested with m128,m8,m163 - feel free to let me know */
/* how/if it works for you. */
/* */
/**********************************************************/
/* some includes */
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
/* the current avr-libc eeprom functions do not support the ATmega168 */
/* own eeprom write/read functions are used instead */
#ifndef __AVR_ATmega168__
#include <avr/eeprom.h>
#endif
/* define F_CPU according to AVR_FREQ set in Makefile */
/* Is there a better way to pass such a parameter from Makefile to source code ? */
#if defined F3686400
#define F_CPU 3686400
#elif defined F7372800
#define F_CPU 7372800
#elif defined F8000000
#define F_CPU 8000000
#elif defined F14745600
#define F_CPU 14745600
#elif defined F16000000
#define F_CPU 16000000
#elif defined F20000000
#define F_CPU 20000000
#else
/* if AVR frequency is not defined in Makefile, default to 14.7456MHz */
#define F_CPU 14745600
#endif
/* set the UART baud rate */
#define BAUD_RATE 115200
/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
/* never allow AVR Studio to do an update !!!! */
#define HW_VER 0x02
#define SW_MAJOR 0x01
#define SW_MINOR 0x0f
/* Adjust to suit whatever pin your hardware uses to enter the bootloader */
/* ATmega128 has two UARTS so two pins are used to enter bootloader and select UART */
/* BL0... means UART0, BL1... means UART1 */
#ifdef __AVR_ATmega128__
#define BL_DDR DDRF
#define BL_PORT PORTF
#define BL_PIN PINF
#define BL0 PINF7
#define BL1 PINF6
#else
/* other ATmegas have only one UART, so only one pin is defined to enter bootloader */
#define BL_DDR DDRC
#define BL_PORT PORTC
#define BL_PIN PINC
#define BL PINC0
#endif
/* onboard LED is used to indicate, that the bootloader was entered (3x flashing) */
/* if monitor functions are included, LED goes on after monitor was entered */
#ifdef __AVR_ATmega128__
/* Onboard LED is connected to pin PB7 (e.g. Crumb128, PROBOmega128, Savvy128) */
#define LED_DDR DDRB
#define LED_PORT PORTB
#define LED_PIN PINB
#define LED PINB7
#else
/* Onboard LED is connected to pin PB2 (e.g. Crumb8, Crumb168) */
#define LED_DDR DDRB
#define LED_PORT PORTB
#define LED_PIN PINB
#define LED PINB2
#endif
/* monitor functions will only be compiled when using ATmega128, due to bootblock size constraints */
#ifdef __AVR_ATmega128__
#define MONITOR
#endif
/* define various device id's */
/* manufacturer byte is always the same */
#define SIG1 0x1E // Yep, Atmel is the only manufacturer of AVR micros. Single source :(
#if defined __AVR_ATmega128__
#define SIG2 0x97
#define SIG3 0x02
#define PAGE_SIZE 0x80U //128 words
#elif defined __AVR_ATmega64__
#define SIG2 0x96
#define SIG3 0x02
#define PAGE_SIZE 0x80U //128 words
#elif defined __AVR_ATmega32__
#define SIG2 0x95
#define SIG3 0x02
#define PAGE_SIZE 0x40U //64 words
#elif defined __AVR_ATmega16__
#define SIG2 0x94
#define SIG3 0x03
#define PAGE_SIZE 0x40U //64 words
#elif defined __AVR_ATmega8__
#define SIG2 0x93
#define SIG3 0x07
#define PAGE_SIZE 0x20U //32 words
#elif defined __AVR_ATmega88__
#define SIG2 0x93
#define SIG3 0x0a
#define PAGE_SIZE 0x20U //32 words
#elif defined __AVR_ATmega168__
#define SIG2 0x94
#define SIG3 0x06
#define PAGE_SIZE 0x40U //64 words
#elif defined __AVR_ATmega162__
#define SIG2 0x94
#define SIG3 0x04
#define PAGE_SIZE 0x40U //64 words
#elif defined __AVR_ATmega163__
#define SIG2 0x94
#define SIG3 0x02
#define PAGE_SIZE 0x40U //64 words
#elif defined __AVR_ATmega169__
#define SIG2 0x94
#define SIG3 0x05
#define PAGE_SIZE 0x40U //64 words
#elif defined __AVR_ATmega8515__
#define SIG2 0x93
#define SIG3 0x06
#define PAGE_SIZE 0x20U //32 words
#elif defined __AVR_ATmega8535__
#define SIG2 0x93
#define SIG3 0x08
#define PAGE_SIZE 0x20U //32 words
#endif
/* function prototypes */
void putch(char);
char getch(void);
void getNch(uint8_t);
void byte_response(uint8_t);
void nothing_response(void);
char gethex(void);
void puthex(char);
void flash_led(uint8_t);
/* some variables */
union address_union {
uint16_t word;
uint8_t byte[2];
} address;
union length_union {
uint16_t word;
uint8_t byte[2];
} length;
struct flags_struct {
unsigned eeprom : 1;
unsigned rampz : 1;
} flags;
uint8_t buff[256];
uint8_t address_high;
uint8_t pagesz=0x80;
uint8_t i;
uint8_t bootuart = 0;
void (*app_start)(void) = 0x0000;
/* main program starts here */
int main(void)
{
uint8_t ch,ch2;
uint16_t w;
asm volatile("nop\n\t");
/* set pin direction for bootloader pin and enable pullup */
/* for ATmega128, two pins need to be initialized */
#ifdef __AVR_ATmega128__
BL_DDR &= ~_BV(BL0);
BL_DDR &= ~_BV(BL1);
BL_PORT |= _BV(BL0);
BL_PORT |= _BV(BL1);
#else
BL_DDR &= ~_BV(BL);
BL_PORT |= _BV(BL);
#endif
#ifdef __AVR_ATmega128__
/* check which UART should be used for booting */
if(bit_is_clear(BL_PIN, BL0)) {
bootuart = 1;
}
else if(bit_is_clear(BL_PIN, BL1)) {
bootuart = 2;
}
#endif
/* check if flash is programmed already, if not start bootloader anyway */
if(pgm_read_byte_near(0x0000) != 0xFF) {
#ifdef __AVR_ATmega128__
/* no UART was selected, start application */
if(!bootuart) {
app_start();
}
#else
/* check if bootloader pin is set low */
if(bit_is_set(BL_PIN, BL)) {
app_start();
}
#endif
}
#ifdef __AVR_ATmega128__
/* no bootuart was selected, default to uart 0 */
if(!bootuart) {
bootuart = 1;
}
#endif
/* initialize UART(s) depending on CPU defined */
#ifdef __AVR_ATmega128__
if(bootuart == 1) {
UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
UBRR0H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
UCSR0A = 0x00;
UCSR0C = 0x06;
UCSR0B = _BV(TXEN0)|_BV(RXEN0);
}
if(bootuart == 2) {
UBRR1L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
UBRR1H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
UCSR1A = 0x00;
UCSR1C = 0x06;
UCSR1B = _BV(TXEN1)|_BV(RXEN1);
}
#elif defined __AVR_ATmega163__
UBRR = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
UBRRHI = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
UCSRA = 0x00;
UCSRB = _BV(TXEN)|_BV(RXEN);
#elif defined __AVR_ATmega168__
UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
UBRR0H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
UCSR0B = (1<<RXEN0) | (1<<TXEN0);
UCSR0C = (1<<UCSZ00) | (1<<UCSZ01);
#else
/* m8,m16,m32,m169,m8515,m8535 */
UBRRL = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
UBRRH = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
//UBRRL = 3;
// UBRRH =0;
UCSRA = 0x00;
UCSRC = 0x86;
UCSRB = _BV(TXEN)|_BV(RXEN);
#endif
/* set LED pin as output */
LED_DDR |= _BV(LED);
/* flash onboard LED to signal entering of bootloader */
#ifdef __AVR_ATmega128__
// 4x for UART0, 5x for UART1
flash_led(3 + bootuart);
#else
flash_led(3);
#endif
putch('\0');
putch('m');
putch('e');
/* forever loop */
for (;;) {
/* get character from UART */
ch = getch();
/* A bunch of if...else if... gives smaller code than switch...case ! */
/* Hello is anyone home ? */
if(ch=='0') {
nothing_response();
}
/* Request programmer ID */
/* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry */
/* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares. */
else if(ch=='1') {
if (getch() == ' ') {
putch(0x14);
putch('A');
putch('V');
putch('R');
putch(' ');
putch('I');
putch('S');
putch('P');
putch(0x10);
}
}
/* AVR ISP/STK500 board commands DON'T CARE so default nothing_response */
else if(ch=='@') {
ch2 = getch();
if (ch2>0x85) getch();
nothing_response();
}
/* AVR ISP/STK500 board requests */
else if(ch=='A') {
ch2 = getch();
if(ch2==0x80) byte_response(HW_VER); // Hardware version
else if(ch2==0x81) byte_response(SW_MAJOR); // Software major version
else if(ch2==0x82) byte_response(SW_MINOR); // Software minor version
else if(ch2==0x98) byte_response(0x03); // Unknown but seems to be required by avr studio 3.56
else byte_response(0x00); // Covers various unnecessary responses we don't care about
}
/* Device Parameters DON'T CARE, DEVICE IS FIXED */
else if(ch=='B') {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -