📄 main.c
字号:
/*
ezLCDboot.c
01-SEP-2004 Michal
Done the following modyfications:
- changed file name to main.c
- removed all references to the MCUs other than ATmega128
- formated the code acording to Sane-C coding standard
- replaced __lpm_inline by GetFlashByte
- replaced __lpm_inline by GetExtFlashByte
- moved the inline assembly into SystemAsm.s
- replaced else if statements by switch structures
because, the new version of GCC does a very good job
optimizing the switch structures.
stk500boot.c 20030810
Copyright (c) 2003, Jason P. Kyle
All rights reserved.
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.
*/
#define F_CPU 7372800
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
typedef unsigned char byte;
typedef unsigned short word;
#define BAUD_RATE 115200
#define DECRYPT 0
#define ENCRYPT 1
//#define DES_ENCRYPTION
#define HW_VER 0x02
#define SW_MAJOR 0x01
#define SW_MINOR 0x12
// Adjust to suit whatever pin your hardware uses to enter the bootloader
#define BL_DDR DDRB
#define BL_PORT PORTB
#define BL_PIN PINB
#define BL PINB0
#define SIG1 0x1E // Yep, Atmel is the only manufacturer of AVR micros.
#define SIG2 0x97
#define SIG3 0x02
#define PAGE_SIZE 0x80U //128 words
#define UART0
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
extern byte GetFlashByte(word address);
extern byte GetExtFlashByte(word address);
extern void ProgrFlash(void);
void putchar_bt(char);
char getch(void);
void getNch(byte);
void byte_response(byte);
void nothing_response(void);
union address_union
{
word word;
byte byte[2];
} address;
union length_union
{
word word;
byte byte[2];
} length;
byte EepromFlag;
byte RampzFlag;
byte buff[256];
byte address_high;
// word Fonts_End __attribute__ ((section (".boot")));
byte pagesz=0x80;
void (*app_start)(void) = 0x0000;
int main(void)
{
byte ch,ch2;
word w;
cbi(BL_DDR,BL);
sbi(BL_PORT,BL);
asm volatile("nop\n\t");
if(GetFlashByte(0x0000) != 0xFF) // Don't start application if
{ // it isn't programmed yet
// Do we start the application or enter bootloader?
if(bit_is_set(BL_PIN,BL)) app_start();
}
#if defined UART0
UBRR0L = (byte)(F_CPU/(BAUD_RATE*16L)-1);
UBRR0H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
UCSR0A = 0x00;
UCSR0C = 0x06;
UCSR0B = _BV(TXEN0)|_BV(RXEN0);
#else
UBRR1L = (byte)(F_CPU/(BAUD_RATE*16L)-1);
UBRR1H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
UCSR1A = 0x00;
UCSR1C = 0x06;
UCSR1B = _BV(TXEN1)|_BV(RXEN1);
#endif
putchar_bt('\0');
while (1)
{
ch = getch();
switch (ch)
{
case '0':
nothing_response();
break;
// Request programmer ID
case '1':
if (getch() == ' ')
{
putchar_bt(0x14);
putchar_bt('A');
putchar_bt('V');
putchar_bt('R');
putchar_bt(' ');
putchar_bt('I');
putchar_bt('S');
putchar_bt('P');
putchar_bt(0x10);
}
break;
// AVR ISP/STK500 board commands
// DON'T CARE so default nothing_response
case '@':
ch2 = getch();
if (ch2 > 0x85) getch();
nothing_response();
break;
// AVR ISP/STK500 board requests
case 'A':
ch2 = getch();
switch (ch2)
{
// Hardware version
case 0x80:
byte_response(HW_VER);
break;
// Software major version
case 0x81:
byte_response(SW_MAJOR);
break;
// Software minor version
case 0x82:
byte_response(SW_MINOR);
break;
// Unknown but seems to be required by avr studio 3.56
case 0x98:
byte_response(0x03);
break;
// Covers various unnecessary responses we don't care about
default:
byte_response(0x00);
break;
}
break;
// Device Parameters DON'T CARE, DEVICE IS FIXED
case 'B':
getNch(20);
nothing_response();
break;
// Parallel programming stuff DON'T CARE
case 'E':
getNch(5);
nothing_response();
break;
// Enter programming mode
case 'P':
// Leave programming mode
case 'Q':
// Erase device, don't care as we will
// erase one page at a time anyway.
case 'R':
nothing_response();
break;
//Set address, little endian. EEPROM in bytes, FLASH in words
//Perhaps extra address bytes may be added in future to support > 128kB FLASH.
//This might explain why little endian was used here, big endian used everywhere else.
case 'U':
address.byte[0] = getch();
address.byte[1] = getch();
nothing_response();
break;
// Universal SPI programming command, disabled.
// Would be used for fuses and lock bits.
case 'V':
getNch(4);
byte_response(0x00);
break;
// Write memory, length is big endian and is in bytes
case 'd':
length.byte[1] = getch();
length.byte[0] = getch();
EepromFlag = 0;
if (getch() == 'E') EepromFlag = 1;
// Store data in buffer,
// can't keep up with serial data stream
// whilst programming pages
for (w = 0; w < length.word; w++)
{
buff[w] = getch();
}
if (getch() == ' ')
{
if (EepromFlag)
{
// Write to EEPROM one byte at a time
for (w =0; w < length.word; w++)
{
eeprom_write_byte((byte *)address.word, buff[w]);
address.word++;
}
}
else
{
// Write to FLASH one page at a time
if (address.byte[1] > 127)
{
address_high = 0x01;
}
else
{
address_high = 0x00;
}
RAMPZ = address_high;
address.word = address.word << 1; // address * 2 -> byte location
// Even up an odd number of bytes
if ((length.byte[0] & 0x01))
{
length.word++;
}
cli();
// Wait for previous EEPROM writes to complete
while(bit_is_set(EECR,EEWE));
ProgrFlash();
// Should really add a wait for RWW section to be enabled, don't actually need it since we never
// exit the bootloader without a power cycle anyhow
}
putchar_bt(0x14);
putchar_bt(0x10);
}
break;
// Read memory block mode, length is big endian.
case 't':
length.byte[1] = getch();
length.byte[0] = getch();
if (address.word > 0x7FFF)
{
RampzFlag = 1;
}
else
{
RampzFlag = 0;
}
if (getch() == 'E')
{
EepromFlag = 1;
}
else
{
EepromFlag = 0;
address.word = address.word << 1; //address * 2 -> byte location
}
// Command terminator
if (getch() == ' ')
{
putchar_bt(0x14);
// Can handle odd and even lengths okay
for (w = 0; w < length.word; w++)
{
if (EepromFlag) // Byte access EEPROM read
{
putchar_bt(eeprom_read_byte((byte *)address.word));
address.word++;
}
else
{
if (!RampzFlag)
{
putchar_bt(GetFlashByte(address.word));
}
else
{
putchar_bt(GetExtFlashByte(address.word + 0x10000));
}
address.word++;
}
}
putchar_bt(0x10);
}
break;
// Get device signature bytes
case 'u':
if (getch() == ' ')
{
putchar_bt(0x14);
putchar_bt(SIG1);
putchar_bt(SIG2);
putchar_bt(SIG3);
putchar_bt(0x10);
}
break;
// Read oscillator calibration byte
case 'v':
byte_response(0x00);
break;
default:
break;
}
}
}
void putchar_bt(char ch)
{
#ifdef UART0
while (bit_is_clear(UCSR0A, UDRE));
UDR0 = ch;
#else
while (bit_is_clear(UCSR1A, UDRE));
UDR1 = ch;
#endif
}
char getch(void)
{
#ifdef UART0
while (bit_is_clear(UCSR0A, RXC));
return UDR0;
#else
while (bit_is_clear(UCSR1A, RXC));
return UDR1;
#endif
}
void getNch(byte count)
{
byte i;
byte n;
for(i = 0; i < count; i++)
{
#ifdef UART0
while (bit_is_clear(UCSR0A, RXC));
n = UDR0;
#else
while (bit_is_clear(UCSR1A, RXC));
n = UDR1;
#endif
}
}
void byte_response(byte val)
{
if (getch() == ' ')
{
putchar_bt(0x14);
putchar_bt(val);
putchar_bt(0x10);
}
}
void nothing_response(void)
{
if (getch() == ' ')
{
putchar_bt(0x14);
putchar_bt(0x10);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -