Reason for development: The company has a lot of customized software, and users will have new requirements after receiving the product. In fact, many of them are pure software modifications. Now engineers have to open the cover and use the downloader to re-burn the program, which is more troublesome. Because the product's external interface has a serial port, and Atmega itself supports the bootloader function, so we thought of using the serial port to upgrade the programJ.
Development environment and tools: Hardware platform: The board used is the company's Atmega128 platform, a parallel port downloader for AVR, software: Compiler: ICCAVR 7.22, serial port debugging assistant, serial port monitor (used to monitor serial port data, a good thing) and Windows HyperTerminal, download software: PonyProg2000 (this software is convenient for reading EEPROM and Flash, but it cannot be used to burn Atmega2561, there are problems), hexbin.exe tool (ready-made one found on the Internet), used to convert Intel's hex file into a pure hexadecimal file (the format stored in the microcontroller Flash).
Function to be realized: If you want to upgrade the program, burn the firmware to address 0 of the flash through the serial port of the hyperterminal (Xmodem protocol), and then jump to address 0 of the flash, otherwise wait for a period of time and automatically jump to address 0 in the flash. Size of bootloader: within 1024 bytes.
Some notes:
1. Burning of fuses: BOOTRST needs to be programmed so that the MCU automatically jumps to the bootloader area to execute the bootloader code after reset. Then, the fuses of the boot area need to be set according to the size of your bootloader: The specific settings are as shown in the figure below. Here I choose 1024 (note that 1 represents programming and 0 represents programmed):
2. Set the boot lock bit: In order to protect the bootloader from being modified or erased by the application, it must be protected. Atmega provides a fuse bit protection method. The specific settings are as follows (I set BLB0 to 11 and BLB1 to 00):
3. Flash page settings: Flash erase and write are done on a page basis. The manual says that 1 page has 128 bytes, but during actual debugging, it is found that 256 bytes need to be written at a time to be effective. If 128 bytes are written, the second 128 bytes will overwrite the first 128 bytes. In this case, the actual situation will prevail.
4. Notes on the Xmodem protocol: The specific xmodem is not described in this article. I will only talk about the points that need attention. The checksum is optional. I use checksum (which is a simple accumulation). You can also choose 16-bit CRC. This is determined based on the first response byte returned by the microcontroller. In addition, when the sequence number of the packet exceeds 255, it will restart from 0 instead of 1. The first transmission starts numbering from 1. Please pay attention to this.
5. File format file: Like many people on the Internet, I encountered the same file. After the bootloader burned the application into the flash, it was found that the application was not executed. At first, I thought it was a problem of unsuccessful jump. I searched the Internet for a long time but couldn't find the answer. There were many people asking questions. There was no way, I had to rely on myself. I was puzzled, why couldn't the program burned into the Flash be executed when the content of the original file was exactly the same? Later, I accidentally opened the firmware to be burned with the burning software and found that the content was different from what I opened with the hexadecimal tool. Oh my god, I suddenly thought of the key to the problem. It turned out that the hex file generated by ICC was in the Intel hex format. The Intel HEX file is an ASCII text file composed of lines of text that conform to the Intel HEX file format. In the Intel HEX file, each line contains a HEX record. These records consist of hexadecimal coded numbers corresponding to machine language codes and/or constant data. Intel HEX files are usually used to transfer programs and data to be stored in ROM or EPROM. Most EPROM programmers or simulators use Intel HEX files. The data actually stored in the Flash needs to be extracted from this HEX file and then sent to the microcontroller through xmodem. Do not directly send the HEX file generated by ICC. For conversion, you can write a small tool yourself or search for tools with similar functions on the Internet. To save trouble, I found a tool called hex2bin to do the conversion.
6. In the ICC project, you need to set it up. My settings are as follows:
7. Regarding the usage of parameters and return values of nested assembly in C: The following is quoted from the ICC help file "
In the absence of a function prototype, integer arguments smaller than ints (for example, char) must be promoted to int type. If the function prototype is available, the C standard leaves the decision to the compiler implementation. ICCV7 for AVR does not promote the argument types if the function prototype is available.
If registers are used to pass byte arguments, it will use both registers but the higher register is undefined. For example, if the first argument is a byte, both R16/R17 will be used with R17 being undefined. Byte arguments passed on the software stack also take up 2 bytes. We may change the behavior and pack byte arguments tightly in some future release.
The first argument is passed in registers R16/R17 if it is an integer and R16/R17/R18/R19 if it is a long or floating point. The second argument is passed in R18/R19 if available. All other remaining arguments are passed on the software stack. If R16/R17 is used to pass the first argument and the second argument is a long or float, the lower half of the second argument is passed in R18/R19 and the upper half is passed on the software stack.
Integer values are returned in R16/R17 and longs and floats are returned in R16/R17/R18/R19. Byte values are returned in R16 with R17 undefined. ”
There is nothing left. The program is attached below (just debugged, not organized yet, very messy)
main.h
#ifndef _MAIN_H
#define _MAIN_H
#define XMODEM_NUL (0x00)
#define XMODEM_SOH (0x01) // Xmodem start header(128 data packets)
#define XMODEM_STX (0x02) // 1K xmoder start header(1024 data packets)
#define XMODEM_EOT (0x04)
#define XMODEM_ACK (0x06)
#define XMODEM_NAK (0x15) // Indicates that the receiver wants to receive according to the cumulative check method
#define XMODEM_CAN (0x18)
#define XMODEM_EOF (0x1A)
#define XMODEM_CRC_CK 'C' // Indicates that the receiver wants to receive according to the CRC check method
#define SYS_STATE_CHOICE (1)
#define SYS_STATE_READ_DAT (2)
//#define SYS_STATE_ACK (3)
#define SYS_STATE_END (4)
#define SYS_STATE_ERROR (5)
#define SYS_STATE_CANCEL (6)
#define SYS_WAIT_TIME (5000) // 5 seconds
#define SYS_RETRY_MAX (3)
#define UART0_BUF_SIZE (150*2)
#define XTAL (6) //晶振频率(MHz) 6MHz
#define FLASH_PG_SIZE (128*2)
#define OSC_VAR (6000000)
#define cbi(reg, bit) (reg &= ~BIT(bit))
#define sbi(reg, bit) (reg |= BIT(bit))
#endif
main.c
#include
#include
#include "main.h"
#include
//#include "assembly.h"
static unsigned long timer_1ms = 0;
static unsigned char sys_state = 0;
static unsigned char uart0_rx_buf[UART0_BUF_SIZE];
static unsigned long flash_addr = 0;
void sys_set_state(unsigned char state)
{
sys_state = state;
}
unsigned long get_sys_time_ms(void)
{
return timer_1ms;
}
extern int _textmode;
int putchar(char c)
{
//if (_textmode && c == '\n')
// putchar('\r');
/* Wait for empty transmit buffer */
while ( !(UCSR0A & (1<
/* Putting data into buffer , sends the data */
UDR0 = c;
return c;
}
int getchar(void)
{
unsigned char dat = 0;
unsigned char status = 0;
WDR();
if(((UCSR0A & 0x80)==0)){
return -1;
}
status = UCSR0A;
dat = UDR0;
if(status & 0x1C){
return -2;
}
return dat;
}
void sendStr(char *str)
{
int len = 0;
unsigned char i = 0;
len = strlen(str);
for(i = 0; i < len; i++)
putchar(str[i]);
while ( !(UCSR0A & (1<
void port_init(void)
{
// MCUCSR |= 0x80;
// MCUCSR |= 0x80;
PORTA = 0x07; //PA3~PA7 IS LOW,PA2~PA0 IS HIGH
DDRA = 0xFF;
PORTB = 0xFb; //MOSI(PB2) is low *****
DDRB = 0xF7; //PB3 IS INPUT
PORTC = 0xFF; //m103 output only
DDRC = 0xFF;
PORTD = 0xFF;
DDRD = 0x00; //PD0~7 IS INPUT
PORTE = 0xFF;
DDRE = 0xFE;
PORTF = 0xFF;
DDRF = 0x00;
PORTG = 0x1F;
DDRG = 0x00;
}
void uart0_init(void)
{
UCSR0B = 0x00; //disable while setting baud rate
UCSR0A = 0x00;
UCSR0C = 0x06;
//6MHz
UBRR0L = 0x26; //set baud rate lo
//14.7456MHz 9600bps
// UBRR0L = 0x5F; //set baud rate lo
//14.7456MHz 115200bps
// UBRR0L = 0x07; //set baud rate lo
UBRR0H = 0x00; //set baud rate hi
// UCSR0B = 0xD8; //0xB8
// UCSR0B = 0xB8; //0xD8
//UCSR0B = 0x98; //0xD8,0xB8
UCSR0B = 0x18; //0xD8,0xB8,disable rcv interrupt
}
// OSC:6MHz, prescale:1024
void timer0_init(void)
{
TCCR0 = 0x00; //stop
ASSR = 0x00; //set async mode
TCNT0 = 0xf9; //set count
OCR0 = 0xD7;
TCCR0 = 0x07; //start timer
}
#pragma interrupt_handler timer0_ovf_isr:17
void timer0_ovf_isr(void)
{
TCNT0 = 0xf9; //reload counter value
timer_1ms++;
}
void watchdog_off(void)
{
// Write logical one to WDCE and WDE
WDTCR = (1<
WDTCR = 0x00;
}
void watchdog_init(unsigned char time)
{
WDR(); //this prevents a timout on enabling
// Write logical one to WDCE and WDE
WDTCR = (1<
time|=0x08; // prescale: n cycles time=0~7,WDE=1
WDTCR=time; //WATCHDOG ENABLED - dont forget to issue WDRs
}
#if 0
void delay_1ms(void)
{
unsigned int i;
for(i=1;i<(unsigned int)(XTAL*143-20);i++)
{
WDR();
}
}
void delay_ms(unsigned int n)
{
unsigned int i=0;
while(i
delay_1ms();
i++;
}
}
#endif
void init_devices(void)
{
CLI(); //disable all interrupts
XDIV = 0x00; //xtal divider
XMCRA = 0x00; //external memory
port_init();
uart0_init();
timer0_init();
MCUCR = 0x00;
EICRA = 0x00; //extended ext ints
sbi(TIMSK,TOIE0);
// sbi(TIMSK,TOIE1); //Enable timer 1 overflow interrupt
// sbi(TIMSK,TOIE2); //Enable timer 2 overflow interrupt
watchdog_init(7);
//SEI(); //re-enable interrupts
//all peripherals are now initialised
}
#if 0
void EEPROMwrite(unsigned int location, unsigned char byte)
//unsigned int eepromwrite(unsigned int location, unsigned char byte)
{
unsigned char oldSREG;
oldSREG = SREG;
SREG &= ~0x80; // disable interrupt
// Wait for completion of previous write
while(EECR & (1<
EEAR = location;
EEDR = byte;
// Write logical one to EEMWE
EECR |= (1<
EECR |= (1<
SREG = oldSREG;
// return 0; // return Success. ?
}
unsigned char EEPROMread(unsigned int location)
//unsigned char eepromread(unsigned int location)
{
unsigned char oldSREG;
oldSREG = SREG;
SREG &= ~0x80; // disable interrupt
// Wait for completion of previous write
while(EECR & (1<
EEAR = location;
// Start eeprom read by writing EERE
EECR |= (1<
SREG = oldSREG;
// Return data from data register
return EEDR;
}
#endif
#if 1
void wait_page_rw_ok(void)
{
//while(SPMCSR & 0x40){
{
while(SPMCSR & 0x01);
//SPMCSR = 0x11;
asm("spm\n");
}
}
// code:0x03:erase, code:0x05:write a page
void boot_page_ew(unsigned long addr,unsigned char code)
{
wait_page_rw_ok();
asm("mov r30,r16\n"
"mov r31,r17\n"
"out 0x3b,r18\n"
); // put addr into Z register and RAMPZ's BIT0
SPMCSR = code; // set operate code
asm("spm\n"); // operate flash page
wait_page_rw_ok();
}
// fill one word into a page
void boot_page_fill(unsigned int pg_addr,unsigned int data)
{
pg_addr = pg_addr;
data = data;
wait_page_rw_ok();
asm("mov r30,r16\n"
"mov r31,r17\n" // Z register is page addr
"mov r0,r18\n"
"mov r1,r19\n" // R0R1 operate word
);
SPMCSR = 0x01;
asm("spm\n"); // operate flash page
}
void write_one_page(unsigned long f_addr)
{
int i = 0;
for(i = 0; i < FLASH_PG_SIZE;i+=2){
boot_page_fill(i,uart0_rx_buf[i]|(uart0_rx_buf[i+1]<<8));
}
boot_page_ew(flash_addr,0x03);
boot_page_ew(flash_addr,0x05);
}
int check_one_page_ok(unsigned long f_addr)
{
unsigned char dat = 0;
int i = 0;
#if 0
asm("mov r30,r16\n"
"mov r31,r17\n"
"out 0x3b,r18\n"
); // put addr into Z register and RAMPZ's BIT0
for(i = 0; i < FLASH_PG_SIZE; i++){
asm("elpm r0,Z+");
asm("mov %dat, r0");
//if(dat != uart0_rx_buf[i])
// return 0;
}
#endif
return 1;
}
#else
void WriteFlash(void)
{
unsigned int i;
unsigned int TempInt;
for (i=0;i
TempInt=uart0_rx_buf[i]+(uart0_rx_buf[i+1]<<8);
fill_temp_buffer(TempInt,i); //call asm routine.
}
write_page(flash_addr,0x03); //擦除页
write_page(flash_addr,0x05); //写页数据
enableRWW();
}
#endif
#if 0
#pragma interrupt_handler uart0_rxc_isr:19 //iv_USART0_RX
void uart0_rxc_isr( void )
{
#if 0
unsigned char data;
unsigned char index;
data = UDR0;
#endif
}
#endif
void sys_choice_process(void)
{
unsigned long time_enter = 0;
int dat = 0;
time_enter = get_sys_time_ms();
//sendStr("press 'd' to download fw:");
while(1){
dat = getchar();
//if('d' == dat){
{
putchar(XMODEM_NAK);
sys_set_state(SYS_STATE_READ_DAT);
return;
}
#if 0
if(get_sys_time_ms() - time_enter >= SYS_WAIT_TIME){
sys_set_state(SYS_STATE_ERROR);
return;
}
#endif
}
return;
}
#if 0
void sys_ack_process(void)
{
// Nothing, put ack to read data process
return;
}
#endif
unsigned char read_start = 0;
void sys_read_data_process(void)
{
int dat = 0;
int count = 0;
unsigned int i = 0,ee_addr = 0,err_count = 0,cancel_flag = 0;
unsigned char checksum = 0;
//unsigned long flash_addr = 0;
unsigned char packet_sn = 0,block = 0;
unsigned long timer = 0;
read_start = 0;
while(1){
#if 1
if(0 == read_start){
timer++;
if((timer > 600000) ){
sys_set_state(SYS_STATE_END);
return;
}
}
#endif
dat = getchar();
if(dat >= 0){
if(0 == count){
if(XMODEM_EOT == dat){
read_start = 1;
if(1 == block){
write_one_page(flash_addr);
}
putchar(XMODEM_ACK);
sys_set_state(SYS_STATE_END);
return;
}else if(XMODEM_SOH == dat){ // start flag
cancel_flag = 0;
}else if(XMODEM_CAN == dat){ // cancel flag
cancel_flag = 1;
}
}else if(1 == count){
if(1 == cancel_flag){
if(XMODEM_CAN == dat){
cancel_flag = 2;
}else{
putchar('1');
goto error;
}
}
// Note:when packet number reach to 255, it reset to zero,not 1
if((dat - packet_sn == 1)|| ((0x0 == dat) &&(0xff == packet_sn))){ // sn ok
packet_sn = dat;
}else{ // sn error
putchar('2');
goto error;
}
}else if(2 == count){
if(2 == cancel_flag){
if(XMODEM_CAN == dat){
sys_set_state(SYS_STATE_CANCEL);
return;
}else{
putchar('3');
goto error;
}
}
if((dat + packet_sn) == 0xff){ // ok
}else{ // error
putchar('4');
goto error;
}
}
read_start = 1;
count++;
if(count > 3 && count < (128 + 4)){ // get data packets
checksum += dat;
uart0_rx_buf[i++] = dat;
}
if(count >= 132){
if(dat == checksum){ // checksum ok
#if 0
for(i = 0; i < FLASH_PG_SIZE; i++){
EEPROMwrite(ee_addr++,uart0_rx_buf[i]);
}
#else
block++;
if(2 == block){
write_one_page(flash_addr);
//WriteFlash();
//if(!check_one_page_ok(flash_addr)){
// putchar('5');
// goto error;
//}
flash_addr += FLASH_PG_SIZE;
i = 0;
block = 0;
}
#endif
putchar(XMODEM_ACK);
err_count = 0;
}else{ // retry
putchar(XMODEM_NAK);
err_count++;
packet_sn--;
}
count = 0;
checksum = 0;
if(err_count > SYS_RETRY_MAX){
putchar('6');
goto error;
}
}
}
}
return;
error:
sys_set_state(SYS_STATE_ERROR);
return;
}
void sys_run_app(void)
{
//while(1); // TODO: just for debug
MCUCR = 0x01;
MCUCR = 0x00; //Move the interrupt vector to the beginning of flash
RAMPZ = 0x00;
asm("jmp 0x00000\n");
}
void sys_end_process(void)
{
sendStr("OK.\r\n");
sys_run_app();
return;
}
void sys_cancel_process(void)
{
sendStr("CANCEL.\r\n");
sys_run_app();
return;
}
void sys_error_process(void)
{
sendStr("ERROR.\r\n");
sys_run_app();
return;
}
void sys_run(void)
{
switch(sys_state){
case SYS_STATE_CHOICE:
sys_choice_process();
break;
//case SYS_STATE_ACK:
//sys_ack_process();
break;
case SYS_STATE_READ_DAT:
sys_read_data_process();
break;
case SYS_STATE_END:
sys_end_process();
break;
case SYS_STATE_CANCEL:
sys_cancel_process();
break;
case SYS_STATE_ERROR:
default:
sys_error_process();
break;
}
}
#if 0
void test_flash(void)
{
int i = 0;
for(i = 0; i < FLASH_PG_SIZE; i++){
uart0_rx_buf[i] = 0x11;
}
write_one_page(flash_addr);
flash_addr += FLASH_PG_SIZE;
for(i = 0; i < FLASH_PG_SIZE; i++){
uart0_rx_buf[i] = 0x22;
}
write_one_page(flash_addr);
flash_addr += FLASH_PG_SIZE;
for(i = 0; i < FLASH_PG_SIZE; i++){
uart0_rx_buf[i] = 0x33;
}
write_one_page(flash_addr);
flash_addr += FLASH_PG_SIZE;
while(1);
}
#endif
void main(void)
{
static unsigned long time_last = 0;
unsigned long time_now = 0;
init_devices();
sys_set_state(SYS_STATE_CHOICE);
//sendStr("started.\r\n");
//EEPROMwrite(0,'M');
//EEPROMwrite(1,'W');
//delay_ms(3000);
while(1){
#if 0
time_now = get_sys_time_ms();
if(time_now - time_last > 2000){
sendStr("alive...\r\n");
time_last = time_now;
}
#endif
sys_run();
//test_flash();
}
}
Previous article:Method of judging pulse width by AVR microcontroller
Next article:Share the design of PWM pulse width modulator based on tc1
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Analysis of the information security mechanism of AUTOSAR, the automotive embedded software framework
- Brief Analysis of Automotive Ethernet Test Content and Test Methods
- How haptic technology can enhance driving safety
- Let’s talk about the “Three Musketeers” of radar in autonomous driving
- Why software-defined vehicles transform cars from tools into living spaces
- How Lucid is overtaking Tesla with smaller motors
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Former Chairman explains the new PCIe5.0 specification. Tektronix invites you to watch and win prizes
- Today I thought of the "collection economy", office workers are very busy
- In adjustment
- RISC-V MCU Development (Part 14): Help and Feedback
- PCB design, which tool software is the best?
- IAR settings let the code run from reset instead of main
- The 19th year holiday schedule is here.
- What basics are needed to learn programming?
- [National Technology N32G457 Review] Implementation of Environmental Status Detection Device
- [BearPi-HM Nano, play Hongmeng "Touch and Go"] Part 2: Setting up the environment is so simple