Chinaunix首页 | 论坛 | 博客
  • 博客访问: 605785
  • 博文数量: 165
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1554
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-23 22:57
个人简介

我本仁慈,奈何苍天不许

文章分类

全部博文(165)

文章存档

2018年(1)

2016年(33)

2015年(5)

2014年(34)

2013年(92)

分类: 嵌入式

2016-07-21 14:11:19


nordic BLE 交流群498676838

本教程说明 如何在带协议栈的BLE工程中使用flash操作。

教程基于sdk9.0 uart工程

xxx\NordicSemiconductor\nRF_Examples\9.0.0\ble_peripheral\ble_app_uart

Nordic的SDKflash操作封装成了一个pstorage模块。 模块提供了很好用的flash操作接口。


使用flash前需要调用 pstorage_init函数来初始化pstorage模块。

然后就可以调用pstorage_register函数来注册自己要使用的block数量和block_size(最好四字节对齐)


之后就可以使用pstorage_block_identifier_get  函数来或得你要操作的block_num (0-申请的block数量) 的地址。然后在使用获得的地址调用pstorage_load pstorage_store  等操作

这里需要注意的是 涉及到存储的操作,比如store updata因为模块内部处理都需要时间,而这些函数内部又不会复制你传进来的buff所以,如果你只用了一个buff的话,连续调用两个updata是会出错的。你需要等待上次的操作完成才能再使用这个buff


用代码来解释下。


错误的使用方式:

 Buff:里面放的是要存储的数据

    Pstorage_update(dest1,buff);

    修改buff数据。

    Pstorage_updata(dest2,buff);

 看过内部源码的都知道updata的是分两次操作的,首先赋值原来的flash数据到swap区然后,然后擦除之前放数据的page,之后再将原来的数据修改后写会。所以这个过程需要时间。未在上次操作完成就又使用了buff,会导致前面一次的flash写操作出问题。


正确的方式:

Buff:里面放的是要存储的数据

    Pstorage_update(dest1,buff);

    等待上面操作完成。

    修改buff数据。

    Pstorage_updata(dest2,buff);

或者:

Buff1:里面放的是要存储到dest1的数据

Buff2:里面放的是要存储到dest2的数据

    Pstorage_update(dest1,buff);

    Pstorage_updata(dest2,buff);



我们在uartdemo上来实验flash的使用。

我们通过手机向设备发送八个字节的数据,设备受到后先存储在flash中然后在flash的回调函数中判断是否存储完成,如果完成就设置标志。 最后在主函数中判断这个标志,如果标志被置位代表存储操作完成,我们就可以调用读操作来读出flash中的数据了


下面介绍代码的编写:

PS:UART例子中要先关流控

首先在main.c#include”pstorage.h”

然后我们要 初始化,再注册自己要使用的flash大小。


添加flash相关的代码和变量。

pstorage_handle_t block_id;//定义全局变量,flash存储的地址索引

uint8_t my_flag = 0;//定义标志标量。Main函数中会根据标志来                      //flash

uint8_t my_buff[8]={0};  //全局数组用来存放手机发过来的数据,                     //然后写到flash

//定义flash操作完成后的回调函数,

static void my_cb(pstorage_handle_t  * handle,uint8_t op_code,uint32_t result,

                   uint8_t  * p_data, uint32_t   data_len)

{

    switch(op_code)

    {      

       case PSTORAGE_UPDATE_OP_CODE:

           if (result == NRF_SUCCESS)

           {

               my_flag = 1; //当flash update完成后置位标志。 Main函数中便可以读flash数据了

           }

           else

           {

               // Update operation failed.

           }

           break;

    }

}


//main中添加flash的初始化和注册代码

int main(void)

{

    uint32_t err_code;

    bool erase_bonds;

    uint8_t  start_string[] = START_STRING;

   pstorage_module_param_t module_param;

   module_param.block_count = 1; // 申请了一个块

   module_param.block_size = 16;  //块大小为16(最小要求是16,但是后面的处理我们都只处理手机发过来的前8字节)

   module_param.cb = my_cb;

   pstorage_init();      //初始化

   pstorage_register(&module_param, &g_block_id);//注册申请

    // Initialize.

    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);

    uart_init();

    buttons_leds_init(&erase_bonds);

   ………..

   ……….

}.

然后我们需要在手机发送数据过来的时候将数据更新到flash中。

ble_nus.c中的ble_nus_on_ble_evt函数中有对手机写事件的处理。处理是在函数on_write中做的,我们在这个函数中添加自己的代码,红色部分为添加的代码

static void on_write(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)

{

    ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;


    if ( (p_evt_write->handle == p_nus->rx_handles.cccd_handle)&& (p_evt_write->len == 2))

    {

         ………………………….

    }

    else if ( (p_evt_write->handle == p_nus->tx_handles.value_handle)&& (p_nus->data_handler != NULL))

    {    //屏蔽掉之前的处理函数,添加flash 更新数据操作。

        //p_nus->data_handler(p_nus, p_evt_write->data, p_evt_write->len);

         pstorage_handle_t      dest_block_id;

         uint8_t len = p_evt_write->len>8?8:p_evt_write->len;

         memcpy(my_buff, p_evt_write->data, len);

         pstorage_block_identifier_get(&g_block_id, 0, &dest_block_id);   //因为只注册了一个flash块,所以其实这个函数可以不调用的。

         pstorage_update(&dest_block_id, my_buff, 8, 0);

     }

    else

    {

        // Do Nothing. This event is not relevant for this service.

    }

}





之后就是main函数中判断标志然后读flash再打印出来的代码

部分代码如下:

 Main(){

       …………….

       …………….

    // Enter main loop.

    for (;;)

    {


        power_manage();


       if ( my_flag == 1 ){

           printf("\r\nread flash: ");

           my_flag = 0;

           pstorage_handle_t    dest_block_id;

           uint8_t buff[8];


       //因为只注册了一个flash块,所以其实这个函数可以不调用的。           pstorage_block_identifier_get(&g_block_id,0,&dest_block_id);

           pstorage_load(buff, &dest_block_id, 8, 0);

           for(int i = 0; i< 8; i++){

              printf("%d ",buff[i]);

           }

           printf("\r\n");

       }

    }

}


最后最重要的一点是 对 sys_evt事件的处理,当flash操作完成后,sd会上抛给app 相应的sys_evt事件。(类似sd会上抛给APP BLE的事件)

因为pstorage的实现是基于状态机的。比如我们上面使用的update,它的实现是分步做的,先擦除交换区,然后将就数据写到交换区,然后修改再写回。每个时刻下一步要做的事都由当前的操作返回后的状态机决定。 所以pstorage需要获得sys_evtflash的操作返回)然后进行下一步的处理。至于这些处理pstorage内部都是做好的。我们只要将事件处理函数添加到代码中就可以了。


首先要注册 sys_evt 的事件派发函数


main.c中的 ble_stack_init函数最后添加注册代码


static void ble_stack_init(void)

{  

    …………………

    …………………   

    err_code=softdevice_sys_evt_handler_set(sys_evt_dispatch);

    APP_ERROR_CHECK(err_code);

}


然后在定义这个函数

static void sys_evt_dispatch(uint32_t sys_evt)

{

    //这个函数时在pstorage模块中实现的

    pstorage_sys_event_handler(sys_evt);

}

 最后编译工程就可以操作了,手机连上设备后,找到tx特征值(可以写的那个),然后写8个数据过去

阅读(1267) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~