📄 stk500boot.c
字号:
/*****************************************************************************
Title: STK500v2 compatible bootloader
Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
File: $Id: stk500boot.c,v 1.11 2006/06/25 12:39:17 peter Exp $
Compiler: avr-gcc 3.4.5 or 4.1 / avr-libc 1.4.3
Hardware: All AVRs with bootloader support, tested with ATmega8
License: GNU General Public License
DESCRIPTION:
This program allows an AVR with bootloader capabilities to
read/write its own Flash/EEprom. To enter Programming mode
an input pin is checked. If this pin is pulled low, programming mode
is entered. If not, normal execution is done from $0000
"reset" vector in Application area.
Size < 500 words, fits into a 512 word bootloader section
when compiled with avr-gcc 4.1
USAGE:
- Set AVR MCU type and clock-frequency (F_CPU) in the Makefile.
- Set baud rate below (AVRISP only works with 115200 bps)
- compile/link the bootloader with the supplied Makefile
- program the "Boot Flash section size" (BOOTSZ fuses),
for boot-size 512 words: program BOOTSZ1
- enable the BOOT Reset Vector (program BOOTRST)
- Upload the hex file to the AVR using any ISP programmer
- Program Boot Lock Mode 3 (program BootLock 11 and BootLock 12 lock bits)
- Reset your AVR while keeping PROG_PIN pulled low
- Start AVRISP Programmer (AVRStudio/Tools/Program AVR)
- AVRISP will detect the bootloader
- Program your application FLASH file and optional EEPROM file using AVRISP
Note:
Erasing the device without flashing, through AVRISP GUI button "Erase Device"
is not implemented, due to AVRStudio limitations.
Flash is always erased before programming.
AVRdude:
Please uncomment #define REMOVE_CMD_SPI_MULTI when using AVRdude.
Comment #define REMOVE_PROGRAM_LOCK_BIT_SUPPORT to reduce code size
Read Fuse Bits and Read/Write Lock Bits is not supported
NOTES:
Based on Atmel Application Note AVR109 - Self-programming
Based on Atmel Application Note AVR068 - STK500v2 Protocol
LICENSE:
Copyright (C) 2006 Peter Fleury
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
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.
*****************************************************************************/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/boot.h>
#include <avr/pgmspace.h>
#include "command.h"
/*
* Uncomment the following lines to save code space
*/
//#define REMOVE_PROGRAM_LOCK_BIT_SUPPORT // disable program lock bits
//#define REMOVE_BOOTLOADER_LED // no LED to show active bootloader
//#define REMOVE_PROG_PIN_PULLUP // disable internal pullup, use external
#define REMOVE_CMD_SPI_MULTI // disable processing of SPI_MULTI commands
/*
* Pin "PROG_PIN" on port "PROG_PORT" has to be pulled low
* (active low) to start the bootloader
* uncomment #define REMOVE_PROG_PIN_PULLUP if using an external pullup
*/
#define PROG_PORT PORTD
#define PROG_DDR DDRD
#define PROG_IN PIND
#define PROG_PIN PIND2
/*
* Active-low LED on pin "PROGLED_PIN" on port "PROGLED_PORT"
* indicates that bootloader is active
*/
#define PROGLED_PORT PORTB
#define PROGLED_DDR DDRB
#define PROGLED_PIN PINB1
/*
* define CPU frequency in Mhz here if not defined in Makefile
*/
#ifndef F_CPU
#define F_CPU 7372800UL
#endif
/*
* UART Baudrate, AVRStudio AVRISP only accepts 115200 bps
*/
#define BAUDRATE 115200
/*
* Enable (1) or disable (0) USART double speed operation
*/
#define UART_BAUDRATE_DOUBLE_SPEED 0
/*
* HW and SW version, reported to AVRISP, must match version of AVRStudio
*/
#define CONFIG_PARAM_BUILD_NUMBER_LOW 0
#define CONFIG_PARAM_BUILD_NUMBER_HIGH 0
#define CONFIG_PARAM_HW_VER 0x0F
#define CONFIG_PARAM_SW_MAJOR 2
#define CONFIG_PARAM_SW_MINOR 7
/*
* Calculate the address where the bootloader starts from FLASHEND and BOOTSIZE
* (adjust BOOTSIZE below and BOOTLOADER_ADDRESS in Makefile if you want to change the size of the bootloader)
*/
#define BOOTSIZE 512
#define APP_END (FLASHEND -(2*BOOTSIZE) + 1)
/*
* Signature bytes are not available in avr-gcc io_xxx.h
*/
#if defined (__AVR_ATmega8__)
#define SIGNATURE_BYTES 0x1E9307
#elif defined (__AVR_ATmega16__)
#define SIGNATURE_BYTES 0x1E9403
#elif defined (__AVR_ATmega32__)
#define SIGNATURE_BYTES 0x1E9502
#elif defined (__AVR_ATmega8515__)
#define SIGNATURE_BYTES 0x1E9306
#elif defined (__AVR_ATmega8535__)
#define SIGNATURE_BYTES 0x1E9308
#elif defined (__AVR_ATmega162__)
#define SIGNATURE_BYTES 0x1E9404
#elif defined (__AVR_ATmega128__)
#define SIGNATURE_BYTES 0x1E9702
#else
#error "no signature definition for MCU available"
#endif
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \
|| defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) \
/* ATMega8 with one USART */
#define UART_BAUD_RATE_LOW UBRRL
#define UART_STATUS_REG UCSRA
#define UART_CONTROL_REG UCSRB
#define UART_ENABLE_TRANSMITTER TXEN
#define UART_ENABLE_RECEIVER RXEN
#define UART_TRANSMIT_COMPLETE TXC
#define UART_RECEIVE_COMPLETE RXC
#define UART_DATA_REG UDR
#define UART_DOUBLE_SPEED U2X
#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) || defined(__AVR_ATmega162__)
/* ATMega with two USART */
#define UART_BAUD_RATE_LOW UBRR0L
#define UART_STATUS_REG UCSR0A
#define UART_CONTROL_REG UCSR0B
#define UART_ENABLE_TRANSMITTER TXEN0
#define UART_ENABLE_RECEIVER RXEN0
#define UART_TRANSMIT_COMPLETE TXC0
#define UART_RECEIVE_COMPLETE RXC0
#define UART_DATA_REG UDR0
#define UART_DOUBLE_SPEED U2X0
#else
#error "no UART definition for MCU available"
#endif
/*
* Macro to calculate UBBR from XTAL and baudrate
*/
#if UART_BAUDRATE_DOUBLE_SPEED
#define UART_BAUD_SELECT(baudRate,xtalCpu) (((float)(xtalCpu))/(((float)(baudRate))*8.0)-1.0+0.5)
#else
#define UART_BAUD_SELECT(baudRate,xtalCpu) (((float)(xtalCpu))/(((float)(baudRate))*16.0)-1.0+0.5)
#endif
/*
* States used in the receive state machine
*/
#define ST_START 0
#define ST_GET_SEQ_NUM 1
#define ST_MSG_SIZE_1 2
#define ST_MSG_SIZE_2 3
#define ST_GET_TOKEN 4
#define ST_GET_DATA 5
#define ST_GET_CHECK 6
#define ST_PROCESS 7
/*
* use 16bit address variable for ATmegas with <= 64K flash
*/
#if defined(RAMPZ)
typedef uint32_t address_t;
#else
typedef uint16_t address_t;
#endif
/*
* function prototypes
*/
static void sendchar(char c);
static unsigned char recchar(void);
/*
* since this bootloader is not linked against the avr-gcc crt1 functions,
* to reduce the code size, we need to provide our own initialization
*/
void __jumpMain (void) __attribute__ ((naked)) __attribute__ ((section (".init9")));
void __jumpMain(void)
{
asm volatile ( ".set __stack, %0" :: "i" (RAMEND) );
asm volatile ( "clr __zero_reg__" ); // GCC depends on register r1 set to 0
asm volatile ( "out %0, __zero_reg__" :: "I" (_SFR_IO_ADDR(SREG)) ); // set SREG to 0
asm volatile ( "rjmp main"); // jump to main()
}
/*
* send single byte to USART, wait until transmission is completed
*/
static void sendchar(char c)
{
UART_DATA_REG = c; // prepare transmission
while (!(UART_STATUS_REG & (1 << UART_TRANSMIT_COMPLETE)));// wait until byte sent
UART_STATUS_REG |= (1 << UART_TRANSMIT_COMPLETE); // delete TXCflag
}
/*
* Read single byte from USART, block if no data available
*/
static unsigned char recchar(void)
{
while(!(UART_STATUS_REG & (1 << UART_RECEIVE_COMPLETE))); // wait for data
return UART_DATA_REG;
}
int main(void)
{
address_t address = 0;
address_t eraseAddress = 0;
unsigned char msgParseState;
unsigned int i = 0;
unsigned char checksum = 0;
unsigned char seqNum = 0;
unsigned int msgLength = 0;
unsigned char msgBuffer[285];
unsigned char c, *p;
/*
* Branch to bootloader or application code ?
*/
#ifndef REMOVE_PROG_PIN_PULLUP
PROG_PORT |= (1<<PROG_PIN); // Enable internal pullup
asm volatile ("nop"); // wait until port has changed
#endif
if(!(PROG_IN & (1<<PROG_PIN)))
{
#ifndef REMOVE_BOOTLOADER_LED
/* PROG_PIN pulled low, indicate with LED that bootloader is active */
PROGLED_DDR |= (1<<PROGLED_PIN);
PROGLED_PORT &= ~(1<<PROGLED_PIN);
#endif
/*
* Init UART
* set baudrate and enable USART receiver and transmiter without interrupts
*/
#if UART_BAUDRATE_DOUBLE_SPEED
UART_STATUS_REG |= (1 <<UART_DOUBLE_SPEED);
#endif
UART_BAUD_RATE_LOW = UART_BAUD_SELECT(BAUDRATE,F_CPU);
UART_CONTROL_REG = (1 << UART_ENABLE_RECEIVER) | (1 << UART_ENABLE_TRANSMITTER);
/* main loop */
for(;;)
{
/*
* Collect received bytes to a complete message
*/
msgParseState = ST_START;
while ( msgParseState != ST_PROCESS )
{
c = recchar();
switch (msgParseState)
{
case ST_START:
if( c == MESSAGE_START )
{
msgParseState = ST_GET_SEQ_NUM;
checksum = MESSAGE_START^0;
}
break;
case ST_GET_SEQ_NUM:
if ( (c == 1) || (c == seqNum) )
{
seqNum = c;
msgParseState = ST_MSG_SIZE_1;
checksum ^= c;
}
else
{
msgParseState = ST_START;
}
break;
case ST_MSG_SIZE_1:
msgLength = c<<8;
msgParseState = ST_MSG_SIZE_2;
checksum ^= c;
break;
case ST_MSG_SIZE_2:
msgLength |= c;
msgParseState = ST_GET_TOKEN;
checksum ^= c;
break;
case ST_GET_TOKEN:
if ( c == TOKEN )
{
msgParseState = ST_GET_DATA;
checksum ^= c;
i = 0;
}
else
{
msgParseState = ST_START;
}
break;
case ST_GET_DATA:
msgBuffer[i++] = c;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -