2017年5月30日 星期二

nRF52 in SDK12 : activate the UART function

There are few articles about nRF52 SDK12, and UART print is a basic function for developers.

This example is modified from ble_app_template
located in : nRF5_SDK_12.2.0_f012efa\examples\ble_peripheral\ble_app_template

Board:nRF52832/ SDK12/s132

STEP 0. project config
I create a project folder "ble_app_uart_porting_file"
located in : nRF5_SDK_12.2.0_f012efa\examples\ble_peripheral\ble_app_uart_porting_file

add  these files into nrf_library
"app_uart_fifo.c"
"app_fifo.c"
"retarget.c"
located in nRF5_SDK_12.2.0_f012efa\components\libraries\uart

and remove "app_uart.c"

next  include path to project option

STEP 1. modify "sdk_config"
I suggest first open sdk_config.h

add these about line  3004
// <h> nRF_Libraries 
//==========================================================
// <q> APP_FIFO_ENABLED  - app_fifo - Software FIFO implementation
 

#ifndef APP_FIFO_ENABLED
#define APP_FIFO_ENABLED 1
#endif

then add these about line 3080
// <e> APP_UART_ENABLED - app_uart - UART driver
//==========================================================
#ifndef APP_UART_ENABLED
#define APP_UART_ENABLED 1
#define APP_UART_DRIVER_INSTANCE 0
#endif

then add these about line 3506

// <q> RETARGET_ENABLED  - retarget - Retargeting stdio functions
 

#ifndef RETARGET_ENABLED
#define RETARGET_ENABLED 1
#endif

and then, go to  Configuration wizard
open nrf_libraries and check :

 then open nrf_drivers and check


for your UART configuration, I suggest to select in configuration wizard - nrf_drivers
in this example, I select as




































but if you prefer to add code , please add in sdk_config.h Text Editor
about line  2724

// <e> UART_ENABLED - nrf_drv_uart - UART/UARTE peripheral driver
//==========================================================
#ifndef UART_ENABLED
#define UART_ENABLED 1
#endif
#if  UART_ENABLED
// <o> UART_DEFAULT_CONFIG_HWFC  - Hardware Flow Control
 
// <0=> Disabled 
// <1=> Enabled 

#ifndef UART_DEFAULT_CONFIG_HWFC
#define UART_DEFAULT_CONFIG_HWFC 0
#endif

// <o> UART_DEFAULT_CONFIG_PARITY  - Parity
 
// <0=> Excluded 
// <14=> Included 

#ifndef UART_DEFAULT_CONFIG_PARITY
#define UART_DEFAULT_CONFIG_PARITY 0
#endif

// <o> UART_DEFAULT_CONFIG_BAUDRATE  - Default Baudrate
 
// <323584=> 1200 baud 
// <643072=> 2400 baud 
// <1290240=> 4800 baud 
// <2576384=> 9600 baud 
// <3862528=> 14400 baud 
// <5152768=> 19200 baud 
// <7716864=> 28800 baud 
// <10289152=> 38400 baud 
// <15400960=> 57600 baud 
// <20615168=> 76800 baud 
// <30801920=> 115200 baud 
// <61865984=> 230400 baud 
// <67108864=> 250000 baud 
// <121634816=> 460800 baud 
// <251658240=> 921600 baud 
// <268435456=> 57600 baud 

#ifndef UART_DEFAULT_CONFIG_BAUDRATE
#define UART_DEFAULT_CONFIG_BAUDRATE 30801920
#endif

// <o> UART_DEFAULT_CONFIG_IRQ_PRIORITY  - Interrupt priority
 

// <i> Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
// <0=> 0 (highest) 
// <1=> 1 
// <2=> 2 
// <3=> 3 
// <4=> 4 
// <5=> 5 
// <6=> 6 
// <7=> 7 

#ifndef UART_DEFAULT_CONFIG_IRQ_PRIORITY
#define UART_DEFAULT_CONFIG_IRQ_PRIORITY 7
#endif

// <q> UART_EASY_DMA_SUPPORT  - Driver supporting EasyDMA
 

#ifndef UART_EASY_DMA_SUPPORT
#define UART_EASY_DMA_SUPPORT 1
#endif

// <q> UART_LEGACY_SUPPORT  - Driver supporting Legacy mode
 

#ifndef UART_LEGACY_SUPPORT
#define UART_LEGACY_SUPPORT 1
#endif

// <e> UART0_ENABLED - Enable UART0 instance
//==========================================================
#ifndef UART0_ENABLED
#define UART0_ENABLED 1
#endif
#if  UART0_ENABLED
// <q> UART0_CONFIG_USE_EASY_DMA  - Default setting for using EasyDMA
 

#ifndef UART0_CONFIG_USE_EASY_DMA
#define UART0_CONFIG_USE_EASY_DMA 1
#endif

