十二FLASH存储之FS和FDS

FLASH存储之FS和FDS

1.fstorage

1.1勾选配置

在这里插入图片描述

1.2相关代码

写flash比较耗时间,此时cpu挂起,可能导致ble连接断开。
1页为4KB
注意大量数据的话要分批写入。擦除和写入分开进行

//FS事件处理函数
static void fstorage_evt_handler(nrf_fstorage_evt_t *p_evt)
{
    //FS操作错误
    if (p_evt->result != NRF_SUCCESS)
    {
        printf("--> Event received: ERROR while executing an fstorage operation.");
        return;
    }
    //判断事件类型,执行相应处理,这里只是打印出事件信息
    switch (p_evt->id)
    {
        //FS写完成事件
    case NRF_FSTORAGE_EVT_WRITE_RESULT:
    {
        printf("--> Event received: wrote %d bytes at address 0x%x.",
               p_evt->len, p_evt->addr);
    }
    break;
    //擦除完成事件
    case NRF_FSTORAGE_EVT_ERASE_RESULT:
    {
        printf("--> Event received: erased %d page from address 0x%x.",
               p_evt->len, p_evt->addr);
    }
    break;

    default:
        break;
    }
}
//定义实例
NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) =
    {
        /* Set a handler for fstorage events. */
        .evt_handler = fstorage_evt_handler, //回调

        /* These below are the boundaries of the flash space assigned to this instance of fstorage.
     * You must set these manually, even at runtime, before nrf_fstorage_init() is called.
     * The function nrf5_flash_end_addr_get() can be used to retrieve the last address on the
     * last page of flash available to write data. */
        .start_addr = 0x3e000, //开始地址
        .end_addr = 0x3ffff,   //结束地址
};

//读写,擦除测试函数
void flash_test(void)
{
    ret_code_t rc;
    printf("fstorage example started.\r\n"); //开始演示

    nrf_fstorage_api_t *p_fs_api;
    p_fs_api = &nrf_fstorage_sd; //处理操作类型设置

    rc = nrf_fstorage_init(&fstorage, p_fs_api, NULL); //flash处理的开始地址和结束地址初始化
    APP_ERROR_CHECK(rc);
    (void)nrf5_flash_end_addr_get();                               //获取地址,判断为可写地址大小。加void是应对语法检查
    rc = nrf_fstorage_erase(&fstorage, FLASH_START_ADDR, 1, NULL); //擦除1页
    APP_ERROR_CHECK(rc);
    rc = nrf_fstorage_write(&fstorage, 0x3e000, &m_data, sizeof(m_data), NULL); //向0x3e000写入数据m_data数据
    APP_ERROR_CHECK(rc);
    wait_for_flash_ready(&fstorage);                //等待写完
    printf("Writing \"%x\" to flash.\r\n", m_data); //打印第一次写入的值
    printf("Done.\r\n");

    m_data = 0xDEADBEEF;                                                        //重新向m_data赋值
    rc = nrf_fstorage_write(&fstorage, 0x3e100, &m_data, sizeof(m_data), NULL); //再把数据写到0x3e100地址去
    APP_ERROR_CHECK(rc);
    wait_for_flash_ready(&fstorage);                //等待完成
    printf("Writing \"%x\" to flash.\r\n", m_data); //打印第二次写入的值
    printf("Done.\r\n");

    nrf_fstorage_read(&fstorage, 0x3e000,
                      &m_data2,
                      sizeof(m_data2)); //从0x3e000地址读取数据

    printf("Read \"%x\" to flash.\r\n", m_data2); //打印读取的值
    nrf_fstorage_read(&fstorage, 0x3e100,
                      &m_data2,
                      sizeof(m_data2));           //从0x3e100地址读取数据
    printf("Read \"%x\" to flash.\r\n", m_data2); //打印读取的值
}

2.FDS

只存储记录,相当于把数据和记录绑定到一起了,文件ID和KEY可以不唯一,取值范围有限制,最后会生成唯一的记录ID

2.1配置

位于nrf_libraries下,同时使能FS,crc16

在这里插入图片描述

1.1FDS使用的虚拟页的数量。FDS使用的flash的大小取决于这两个值
1.2默认情况4K,可以增加以便能够存储大于物理页面的数据
2.
3.如果FDS用户较多或者APP希望一次排队更多的操作而不等待先前的操作完成,可以增加大小。一般情况下,如果出现FDS_ERR_NO_SPACE_IN_QUEUES则增加队列大小
4.CRC可选,如果使能,FDS打开记录读数据的时候会对记录校验
读操作校验,还有写操作校验
5.表示最大用户数量,一个用户对应一个回调函数。不同的程序模块要使用FDS需要注册各自的回调

2.2相关代码

static bool volatile m_fds_initialized;

static void fds_evt_handler(fds_evt_t const *p_evt) //fds处理事件回调
{
    switch (p_evt->id)
    {
    case FDS_EVT_INIT:
        if (p_evt->result == FDS_SUCCESS)
        {
            m_fds_initialized = true;
        }
        break;

    case FDS_EVT_WRITE:
    {
        if (p_evt->result == FDS_SUCCESS)
        {
            NRF_LOG_INFO("Record ID:\t0x%04x", p_evt->write.record_id);
            NRF_LOG_INFO("File ID:\t0x%04x", p_evt->write.file_id);
            NRF_LOG_INFO("Record key:\t0x%04x", p_evt->write.record_key);
        }
    }
    break;

    case FDS_EVT_DEL_RECORD:
    {
        if (p_evt->result == FDS_SUCCESS)
        {
            NRF_LOG_INFO("Record ID:\t0x%04x", p_evt->del.record_id);
            NRF_LOG_INFO("File ID:\t0x%04x", p_evt->del.file_id);
            NRF_LOG_INFO("Record key:\t0x%04x", p_evt->del.record_key);
        }
        m_delete_all.pending = false;
    }
    break;

    default:
        break;
    }
}

bool record_delete_next(void)
{
    ret_code_t rc;
    fds_find_token_t tok = {0};
    fds_record_desc_t desc = {0};
    rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok);
    if (rc == FDS_SUCCESS)
    {
        ret_code_t rc = fds_record_delete(&desc);
        if (rc != FDS_SUCCESS)
        {
            return false;
        }

        return true;
    }
    else
    {
        /* No records left to delete. */
        return false;
    }
}

#define CONFIG_FILE (0xF010)
#define CONFIG_REC_KEY (0x7010)

typedef struct //可以为任意类型,但需要4字节对齐
{
    uint32_t device_name;

} __attribute__((aligned(4))) configuration_t;
/* Dummy configuration data. */
static configuration_t m_dummy_cfg =
    {
        .device_name = 0x123456,
};

/* A record containing dummy configuration data.包含仿真配置数据的记录 */
static fds_record_t const m_dummy_record =
    {
        .file_id = CONFIG_FILE,      //文件ID
        .key = CONFIG_REC_KEY,       //记录钥匙
        .data.p_data = &m_dummy_cfg, //仿真数据配置
        /* The length of a record is always expressed in 4-byte units (words). 数据长度一般超过4个字节*/
        .data.length_words = (sizeof(m_dummy_cfg) + 3) / sizeof(uint32_t),
};

