搜索
bottom↓
回复: 3

我的bootloader,死活写不了程序

[复制链接]

出0入0汤圆

发表于 2013-5-23 20:49:53 | 显示全部楼层 |阅读模式
本帖最后由 guew 于 2013-5-23 21:01 编辑

参照马老师的程序,用cvavr给mega32写bootloader,上位机通讯正常,数据传送成功,单步调试确认接受到的数据也正常。但从0x0000开始的flash就是没有数据,那三个加载、页写,等待函数看不出有什么问题,好心人帮帮我。。。
  1. /*****************************************************
  2. This program was produced by the
  3. CodeWizardAVR V2.05.0 Professional
  4. Automatic Program Generator
  5. ?Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
  6. http://www.hpinfotech.com
  7. Chip type               : ATmega32
  8. Program type            : Boot Loader - Size:512words
  9. AVR Core Clock frequency: 12.000000 MHz
  10. Memory model            : Small
  11. External RAM size       : 0
  12. Data Stack size         : 512
  13. *****************************************************/
  14. #include <mega32.h>
  15. #include <dtype.h>
  16. #define PAGE_SIZE 128
  17. #define DATA_BUFFER_SIZE PAGE_SIZE

  18. #define XMODEM_NUL 0x00
  19. #define XMODEM_SOH 0x01
  20. #define XMODEM_STX 0x02
  21. #define XMODEM_EOT 0x04
  22. #define XMODEM_ACK 0x06
  23. #define XMODEM_NAK 0x15
  24. #define XMODEM_CAN 0x18
  25. #define XMODEM_EOF 0x1A
  26. #define XMODEM_RECIEVING_WAIT_CHAR 'C'

  27. flash uint8 startup_message[] = "type 'd' download, others run app.\0";
  28. uint8 data[DATA_BUFFER_SIZE];
  29. uint16 address = 0;

  30. //擦除(code = 0x03)和写入(code = 0x05)一个flash页
  31. void write_page(uint16 p_address,uint8 p_code)
  32. {
  33.     #asm("lds r30,$025a");   //将p_address的低八位放入Y寄存器的低八位
  34.     #asm("lds r31,$025b");   //将p_address的高八位放入Y寄存器的高八位
  35.     SPMCR = p_code;   //给SPMCR寄存器赋擦除控制指令
  36.     #asm("spm");      //擦除指令生效
  37. }

  38. // 填充一个flash缓冲页中的一个字
  39. void page_fill(uint16 p_address,uint16 p_data)
  40. {
  41.     #asm("lds r30,$025a");   //将p_address的低八位放入Y寄存器的低八位
  42.     #asm("lds r31,$025b");   //将p_address的高八位放入Y寄存器的高八位
  43.     #asm("lds r0,$0258");    //将data的低八位放入r0寄存器
  44.     #asm("lds r1,$0259");    //将data的高八位放入r1寄存器
  45.     SPMCR = 0x01;   //给SPMCR寄存器赋加载页指令
  46.     #asm("spm");    //加载页指令生效
  47. }

  48. //等待一个flash页的写完成
  49. void wait_page_write_done(void)
  50. {
  51.     while(SPMCR & 0x40)     //如果正在擦除或页写RWWSB置位,执行while
  52.     {
  53.         while(SPMCR & 0x01);    //如果正在擦除,等待
  54.         SPMCR = 0x11;   //给SPMCR寄存器写入RWW区使能(读)命令 ,并清除RWWSB,while结束,跳出等待  
  55.         #asm("spm");    //使能指令生效
  56.     }
  57. }

  58. //更新一个flash页的完整处理
  59. void write_one_page(void)
  60. {
  61.     uint16 i;
  62.     write_page(address,0x03);   //擦除一个flash页
  63.     wait_page_write_done();    //等待擦除完成
  64.     for(i = 0;i < PAGE_SIZE;i += 2) //将数据填入flash缓冲页中
  65.     {
  66.         page_fill(i,data[i]+(data[i+1] << 8));
  67.               
  68.     }
  69.     write_page(address,0x05);   //将缓冲数据写入一个flash页
  70.     wait_page_write_done();     //等待写入完成
  71. }

  72. //从RS232发送一个字节
  73. void uart_putchar(uint8 c)
  74. {
  75.     while(!(UCSRA & 0x20));      //等待上一个发送完成
  76.     UDR = c;    //发送一个数据
  77. }

  78. //从RS232接受一个字节
  79. int16 uart_getchar(void)
  80. {
  81.     uint8 status,res;
  82.     if(!(UCSRA & 0x80))     //如果没有数据,返回-1
  83.         return -1;
  84.     status = UCSRA;
  85.     res = UDR;
  86.     if(status & 0x1c)       //如果通信硬件有错误
  87.         return -1;
  88.     return res;     //如果没有错误,返回收到的结果   
  89. }

  90. //等待从RS232接收一个有效字节
  91. uint8 uart_waitchar(void)
  92. {
  93.     int16 c;
  94.     while((c = uart_getchar()) == -1);
  95.     return (uint8)c;   
  96. }

  97. //计算CRC
  98. int16 cal_crc(uint8 *ptr, int16 counter)
  99. {
  100.     int16 crc = 0;
  101.     uint8 i;
  102.     while(--counter >= 0)
  103.     {
  104.         crc = crc^(int16)*ptr++ << 8;
  105.         i = 8;
  106.         do
  107.         {
  108.             if(crc & 0x8000)
  109.                 crc = crc << 1^0x1021;
  110.             else
  111.                 crc = crc << 1;
  112.         }while(--i);
  113.     }
  114.     return crc;
  115. }

  116. //退出bootlaoder程序,从0x0000处执行应用程序
  117. void quit(void)
  118. {
  119.     uart_putchar('O');
  120.     uart_putchar('K');
  121.     uart_putchar(0x0d);
  122.     uart_putchar(0x0a);
  123.     while(!(UCSRA & 0x20));//等待结束提示信息发送完成
  124.     GICR = 0x01;   //打开中断迁移允许开关
  125.     GICR = 0x00;   //将中断向量表迁回到应用程序区头部
  126.     #asm("jmp $0000");    //转跳到flash的0x0000处,执行用户的应用程序
  127. }

  128. void main(void)
  129. {
  130.     uint8 i = 0;
  131.     uint8 timercount = 0;
  132.     uint8 pack_no = 1;
  133.     uint16 buffer_pointer = 0;
  134.     uint16 crc;
  135.     //GICR = 0x01;   //打开中断迁移允许开关
  136.     //GICR = 0x02;   //将中断向量表迁回到应用程序区头部
  137.     UBRRL = 0x4d; //波特率9600
  138.     UCSRB = 0x18;   //使能传输与发送
  139.     UCSRC = 0x86;   //8个数据位,1个stop位
  140.     OCR0 = 0xea;    //(234+1) 30ms计时
  141.     TCCR0 = 0x0d;   //CTC模式,1024分频
  142.     //#asm("sei");
  143.    
  144.     //向PC发送开始提示信息
  145.     while(startup_message[i] != '\0')
  146.     {   
  147.         uart_putchar(startup_message[i]);
  148.         i++;
  149.     }
  150.    
  151.     //3秒钟等待PC下发'd',否则退出bootloader程序,从0x0000处执行应用程序
  152.     while(1)
  153.     {
  154.         if(uart_getchar() == 'd')
  155.             break;
  156.         if(TIFR & 0x02)     //timer0 overflow
  157.         {
  158.             if(++timercount > 250)      //100*30ms = 3s到点
  159.                 quit();
  160.             TIFR = TIFR | 0x02;
  161.         }
  162.     }
  163.    
  164.     //每秒向PC机发送一个控制字符'C',等待控制字符 <soh>
  165.     while(uart_getchar() != XMODEM_SOH)    //没有收到开始字符就等待
  166.     {
  167.         if(TIFR & 0x02)
  168.         {
  169.             if(++timercount > 100)
  170.             {
  171.                 uart_putchar(XMODEM_RECIEVING_WAIT_CHAR);   //发送'C'
  172.                 timercount = 0;
  173.             }
  174.             TIFR |= 0x02;
  175.         }
  176.     }
  177.    
  178.     do
  179.     {
  180.         if((pack_no == uart_waitchar()) && (pack_no == (~uart_waitchar())))//校对阴阳两个数据包号
  181.         {
  182.             for(i = 0; i < 128;i++)
  183.             {
  184.                 data[buffer_pointer] = uart_waitchar();
  185.                 buffer_pointer++;
  186.             }
  187.             crc = (uart_waitchar() << 8);
  188.             crc += uart_waitchar();
  189.             if(cal_crc(&data[buffer_pointer - 128],128) == crc)     //CRC校验
  190.             {
  191.                 while(buffer_pointer >= PAGE_SIZE)
  192.                 {
  193.                     write_one_page();
  194.                     address += PAGE_SIZE;   
  195.                     buffer_pointer = 0;
  196.                 }
  197.                 uart_putchar(XMODEM_ACK);
  198.                 pack_no++;
  199.             }
  200.             else
  201.             {
  202.                 uart_putchar(XMODEM_NAK);   //要求重发数据块   
  203.             }
  204.         }
  205.         
  206.         else
  207.         {
  208.             uart_putchar(XMODEM_ACK);   //要求重发数据块
  209.         }
  210.     }
  211.     while(uart_waitchar() != XMODEM_EOT);
  212.    
  213.     uart_putchar(XMODEM_ACK);   //通知PC全部数据收到
  214.    
  215.     if(buffer_pointer)
  216.         write_one_page();   //写最后一页零散数据???
  217.     quit();     //退出bootloader程序,从0x0000处执行应用程序  
  218. }