#endif //UART0_ENABLED
// </e>

// <e> UART_CONFIG_LOG_ENABLED - Enables logging in the module.
//==========================================================
#ifndef UART_CONFIG_LOG_ENABLED
#define UART_CONFIG_LOG_ENABLED 0
#endif
#if  UART_CONFIG_LOG_ENABLED
// <o> UART_CONFIG_LOG_LEVEL  - Default Severity level
 
// <0=> Off 
// <1=> Error 
// <2=> Warning 
// <3=> Info 
// <4=> Debug 

#ifndef UART_CONFIG_LOG_LEVEL
#define UART_CONFIG_LOG_LEVEL 3
#endif

// <o> UART_CONFIG_INFO_COLOR  - ANSI escape code prefix.
 
// <0=> Default 
// <1=> Black 
// <2=> Red 
// <3=> Green 
// <4=> Yellow 
// <5=> Blue 
// <6=> Magenta 
// <7=> Cyan 
// <8=> White 

#ifndef UART_CONFIG_INFO_COLOR
#define UART_CONFIG_INFO_COLOR 0
#endif

// <o> UART_CONFIG_DEBUG_COLOR  - ANSI escape code prefix.
 
// <0=> Default 
// <1=> Black 
// <2=> Red 
// <3=> Green 
// <4=> Yellow 
// <5=> Blue 
// <6=> Magenta 
// <7=> Cyan 
// <8=> White 

#ifndef UART_CONFIG_DEBUG_COLOR
#define UART_CONFIG_DEBUG_COLOR 0
#endif

#endif //UART_CONFIG_LOG_ENABLED
// </e>

#endif //UART_ENABLED
// </e>

STEP 2.  add code in main.c


#include "app_uart.h"

#define UART_TX_BUF_SIZE                256                                         
#define UART_RX_BUF_SIZE                256
#define UART_MAX_DATA_LEN  (20)   


void uart_event_handle(app_uart_evt_t * p_event)
{

    static uint8_t data_array[UART_MAX_DATA_LEN]; 
    static uint8_t index = 0;
    uint32_t       err_code;

    switch (p_event->evt_type)
    {
        case APP_UART_DATA_READY:
            break;

        case APP_UART_COMMUNICATION_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;

        case APP_UART_FIFO_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;

        default:
            break;
    }
}


static void uart_init(void)
{
    uint32_t                     err_code;
    const app_uart_comm_params_t comm_params =
    {
        RX_PIN_NUMBER,
        TX_PIN_NUMBER,
        RTS_PIN_NUMBER,
        CTS_PIN_NUMBER,
        APP_UART_FLOW_CONTROL_DISABLED,
        false,
        UART_BAUDRATE_BAUDRATE_Baud115200
    };

    APP_UART_FIFO_INIT( &comm_params,
                       UART_RX_BUF_SIZE,
                       UART_TX_BUF_SIZE,
                       uart_event_handle,
                       APP_IRQ_PRIORITY_LOWEST,
                       err_code);
    APP_ERROR_CHECK(err_code);
}


int main(void)
{
    uint32_t err_code;
    bool     erase_bonds;

    // Initialize.  
    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
    uart_init();   
    printf("system start\r\n");
 
    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    //timers_init();
    buttons_leds_init(&erase_bonds);
    ble_stack_init();
    peer_manager_init(erase_bonds);
    if (erase_bonds == true)
    {
        NRF_LOG_INFO("Bonds erased!\r\n");
    }
    gap_params_init();
    advertising_init();
    services_init();
    conn_params_init();

    // Start execution.
    NRF_LOG_INFO("Template started\r\n");
    application_timers_start();
    err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
    APP_ERROR_CHECK(err_code);
    

    // Enter main loop.
    for (;;)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            power_manage();
        }
    }
}

and the result print by UART will be like :
(I used SSCOM. a UART print console on PC )




























NOTE:
1. in SDK12, the developer must assign UART, PWM,WDT...etc in sdk_config.h
otherwise, even they include all the paths and files needed, they still can not open UART.


reference:
https://devzone.nordicsemi.com/question/107836/undefined-symbol-problem-app_uart_get/

http://gaiger-programming.blogspot.tw/2016/12/nrf51-make-printf-works-well.html?m=1

2017年5月28日 星期日

nRF52 fstorage (1):a simple example

There are few examples about SDK12, and that is the reason why I wrote this.

the pstorage function(persistent storage)  of nRF5X has been changed as fstorage in SDK12.
the APIs have been changed. So I write the example for demonstrating how to adopt those .

Board :nRF52832/SDK12/s132

STEP 0.
I create the project file "ble_app_fstoarge_test_file" in example\ble_peripheral
And the example is coopied from  nRF5_SDK_12.2.0_f012efa\examples\ble_peripheral\ble_app_template