void fds_test(void)//要在协议栈初始化之前调用
{
	//fds_gc()垃圾回收
    ret_code_t rc;
    uint32_t *data;
    (void)fds_register(fds_evt_handler); //注册FDS事件回调函数接收FS事件
    rc = fds_init();                     //fds初始化

    APP_ERROR_CHECK(rc);

    while (!m_fds_initialized) //等待初始化完成
    {
        sd_app_evt_wait(); //等待过程中待机
    }

    fds_stat_t stat = {0};
    rc = fds_stat(&stat); //设置统计数据
    APP_ERROR_CHECK(rc);

    record_delete_next(); //把所有记录清零, 

    fds_record_desc_t desc = {0}; //用来操作记录的描述符结构清零
    fds_find_token_t tok = {0};   //保存秘钥的令牌清零

    rc = fds_record_write(&desc, &m_dummy_record); //写记录和数据
    APP_ERROR_CHECK(rc);

    rc = fds_record_find(CONFIG_FILE, CONFIG_REC_KEY, &desc, &tok); //对应KEY记录查找数据

    if (rc == FDS_SUCCESS) //如果查找成功
    {
        /* A config file is in flash. Let's update it. */
        fds_flash_record_t config = {0}; //把配置清零

        /* Open the record and read its contents. */
        rc = fds_record_open(&desc, &config); //打开记录读取数据
        APP_ERROR_CHECK(rc);

        /* Copy the configuration from flash into m_dummy_cfg.复制数据到cfg */
        memcpy(&m_dummy_cfg, config.p_data, sizeof(configuration_t));

        NRF_LOG_INFO("Found Record ID = %d", desc.record_id);
        NRF_LOG_INFO("Data = ");
        data = (uint32_t *)config.p_data;
        for (uint16_t i = 0; i < config.p_header->length_words; i++)
        {
            NRF_LOG_INFO("0x%8x ", data[i]); //打印输出数据
        }
        NRF_LOG_INFO("\r\n");

        /* Close the record when done reading. */
        rc = fds_record_close(&desc); //关闭记录
        APP_ERROR_CHECK(rc);

        /* Write the updated record to flash. 更新flash上的记录*/
        rc = fds_record_update(&desc, &m_dummy_record);
        APP_ERROR_CHECK(rc);
    }
    else
    {
        /* System config not found; write a new one. */
        NRF_LOG_INFO("Writing config file...");

        rc = fds_record_write(&desc, &m_dummy_record); //重新写记录
        APP_ERROR_CHECK(rc);
    }
}

