cumt_123456 发表于 2012-12-18 15:09:56

求助:深入浅出AVR(IAP移植),谢谢

硬件:mega16L软件:ICC6.31
1、我使用书中的例程(boot基础事例程序)改写成mega16的程序,读取flash,可以看到flash被改写成“串口数据包计算助手”生成的数据。
但我,根据例程(实例18_ATmega48在线程序更新_闪烁方式1)修改后,mega48在线下载后台软件可以下载成功程序,但程序运行的不是IAP下载的程序。不知道是怎么回事。
谢谢。

程序如下:
#include "iom16v.h"
#include "macros.h"

#definemclk   16000000

#define Con_true        1
#define CmdByte IapBuffer
#define PageAddrL IapBuffer
#define PageAddrH IapBuffer

void Iap (void);

union Char_Int
{
        unsigned char chr_dat;
        unsigned int Int_dat;
};

#define CHAR_H                1
#define CHAR_L                0

void Delay_mS(unsigned int Time)
{
    unsigned char n;
    while(Time>0)
    {
      for (n=1;n<187;n++)
      {
            asm("nop");
      }
      Time--;
    }
}

void main (void)
{
    DDRC = 0xFF;
    PORTC = 0xFF;
    DDRB = 0x00;      //PB端口输入状态
    PORTB = 0xFF;       //PB端口开启内建上拉
   
        uart_init(9600);
   // uart_putchar('a') ;
/*
    while(PINB&0x01)
    {
      PORTC ^= 0xFF;
      Delay_mS(500);
    }
   */
        Iap();
}

#pragma text:boot_zone


/*******************************************
函数名称: Uart_init
功    能: 异步串口初始化
参    数: 无
返回值: 无
/********************************************/
void uart_init(unsigned int baud)
{
   UCSRB=0x00;
   UCSRA=0x00;                   //控制寄存器清零
   UCSRC=(1<<URSEL)|(0<<UPM0)|(3<<UCSZ0);   //选择UCSRC,异步模式,禁止   
   baud=mclk/16/baud-1        ;    //   校验,1位停止位,8位数据位
   UBRRL=baud;                                //波特率最大为65K                       
   UBRRH=baud>>8;                    //设置波特率
   UCSRB=(1<<TXEN)|(1<<RXEN);         //接收、发送使能,接收中断使能
// SREG|=0x80;                      //全局中断开放
   DDRD|=0X02;                      //配置TX为输出(很重要)

}
//从RS232发送一个字节
void uart_putchar(char c)
{
      while(!(UCSRA & 0x20));
      UDR = c;
}
//从RS232接收一个字节
int uart_getchar(void)
{
      unsigned char status,res;
      if(!(UCSRA & 0x80)) return -1; //no data to be received
      status = UCSRA;
      res = UDR;
      if (status & 0x1c) return -1; // If error, return -1
      return res;
}
unsigned char Iap_Receive (void)
{
    unsigned int counter;

    counter = 30000;

    while(!(UCSRA&(1<<RXC)))
    {
      if (counter==0)
      {
            PORTC ^= (1<<5);
            counter = 30000;
      }
      counter--;
    };

    return UDR;
}

void Iap_OK ()      //发送应答包 AA 05 50 55 55
{
    unsigned char Iap_Pack_OK;
    unsigned char i;
   
    Iap_Pack_OK = 0xAA;
    Iap_Pack_OK = 0x05;
    Iap_Pack_OK = 0x50;
    Iap_Pack_OK = 0x55;
    Iap_Pack_OK = 0x55;

    for (i = 0 ; i < 5 ; i++)
    {
       uart_putchar(Iap_Pack_OK);
    }
}

void Fill_Tb (unsigned int dat, unsigned int addr)
{
        asm("movw R30,R18");
        asm("movw R0,R16");
        asm("ldi R16,0x01");
        asm("sts 0x57,R16");
        asm("spm");
        while(SPMCR&(1<<SPMEN));
}

void Erase_Page (unsigned int addr)
{
        asm("movw R30,R18");
        asm("ldi R16,0x03");
        asm("sts 0x57,R16");
        asm("spm");
        while(SPMCR&(1<<SPMEN));
}

void Prog_Page (unsigned int addr)
{
        asm("movw R30,R18");
        asm("ldi R16,0x05");
        asm("sts 0x57,R16");
        asm("spm");
        while(SPMCR&(1<<SPMEN));
   
}

#pragma ctask Iap

void Iap (void)
{
        unsigned char counter,IapStatu,CheckSum, i;
        unsigned char IapBuffer;
        union Char_Int Iap_dat,Iap_addr;

        CLI();                                          //整个IAP过程中都将禁止中断
        DDRC = (1<<5);                                  //PC5端口上的发光二极管闪烁以指示IAP状态
   // uart0_init();                                 //重新初始化串口模块
    IapStatu = 1;                                 //进入IAP状态
   //   uart_putchar('b') ;
        //   Iap_OK();
    while (IapStatu)
    {
      while(Iap_Receive() != 0xAA);               //等待包头到来,包头不参与校验计算,可不存储
      IapBuffer = Iap_Receive();               //接收包长度字节

      for (counter = 0 ; counter < (IapBuffer-2) ; counter++)
      {
            IapBuffer = Iap_Receive();       //依长度字节指示,循环接收所有数据
      }
                /*
      if(CmdByte==0x09)
                {
            IapStatu = 0;
            continue;
                }
                */
      CheckSum = 0;
      
      for (i = 0 ; i < (IapBuffer-2) ; i++)
      {
            CheckSum ^= (IapBuffer);
      }
                /*
        for (i = 0 ; i < (IapBuffer-2) ; i++)
    {
       uart_putchar(IapBuffer);
    }
        */
       
       // CheckSum ^= (IapBuffer-2]);
                //uart_putchar('a') ;
      if (CheckSum!= 0x00)
      {   
            continue;                              //校验失败,返回等待下一次通讯
      }
               
   //   uart_putchar('c') ;
      if (CmdByte != 'P')       //接到退出下载命令,退出IAP状态 'P'=0x50
      {
               //   uart_putchar('d') ;
            IapStatu = 0;
            continue;
      }

      Iap_OK();

            Iap_addr.chr_dat = PageAddrH;
            Iap_addr.chr_dat = PageAddrL;

            for(counter = 0 ; counter < 64 ; counter++)   //缓冲页面填充
            {   
                    Iap_dat.chr_dat = IapBuffer[(counter*2)+4];
                    Iap_dat.chr_dat = IapBuffer[(counter*2)+5];
                    Fill_Tb(Iap_dat.Int_dat, (unsigned int)(Iap_addr.Int_dat+(counter*2)));
            }

            Erase_Page(Iap_addr.Int_dat);                   //页面擦除
            Prog_Page(Iap_addr.Int_dat);                  //页面写入
               
        //   uart_putchar('c') ;
          // break;
    }
    uart_putchar('b') ;
    asm("rjmp __start");                              //软件实现的从新启动
}

cumt_123456 发表于 2012-12-19 01:06:36

难道没人喜欢IAP下载程序?那我自己坐沙发了。{:victory:}一定会调试通过的。

Gorgon_Meducer 发表于 2012-12-19 02:00:12

1、你不能说通讯成功了就是写Flash成功了
2、调试的时候是否检查过跳转到应用区的汇编是正确的
3、书中介绍的的IAP写法并不是最优的--以现在的眼光看来。

回头我给你看Snail Bootloader的工程
页: [1]
查看完整版本: 求助:深入浅出AVR(IAP移植),谢谢