project config:
please include all the files in this folder
nRF5_SDK_12.2.0_f012efa\components\libraries\fds

include
"fds.h"
"fds.c"
"fstorage.h"
"fds.c"

and do not forget to paste the path to project option



STEP 1.
the line begins about 3124 in "sdk_config.h" should be modified as  following for fds purpose.
("sdk_config.h" is located in nRF5_SDK_12.2.0_f012efa\examples\ble_peripheral\ble_app_fstorage_test_file\pca10040\s132\config)

add these codes to test fstorage

// <e> FDS_ENABLED - fds - Flash data storage module
//==========================================================
#ifndef FDS_ENABLED
#define FDS_ENABLED 1
#endif
#if  FDS_ENABLED
// <o> FDS_OP_QUEUE_SIZE - Size of the internal queue. 
#ifndef FDS_OP_QUEUE_SIZE
#define FDS_OP_QUEUE_SIZE 4
#endif

// <o> FDS_CHUNK_QUEUE_SIZE - Determines how many @ref fds_record_chunk_t structures can be buffered at any time. 
#ifndef FDS_CHUNK_QUEUE_SIZE
#define FDS_CHUNK_QUEUE_SIZE 8
#endif

// <o> FDS_MAX_USERS - Maximum number of callbacks that can be registered. 
#ifndef FDS_MAX_USERS
#define FDS_MAX_USERS 8
#endif

// <o> FDS_VIRTUAL_PAGES - Number of virtual flash pages to use. 
// <i> One of the virtual pages is reserved by the system for garbage collection.
// <i> Therefore, the minimum is two virtual pages: one page to store data and
// <i> one page to be used by the system for garbage collection. The total amount
// <i> of flash memory that is used by FDS amounts to @ref FDS_VIRTUAL_PAGES
// <i> @ref FDS_VIRTUAL_PAGE_SIZE * 4 bytes.

#ifndef FDS_VIRTUAL_PAGES
#define FDS_VIRTUAL_PAGES 3
#endif

// <o> FDS_VIRTUAL_PAGE_SIZE  - The size of a virtual page of flash memory, expressed in number of 4-byte words.
 

// <i> By default, a virtual page is the same size as a physical page.
// <i> The size of a virtual page must be a multiple of the size of a physical page.
// <1024=> 1024 
// <2048=> 2048 

#ifndef FDS_VIRTUAL_PAGE_SIZE
#define FDS_VIRTUAL_PAGE_SIZE 1024
#endif

#endif //FDS_ENABLED
// </e>

// <e> FSTORAGE_ENABLED - fstorage - Flash storage module
//==========================================================
#ifndef FSTORAGE_ENABLED
#define FSTORAGE_ENABLED 1
#endif
#if  FSTORAGE_ENABLED
// <o> FS_QUEUE_SIZE - Configures the size of the internal queue. 
// <i> Increase this if there are many users, or if it is likely that many
// <i> operation will be queued at once without waiting for the previous operations
// <i> to complete. In general, increase the queue size if you frequently receive
// <i> @ref FS_ERR_QUEUE_FULL errors when calling @ref fs_store or @ref fs_erase.

#ifndef FS_QUEUE_SIZE
#define FS_QUEUE_SIZE 4
#endif

// <o> FS_OP_MAX_RETRIES - Number attempts to execute an operation if the SoftDevice fails. 
// <i> Increase this value if events return the @ref FS_ERR_OPERATION_TIMEOUT
// <i> error often. The SoftDevice may fail to schedule flash access due to high BLE activity.

#ifndef FS_OP_MAX_RETRIES
#define FS_OP_MAX_RETRIES 3
#endif

// <o> FS_MAX_WRITE_SIZE_WORDS - Maximum number of words to be written to flash in a single operation. 
// <i> Tweaking this value can increase the chances of the SoftDevice being
// <i> able to fit flash operations in between radio activity. This value is bound by the
// <i> maximum number of words which the SoftDevice can write to flash in a single call to
// <i> @ref sd_flash_write, which is 256 words for nRF51 ICs and 1024 words for nRF52 ICs.

#ifndef FS_MAX_WRITE_SIZE_WORDS
#define FS_MAX_WRITE_SIZE_WORDS 1024
#endif

#endif //FSTORAGE_ENABLED
// </e>

the "sdk_config.h" is first time added in SDK12, almost every function must config in this file.


STEP 2.
example code:
add these functions to test fstorage
about  line 706

/*the definition for fstorage*/
static volatile uint8_t write_flag=0;
static uint8_t fs_callback_flag; 
#define NUM_PAGES 4
#define PAGE_SIZE_WORDS 256

static uint32_t data;
static uint32_t flash_data[4];

/**@brief Function for the Power manager.
 */
