BLE-NRF51822教程7-带协议栈工程中使用flash

来源:互联网 发布:全国城市 首字母 json 编辑:程序博客网 时间:2024/04/28 04:21

本教程说明如何在带协议栈的BLE工程中使用flash操作。教程基于sdk9.0的 uart工程xxx\NordicSemiconductor\nRF_Examples\9.0.0\ble_peripheral\ble_app_uart,Nordic的SDK将flash操作封装成了一个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);


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

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

下面介绍代码的编写:

PS:UART例子中要先关流控

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

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


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

storage_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;    }}
<pre name="code" class="cpp">//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_evt(flash的操作返回)然后进行下一步的处理。至于这些处理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个数据过去

0 0
原创粉丝点击