复制代码

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2013-5-30 20:16:07 | 显示全部楼层
问题解决了!~
原来是CVAVR编译器在编译“SPMCR = 0x01”时,也用到了r30寄存器(见图)。这样一来,本应用来给spm寻址的Z寄存器(r30,r31)中的地址就被破坏了,程序自然就不能正常运行了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入8汤圆

发表于 2013-5-30 20:17:41 | 显示全部楼层
楼主这是没保护好现场啊

出0入0汤圆

 楼主| 发表于 2013-5-30 20:20:51 | 显示全部楼层
本帖最后由 guew 于 2013-5-30 20:23 编辑
guew 发表于 2013-5-30 20:16
问题解决了!~
原来是CVAVR编译器在编译“SPMCR = 0x01”时,也用到了r30寄存器(见图)。这样一来,本应用 ...


这是修改后的代码
  1. void page_fill(uint16 p_address,uint16 p_data)
  2. {
  3.     #asm("lds r30,$025b");   //将p_address的低八位放入Z寄存器的低八位
  4.     #asm("lds r31,$025c");   //将p_address的高八位放入Z寄存器的高八位
  5.     #asm("lds r0,$0259");    //将data的低八位放入r0寄存器
  6.     #asm("lds r1,$025a");    //将data的高八位放入r1寄存器
  7.     #asm("ldi r22,0x01");
  8.     #asm("sts $57,r22");
  9.     #asm("spm");    //加载页指令生效
  10. }
复制代码
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 05:25

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表