static void power_manage(void)
{
    uint32_t err_code = sd_app_evt_wait();

    APP_ERROR_CHECK(err_code);
}


static void fs_evt_handler(fs_evt_t const * const evt, fs_ret_t result)
{
    if (result != FS_SUCCESS)
    {
        bsp_indication_set(BSP_INDICATE_FATAL_ERROR);
    }
  else
  {
    NRF_LOG_INFO("fstorage command successfully completed\n\r");    
    fs_callback_flag = 0;
  }
}


static void fstorage_test(void)
{
 PRINTF("fstorage_test\r\n");
 
 FS_REGISTER_CFG(fs_config_t fs_config) =
 {
  .callback  = fs_evt_handler, // Function for event callbacks.
  .num_pages = NUM_PAGES,      // Number of physical flash pages required.
  .priority  = 0xFE            // Priority for flash usage.
 };

 fs_ret_t ret = fs_init();
 if (ret != FS_SUCCESS)
 {
  bsp_indication_set(BSP_INDICATE_FATAL_ERROR);
 }
  
 // Erase one page (256*4).
 NRF_LOG_INFO("Erasing a flash page at address 0x%X\r\n", (uint32_t)fs_config.p_start_addr);  
 
 fs_callback_flag = 1;
 ret = fs_erase(&fs_config, fs_config.p_start_addr, 1, NULL);
 if (ret != FS_SUCCESS)
 {
  bsp_indication_set(BSP_INDICATE_FATAL_ERROR);
 }
 while(fs_callback_flag == 1)  { power_manage(); }
 
 //Read the first 4 words of the page
 NRF_LOG_INFO("Data read from flash address 0x%X: \r\n", (uint32_t)fs_config.p_start_addr);  
  
 for(int i=0; i<4; i++)
 {
  flash_data[i] = *(fs_config.p_start_addr + i);
  NRF_LOG_INFO("%X \r\n", flash_data[i]);    
 } 
  
  /*agatha*/  
 NRF_LOG_INFO("from agatha\r\n"); 
 
 data = 0x19950225;
 NRF_LOG_INFO("Writing data 0x%X to address 0x%X\r\n", data, (uint32_t)fs_config.p_start_addr );
 
 fs_callback_flag = 1;
 ret = fs_store(&fs_config, fs_config.p_start_addr, &data, 1, NULL); 
 if (ret != FS_SUCCESS)
 {
  bsp_indication_set(BSP_INDICATE_FATAL_ERROR);
 }
 while(fs_callback_flag == 1)  { power_manage(); }
 
 //Read the first 4 words of the page
 NRF_LOG_INFO("Data read from flash address 0x%X: \r\n", (uint32_t)fs_config.p_start_addr);  
    
 flash_data[2] = *(fs_config.p_start_addr);
 NRF_LOG_INFO("%X ", flash_data[2]);     
}


/**@brief Function for application main entry.
 */
int main(void)
{
 PRINTF("DEVICE START \r\n");
 
 uint32_t err_code;
    bool     erase_bonds;

    // Initialize.
    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    
    ble_stack_init();
 
    peer_manager_init(erase_bonds);
    if (erase_bonds == true)
    {
        NRF_LOG_INFO("Bonds erased!\r\n");
    }
    gap_params_init();
    advertising_init();
 
    services_init();
    conn_params_init();
 
  // Start execution.
    NRF_LOG_INFO("Proximity Start!\r\n");
    advertising_start();
  
  /*the example function of  fstorage*/
  PRINTF("start fstorage test\r\n");
  fstorage_test();
  

    // Enter main loop.
    for (;;)
    {
        if (NRF_LOG_PROCESS() == false)
        {
            power_manage();
        }   
    }
}


these code demo how to :
initialize fstorage ->clear the code page  -> write at specific address (0x79000) ->read the address

and I define
the number of code pages and page_size should be a multiple of 4.

/*the definition for fstorage*/
static volatile uint8_t write_flag=0;
static uint8_t fs_callback_flag; 
#define NUM_PAGES 4
#define PAGE_SIZE_WORDS 256

static uint32_t data;
static uint32_t flash_data[4];

and the result print in segger_RTT will be like this :


NOTES:

1.this article only shows  the most basic way to use fstorage, and how to prevent the conflict of
power_manage and  fstorage. 

2.I register the space and clear/ write at the same time, so the space for data to store is limited .

3.I did not define the start code page , so the fstorage will start at 0x79000 (in default)
but the start point is able to be assigned by yourself.

try to assign start point in 
fs_config.p_start_addr

your could change the address 0x79000 as 0x78000 to observe the storaging address be entailed changed.

4.KNOWN insuffience :I have not implement how to use fstorage in interrupt (press button, UART...etc). Maybe I should write an example  relate to fstorage and interrupt ?