原文地址:https://blog.csdn.net/qq_27182175/article/details/110791961

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


  译序:JWMediaPlayer是开源的网页使用的Flash播放器。本文采摘于JWPlayer的官方文档,讲解了JWPlayer对于RTMP的使用方法,我们可以从JWPlayer客户端的角度来了解RTMP协议。以下是官方原文:      简介    RTMP(RealTimeMessagingProtocol
    Flash编程原理都是只能将1写为0,而不能将0写成1.所以在Flash编程之前,必须将对应的块擦除,而擦除的过程就是将所有位都写为1的过程,块内的所有字节变为0xFF.因此可以说,编程是将相应位写0的过程,而擦除是将相应位写1的过程,两者的执行过程完全相反.一、Nor和NandFlash
 上传setenvgatewayip192.168.1.1;setenvserverip192.168.1.7;setenvipaddr192.168.1.156;mw.b0x820000000xff0x1000000sfprobe0sfread0x8200000000x1000000tftp0x82000000test.bin0x1000000 下载mw.b82000000ff1000000tftp82000000test.bi
Error:FlashDownloadFailed-"Cortex-M3"出现一般有两种情况:1.SWD模式下,Debug菜单中,Reset菜单选项(Autodetect/HWreset/sysresetReq/Vectreset)默认是AutoDetect,改成SysResetReq即可。2.Jtag模式下,主要是芯片大小选错。Flash->ConfigureFalshTools配置窗口,切换到“Utilities"
jPlayer是一个用于控制和播放mp3文件的jQuery插件。它在后台使用Flash来播放mp3文件,前台播放器外观完全可以使用XHML/CSS自定义。支持:有一点比较好的是,在支持html5的浏览器上会使用html5的标签audio或者video,而不支持的浏览器上使用swf来播放选择需要播放的Mp3文件。播放、暂停
#ifndef__FONTUPD_H__#define__FONTUPD_H__#include"sys.h" //字库信息结构体定义33字节__packedtypedefstruct{u8fontok;//字库存在标志,0XAA,字库正常;其他,字库不存在u32ugbkaddr;//unigbk的地址u32ugbksize;//unigbk的大小u32f12addr;//gbk12地址u32g
ROM(ReadOnlyMemory)和RAM(RandomAccessMemory)指的都是半导体存储器。ROM在系统停止供电的时候仍然可以保持数据,而RAM通常都是在掉电之后就丢失数据,但是访问速度快。典型的RAM就是计算机的内存。RAM有两大类,一种称为静态RAM(StaticRAM/SRAM),SRAM速度非常快,是目前读写最快的存储
JSpc端和移动端实现复制到剪贴板功能实现在网页上复制文本到剪切板,一般是使用JS+Flash结合的方法,网上有很多相关文章介绍。随着HTML5技术的发展,Flash已经在很多场合不适用了,甚至被屏蔽。本文介绍的一款JS插件,实现了纯JS方法复制文本到剪切板。插件名是Clipboard.js,该插件不依
例子:R0=1R1=1R2=10R3=e000ed10R12=0LR=fffffff9(中断返回值)PC=0PSR=60000013或60000016或60000036(Z、C、EXCEPT_NUM:RTC_WKUP_IRQn、EXTI0_IRQn、USART2_IRQn)BFAR=e000ed38(不关心)CFSR=20000(INVSTATE:Invalidstateusagefault thePCvaluestackedf
 内存接口概念首先来分析下操作GPIO控制器和操作UART控制器两者的区别如图是S3C2440是个片上系统,有GPIO控制器(接有GPIO管脚),有串口控制器(接有TXDRXD引脚)配置GPIO控制器相应的寄存器,即可让引脚输出高低电平;配置UART控制器相应的寄存器,即可让引脚输出波形。前者相对简单,类
小编导语:    近几年来,网页游戏成为了游戏界关注的焦点,由于其制作简单,成本低并且收益率较高,因此成为了众多游戏厂商追逐的对象,但是除了商家夸张的炒作宣传外,很少有页游佳作出现。然而,随着Unity3D游戏引擎的出现,网页游戏的3D化成了页游冲出重围的杀手锏,那么在flash网页游戏称
1.指定数组到特定的Flash单元#pragmalocation=0x000FFF00 __rootconstcharFlash_config[]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0
继续研究发现,计算机的固件真的很有趣。参考了一些重要的资料,比如http://donovan6000.blogspot.com/2013/06/insyde-bios-modding-advanced-and-power-tabs.html等,对于IDA的使用也了解了一些。最后,总结一下目前看来可行性的方案:0.基础知识储备,包括UEFIBIOS的概念,InsydeBIOS的
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>navigator对象<itle></head><body><buttononclick="checkFlash()">检测</button>
修改网上流传的flash-marker.js(function(global,factory){typeofexports==='object'&&typeofmodule!=='undefined'?module.exports=factory():typeofdefine==='function'&&define.amd?define(factory
shareObject本地缓存存储位置:win7系统用户到C:\Users\[你的用户名]\AppData\Roaming\Macromedia\FlashPlayer\#SharedObjects\XP或2003用户到:C:\DocumentsandSettings\用户名\ApplicationData\Macromedia\FlashPlayer\#SharedObjects\ ---------------------作者:iteye_
安装谷歌浏览器之后经常遇到Flash崩溃或者浏览器在浏览Flash内容时卡死的情况。在网上查找资料大多都认为应该是浏览器自带的Flash插件工作模式引起的问题,解决方法如下:首先在地址栏输入chrome://plugins/显示浏览器使用的插件。点击右上角的详细信息,可以看到Flash插件为进程外
之前一直使用的W25Q16spiflash都没问题,换了一款W25Q80后发现工作不正常,经过测试,初步定位到问题在于初始化SPI后是否将CS拉高。于是又去查看了一下原厂代码:发现原厂的代码初始化SPI接口时是专门拉高CS的。结论:网上很多代码初始化SPI接口时没有专门拉高CS,对某些型号可能确实
======================================================NANDFlash最小存储单元:写数据操作:通过对控制闸(ControlGate)施加高电压,然后允许源极(SOURCE)和汲极(RRAIN)间的N信道(N-Channel)流入电子,等到电流够强,电子获得足够能量时,便会越过浮置闸(FloatingGate)底下的二氧化硅层(S
安装CnarioPlayer3.8.1.156或其他版本时,有时会出现如下提示:Warning4154.AdobeFlashPlayer13...notcorrectlyinstalled:请前往AdobeFlash网站,并选择下图示的版本下载安装: