AVR单片机在程序中写flash时必须从Flash中NRWW区执行写操作,页一般的用户程序都在RWW区,为此要在应用中写flash需要将写flash相关函数定位到NRWW区;
下面是一种应用案例,在bootloader程序中提供一个函数用于写flash页,在用户程序中调用;代码如下:
//用户程序写flash页接口函数
//注:在makefile中指定.mysection段的开始地址,在用户程序中调用时函数地址为此指定地址除2
//注意该函数不能使用全局变量
void AppWriteFlashPage(uint32_t,uint8_t*) __attribute__((section(".mysection")));
void AppWriteFlashPage(uint32_t addr,uint8_t *buf)
{
uint16_t j;
uint16_t i;
for(i=0;i
{
// 页擦除操作
boot_page_erase(addr);
boot_spm_busy_wait ();//等待擦除完成
// 填充缓冲页
for(j = 0; j < DEV_PAGE_SIZE; j += 2)
boot_page_fill((unsigned long)j,*((uint16_t *)(buf+i+j)));
// 页写操作
boot_page_write(addr); // Store buffer in flash page.
boot_spm_busy_wait(); // Wait until the memory is written.
boot_rww_enable (); // Reenable RWW-section again.
}
}
该函数根据参数指定地址写入一个页到flash,定位是通过自定义段.mysection来实现的,在makefile中连接选项增加:
LDFLAGS += -Wl,--section-start=.mysection=0x1E670
这个地址可以是在nrww区内的任意地址,在本项目中我选择了一个boot未占用的地址0x1E670,
测试程序如下:
//mcu:atmega128 clk:11059200Hz
#include "avr/io.h"
#include
#include "util/delay.h"
#include "string.h"
#define LED_TOGGLE PORTB^=_BV(PB6)
void (*WriteFlashPage)(uint32_t,uint8_t*)= 0xf338;//boot程序中将该函数定位到:0x1e670(RWW区写flash函数)
uint8_t g_Buffer[512];
void DelayMs(uint16_t t)
{
uint16_t i;
for(i=0;i
{
_delay_loop_2(8*250);
}
}
#define UART_BAUD 9600
void SendChar(uint8_t c)
{
while(!(UCSR0A & (1<
UDR0=c;
}
int main(void)
{
uint16_t i;
uint32_t addr;
uint8_t c;
//IO口初始化
DDRB=_BV(PB6); //LED
//USART 初始化
UBRR0H=((F_CPU/UART_BAUD/16)-1)/256;
UBRR0L=((F_CPU/UART_BAUD/16)-1)%256;
UCSR0B=_BV(TXEN0);
DelayMs(1000);
SendChar(0xBB);
memset(g_Buffer,0x55,512);
WriteFlashPage(0x10000,g_Buffer); //0x10000为64k处
memset(g_Buffer,0,512);
DelayMs(5000);
//读取并打印到串口
addr=0x10000;
for(i=0;i<50;i++)
{
c=pgm_read_byte_far(addr++);
SendChar(c);
}
while(1)
{
DelayMs(500);
LED_TOGGLE;
}
}
注意bootloader和用户程序是分别编译的,该测试同时展示了不同的两个项目之间调用函数的方法。
|
|