根据STM32F10xxx闪存编程手册定义FLASH寄存器
#pragma once
#define FLASH_BASE 0x40022000
typedef struct
{
volatile unsigned int ACR;
volatile unsigned int KEYR;
volatile unsigned int OPTKEYR;
volatile unsigned int SR;
volatile unsigned int CR;
volatile unsigned int AR;
volatile unsigned int RESERVED;
volatile unsigned int OBR;
volatile unsigned int WRPR;
}FLASH_Def;
#define FLASH ((FLASH_Def *)(FLASH_BASE))
#define KEY1 0x45670123
#define KEY2 0xcdef89ab
#define RDPRT 0x000000a5
flash操作头文件
#pragma once
#include "debug.h"
#include "flash_reg.h"
#define FLASH_ADDR_BASE 0x8000000
#define FLASH_PAGE_SIZE 1024
#define FLASH_PAGE_NUM 128
#define FLASH_ADDR_MIN FLASH_ADDR_BASE
#define FLASH_ADDR_MAX 0x801fffe//(FLASH_ADDR_BASE+FLASH_PAGE_SIZE*128-2)
#define FLASH_SAFE_ADDR (FLASH_ADDR_BASE+FLASH_PAGE_SIZE*40)
void flashWrite2Bytes(unsigned int addr, unsigned short data);
void flashWriteBuff(unsigned int addr,void *buff,unsigned int length);
unsigned short flashRead2Bytes(unsigned int addr);
void flashReadBuff(unsigned int addr,void *buff,unsigned int length);
void flashErasePage(unsigned int pageAddr);
void flashEraseAll();
进行解锁
static void unLockFlash()
{
//判断lock位
if (FLASH->CR & (1 << 7))
{
FLASH->KEYR = KEY1;
FLASH->KEYR = KEY2;
}
}
读写半字和buffer,用while (FLASH->SR & (1 << 0))等待闪存编程操作完成
//所写区域未被擦除时,函数无效
void flashWrite2Bytes(unsigned int addr, unsigned short data)
{
ASSERT(addr >= FLASH_ADDR_MIN && addr <= FLASH_ADDR_MAX && !(addr % 2), "addr invalid");
unLockFlash();
FLASH->CR |= 1 << 0;
while (FLASH->SR & (1 << 0))
;
*(unsigned short *)addr = data;
while (FLASH->SR & (1 << 0))
;
//清除标志
FLASH->CR &= ~7;
enLockFlash();
}
void flashWriteBuff(unsigned int addr, void *buff, unsigned int length)
{
ASSERT(!(length % 2), "length invalid");
ASSERT(addr >= FLASH_ADDR_MIN && addr + length <= FLASH_ADDR_MAX && !(addr % 2), "addr invalid");
unsigned short *temp = buff;
for (int i = 0; i < length; i += 2)
{
flashWrite2Bytes(addr + i, *temp);
temp++;
}
}
unsigned short flashRead2Bytes(unsigned int addr)
{
ASSERT(addr >= FLASH_ADDR_MIN && addr <= FLASH_ADDR_MAX && !(addr % 2), "addr invalid");
return *(volatile unsigned short *)addr;
}
void flashReadBuff(unsigned int addr, void *buff, unsigned int length)
{
ASSERT(!(length % 2), "length invalid");
ASSERT(addr >= FLASH_ADDR_MIN && addr + length <= FLASH_ADDR_MAX && !(addr % 2), "addr invalid");
unsigned short *temp = buff;
for (int i = 0; i < length; i += 2)
{
*temp = flashRead2Bytes(addr + i);
temp++;
}
}
擦除页和全部flash
void flashErasePage(unsigned int pageAddr)
{
ASSERT(!((pageAddr - FLASH_ADDR_BASE) % 1024) && pageAddr >= FLASH_ADDR_MIN && pageAddr <= FLASH_ADDR_MAX, "pageAddr invalid");
unLockFlash();
while (FLASH->SR & (1 << 0))
;
FLASH->CR |= 1 << 1;
FLASH->AR = pageAddr;
FLASH->CR |= 1 << 6;
while (FLASH->SR & (1 << 0))
;
FLASH->CR &= ~7;
enLockFlash();
}
void flashEraseAll()
{
unLockFlash();
while (FLASH->SR & (1 << 0))
;
FLASH->CR |= 1 << 2;
FLASH->CR |= 1 << 6;
while (FLASH->SR & (1 << 0))
;
FLASH->CR &= ~7;
enLockFlash();
}
吃个饭
移植FatFs,编辑ffconf.h,修改如下配置
#define FF_USE_MKFS 1
#define FF_VOLUMES 1
#define FF_MULTI_PARTITION 1
#define FF_MIN_SS 1024
#define FF_MAX_SS 1024
在diskio.c文件中,将所有的DEV_RAM更改为DEV_FLASH。
disk_status函数中,case DEV_RAM变成 case DEV_FLASH(后续switch分支同理),直接返回RES_OK.
case DEV_FLASH:
// result = FLASH_disk_status();
// translate the reslut code here
stat = RES_OK;
return stat;
disk_initialize中返回RES_OK.
case DEV_FLASH:
// result = FLASH_disk_initialize();
// translate the reslut code here
stat = RES_OK;
return stat;
disk_read中添加flash读buffer函数
case DEV_FLASH:
// translate the arguments here
result = FLASH_disk_read(buff, sector, count);
// translate the reslut code here
res = result;
return res;
FLASH_disk_read函数如下
int FLASH_disk_read(BYTE *buff, /* Data buffer to store read data */
LBA_t sector, /* Start sector in LBA */
UINT count)
{
flashReadBuff(FLASH_SAFE_ADDR + sector * FF_MIN_SS, buff, count * FF_MIN_SS);
return RES_OK;
}
disk_write中添加flash写buffer函数
case DEV_FLASH:
// translate the arguments here
result = FLASH_disk_write(buff, sector, count);
// translate the reslut code here
res = result;
return res;
FLASH_disk_write函数如下
int FLASH_disk_write(const BYTE *buff, /* Data to be written */
LBA_t sector, /* Start sector in LBA */
UINT count)
{
//先擦除
for (int i = 0; i < count; i++)
flashErasePage(FLASH_SAFE_ADDR + (sector + i) * FF_MIN_SS);
//再写入
flashWriteBuff(FLASH_SAFE_ADDR + sector * FF_MIN_SS, buff, count * FF_MIN_SS);
return RES_OK;
}
disk_ioctl中添加控制函数
case DEV_FLASH:
// Process of the command for the RAM drive
res = FLASH_disk_ioctl(cmd, buff);
return res;
FLASH_disk_ioctl函数如下,f103只有128k,每个page大小1k,ffconf.h中定义FF_MIN_SS=FF_MAX_SS=1k,因此GET_SECTOR_COUNT命令返回最大为128(还得减去本身代码所占空间),但是返回值太小导致初始化失败,此处返回280.
int FLASH_disk_ioctl(BYTE cmd, /* Control code */
void *buff)
{
switch (cmd)
{
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*(LBA_t *)buff = 280;//假的,没有这么多
return RES_OK;
case GET_SECTOR_SIZE:
*(WORD *)buff = 1024;
return RES_OK;
case GET_BLOCK_SIZE:
*(DWORD *)buff = 1;
return RES_OK;
case CTRL_TRIM:
//*(DWORD *)buff=1024;
return RES_OK;
default:
DEBUG("fatfs cmd %d", cmd);
return RES_ERROR;
}
}
开始测试
//指向函数工作区的指针。大小必须至少为FF_MAX_SS字节
unsigned char work[1024];
//卷映射表,逻辑驱动器0绑定在物理驱动器0上第一个分区
PARTITION VolToPart[FF_VOLUMES] = {
{0, 1}, /* "0:" ==> 1st partition in PD#0 */
};
int main()
{
usartInit();
printf("usartInit\n");
ledInit();
printf("ledInit\n");
// printf("res=%d",f_fdisk(0,));
FATFS fs;
FIL file;
MKFS_PARM opt;
opt.fmt = FM_FAT;
opt.au_size = 1024;
opt.align = 1;
opt.n_fat = 1;
opt.n_root = 512;
LBA_t ptbl[] = {100, 0};//将物理驱动器分成一个分区,占用100%
int res;
res = f_mount(&fs, "0:", 1);//强制挂载
if (res)
{
printf("mount error\n");
res = f_fdisk(0, ptbl, work);//挂载失败则创建分区
if (res)
{
printf("fdisk error\n");
return -1;
}
printf("fdisk OK\n");
res = f_mkfs("0:", &opt, work, 1024);//创建分区后,创建一个fat卷
if (res)
{
printf("mkfs error\n");
return -1;
}
printf("mkfs OK\n");
res = f_mount(&fs, "0:", 1);//重新挂载
if (res)
{
printf("critical error\n");
return -1;
}
}
printf("mount OK\n");
res = f_open(&file, "0:/test.txt", FA_CREATE_NEW|FA_WRITE);
if(res==FR_OK)
{
printf("open ok\n");
}
unsigned int coun = 0;
unsigned char pp[20]="this is a test file";
res=f_write(&file,pp,20,&coun);
if(res==FR_OK)
{
printf("write %d\n",coun);
}
f_close(&file);
res = f_open(&file, "0:/test.txt", FA_READ);
if(res==FR_OK)
{
printf("open ok\n");
}
unsigned char dd[20]="this is a test file";
res = f_read(&file, dd, 20, &coun);
if(res==FR_OK)
{
printf("read %d :%s\n", coun,dd);
}
f_close(&file);
while (1)
{
ledOn();
delay(1000);
ledOff();
delay(1000);
}
}
串口结果
usartInit
ledInit
mount error
fdisk OK
mkfs OK
mount OK
open ok
write 20
open ok
read 20 :this is a test file
最近编辑记录 wonderxue (2022-02-20 23:23:27)
离线