您尚未登录。

楼主 # 2022-02-20 17:34:28

wonderxue
会员
注册时间: 2021-04-16
已发帖子: 12
积分: 33

stm32f103c8使用寄存器实现读写内部FLASH并移植FATFS

根据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)

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn