Skip to main content

Need help - use of arch_printf in barebone/ble_peripheral example and SPI flash integration

DA14580

1 year ago

Posted by theultimateprasad 0 points 6 replies
0 upvotes

Hi I'm using Murata's ZY module which having DA14580 chipset. During the integration of SPI flash storage with ble_examples - ble_app_barebone or ble_app_peripheral I have two issues :

1. Unable to use the common_uart.h in ble examples / Also not able to get the results of arch_printf() function on UART.

2. Unable to use the SPI flash - spi_test() function in the ble example - ble_app_barebone or ble_app_peripheral

Details :

While I was exploring the peripheral examples from the SDK, I could use the SPI flash example on the development kit and could test the printf_string /printf_byte to print the results on UART. However when I'm using the arch_printf() to print the messages on the UART in any of the ble examples mentioned above, its not working for me. Also when I'm integrating the spi_test() function to the example, it is not working.   

I've e done the following changes:

ble_app_barebone :

arch_main.c :

after system_init() function trying to print some test message using arch_printf()

user_periph_setup.h:

changed the pin mapping as per the development board (TX - P0_4 for UART message)

user_periph_setup.c:

copied the system init functions from the SPI flash examples and added over there, Also declared the initialization for the SPI pins.

user_barebone.c:

Added the "spi_flash.h" , "user_periph_setup.h" and "arch_console.h" for SPI flash_test() and arch_printf(). 

Calling the spi_test() in the mnf_data_update() function to store some random value to memory location.

After doing all of the above changes, I've tested the code using UART but found no messages on screen. I also tested the memory content of SPI flash storage using Smart snippet but could not see any updated content. 

I've attached all the supporting files for your reference. pls, help me to integrate the SPI flash to store some data (intention is to store scanned result to SPI flas) and debug message function on UART.

Pls consider this as a high priority and send me the exact details to make changes in the code.

arch_main.c:

/**
 ****************************************************************************************
 *
 * @file arch_main.c
 *
 * @brief Main loop of the application.
 *
 * Copyright (C) 2012. Dialog Semiconductor Ltd, unpublished work. This computer
 * program includes Confidential, Proprietary Information and is a Trade Secret of
 * Dialog Semiconductor Ltd.  All use, disclosure, and/or reproduction is prohibited
 * unless authorized in writing. All Rights Reserved.
 *
 * <bluetooth.support@diasemi.com> and contributors.
 *
 ****************************************************************************************
 */

/*
 * INCLUDES
 ****************************************************************************************
 */
#include "da1458x_scatter_config.h"
#include "arch.h"
#include "arch_api.h"
#include <stdlib.h>
#include <stddef.h>     // standard definitions
#include <stdbool.h>    // boolean definition
#include "boot.h"       // boot definition
#include "rwip.h"       // BLE initialization
#include "syscntl.h"    // System control initialization
#include "emi.h"        // EMI initialization
#include "intc.h"       // Interrupt initialization
#include "em_map_ble.h"
#include "ke_mem.h"
#include "ke_event.h"
#include "user_periph_setup.h"

#include "uart.h"   // UART initialization
#include "nvds.h"   // NVDS initialization
#include "rf.h"     // RF initialization
#include "app.h"    // application functions
#include "dbg.h"    // For dbg_warning function

#include "global_io.h"

#include "datasheet.h"

#include "em_map_ble_user.h"
#include "em_map_ble.h"

#include "lld_sleep.h"
#include "rwble.h"
#include "rf_580.h"
#include "gpio.h"

#include "lld_evt.h"
#include "arch_console.h"

#include "arch_system.h"

#include "arch_patch.h"

#include "arch_wdg.h"

#include "user_callback_config.h"

//#include "spi_flash.h"
#include "user_periph_setup.h"
#include "uart.h"






/**
 * @addtogroup DRIVERS
 * @{
 */

/*
 * DEFINES
 ****************************************************************************************
 */

/*
 * STRUCTURE DEFINITIONS
 ****************************************************************************************
 */

/*
 * GLOBAL VARIABLE DEFINITIONS
 ****************************************************************************************
 */

#ifdef __DA14581__
uint32_t error;              /// Variable storing the reason of platform reset
#endif

extern uint32_t error;              /// Variable storing the reason of platform reset

/// Reserve space for Exchange Memory, this section is linked first in the section "exchange_mem_case"
extern uint8_t func_check_mem_flag;
extern struct arch_sleep_env_tag sleep_env;

volatile uint8_t descript[EM_SYSMEM_SIZE] __attribute__((section("BLE_exchange_memory"), zero_init, used)); //CASE_15_OFFSET
#if ((EM_SYSMEM_START != EXCHANGE_MEMORY_BASE) || (EM_SYSMEM_SIZE > EXCHANGE_MEMORY_SIZE))
#error("Error in Exhange Memory Definition in the scatter file. Please correct da14580_scatter_config.h settings.");
#endif
bool sys_startup_flag __attribute__((section("retention_mem_area0"), zero_init));

/*
 * LOCAL FUNCTION DECLARATIONS
 ****************************************************************************************
 */
static inline void otp_prepare(uint32_t code_size);
static inline bool ble_is_powered(void);
static inline void ble_turn_radio_off(void);
static inline void schedule_while_ble_on(void);
static inline sleep_mode_t ble_validate_sleep_mode(sleep_mode_t current_sleep_mode);
static inline void arch_turn_peripherals_off(sleep_mode_t current_sleep_mode);
static inline void arch_goto_sleep(sleep_mode_t current_sleep_mode);
static inline void arch_switch_clock_goto_sleep(sleep_mode_t current_sleep_mode);
static inline void arch_resume_from_sleep(void);
static inline sleep_mode_t rwip_power_down(void);
static inline arch_main_loop_callback_ret_t app_asynch_trm(void);
static inline arch_main_loop_callback_ret_t app_asynch_proc(void);
static inline void app_asynch_sleep_proc(void);
static inline void app_sleep_prepare_proc(sleep_mode_t *sleep_mode);
static inline void app_sleep_exit_proc(void);
static inline void app_sleep_entry_proc(sleep_mode_t sleep_mode);

#if USE_POWER_OPTIMIZATIONS
extern bool fine_hit;
#endif

/*
 * MAIN FUNCTION
 ****************************************************************************************
 */

/**
 ****************************************************************************************
 * @brief BLE main function.
 *        This function is called right after the booting process has completed.
 *        It contains the main function loop.
 ****************************************************************************************
 */
int main_func(void) __attribute__((noreturn));

int main_func(void)
{
    sleep_mode_t sleep_mode;

    //global initialise
    system_init();
	  
	
	  arch_puts("Test fucntion for the arch_printf");
		arch_printf("Test fucntion for the arch_printf");
		arch_printf_process();
		arch_puts("Test fucntion for the arch_printf");
		arch_printf("Test fucntion for the arch_printf");
	  
	
    /*
     ************************************************************************************
     * Platform initialization
     ************************************************************************************
     */
    while(1)
    {
        do {
            // schedule all pending events
            schedule_while_ble_on();
        }
        while (app_asynch_proc() != GOTO_SLEEP);    //grant control to the application, try to go to power down
                                                              //if the application returns GOTO_SLEEP
              //((STREAMDATA_QUEUE)&& stream_queue_more_data())); //grant control to the streamer, try to go to power down
                                                                //if the application returns GOTO_SLEEP

        //wait for interrupt and go to sleep if this is allowed
        if (((!BLE_APP_PRESENT) && (check_gtl_state())) || (BLE_APP_PRESENT))
        {
            //Disable the interrupts
            GLOBAL_INT_STOP();

            app_asynch_sleep_proc();

            // get the allowed sleep mode
            // time from rwip_power_down() to WFI() must be kept as short as possible!!
            sleep_mode = rwip_power_down();

            if ((sleep_mode == mode_ext_sleep) || (sleep_mode == mode_deep_sleep))
            {
                //power down the radio and whatever is allowed
                arch_goto_sleep(sleep_mode);

                // In extended or deep sleep mode the watchdog timer is disabled
                // (power domain PD_SYS is automatically OFF). Although, if the debugger
                // is attached the watchdog timer remains enabled and must be explicitly
                // disabled.
                if ((GetWord16(SYS_STAT_REG) & DBG_IS_UP) == DBG_IS_UP)
                {
                    wdg_freeze();    // Stop watchdog timer
                }
                
                //wait for an interrupt to resume operation
                WFI();
                
                //resume operation
                arch_resume_from_sleep();
            }
            else if (sleep_mode == mode_idle)
            {
                if (((!BLE_APP_PRESENT) && check_gtl_state()) || (BLE_APP_PRESENT))
                {   
                    //wait for an interrupt to resume operation
                    WFI();
                }
            }
            // restore interrupts
            GLOBAL_INT_START();
        }
        wdg_reload(WATCHDOG_DEFAULT_PERIOD);
    }
}




/**
 ****************************************************************************************
 * @brief Power down the BLE Radio and whatever is allowed according to the sleep mode and
 *        the state of the system and application
 * @param[in] current_sleep_mode The current sleep mode proposed by the application.
 * @return void
 ****************************************************************************************
 */
static inline void arch_goto_sleep (sleep_mode_t current_sleep_mode)
{
    sleep_mode_t sleep_mode = current_sleep_mode;

    ble_turn_radio_off ( );
    //turn the radio off and check if we can go into deep sleep
    sleep_mode = ble_validate_sleep_mode(sleep_mode);

    // grant access to the application to check if we can go to sleep
    app_sleep_prepare_proc(&sleep_mode);    //SDK Improvements for uniformity this one should be changed?

    //turn the peripherals off according to the current sleep mode
    arch_turn_peripherals_off(sleep_mode);

    #if (USE_POWER_OPTIMIZATIONS)
        fine_hit = false;
    #endif

    // hook for app specific tasks just before sleeping
    app_sleep_entry_proc(sleep_mode);

    #if ((EXTERNAL_WAKEUP) && (!BLE_APP_PRESENT)) // external wake up, only in external processor designs
        ext_wakeup_enable(EXTERNAL_WAKEUP_GPIO_PORT, EXTERNAL_WAKEUP_GPIO_PIN, EXTERNAL_WAKEUP_GPIO_POLARITY);
    #endif

    // do the last house keeping of the clocks and go to sleep
    arch_switch_clock_goto_sleep (sleep_mode);
}

/**
 ****************************************************************************************
 * @brief Manage the clocks and go to sleep.
 * @param[in] current_sleep_mode The current sleep mode proposed by the system so far
 * @return void
 ****************************************************************************************
 */
static inline void arch_switch_clock_goto_sleep(sleep_mode_t current_sleep_mode)
{
    if ( (current_sleep_mode == mode_ext_sleep) || (current_sleep_mode == mode_deep_sleep) )
    {
        SetBits16(CLK_16M_REG, XTAL16_BIAS_SH_ENABLE, 0);      // Set BIAS to '0' if sleep has been decided

        if (USE_POWER_OPTIMIZATIONS)
        {
            clk_freq_trim_reg_value = GetWord16(CLK_FREQ_TRIM_REG); // store used trim value

            SetBits16(CLK_16M_REG, RC16M_ENABLE, 1);                // Enable RC16

            for (volatile int i = 0; i < 20; i++);

            SetBits16(CLK_CTRL_REG, SYS_CLK_SEL, 1);                // Switch to RC16

            while( (GetWord16(CLK_CTRL_REG) & RUNNING_AT_RC16M) == 0 );

            // Do not disable XTAL16M! It will be disabled when we sleep...
            SetWord16(CLK_FREQ_TRIM_REG, 0x0000);                   // Set zero value to CLK_FREQ_TRIM_REG
        }
    }
}

/**
 ****************************************************************************************
 * @brief  An interrupt came, resume from sleep.
 * @return void
 ****************************************************************************************
 */
static inline void arch_resume_from_sleep(void)
{
    // hook for app specific tasks just after waking up
    app_sleep_exit_proc( );

#if ((EXTERNAL_WAKEUP) && (!BLE_APP_PRESENT)) // external wake up, only in external processor designs
    // Disable external wakeup interrupt
    ext_wakeup_disable();
#endif

    // restore ARM Sleep mode
    // reset SCR[2]=SLEEPDEEP bit else the mode=idle WFI will cause a deep sleep
    // instead of a processor halt
    SCB->SCR &= ~(1<<2);
}

/**
 ****************************************************************************************
 * @brief Check if the BLE module is powered on.
 * @return void
 ****************************************************************************************
 */
static inline bool ble_is_powered()
{
    return ((GetBits16(CLK_RADIO_REG, BLE_ENABLE) == 1) &&
            (GetBits32(BLE_DEEPSLCNTL_REG, DEEP_SLEEP_STAT) == 0) &&
            !(rwip_prevent_sleep_get() & RW_WAKE_UP_ONGOING));
}

/**
 ****************************************************************************************
 * @brief Call the scheduler if the BLE module is powered on.
 * @return void
 ****************************************************************************************
 */
static inline void schedule_while_ble_on(void)
{
    // BLE clock is enabled
    while (ble_is_powered())
    {
        // BLE event end is set. conditional RF calibration can run.
        uint8_t ble_evt_end_set = ke_event_get(KE_EVENT_BLE_EVT_END);

        //execute messages and events
        rwip_schedule();

        if (ble_evt_end_set)
        {
           uint32_t sleep_duration = 0;
           rcx20_read_freq();

            //if you have enough time run a temperature calibration of the radio
            if (lld_sleep_check(&sleep_duration, 4)) //6 slots -> 3.750 ms
                // check time and temperature to run radio calibrations.
                conditionally_run_radio_cals();
        }

        //grant control to the application, try to go to sleep
        //if the application returns GOTO_SLEEP
        if (app_asynch_trm() != GOTO_SLEEP)
        {
            continue; // so that rwip_schedule() is called again
        }
        else
        {
            arch_printf_process();
            break;
        }
    }
}

/**
 ****************************************************************************************
 * @brief Power down the ble ip if possible.
 * @return sleep_mode_t return the current sleep mode
 ****************************************************************************************
 */
static inline sleep_mode_t rwip_power_down(void)
{
    sleep_mode_t sleep_mode;
    // if app has turned sleep off, rwip_sleep() will act accordingly
    // time from rwip_sleep() to WFI() must be kept as short as possible!
    sleep_mode = rwip_sleep();

    // BLE is sleeping ==> app defines the mode
    if (sleep_mode == mode_sleeping) {
        if (sleep_env.slp_state == ARCH_EXT_SLEEP_ON) {
            sleep_mode = mode_ext_sleep;
        } else {
            sleep_mode = mode_deep_sleep;
        }
    }
    return (sleep_mode);
}

/**
 ****************************************************************************************
 * @brief Turn the radio off according to the current sleep_mode and check if we can go
 *        into deep sleep.
 * @param[in] current_sleep_mode The current sleep mode proposed by the system so far
 * @return sleep_mode_t return the allowable sleep mode
 ****************************************************************************************
 */
static inline void ble_turn_radio_off(void)
{
    SetBits16(PMU_CTRL_REG, RADIO_SLEEP, 1); // turn off radio
}

/**
 ****************************************************************************************
 * @brief Validate that we can use the proposed sleep mode.
 * @param[in] current_sleep_mode The current sleep mode proposed by the system so far
 * @return sleep_mode_t return the allowable sleep mode
 ****************************************************************************************
 */
static inline sleep_mode_t ble_validate_sleep_mode(sleep_mode_t current_sleep_mode)
{
    sleep_mode_t sleep_mode = current_sleep_mode;

    if (jump_table_struct[nb_links_user] > 1)
    {
        if ((sleep_mode == mode_deep_sleep) && func_check_mem() && test_rxdone() && ke_mem_is_empty(KE_MEM_NON_RETENTION))
        {
            func_check_mem_flag = 2; //true;
        }
        else
        {
            sleep_mode = mode_ext_sleep;
        }
    }
    else
    {
        if ((sleep_mode == mode_deep_sleep) && ke_mem_is_empty(KE_MEM_NON_RETENTION))
        {
            func_check_mem_flag = 1; //true;
        }
        else
        {
            sleep_mode = mode_ext_sleep;
        }
    }
    return (sleep_mode);
}

/**
 ****************************************************************************************
 * @brief  Turn the peripherals off according to the current sleep mode.
 * @param[in] current_sleep_mode The current sleep mode proposed by the system so far
 * @return void
 ****************************************************************************************
 */
static inline void arch_turn_peripherals_off (sleep_mode_t current_sleep_mode)
{
    if (current_sleep_mode == mode_ext_sleep || current_sleep_mode == mode_deep_sleep)
    {
        SCB->SCR |= 1<<2; // enable deep sleep  mode bit in System Control Register (SCR[2]=SLEEPDEEP)

        SetBits16(SYS_CTRL_REG, PAD_LATCH_EN, 0);           // activate PAD latches
        SetBits16(PMU_CTRL_REG, PERIPH_SLEEP, 1);           // turn off peripheral power domain
        if (current_sleep_mode == mode_ext_sleep)
        {
            SetBits16(SYS_CTRL_REG, RET_SYSRAM, 1);         // retain System RAM
            SetBits16(SYS_CTRL_REG, OTP_COPY, 0);           // disable OTP copy
        }
        else
        {
            // mode_deep_sleep
#if DEVELOPMENT_DEBUG
            SetBits16(SYS_CTRL_REG, RET_SYSRAM, 1);         // retain System RAM
#else
            SetBits16(SYS_CTRL_REG, RET_SYSRAM, 0);         // turn System RAM off => all data will be lost!
#endif
            otp_prepare(0x1FC0);                            // this is 0x1FC0 32 bits words, so 0x7F00 bytes
        }
    }
}

/**
 ****************************************************************************************
 * @brief Prepare OTP Controller in order to be able to reload SysRAM at the next power-up.
 ****************************************************************************************
 */
static inline void otp_prepare(uint32_t code_size)
{
    // Enable OPTC clock in order to have access
    SetBits16 (CLK_AMBA_REG, OTP_ENABLE, 1);

    // Wait a little bit to start the OTP clock...
    for(uint8_t i = 0 ; i<10 ; i++); //change this later to a defined time

    SetBits16(SYS_CTRL_REG, OTP_COPY, 1);

    // Copy the size of software from the first word of the retention mem.
    SetWord32 (OTPC_NWORDS_REG, code_size - 1);

    // And close the OPTC clock to save power
    SetBits16 (CLK_AMBA_REG, OTP_ENABLE, 0);
}

/**
 ****************************************************************************************
 * @brief Used for sending messages to kernel tasks generated from
 *        asynchronous events that have been processed in app_asynch_proc.
 * @return KEEP_POWERED to force calling of schedule_while_ble_on(), else GOTO_SLEEP
 ****************************************************************************************
 */
static inline arch_main_loop_callback_ret_t app_asynch_trm(void)
{
    if (user_app_main_loop_callbacks.app_on_ble_powered != NULL)
    {
        return user_app_main_loop_callbacks.app_on_ble_powered();
    }
    else
    {
        return GOTO_SLEEP;
    }
}

/**
 ****************************************************************************************
 * @brief Used for processing of asynchronous events at “user” level. The
 *        corresponding ISRs should be kept as short as possible and the
 *        remaining processing should be done at this point.
 * @return KEEP_POWERED to force calling of schedule_while_ble_on(), else GOTO_SLEEP
 ****************************************************************************************
 */
static inline arch_main_loop_callback_ret_t app_asynch_proc(void)
{
    if (user_app_main_loop_callbacks.app_on_system_powered != NULL)
    {
        return user_app_main_loop_callbacks.app_on_system_powered();
    }
    else
    {
        return GOTO_SLEEP;
    }
}

/**
 ****************************************************************************************
 * @brief Used for updating the state of the application just before sleep checking starts.
 * @return void
 ****************************************************************************************
 */
static inline void app_asynch_sleep_proc(void)
{
    if (user_app_main_loop_callbacks.app_before_sleep != NULL)
        user_app_main_loop_callbacks.app_before_sleep();
}

/**
 ****************************************************************************************
 * @brief Used to disallow extended or deep sleep based on the current application state.
 *        BLE and Radio are still powered off.
 * @param[in] sleep_mode     Sleep Mode
 * @return void
 ****************************************************************************************
 */
static inline void app_sleep_prepare_proc(sleep_mode_t *sleep_mode)
{
    if (user_app_main_loop_callbacks.app_validate_sleep != NULL)
        (*sleep_mode) = user_app_main_loop_callbacks.app_validate_sleep(*sleep_mode);
}

/**
 ****************************************************************************************
 * @brief Used for application specific tasks just before entering the low power mode.
 * @param[in] sleep_mode     Sleep Mode
 * @return void
 ****************************************************************************************
 */
static inline void app_sleep_entry_proc(sleep_mode_t sleep_mode)
{
    if (user_app_main_loop_callbacks.app_going_to_sleep != NULL)
        user_app_main_loop_callbacks.app_going_to_sleep(sleep_mode);
}

/**
 ****************************************************************************************
 * @brief Used for application specific tasks immediately after exiting the low power mode.
 * @param[in] sleep_mode     Sleep Mode
 * @return void
 ****************************************************************************************
 */
static inline void app_sleep_exit_proc(void)
{
    if (user_app_main_loop_callbacks.app_resume_from_sleep != NULL)
        user_app_main_loop_callbacks.app_resume_from_sleep();
}



/// @} DRIVERS
/**
 ****************************************************************************************
 *
 * @file user_barebone.c
 *
 * @brief Barebone project source code.
 *
 * Copyright (C) 2015. Dialog Semiconductor Ltd, unpublished work. This computer
 * program includes Confidential, Proprietary Information and is a Trade Secret of
 * Dialog Semiconductor Ltd.  All use, disclosure, and/or reproduction is prohibited
 * unless authorized in writing. All Rights Reserved.
 *
 * <bluetooth.support@diasemi.com> and contributors.
 *
 ****************************************************************************************
 */

/**
 ****************************************************************************************
 * @addtogroup APP
 * @{
 ****************************************************************************************
 */

/*
 * INCLUDE FILES
 ****************************************************************************************
 */

#include "rwip_config.h"             // SW configuration
#include "user_barebone.h"
#include "arch_api.h"
#include "gap.h"
#include "arch_console.h"
#include "spi_flash.h"
#include "user_periph_setup.h"

uint8_t rd_data[512];
uint8_t wr_data[512];
uint8_t wr_data2[512];
int8_t detected_spi_flash_device_index;
SPI_Pad_t spi_FLASH_CS_Pad;

void system_init(void);
void spi_test(void);


/*
 * TYPE DEFINITIONS
 ****************************************************************************************
 */

// Manufacturer Specific Data ADV structure type
struct mnf_specific_data_ad_structure
{
    uint8_t ad_structure_size;
    uint8_t ad_structure_type;
    uint8_t company_id[APP_AD_MSD_COMPANY_ID_LEN];
    uint8_t proprietary_data[APP_AD_MSD_DATA_LEN];
};

/*
 * GLOBAL VARIABLE DEFINITIONS
 ****************************************************************************************
 */

uint8_t app_connection_idx;
timer_hnd app_adv_data_update_timer_used;
timer_hnd app_param_update_request_timer_used;

// Manufacturer Specific Data
struct mnf_specific_data_ad_structure mnf_data __attribute__((section("retention_mem_area0"),zero_init)); //@RETENTION MEMORY

/*
 * FUNCTION DEFINITIONS
 ****************************************************************************************
*/

/**
 ****************************************************************************************
 * @brief Initialize Manufacturer Specific Data
 * @return void
 ****************************************************************************************
 */
static void mnf_data_init()
{
    mnf_data.ad_structure_size = sizeof(struct mnf_specific_data_ad_structure ) - sizeof(uint8_t); // minus the size of the ad_structure_size field
    mnf_data.ad_structure_type = GAP_AD_TYPE_MANU_SPECIFIC_DATA;
    mnf_data.company_id[0] = APP_AD_MSD_COMPANY_ID & 0xFF; // LSB
    mnf_data.company_id[1] = (APP_AD_MSD_COMPANY_ID >> 8 )& 0xFF; // MSB
    mnf_data.proprietary_data[0] = 0;
    mnf_data.proprietary_data[1] = 0;
}

/**
 ****************************************************************************************
 * @brief Update Manufacturer Specific Data
 * @return void
 ****************************************************************************************
 */
static void mnf_data_update()
{
    uint16_t data;

    data = mnf_data.proprietary_data[0] | (mnf_data.proprietary_data[1] << 8);
    data += 1;
    mnf_data.proprietary_data[0] = data & 0xFF;
    mnf_data.proprietary_data[1] = (data >> 8) & 0xFF;

    if (data == 0xFFFF) {
         mnf_data.proprietary_data[0] = 0;
         mnf_data.proprietary_data[1] = 0;
    }
		
		arch_printf("Test fucntion for the user_barebone.c");
		spi_test();
}

/**
 ****************************************************************************************
 * @brief Advertisement data update timer callback function.
 * @return void
 ****************************************************************************************
*/
static void adv_data_update_timer_cb()
{
    app_easy_gap_advertise_stop();
}

/**
 ****************************************************************************************
 * @brief Parameter update request timer callback function.
 * @return void
 ****************************************************************************************
*/
static void param_update_request_timer_cb()
{
    app_easy_gap_param_update_start(app_connection_idx);
    app_param_update_request_timer_used = EASY_TIMER_INVALID_TIMER;
}

void user_app_init(void)
{
    app_param_update_request_timer_used = EASY_TIMER_INVALID_TIMER;
    
    // Initialize Manufacturer Specific Data
    mnf_data_init();

    default_app_on_init();
}

/**
 * @brief Add an AD structure in the Advertising or Scan Response Data of the GAPM_START_ADVERTISE_CMD parameter struct.
 * @param[in] cmd               GAPM_START_ADVERTISE_CMD parameter struct
 * @param[in] ad_struct_data    AD structure buffer
 * @param[in] ad_struct_len     AD structure length
 * @return void
 */
static void app_add_ad_struct(struct gapm_start_advertise_cmd *cmd, void *ad_struct_data, uint8_t ad_struct_len)
{
    if ( (APP_ADV_DATA_MAX_SIZE - cmd->info.host.adv_data_len) >= ad_struct_len)
    {
        // Copy data
        memcpy(&cmd->info.host.adv_data[cmd->info.host.adv_data_len], ad_struct_data, ad_struct_len);

        // Update Advertising Data Length
        cmd->info.host.adv_data_len += ad_struct_len;
    }
    else if ( (APP_SCAN_RESP_DATA_MAX_SIZE - cmd->info.host.scan_rsp_data_len) >= ad_struct_len)
    {
        // Copy data
        memcpy(&cmd->info.host.scan_rsp_data[cmd->info.host.scan_rsp_data_len], ad_struct_data, ad_struct_len);

        // Update Scan Responce Data Length
        cmd->info.host.scan_rsp_data_len += ad_struct_len;
    }
    else
    {
        // Manufacturer Specific Data do not fit in either Advertising Data or Scan Response Data
        ASSERT_ERROR(0);
    }
}

void user_app_adv_start(void)
{
    // Schedule the next advertising data update
    app_adv_data_update_timer_used = app_easy_timer(APP_ADV_DATA_UPDATE_TO, adv_data_update_timer_cb);

    struct gapm_start_advertise_cmd* cmd;
    cmd = app_easy_gap_undirected_advertise_get_active();

    // add manufacturer specific data dynamically
    mnf_data_update();
    app_add_ad_struct(cmd, &mnf_data, sizeof(struct mnf_specific_data_ad_structure));

    app_easy_gap_undirected_advertise_start();
}

void user_app_connection(uint8_t connection_idx, struct gapc_connection_req_ind const *param)
{
    if (app_env[connection_idx].conidx != GAP_INVALID_CONIDX)
    {
        app_connection_idx = connection_idx;

        // Stop the advertising data update timer
        app_easy_timer_cancel(app_adv_data_update_timer_used);

        // Check if the parameters of the established connection are the preferred ones.
        // If not then schedule a connection parameter update request.
        if ((param->con_interval < user_connection_param_conf.intv_min) ||
            (param->con_interval > user_connection_param_conf.intv_max) ||
            (param->con_latency != user_connection_param_conf.latency) ||
            (param->sup_to != user_connection_param_conf.time_out))
        {
            // Connection params are not these that we expect
            app_param_update_request_timer_used = app_easy_timer(APP_PARAM_UPDATE_REQUEST_TO, param_update_request_timer_cb);
        }
    }
    else
    {
        // No connection has been established, restart advertising
        user_app_adv_start();
    }

    default_app_on_connection(connection_idx, param);
}

void user_app_adv_undirect_complete(uint8_t status)
{
    // If advertising was canceled then update advertising data and start advertising again
    if (status == GAP_ERR_CANCELED)
    {
        user_app_adv_start();
    }
}

void user_app_disconnect(struct gapc_disconnect_ind const *param)
{
    // Cancel the parameter update request timer
    if (app_param_update_request_timer_used != EASY_TIMER_INVALID_TIMER)
    {
        app_easy_timer_cancel(app_param_update_request_timer_used);
        app_param_update_request_timer_used = EASY_TIMER_INVALID_TIMER;
    }
    
    uint8_t state = ke_state_get(TASK_APP);

    if ((state == APP_SECURITY) ||
        (state == APP_CONNECTED) ||
        (state == APP_PARAM_UPD))
    {
        // Restart Advertising
        user_app_adv_start();
    }
    else
    {
        // We are not in a Connected State
        ASSERT_ERR(0);
    }
}

void user_catch_rest_hndl(ke_msg_id_t const msgid,
                          void const *param,
                          ke_task_id_t const dest_id,
                          ke_task_id_t const src_id)
{
    switch(msgid)
    {
        case GAPC_PARAM_UPDATED_IND:
        {
            // Cast the "param" pointer to the appropriate message structure
            struct gapc_param_updated_ind const *msg_param = (struct gapc_param_updated_ind const *)(param);

            // Check if updated Conn Params filled to preffered ones
            if ((msg_param->con_interval >= user_connection_param_conf.intv_min) &&
                (msg_param->con_interval <= user_connection_param_conf.intv_max) &&
                (msg_param->con_latency == user_connection_param_conf.latency) &&
                (msg_param->sup_to == user_connection_param_conf.time_out))
            {
            }
        } break;

        default:
            break;
    }
}

/**
 ****************************************************************************************
 * @brief SPI and SPI flash Initialization function
 * 
 ****************************************************************************************
 */
static void spi_flash_peripheral_init()
{
    spi_FLASH_CS_Pad.pin = SPI_EN_GPIO_PIN;
    spi_FLASH_CS_Pad.port = SPI_GPIO_PORT;
    // Enable SPI & SPI FLASH

    spi_init(&spi_FLASH_CS_Pad, SPI_MODE_8BIT, SPI_ROLE_MASTER, SPI_CLK_IDLE_POL_LOW, SPI_PHA_MODE_0, SPI_MINT_DISABLE, SPI_XTAL_DIV_8);

    detected_spi_flash_device_index = spi_flash_auto_detect(); // checking the devices one by one by their JDEC ID

    if(detected_spi_flash_device_index == SPI_FLASH_AUTO_DETECT_NOT_DETECTED) // if -1
    {
        // The device was not identified.
        // The default parameters are used (SPI_FLASH_SIZE, SPI_FLASH_PAGE)
        // Alternatively, an error can be asserted here.
        spi_flash_init(SPI_FLASH_DEFAULT_SIZE, SPI_FLASH_DEFAULT_PAGE);
    }
}
/**
 ****************************************************************************************
 * @brief SPI and SPI flash test function
 * 
 ****************************************************************************************
 */
void spi_test(void)
{

    int16_t btrd;
    int16_t i;

    uint16_t read_size = 256;  // set this variable to the desired read size
    uint16_t write_size = 512; // set this variable to the desired read size
    wr_data[0] = 0;
		wr_data2[0] = 0;
	
    
    for(i = 1 ; i < 512 ; i++)
    {
        wr_data[i] = 44;  // writing the array with wr_data[] = {1,2,3,...511}
    }
		    for(i = 1 ; i < 512 ; i++)
    {
        wr_data2[i] = wr_data2[i-1] +1;  // writing the array with wr_data[] = {1,2,3,...511}
    }
    
			arch_printf("\n\r\n\r************");
			arch_printf("\n\r* SPI TEST *\n\r");
			arch_printf("************\n\r");
  
    // Enable FLASH and SPI
    spi_flash_peripheral_init(); // Scaning the Flash chip one by one with JDEC ID
    // spi_flash_chip_erase();
    // Read SPI Flash Manufacturer/Device ID
    //man_dev_id = spi_read_flash_memory_man_and_dev_id(); //0xEF12 for the W25X40CL
    
    spi_cs_low();
    
    spi_cs_high();
    
    // Erase flash
    spi_flash_chip_erase();
   
    // Read existing SPI Flash first 256 bytes
    arch_printf("\n\r\n\rReading SPI Flash first 256 bytes...");
    btrd = spi_flash_read_data(rd_data, 0, read_size);  //(uint8_t *rd_data_ptr = [512] , uint32_t address =0, uint32_t size = 256)
    // Display Results
    for(i = 0 ; i < read_size ; i++)
    {
        arch_printf("%2x",rd_data[i]);
        arch_printf(" ");
    }
    // shift operator is being used to split the hex values and print ex. if btrd = 0x2345
		arch_printf("\n\r\n\rBytes Read: 0x");
    arch_printf("%2x",(btrd >> 8) & 0xFF);   // here only 23 will print
    arch_printf("%2x",(btrd) & 0xFF);				// here 45 will print	
    arch_printf("\n\r"); 					 // newline Enter

 
    // Program Page example (256 bytes)
    arch_printf("\n\r\n\rPerforming Program Page...");
    spi_flash_page_program(wr_data, 32768, 256);
    arch_printf("Page programmed. (");
    arch_printf("%2x",spi_flash_read_status_reg());
    arch_printf(")\n\r");
    
    // Read SPI Flash first 256 bytes
    arch_printf("\n\r\n\rReading SPI Flash first 256 bytes...");
    btrd = spi_flash_read_data(rd_data, 32768 ,read_size);
    // Display Results
    for(i = 0 ; i < read_size ; i++)
    {
        arch_printf("%2x",rd_data[i]);
        arch_printf(" ");
    }
    arch_printf("\n\r\n\rBytes Read: 0x");
    arch_printf("%2x",(btrd >> 8) & 0xFF);
    arch_printf("%2x",(btrd) & 0xFF);
    arch_printf("\n\r");

		// Performing sector earase
    arch_printf("\n\rPerforming Sector Erase...");
    spi_flash_block_erase(32768, SECTOR_ERASE);
    arch_printf("Sector erased. (");
    arch_printf("%2x",spi_flash_read_status_reg());
    arch_printf(")\n\r");

    // Write data example (512 bytes)
    arch_printf("\n\r\n\rPerforming 512 byte write...");
    spi_flash_write_data(wr_data2, 32768, 512);
    arch_printf("Data written. (");
    arch_printf("%2x",spi_flash_read_status_reg());
    arch_printf(")\n\r");
    
    // Read SPI Flash first 512 bytes
    arch_printf("\n\r\n\rReading SPI Flash first 512 bytes...");
    btrd = spi_flash_read_data(rd_data, 32768 ,512);
    // Display Results
    for(i = 0 ; i < 512 ; i++)
    {
        arch_printf("%2x",rd_data[i]);
        arch_printf(" ");

				
		if (rd_data[511] == 0xFF){
		arch_printf("Perfect!");
		GPIO_SetActive( GPIO_LED_PORT, GPIO_LED_PIN);	
		}
		else{
		GPIO_SetInactive( GPIO_LED_PORT, GPIO_LED_PIN);
		}
    }
    arch_printf("\n\r\n\rBytes Read: 0x");
    arch_printf("%2x",(btrd >> 8) & 0xFF);
    arch_printf("%2x",(btrd) & 0xFF);
    arch_printf("\n\r");
    
    // SPI FLASH memory protection features
   // spi_protection_features_test();
    
    arch_printf("\n\rEnd of test\n\r");
}


/// @} APP

user_periph_setup.h:

/**
 ****************************************************************************************
 *
 * @file user_periph_setup.h
 *
 * @brief Peripherals setup header file.
 *
 * Copyright (C) 2015. Dialog Semiconductor Ltd, unpublished work. This computer
 * program includes Confidential, Proprietary Information and is a Trade Secret of
 * Dialog Semiconductor Ltd.  All use, disclosure, and/or reproduction is prohibited
 * unless authorized in writing. All Rights Reserved.
 *
 * <bluetooth.support@diasemi.com> and contributors.
 *
 ****************************************************************************************
 */

#ifndef _USER_PERIPH_SETUP_H_
#define _USER_PERIPH_SETUP_H_

/*
 * INCLUDE FILES
 ****************************************************************************************
 */

#include "rwip_config.h"
#include "global_io.h"
#include "arch.h"
#include "da1458x_periph_setup.h"
#include "i2c_eeprom.h"

/*
 * DEFINES
 ****************************************************************************************
 */

//*** <<< Use Configuration Wizard in Context Menu >>> ***

// <o> DK selection <0=> As in da1458x_periph_setup.h <1=> Basic <2=> Pro <3=> Expert
#define HW_CONFIG (2)

#define HW_CONFIG_BASIC_DK  ((HW_CONFIG==0 && SDK_CONFIG==1) || HW_CONFIG==1)
#define HW_CONFIG_PRO_DK    ((HW_CONFIG==0 && SDK_CONFIG==2) || HW_CONFIG==2)
#define HW_CONFIG_EXPERT_DK ((HW_CONFIG==0 && SDK_CONFIG==3) || HW_CONFIG==3)

//*** <<< end of configuration section >>>    ***

/****************************************************************************************/
/* I2C EEPROM configuration                                                             */
/****************************************************************************************/

#define I2C_EEPROM_SIZE   0x20000         // EEPROM size in bytes
#define I2C_EEPROM_PAGE   256             // EEPROM's page size in bytes
#define I2C_SPEED_MODE    I2C_FAST        // 1: standard mode (100 kbits/s), 2: fast mode (400 kbits/s)
#define I2C_ADDRESS_MODE  I2C_7BIT_ADDR   // 0: 7-bit addressing, 1: 10-bit addressing
#define I2C_ADDRESS_SIZE  I2C_2BYTES_ADDR // 0: 8-bit memory address, 1: 16-bit memory address, 3: 24-bit memory address

/****************************************************************************************/
/* SPI FLASH configuration                                                              */
/****************************************************************************************/

#define SPI_FLASH_DEFAULT_SIZE  131072    // SPI Flash memory size in bytes
#define SPI_FLASH_DEFAULT_PAGE  256
#define SPI_SECTOR_SIZE         4096

#ifndef __DA14583__
    #define SPI_GPIO_PORT       GPIO_PORT_0
		#define SPI_EN_GPIO_PORT    GPIO_PORT_0
    #define SPI_EN_GPIO_PIN     GPIO_PIN_3

    #define SPI_CLK_GPIO_PORT   GPIO_PORT_0
    #define SPI_CLK_GPIO_PIN    GPIO_PIN_0

    #define SPI_DO_GPIO_PORT    GPIO_PORT_0
    #define SPI_DO_GPIO_PIN     GPIO_PIN_6

    #define SPI_DI_GPIO_PORT    GPIO_PORT_0
    #define SPI_DI_GPIO_PIN     GPIO_PIN_5
#else // DA14583
    #define SPI_EN_GPIO_PORT    GPIO_PORT_0
    #define SPI_EN_GPIO_PIN     GPIO_PIN_3

    #define SPI_CLK_GPIO_PORT   GPIO_PORT_0
    #define SPI_CLK_GPIO_PIN    GPIO_PIN_0

    #define SPI_DO_GPIO_PORT    GPIO_PORT_0
    #define SPI_DO_GPIO_PIN     GPIO_PIN_6

    #define SPI_DI_GPIO_PORT    GPIO_PORT_0
    #define SPI_DI_GPIO_PIN     GPIO_PIN_5
#endif


/****************************************************************************************/
/* UART2 pin configuration (debug print console)                                        */
/****************************************************************************************/

#ifdef CFG_PRINTF_UART2
    #if HW_CONFIG_BASIC_DK
        #define UART2_TX_GPIO_PORT  GPIO_PORT_0
        #define UART2_TX_GPIO_PIN   GPIO_PIN_4

        #define UART2_RX_GPIO_PORT  GPIO_PORT_0
        #define UART2_RX_GPIO_PIN   GPIO_PIN_7

    #elif HW_CONFIG_PRO_DK
        #define UART2_TX_GPIO_PORT  GPIO_PORT_0
        #define UART2_TX_GPIO_PIN   GPIO_PIN_4

        #define UART2_RX_GPIO_PORT  GPIO_PORT_0
        #define UART2_RX_GPIO_PIN   GPIO_PIN_7

    #elif HW_CONFIG_EXPERT_DK
        #define UART2_TX_GPIO_PORT  GPIO_PORT_0
        #define UART2_TX_GPIO_PIN   GPIO_PIN_4

        #define UART2_RX_GPIO_PORT  GPIO_PORT_0
        #define UART2_RX_GPIO_PIN   GPIO_PIN_7

    #else // (e.g. HW_CONFIG_USB_DONGLE)
        #define UART2_TX_GPIO_PORT  GPIO_PORT_0
        #define UART2_TX_GPIO_PIN   GPIO_PIN_4

        #define UART2_RX_GPIO_PORT  GPIO_PORT_0
        #define UART2_RX_GPIO_PIN   GPIO_PIN_7

    #endif
#endif

/****************************************************************************************/
/* LED configuration                                                                    */
/****************************************************************************************/

#if HW_CONFIG_BASIC_DK
    #define GPIO_LED_PORT     GPIO_PORT_1
    #define GPIO_LED_PIN      GPIO_PIN_0

#elif HW_CONFIG_PRO_DK
    #define GPIO_LED_PORT     GPIO_PORT_1
    #define GPIO_LED_PIN      GPIO_PIN_0

#elif HW_CONFIG_EXPERT_DK
    #define GPIO_LED_PORT     GPIO_PORT_1
    #define GPIO_LED_PIN      GPIO_PIN_0

#else // (other configuration)
#endif

/*
 * FUNCTION DECLARATIONS
 ****************************************************************************************
 */

/**
 ****************************************************************************************
 * @brief Enable pad's and peripheral clocks assuming that peripherals' power domain
 * is down. The Uart and SPI clocks are set.
 * @return void
 ****************************************************************************************
 */
void periph_init(void);

/**
 ****************************************************************************************
 * @brief Map port pins. The Uart and SPI port pins and GPIO ports are mapped.
 * @return void
 ****************************************************************************************
 */
void set_pad_functions(void);

/**
 ****************************************************************************************
 * @brief Each application reserves its own GPIOs here.
 * @return void
 ****************************************************************************************
 */
void GPIO_reservations(void);

#endif // _USER_PERIPH_SETUP_H_

user_periph_setup.c

/**
 ****************************************************************************************
 *
 * @file user_periph_setup.c
 *
 * @brief Peripherals setup and initialization.
 *
 * Copyright (C) 2015. Dialog Semiconductor Ltd, unpublished work. This computer
 * program includes Confidential, Proprietary Information and is a Trade Secret of
 * Dialog Semiconductor Ltd.  All use, disclosure, and/or reproduction is prohibited
 * unless authorized in writing. All Rights Reserved.
 *
 * <bluetooth.support@diasemi.com> and contributors.
 *
 ****************************************************************************************
 */

/*
 * INCLUDE FILES
 ****************************************************************************************
 */

#include "rwip_config.h"             // SW configuration
#include "user_periph_setup.h"       // peripheral configuration
#include "global_io.h"
#include "gpio.h"
#include "uart.h"                    // UART initialization

#if DEVELOPMENT_DEBUG

void GPIO_reservations(void)
{
/*
* Globally reserved GPIOs reservation
*/

/*
* Application specific GPIOs reservation. Used only in Development mode (#if DEVELOPMENT_DEBUG)

i.e.
    RESERVE_GPIO(DESCRIPTIVE_NAME, GPIO_PORT_0, GPIO_PIN_1, PID_GPIO);    //Reserve P_01 as Generic Purpose I/O
*/

#ifdef CFG_PRINTF_UART2
    RESERVE_GPIO(UART2_TX, UART2_TX_GPIO_PORT, UART2_TX_GPIO_PIN, PID_UART2_TX);
    RESERVE_GPIO(UART2_RX, UART2_RX_GPIO_PORT, UART2_RX_GPIO_PIN, PID_UART2_RX);
#endif
}
#endif //DEVELOPMENT_DEBUG

void set_pad_functions(void)        // set gpio port function mode
{
#ifdef CFG_PRINTF_UART2
    GPIO_ConfigurePin(UART2_TX_GPIO_PORT, UART2_TX_GPIO_PIN, OUTPUT, PID_UART2_TX, false);
    GPIO_ConfigurePin(UART2_RX_GPIO_PORT, UART2_RX_GPIO_PIN, INPUT, PID_UART2_RX, false);
#endif

/*
* Configure application ports.
i.e.
    GPIO_ConfigurePin( GPIO_PORT_0, GPIO_PIN_1, OUTPUT, PID_GPIO, false ); // Set P_01 as Generic purpose Output
*/
}

void periph_init(void)
{
    // system init
    SetWord16(CLK_AMBA_REG, 0x00);                 // set clocks (hclk and pclk ) 16MHz
    SetWord16(SET_FREEZE_REG,FRZ_WDOG);            // stop watch dog    
    SetBits16(SYS_CTRL_REG,PAD_LATCH_EN,1);        // open pads
    SetBits16(SYS_CTRL_REG,DEBUGGER_ENABLE,1);     // open debugger
    SetBits16(PMU_CTRL_REG, PERIPH_SLEEP,0);       // exit peripheral power down

	
		GPIO_ConfigurePin(SPI_EN_GPIO_PORT, SPI_EN_GPIO_PIN, OUTPUT, PID_SPI_EN, true);
    GPIO_ConfigurePin(SPI_CLK_GPIO_PORT, SPI_CLK_GPIO_PIN, OUTPUT, PID_SPI_CLK, false);
    GPIO_ConfigurePin(SPI_DO_GPIO_PORT, SPI_DO_GPIO_PIN, OUTPUT, PID_SPI_DO, false);
    GPIO_ConfigurePin(SPI_DI_GPIO_PORT, SPI_DI_GPIO_PIN, INPUT, PID_SPI_DI, false);
		// Power up peripherals' power domain
    SetBits16(PMU_CTRL_REG, PERIPH_SLEEP, 0);
    while (!(GetWord16(SYS_STAT_REG) & PER_IS_UP));

    SetBits16(CLK_16M_REG, XTAL16_BIAS_SH_ENABLE, 1);

    //rom patch
    patch_func();

    //Init pads
    set_pad_functions();

    // (Re)Initialize peripherals
    // i.e.
    //  uart_init(UART_BAUDRATE_115K2, 3);

#ifdef CFG_PRINTF_UART2
    SetBits16(CLK_PER_REG, UART2_ENABLE, 1);
    uart2_init(UART_BAUDRATE_115K2, 3);
#endif

   // Enable the pads
    SetBits16(SYS_CTRL_REG, PAD_LATCH_EN, 1);
}

spi_flash.h

/**
 ****************************************************************************************
 *
 * @file spi_flash.h
 *
 * @brief flash memory driver over spi interface header file.
 *
 * Copyright (C) 2012. Dialog Semiconductor Ltd, unpublished work. This computer
 * program includes Confidential, Proprietary Information and is a Trade Secret of
 * Dialog Semiconductor Ltd.  All use, disclosure, and/or reproduction is prohibited
 * unless authorized in writing. All Rights Reserved.
 *
 * <bluetooth.support@diasemi.com> and contributors.
 *
 ****************************************************************************************
 */

#ifndef _SPI_FLASH_H_
#define _SPI_FLASH_H_

/*
 * INCLUDE FILES
 ****************************************************************************************
 */

#include "spi.h"
#include <stdint.h>

/*
 * DEFINES
 ****************************************************************************************
 */

#define SPI_FLASH_DRIVER_VERSION (2)
#define SPI_FLASH_DRIVER_SUBVERSION (1)

/*
	Tested SPI FLASH devices
		- W25x10/Windbond
		- W25x20/Winbond
        - AT25DS011/Adesto
        - MX25V1006E/Macronix (embedded in DA14583)
*/

// Definitions for the various SPI Flash Devices

#define SPI_FLASH_DEVICES_SUPPORTED_COUNT (4)

// 1. W25X10CL
#define SPI_FLASH_DEVICE_INDEX_W25X10 0
#define W25X10_MAN_DEV_ID 0xEF10
#define	W25X10_JEDEC_ID 0xEF3011
#define W25X10_JEDEC_ID_MATCHING_BITMASK 0xFFFFFF
#define W25X10_TOTAL_FLASH_SIZE 0x20000
#define W25X10_PAGE_SIZE 0x100
#define W25x10_MEM_PROT_NONE 0
#define W25x10_MEM_PROT_UPPER_HALF 4
#define W25x10_MEM_PROT_LOWER_HALF 36
#define W25x10_MEM_PROT_ALL 8

// 2. W25X20CL
#define SPI_FLASH_DEVICE_INDEX_W25X20 1
#define W25X20_MAN_DEV_ID 0xEF11
#define	W25X20_JEDEC_ID 0xEF3012
#define W25X20_JEDEC_ID_MATCHING_BITMASK 0xFFFFFF
#define W25X20_TOTAL_FLASH_SIZE 0x40000
#define W25X20_PAGE_SIZE 0x100
#define W25x20_MEM_PROT_NONE 0
#define W25x20_MEM_PROT_UPPER_QUARTER 4
#define W25x20_MEM_PROT_UPPER_HALF 8
#define W25x20_MEM_PROT_LOWER_QUARTER 36
#define W25x20_MEM_PROT_LOWER_HALF 40
#define W25x20_MEM_PROT_ALL 12

// Parameters common to both W25X10 and W25X20
#define W25x_MEM_PROT_BITMASK 0x2C

// 3. AT25DN011, AT25DF011
#define SPI_FLASH_DEVICE_INDEX_AT25Dx011 2
#define AT25Dx011_JEDEC_ID 0x1F4200
#define AT25Dx011_JEDEC_ID_MATCHING_BITMASK 0xFFFF00
#define AT25Dx011_TOTAL_FLASH_SIZE 0x20000
#define AT25Dx011_PAGE_SIZE 0x100
#define AT25Dx011_MEM_PROT_BITMASK 4
#define AT25Dx011_MEM_PROT_NONE 0
#define AT25Dx011_MEM_PROT_ENTIRE_MEMORY_PROTECTED 4

// 4. MX25V1006E
#define SPI_FLASH_DEVICE_INDEX_MX25V1006E 3
#define MX25V1006E_MAN_DEV_ID 0xC210
#define MX25V1006E_JEDEC_ID 0xC22011
#define MX25V1006E_JEDEC_ID_MATCHING_BITMASK 0xFFFFFF
#define MX25V1006E_TOTAL_FLASH_SIZE 0x20000
#define MX25V1006E_PAGE_SIZE 0x100
#define MX25V1006E_MEM_PROT_BITMASK 0x0C
#define MX25V1006E_MEM_PROT_NONE 0
#define MX25V1006E_MEM_PROT_ENTIRE_MEMORY_PROTECTED 0x0C

typedef struct
{
	uint32_t jedec_id;							// JEDEC ID (3 bytes)
	uint32_t jedec_id_matching_bitmask;			// bitmask of the JEDEC ID to derive matching
	uint32_t flash_size;						// the total size in bytes
	uint32_t page_size;							// the page size in bytes
	uint8_t memory_protection_bitmask;			// the memory protection-related bits of the status register
	uint8_t memory_protection_unprotected;  	// the 'entire memory unprotected' status register value
} SPI_FLASH_DEVICE_PARAMETERS_BY_JEDEC_ID_t;

typedef enum SPI_ERASE_MODULE
{
    BLOCK_ERASE_64  = 0xd8,
    BLOCK_ERASE_32  = 0x52,
    SECTOR_ERASE    = 0x20,
} SPI_erase_module_t;

#define	MAX_READY_WAIT_COUNT   2000000
#define	MAX_COMMAND_SEND_COUNT 50

/* Status Register Bits */
#define STATUS_BUSY		0x01
#define	STATUS_WEL		0x02
#define	STATUS_BP0		0x04
#define	STATUS_BP1		0x08
#define	STATUS_TB   	0x20
#define	STATUS_SRP		0x80

#define ERR_OK				    0
#define ERR_TIMEOUT			    -1
#define ERR_NOT_ERASED  	    -2
#define ERR_PROTECTED	        -3
#define ERR_INVAL			    -4
#define ERR_ALIGN			    -5
#define ERR_UNKNOWN_FLASH_VENDOR -6
#define ERR_UNKNOWN_FLASH_TYPE	 -7
#define ERR_PROG_ERROR			 -8

/* commands */
#define WRITE_ENABLE      0x06
#define WRITE_ENABLE_VOL  0x50
#define WRITE_DISABLE     0x04

#define READ_STATUS_REG   0x05
#define WRITE_STATUS_REG  0x01
#define PAGE_PROGRAM      0x02
#define QUAD_PAGE_PROGRAM 0x32
#define CHIP_ERASE        0xC7
//                        ^^^// or 0x60
#define ERASE_SUSPEND     0x75
#define ERASE_RESUME      0x7a
#define POWER_DOWN        0xb9
#define HIGH_PERF_MODE    0xa3
#define MODE_BIT_RESET    0xff
#define REL_POWER_DOWN    0xab
#define MAN_DEV_ID        0x90
#define READ_UNIQUE_ID    0x4b
#define JEDEC_ID          0x9f
#define READ_DATA         0x03
#define FAST_READ         0x0b

#define SPI_FLASH_AUTO_DETECT_NOT_DETECTED (-1)

/*
 * FUNCTION DECLARATIONS
 ****************************************************************************************
 */

/**
 ****************************************************************************************
 * @brief Initialize SPI Flash.
 * @param[in ]spi_flash_size_param         Flash Size
 * @param[in] spi_flash_page_size_param    Flash Page Size
 * @return void
 ****************************************************************************************
 */
void spi_flash_init(uint32_t spi_flash_size_param, uint32_t spi_flash_page_size_param);

/**
 ****************************************************************************************
 * @brief Detect the SPI flash device, based on the JEDEC manufacturer id and the
 *        manufacturer-defined data(2 bytes) which is retrieved when the command 9Fh
 *        is issued. If the device is successfully identified, the total memory size
 *        and page size are retrieved from a lookup table.
 * @return the index of the device in the SPI_FLASH_KNOWN_DEVICES_PARAMETERS_LIST or
 *         (SPI_FLASH_AUTO_DETECT_NOT_DETECTED) if the device is not found
 ****************************************************************************************
 */
int8_t spi_flash_auto_detect(void);

/**
 ****************************************************************************************
 * @brief Wait till flash is ready for next action.
 * @return Success : ERR_OK
 *         Failure : ERR_TIMEOUT
 ****************************************************************************************
 */
int8_t spi_flash_wait_till_ready (void);

/**
 ****************************************************************************************
 * @brief Read Status Register.
 * @return Status Register value
 ****************************************************************************************
 */
uint8_t spi_flash_read_status_reg(void);

 /**
 ****************************************************************************************
 * @brief Issue a Write Enable Command.
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int8_t spi_flash_set_write_enable(void);

/**
 ****************************************************************************************
 * @brief Issue a Write Enable Volatile Command.
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int8_t spi_flash_write_enable_volatile(void);

/**
 ****************************************************************************************
 * @brief Issue a Write Disable Command.
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int8_t spi_flash_set_write_disable(void);

/**
 ****************************************************************************************
 * @brief Write Status Register.
 * @param[in] dataToWrite Value to be written to Status Register
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int32_t spi_flash_write_status_reg(uint8_t dataToWrite);

/**
 ****************************************************************************************
 * @brief Read data from a given starting address (up to the end of the flash).
 * @param[in] *rd_data_ptr  Points to the position the read data will be stored
 * @param[in] address       Starting address of data to be read
 * @param[in] size          Size of the data to be read
 * @return Number of read bytes or error code
 ****************************************************************************************
 */
int32_t spi_flash_read_data (uint8_t *rd_data_ptr, uint32_t address, uint32_t size);

/**
 ****************************************************************************************
 * @brief Program page (up to <SPI Flash page size> bytes) starting at given address.
 * @param[in] *wr_data_ptr  Pointer to the data to be written
 * @param[in] address       Starting address of data to be written
 * @param[in] size          Size of the data to be written (should not be larger than SPI Flash page size)
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int32_t spi_flash_page_program(uint8_t *wr_data_ptr, uint32_t address, uint16_t size);

 /**
 ****************************************************************************************
 * @brief Issue a comamnd to Erase a given address.
 * @param[in] address        Address that belongs to the block64/block32/sector range
 * @param[in] spiEraseModule BLOCK_ERASE_64, BLOCK_ERASE_32, SECTOR_ERASE
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int8_t spi_flash_block_erase(uint32_t address, SPI_erase_module_t spiEraseModule);

/**
 ****************************************************************************************
 * @brief Erase chip.
 * @note In order for the erasure to succeed, all locking options must be disabled.
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int8_t spi_flash_chip_erase(void);

/**
 ****************************************************************************************
 * @brief Get Manufacturer/Device ID.
 * @return Manufacturer/Device ID
 ****************************************************************************************
 */
int16_t spi_read_flash_memory_man_and_dev_id(void);

/**
 ****************************************************************************************
 * @brief Get Unique ID Number.
 * @return Unique ID Number
 ****************************************************************************************
 */
uint64_t spi_read_flash_unique_id(void);

/**
 ****************************************************************************************
 * @brief Get JEDEC ID.
 * @return JEDEC ID
 ****************************************************************************************
 */
int32_t spi_read_flash_jedec_id(void);

/**
 ****************************************************************************************
 * @brief Write data to flash across page boundaries and at any starting address.
 * @param[in] *wr_data_ptr Pointer to the data to be written
 * @param[in] address      Starting address of page to be written (must be a multiple of SPI Flash page size)
 * @param[in] size         Size of the data to be written (can be larger than SPI Flash page size)
 * @return Number of bytes actually written
 ****************************************************************************************
 */
int32_t spi_flash_write_data (uint8_t * wr_data_ptr, uint32_t address, uint32_t size);


 /**
 ****************************************************************************************
 * @brief Sends the Power-Down instruction.
 * Remark: The function spi_flash_release_from_powerdown() is used to enable the IC again
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int32_t spi_flash_power_down(void);

/**
 ****************************************************************************************
 * @brief Sends the Release from Power-Down instruction.
 * Remark: This function is used to restore the IC from power-down mode
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int32_t spi_flash_release_from_power_down(void);

/**
 ****************************************************************************************
 * @brief Selects the the memory protection configuration.
 * @param[in] SPI_flash_memory_protection_setting
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int32_t spi_flash_configure_memory_protection(uint8_t spi_flash_memory_protection_setting);

/**
 ****************************************************************************************
 * @brief Erase chip even if locked.
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int8_t spi_flash_chip_erase_forced(void);

/**
 ****************************************************************************************
 * @brief Fill memory page (up to <SPI Flash page size> bytes) with a given 1-byte value
 *        starting at given address.
 * @param[in] value         Value used to fill memory
 * @param[in] address       Starting address
 * @param[in] size          Size of the area to be filled (should not be larger than SPI Flash page size)
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int8_t spi_flash_page_fill(uint8_t value, uint32_t address, uint16_t size);

/**
 ****************************************************************************************
 * @brief Fill memory with a 1-byte value, across page boundaries and at any starting address.
 * @param[in] value    The value with which memory will be filled
 * @param[in] address  Starting address of page to be written (must be a multiple of SPI Flash page size)
 * @param[in] size     Size of the area to be filled (can be larger than SPI Flash page size)
 * @return  Number of bytes actually written
 ****************************************************************************************
*/
int32_t spi_flash_fill (uint8_t value, uint32_t address, uint32_t size);

/**
 ****************************************************************************************
 * @brief Initializes spi and spi_flash drivers, discovers jedec id and releases from power down.
 * @param[in] cs_port  Chip select port
 * @param[in] cs_pin   Chip select pin
 * @return Number of bytes actually written
 ****************************************************************************************
*/
int8_t spi_flash_enable(GPIO_PORT cs_port, GPIO_PIN cs_pin);

#endif //_SPI_FLASH_H_

spi_flash.c:

/**
 ****************************************************************************************
 *
 * @file spi_flash.c
 *
 * @brief flash driver over spi interface.
 *
 * Copyright (C) 2012. Dialog Semiconductor Ltd, unpublished work. This computer 
 * program includes Confidential, Proprietary Information and is a Trade Secret of 
 * Dialog Semiconductor Ltd.  All use, disclosure, and/or reproduction is prohibited 
 * unless authorized in writing. All Rights Reserved.
 *
 * <bluetooth.support@diasemi.com> and contributors.
 *
 ****************************************************************************************
 */


#include "spi_flash.h"

// local copy of FLASH setup parameters
int16_t spi_flash_device_index;
const SPI_FLASH_DEVICE_PARAMETERS_BY_JEDEC_ID_t *spi_flash_detected_device;
uint32_t spi_flash_size;         
uint32_t spi_flash_page_size;

const SPI_FLASH_DEVICE_PARAMETERS_BY_JEDEC_ID_t SPI_FLASH_KNOWN_DEVICES_PARAMETERS_LIST[] = 
{
	{W25X10_JEDEC_ID, W25X10_JEDEC_ID_MATCHING_BITMASK, W25X10_TOTAL_FLASH_SIZE, W25X10_PAGE_SIZE, W25x_MEM_PROT_BITMASK, W25x10_MEM_PROT_NONE},
	{W25X20_JEDEC_ID, W25X20_JEDEC_ID_MATCHING_BITMASK, W25X20_TOTAL_FLASH_SIZE, W25X20_PAGE_SIZE, W25x_MEM_PROT_BITMASK, W25x20_MEM_PROT_NONE},
	{AT25Dx011_JEDEC_ID, AT25Dx011_JEDEC_ID_MATCHING_BITMASK, AT25Dx011_TOTAL_FLASH_SIZE, AT25Dx011_PAGE_SIZE, AT25Dx011_MEM_PROT_BITMASK, AT25Dx011_MEM_PROT_NONE},
	{MX25V1006E_JEDEC_ID, MX25V1006E_JEDEC_ID_MATCHING_BITMASK, MX25V1006E_TOTAL_FLASH_SIZE, MX25V1006E_PAGE_SIZE, MX25V1006E_MEM_PROT_BITMASK, MX25V1006E_MEM_PROT_NONE},
};

/**
 ****************************************************************************************
 * @brief Initialize SPI Flash
 * @param[in ]spi_flash_size_param:         Flash Size
 * @param[in] spi_flash_page_size_param:    Flash Page Size
 ****************************************************************************************
 */
void spi_flash_init(uint32_t spi_flash_size_param, uint32_t spi_flash_page_size_param)
{
	spi_flash_size = spi_flash_size_param;
	spi_flash_page_size = spi_flash_page_size_param;
}

/**
 ****************************************************************************************
 * @brief Detect the SPI flash device, based on the JEDEC manufacturer id and the		
 *		  manufacturer-defined data(2 bytes) which is retrieved when the command 9Fh
 *		  is issued. If the device is successfully identified, the total memory size
 *		  and page size are retrieved from a lookup table.
 * @return the index of the device in the SPI_FLASH_KNOWN_DEVICES_PARAMETERS_LIST or
 *         (SPI_FLASH_AUTO_DETECT_NOT_DETECTED) if the device is not found
 ****************************************************************************************
 */
int8_t spi_flash_auto_detect(void)
{
	uint32_t jedec_id;
	uint16_t i;
	
	jedec_id = spi_read_flash_jedec_id();
	for (i=0; i<SPI_FLASH_DEVICES_SUPPORTED_COUNT; i++)
	{
		if ( (jedec_id & SPI_FLASH_KNOWN_DEVICES_PARAMETERS_LIST[i].jedec_id_matching_bitmask) ==\
				 (SPI_FLASH_KNOWN_DEVICES_PARAMETERS_LIST[i].jedec_id & SPI_FLASH_KNOWN_DEVICES_PARAMETERS_LIST[i].jedec_id_matching_bitmask) )
		{
			spi_flash_device_index = i;
			spi_flash_size = SPI_FLASH_KNOWN_DEVICES_PARAMETERS_LIST[i].flash_size;
			spi_flash_page_size = SPI_FLASH_KNOWN_DEVICES_PARAMETERS_LIST[i].page_size;
			spi_flash_detected_device = &SPI_FLASH_KNOWN_DEVICES_PARAMETERS_LIST[spi_flash_device_index];
			return i;
		}	
	}
	// SPI flash device not recognized
	spi_flash_detected_device = 0;	
	return SPI_FLASH_AUTO_DETECT_NOT_DETECTED;
}

/**
 ****************************************************************************************
 * @brief Read Status Register
 * @return  Status Register value
 ****************************************************************************************
 */
uint8_t spi_flash_read_status_reg(void)
{
	//no 'add spi_flash_wait_till_ready()' here
	spi_set_bitmode(SPI_MODE_16BIT);                          // set SPI bitmode to 16-bit      
	return spi_transaction((uint16_t)(READ_STATUS_REG<<8));
}

/**
 ****************************************************************************************
 * @brief Wait till flash is ready for next action 
* @return  Success : ERR_OK
*          Failure : ERR_TIMEOUT 
 ****************************************************************************************
 */
int8_t spi_flash_wait_till_ready (void)
{
	uint32_t statusReadCount;
	for (statusReadCount = 0; statusReadCount < MAX_READY_WAIT_COUNT; statusReadCount++)
	{
		if ((spi_flash_read_status_reg() & STATUS_BUSY) == 0)
			return ERR_OK;
	}
	return ERR_TIMEOUT;
}

/**
 ****************************************************************************************
 * @brief Issue a Write Enable Command  
 * @return error code or success (ERR_OK)  
 ****************************************************************************************
 */  
int8_t spi_flash_set_write_enable(void)
{
	uint32_t commandSendCount;
	uint32_t statusReadCount;
	uint8_t status;
	if (spi_flash_wait_till_ready() == ERR_OK)
	{
		spi_set_bitmode(SPI_MODE_8BIT);           // set SPI bitmode to 8-bit               
		for (commandSendCount = 0; commandSendCount < MAX_COMMAND_SEND_COUNT; commandSendCount++)   
		{        
			spi_transaction(WRITE_ENABLE);      // send instruction              
			for (statusReadCount = 0; statusReadCount < MAX_READY_WAIT_COUNT; statusReadCount++)
			{
				status = spi_flash_read_status_reg();
				if  ( ((status & STATUS_BUSY) == 0) && ((status & STATUS_WEL) != 0) ) 
					return ERR_OK;    
			}
		}
	}
	return ERR_TIMEOUT;
}

/**
 ****************************************************************************************
 * @brief Issue a Write Enable Volatile Command  
 * @return error code or success (ERR_OK)  
 ****************************************************************************************
 */  
int8_t spi_flash_write_enable_volatile(void)
{
	uint32_t commandSendCount;
	uint32_t statusReadCount;
	uint8_t status;
	if (spi_flash_wait_till_ready() == ERR_OK)
	{
		spi_set_bitmode(SPI_MODE_8BIT);           // set SPI bitmode to 8-bit               
		for (commandSendCount = 0; commandSendCount < MAX_COMMAND_SEND_COUNT; commandSendCount++)   
		{        
			spi_transaction(WRITE_ENABLE_VOL);          // send instruction              
			for (statusReadCount = 0; statusReadCount < MAX_READY_WAIT_COUNT; statusReadCount++)
			{
				status = spi_flash_read_status_reg();
				if  ( ((status & STATUS_BUSY) == 0) && ((status & STATUS_WEL) != 0) ) 
					return ERR_OK;    
			}
		}
	}
	return ERR_TIMEOUT;    
}

/**
 ****************************************************************************************
 * @brief Issue a Write Disable Command  
 * @return error code or success (ERR_OK)  
 ****************************************************************************************
 */  
int8_t spi_flash_set_write_disable(void)
{
	uint32_t commandSendCount;
	uint32_t statusReadCount;
	uint8_t status;
	if (spi_flash_wait_till_ready() == ERR_OK)
	{
		spi_set_bitmode(SPI_MODE_8BIT);           	// set SPI bitmode to 8-bit               
		for (commandSendCount = 0; commandSendCount < MAX_COMMAND_SEND_COUNT; commandSendCount++)   
		{
			spi_transaction(WRITE_DISABLE);         // send instruction              
			for (statusReadCount = 0; statusReadCount < MAX_READY_WAIT_COUNT; statusReadCount++)
			{
				status = spi_flash_read_status_reg();
				if ( ((status & STATUS_BUSY) == 0) && ((status & STATUS_WEL) == 0) ) 
					return ERR_OK;    
			}
		}
	}
	return ERR_TIMEOUT;    
}

/**
 ****************************************************************************************
 * @brief Write Status Register
 * @param[in] dataToWrite:   Value to be written to Status Register
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int32_t spi_flash_write_status_reg(uint8_t dataToWrite)
{
	int8_t spi_flash_status;
	spi_flash_status = spi_flash_wait_till_ready();
	if (spi_flash_status != ERR_OK)
		return spi_flash_status; // an error has occured        
  
	spi_set_bitmode(SPI_MODE_16BIT);    
	spi_transaction((WRITE_STATUS_REG<<8) | dataToWrite);     // send  Write Status Register-1 instruction
	return spi_flash_wait_till_ready();
}

/**
 ****************************************************************************************
 * @brief Read data from a given starting address (up to the end of the flash)
 *
 * @param[in] *rd_data_ptr:  Points to the position the read data will be stored
 * @param[in] address:       Starting address of data to be read
 * @param[in] size:          Size of the data to be read
 * 
 * @return  Number of read bytes or error code
 ****************************************************************************************
 */
int32_t spi_flash_read_data (uint8_t *rd_data_ptr, uint32_t address, uint32_t size)
{
	int8_t spi_flash_status;
	uint32_t bytes_read, i, temp_size;
	
	// check that all bytes to be retrieved are located in valid flash memory address space
	if (size + address > spi_flash_size)
	{
		temp_size = spi_flash_size - address;
		bytes_read = temp_size;
	}
	else
	{
		temp_size = size;
		bytes_read = size;
	}
    
	spi_flash_status = spi_flash_wait_till_ready();
	if (spi_flash_status != ERR_OK)
		return spi_flash_status; 						// an error has occured     

	spi_set_bitmode(SPI_MODE_32BIT);    
	spi_cs_low();            			            	// pull CS low    
	spi_access( (READ_DATA<<24) | address);             // Command for sequencial reading from memory		
	spi_set_bitmode(SPI_MODE_8BIT);   
	for(i=0; i<temp_size; i++)
	{
		*rd_data_ptr++ = (uint8_t)spi_access(0x0000);   // bare SPI transaction
	}
	spi_cs_high();               			            // push CS high
	return bytes_read;
}


/**
 ****************************************************************************************
 * @brief Program page (up to <SPI Flash page size> bytes) starting at given address
 *
 * @param[in] *wr_data_ptr:  Pointer to the data to be written
 * @param[in] address:       Starting address of data to be written
 * @param[in] size:          Size of the data to be written (should not be larger than SPI Flash page size)
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int32_t spi_flash_page_program(uint8_t *wr_data_ptr, uint32_t address, uint16_t size)
{
	int8_t spi_flash_status;
	uint16_t temp_size = size;
    	
	if (temp_size > spi_flash_page_size)                // check for max page size
		temp_size = spi_flash_page_size;
	
	spi_flash_status = spi_flash_wait_till_ready();
	if (spi_flash_status != ERR_OK)
		return spi_flash_status; 						// an error has occured   
  
	spi_flash_status = spi_flash_set_write_enable();    // send [Write Enable] instruction
	if (spi_flash_status != ERR_OK)
		return spi_flash_status; 						// an error has occured       
    
	spi_set_bitmode(SPI_MODE_32BIT);
	spi_cs_low();            			            	// pull CS low
	spi_access( (PAGE_PROGRAM<<24) | address);        	// Command for page programming
	spi_set_bitmode(SPI_MODE_8BIT);           
	while(temp_size>0)                                  // Write data bytes
	{
		spi_access(*wr_data_ptr++);
		temp_size--;
	}
	spi_cs_high();                                      // push CS high  
 	return spi_flash_wait_till_ready();
}


/**
 ****************************************************************************************
 * @brief Issue a command to Erase a given address
 *
 * @param[in] address:  Address that belongs to the block64/block32/sector range
 * @param[in] spiEraseModule: BLOCK_ERASE_64, BLOCK_ERASE_32, SECTOR_ERASE
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int8_t spi_flash_block_erase(uint32_t address, SPI_erase_module_t spiEraseModule)
{
	if (spi_flash_set_write_enable() != ERR_OK)         // send [Write Enable] instruction
		return ERR_TIMEOUT;

	spi_set_bitmode(SPI_MODE_32BIT);
	spi_transaction( (spiEraseModule<<24) | address);   // Command for erasing a sector    
	return spi_flash_wait_till_ready();                 
 }

/**
 ****************************************************************************************
 * @brief Erase chip
 * @note In order for the erasure to succeed, all locking options must be disabled.
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int8_t spi_flash_chip_erase(void)
{
	uint8_t status;
	
	if (spi_flash_set_write_enable() != ERR_OK)      // send [Write Enable] instruction
		return ERR_TIMEOUT;
	
	spi_set_bitmode(SPI_MODE_8BIT);
	spi_transaction(CHIP_ERASE);                    // Command for Chip Erase
	status = spi_flash_wait_till_ready();
	
	return status;
}


/**
 ****************************************************************************************
 * @brief Get Manufacturer / Device ID
 * @return  Manufacturer/Device ID (0 in case of time-out)
 ****************************************************************************************
 */
int16_t spi_read_flash_memory_man_and_dev_id(void)
{
	int8_t spi_flash_status;
	uint16_t idWord = 0;

	spi_flash_status = spi_flash_wait_till_ready();
	if (spi_flash_status == ERR_OK)
	{
		spi_set_bitmode(SPI_MODE_16BIT);
		spi_cs_low();            			// pull CS low
		spi_access(MAN_DEV_ID<<8);			// SPI transaction to send command
		spi_access(0x0000);         		// dummy   SPI transaction to send (A23-A0)
		idWord = spi_access(0x0000);		// SPI transaction to read Manufacturer Id, Device ID
		spi_cs_high();               		// push CS high
	}

	return idWord;
}



/**
 ****************************************************************************************
 * @brief Get Unique ID Number
 * @return  Unique ID Number (0 in case of time-out)
 ****************************************************************************************
 */
uint64_t spi_read_flash_unique_id(void)
{
	int8_t spi_flash_status;
	uint64_t unique_id = 0;
              
	spi_flash_status = spi_flash_wait_till_ready();
	if (spi_flash_status == ERR_OK)
	{
		spi_set_bitmode(SPI_MODE_8BIT);
		spi_cs_low();            				  // pull CS low
		spi_access(READ_UNIQUE_ID);               // SPI access to send [Read Unique ID] command
		spi_set_bitmode(SPI_MODE_32BIT);           // dummy transaction for the 4 dummy bytes
		spi_access(0x0000);                      // dummy bare SPI transaction
		unique_id = ((uint64_t)spi_access(0x0000) << 32);     // SPI access to get the high part of unique id
		unique_id |= (uint64_t)spi_access(0x0000);          // bare SPI access to get the high part of unique id
		spi_cs_high();                           // push CS high
	}

	return unique_id;	
}


/**
 ****************************************************************************************
 * @brief Get JEDEC ID
 * @return  JEDEC ID
 ****************************************************************************************
 */
int32_t spi_read_flash_jedec_id(void)
{
	int8_t spi_flash_status;   
	uint32_t jedec_id;
	
	spi_flash_status = spi_flash_wait_till_ready();
	if (spi_flash_status != ERR_OK)
		return spi_flash_status; // an error has occured      
    
	spi_set_bitmode(SPI_MODE_8BIT);   
	spi_cs_low();            		   	  // pull CS low
	spi_access(JEDEC_ID);                 //  SPI accsss to send [Read Unique ID] command   
	jedec_id = spi_access(0x0000) << 16;  //  SPI accsss to get the JEDEC Manufacturer ID
	jedec_id |= spi_access(0x0000) << 8;  //  SPI accsss to get device information byte 1
	jedec_id |= spi_access(0x0000);       //  SPI accsss to get device information byte 2 
	spi_cs_high();                        // push CS high  
	return jedec_id;	   
}

/**
 ****************************************************************************************
 * @brief Write data to flash across page boundaries and at any starting address
 *
 * @param[in] *wr_data_ptr:  Pointer to the data to be written
 * @param[in] address:       Starting address of page to be written (must be a multiple of SPI Flash page size)
 * @param[in] size:          Size of the data to be written (can be larger than SPI Flash page size)
 * 
 * @return  Number of bytes actually written
 ****************************************************************************************
 */
int32_t spi_flash_write_data (uint8_t *wr_data_ptr, uint32_t address, uint32_t size)
{
	uint32_t bytes_written; 
	uint32_t feasible_size = size;
	uint32_t currentAddress = address;
	uint32_t currentEndOfPage = (currentAddress / spi_flash_page_size + 1) * spi_flash_page_size - 1;
	uint32_t bytes_left_to_send;

	spi_set_bitmode(SPI_MODE_8BIT);
    
  	// limit to the maximum count of bytes that can be written to a (SPI_FLASH_SIZE x 8) flash
	if (size > spi_flash_size - address)
		feasible_size = spi_flash_size - address;
 
	bytes_left_to_send = feasible_size;
	bytes_written = 0;
	
	while (bytes_written < feasible_size)
	{
		// limit the transaction to the upper limit of the current page
		if (currentAddress + bytes_left_to_send > currentEndOfPage)
			bytes_left_to_send = currentEndOfPage - currentAddress + 1;             
		if (spi_flash_page_program(wr_data_ptr + bytes_written, currentAddress, bytes_left_to_send) != ERR_OK) //write the current page data
			return ERR_TIMEOUT;
		bytes_written += bytes_left_to_send;                                                     
		currentAddress = currentEndOfPage + 1;  //address points to the first memory position of the next page
		currentEndOfPage += spi_flash_page_size;
		bytes_left_to_send = feasible_size - bytes_written;
	}
	return bytes_written;
}


/**
 ****************************************************************************************
 * @brief Sends the Power-Down instruction
 * Remark: The function spi_flash_release_from_powerdown() is used to enable the IC again
 * The power-down state will be entered tDP (3uS for W25X10CL) after CS is returned to high.
 ****************************************************************************************
 */
int32_t spi_flash_power_down(void)
{
	int8_t spi_flash_status;
    
	spi_flash_status = spi_flash_wait_till_ready();
	if (spi_flash_status != ERR_OK)
		return spi_flash_status;    // an error has occured   
    
	spi_set_bitmode(SPI_MODE_8BIT);    
	spi_transaction(POWER_DOWN);    // SPI transaction to Power-down the SPI Flash IC 
    
	return ERR_OK;
}

/**
 ****************************************************************************************
 * @brief Sends the Release from Power-Down instruction
 * Remark: This function is used to restore the IC from power-down mode
 * You must ensure that the CS line will stay high after this instruction is sent for 
 * at least tRES1 DP (3uS for W25X10CL).
 ****************************************************************************************
 */
int32_t spi_flash_release_from_power_down(void)
{
	spi_set_bitmode(SPI_MODE_8BIT);    
	spi_transaction(REL_POWER_DOWN);            // SPI transaction to Power-down the SPI Flash IC 
	return ERR_OK;    
}

/**
 ****************************************************************************************
 * @brief Selects the memory protection configuration
 * @param[in] SPI_flash_memory_protection_setting
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int32_t spi_flash_configure_memory_protection(uint8_t spi_flash_memory_protection_setting)
{
	if (spi_flash_detected_device == 0)
		return ERR_UNKNOWN_FLASH_VENDOR;        // cannot configure memory protection for an unknown device	
	
	if (spi_flash_set_write_enable() != ERR_OK) // send [Write Enable] instruction
		return ERR_TIMEOUT;   
	
	return spi_flash_write_status_reg((spi_flash_read_status_reg() & (~spi_flash_detected_device->memory_protection_bitmask)) |\
		((spi_flash_memory_protection_setting)&(spi_flash_detected_device->memory_protection_bitmask)));        
}

/**
 ****************************************************************************************
 * @brief Erase chip, removing all memory areas protection prior to erasure
 * @param forced: Protection for the whole memory array is removed prior to chip erasure
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int8_t spi_flash_chip_erase_forced(void)
{
	int32_t result;
	
	// Memory protection for the entire memory array is removed prior to chip erasure
	result = spi_flash_configure_memory_protection(spi_flash_detected_device->memory_protection_unprotected);

    // if memory protection has not been removed(e.g. JEDEC id not recognized), return with error code
	if (result != ERR_OK)
		return result;

	return spi_flash_chip_erase();
}

/**
 ****************************************************************************************
 * @brief Fill memory page (up to <SPI Flash page size> bytes) with a given 1-byte value
 *        starting at given address
 *
 * @param[in] value:         Value used to fill memory
 * @param[in] address:       Starting address
 * @param[in] size:          Size of the area to be filled (should not be larger than SPI Flash page size)
 * @return error code or success (ERR_OK)
 ****************************************************************************************
 */
int8_t spi_flash_page_fill(uint8_t value, uint32_t address, uint16_t size)
{
	int8_t spi_flash_status;
	uint16_t temp_size = size;
    	
	if (temp_size > spi_flash_page_size)                // check for max page size
		temp_size = spi_flash_page_size;
	
	spi_flash_status = spi_flash_wait_till_ready();
	if (spi_flash_status != ERR_OK)
		return spi_flash_status; 						// an error has occured   

	spi_flash_status = spi_flash_set_write_enable();    // send [Write Enable] instruction
	if (spi_flash_status != ERR_OK)  
		return spi_flash_status; // an error has occured       
	
	spi_set_bitmode(SPI_MODE_32BIT);
	spi_cs_low();            			            	// pull CS low
	spi_access( (PAGE_PROGRAM<<24) | address);          // Command for page programming
	spi_set_bitmode(SPI_MODE_8BIT);           
	while(temp_size>0)                                  // Write data bytes
  	{
		spi_access(value);
		temp_size--;
	}
	spi_cs_high();                                      // push CS high  
	return spi_flash_wait_till_ready();
}

/**
 ****************************************************************************************
 * @brief Fill memory with a 1-byte value, across page boundaries and at any starting address
 *
 * @param[in] value:    The value with which memory will be filled
 * @param[in] address:  Starting address of page to be written (must be a multiple of SPI Flash page size)
 * @param[in] size:     Size of the area to be filled (can be larger than SPI Flash page size)
 * 
 * @return  Number of bytes actually written
 ****************************************************************************************
 */
int32_t spi_flash_fill (uint8_t value, uint32_t address, uint32_t size)
{
	uint32_t bytes_written; 
	uint32_t feasible_size = size;
	uint32_t currentAddress = address;
	uint32_t currentEndOfPage = (currentAddress / spi_flash_page_size + 1) * spi_flash_page_size - 1;
	uint32_t bytes_left_to_send;

	spi_set_bitmode(SPI_MODE_8BIT);
    
	// limit to the maximum count of bytes that can be written to a (SPI_FLASH_SIZE x 8) flash
	if (size > spi_flash_size - address)
		feasible_size = spi_flash_size - address;
 
	bytes_left_to_send = feasible_size;
	bytes_written = 0;
    
	while (bytes_written < feasible_size)
	{
		// limit the transaction to the upper limit of the current page
		if (currentAddress + bytes_left_to_send > currentEndOfPage)
			bytes_left_to_send = currentEndOfPage - currentAddress + 1;             
		if (spi_flash_page_fill(value, currentAddress, bytes_left_to_send) != ERR_OK) //write the current page data
			return ERR_TIMEOUT;
		bytes_written += bytes_left_to_send;                                                     
		currentAddress = currentEndOfPage + 1;  //address points to the first memory position of the next page
		currentEndOfPage += spi_flash_page_size;
		bytes_left_to_send = feasible_size - bytes_written;
	}
	return bytes_written;
}

/**
 ****************************************************************************************
 * @brief Initializes spi and spi_flash drivers, discovers jedec id and releases from power down
 *
 * @param[in] cs_port:  Chip select port
 * @param[in] cs_pin:   Chip select pin
 * 
 * @return  Number of bytes actually written
 ****************************************************************************************
*/
int8_t spi_flash_enable(GPIO_PORT cs_port, GPIO_PIN cs_pin)
{
    int8_t detected_spi_flash_device_index;
    SPI_Pad_t cs_pad_param;
    
    cs_pad_param.pin = cs_pin;
    cs_pad_param.port = cs_port;
    
    spi_init(&cs_pad_param, SPI_MODE_8BIT, SPI_ROLE_MASTER, SPI_CLK_IDLE_POL_LOW, SPI_PHA_MODE_0, SPI_MINT_DISABLE, SPI_XTAL_DIV_8);
    
    spi_flash_release_from_power_down();
    
    detected_spi_flash_device_index = spi_flash_auto_detect();
    
    return detected_spi_flash_device_index;
}

 

1 year ago

PM_Dialog

Hi theultimateprasad,

  1. Posting all this code snippets into the forum thread it will not help us to understand what the issue might be. I would suggest to attach only the modifications you have done or zip & attached the modified files in order to replicate the problem.
  2. All the code implementation should be done in the application layer files – they are all the files that start with user_ . Any other SDK modifications it is up to you as the SDK is supported as provided by Dialog.
  3. It’s strongly recommended to NOT modify any of the SDK files. The main_func() is SDK function, so my suggestion would be to keep it provides by the SDK.
  4. It is expected that you are not able to print or interact with the SPI flash, because if you run your code in debug mode, then you will see that it gets stuck into an assertion. The problem I sin GPIO configuration. Please check the attached screenshot – the problem is that any of the pin has not been previously reserved!  
  5. Copy – paste the code from the SPI peripheral SDK example to ble_app_barebone is not the best practice.
  6. Please try to run the SPI peripheral SDK example as provided. Can you please indicate if it running correctly ?
  7. Then, if you are interested in using the SPI flash in a BLE project, please take a look at the ble_app_security or prox_reporter examples of the SDK and check out the user_periph_setup.h / .c in order to understand how you should reserve and configure the GPIOs.

 

Please find below some steps in order to use the arch_printf()

 

  1.  #define CFG_PRINTF in the da1458x_config_basic.h
  2. Change the uart ports of the fw and assign the UART_TX port/pin to P04 and UART_RX port/pin to P05

    #elif HW_CONFIG_PRO_DK

        #define UART2_TX_GPIO_PORT  GPIO_PORT_0

        #define UART2_TX_GPIO_PIN   GPIO_PIN_4

        #define UART2_RX_GPIO_PORT  GPIO_PORT_0

        #define UART2_RX_GPIO_PIN   GPIO_PIN_5

If you have one other of our DKs or if you are working on a custom board, please modify the definitions above with the appropriate GPIOs

  1. Include the arch_console.h file into user_barebone.c
  2. Change the baud rate of the terminal into 115200.

 

Thanks, PM_Dialog

Attachment Size
assertion.zip 53.39 KB

1 year ago

theultimateprasad 0 points

Thanks a lot for the suggestions on UART. 

Also for the SPI flash, I need your help. For me, the SPI flash test code is working fine under peripheral examples. But when I'm adding and spi_test()  function in the ble_app_peripheral example, I can't see any update on the SPI flash memory location.

Could you pls tell me the specific changes I need to do to call spi_flash_write_data(x,x,x) function and spi_flash_read_data(x,x,x) in the ble_app_peripheral example. 

  • What headers needs to be updated
  • Where and how to call the SPI initialization
  • Where to call the spi_test() function to read and write the test data?

Regards,

Prasad

1 year ago

Thanhtu131 0 points

Hi, i have some information. The defination of uart pins are deferent for each example. In ble_examples, the uart pins are P2_6 and P2_7 for DA14580 basic kit, so if want to use arch_printf() function, you have to redefine the pins. 

1 year ago

PM_Dialog

Hi theultimateprasad,

If you are starting a new design, we would strongly recommend to start with DA14531 or DA14585/586 products and our latest SDK6.0.14, as it is much more improved. We have a lot of code examples and improved documentation, and there is also software roadmap support. There is not any software roadmap support for DA14580 product family and SDK5.

Please check out DA14531:

https://www.dialog-semiconductor.com/products/connectivity/bluetooth-low-energy/products/da14531

Additionally the DA14531 SmartBond TINY™ Module is now released! Follow the link below to find datasheet, documentation and HW collaterals for the module:

https://www.dialog-semiconductor.com/products/bluetooth-module-da14531-smartbond-tiny

For the DA14531, there is a very details tutorial for using the SPI flash interface :

http://lpccs-docs.dialog-semiconductor.com/da145xx_tutorial_sdk6_peripherals/da14531_spi_flash.html

Moreover, Dialog Serial Port Service (DSPS) and CodeLess are now available for the DA14531!

CodeLes

The CodeLess allows you to quickly get started with wireless IoT applications with a set of AT Commands.  The CodeLess AT commands platform allows control over a local UART connected device as well as a remote device via BLE. You can create simple demos / applications / proof of concepts without any code development or build you own application on top!

https://www.dialog-semiconductor.com/products/smartbond-codeless-comman…

Dialog Serial Port Service (DSPS)

The DSPS emulates a serial cable communication. It provides a simple substitute for RS-232 connections, including the familiar software flow control logic via Bluetooth low energy. The SPS software distribution includes the application and profile source codes and supports GAP Central/Peripheral roles.

https://www.dialog-semiconductor.com/products/dialog-serial-port-servic…

 

In case of the you could follow the ble_app_security example of the SDK that uses the SPI flash.

What is the development board that you are using? Is it the Pro-DK? If yes, you should put the jumpers into the SPI position – please refer to the user guide

As mentioned before, calling the spi_test() will not work – keep in mind that the probably the WDOG will be expired.

Thanks, PM_Dialog

1 year ago

theultimateprasad 0 points

Hi I could not find the SPI memory integration in ble_app_security. However, I wanted to ask one more question. Will I2C and SPI work simultaneously on DA14580?

I'm using 4MB SPI flash to store the result and I2C port for the LED and buzzer using port expander. I could use the I2C successfully but when I'm calling the fuction to store the data into the integration both of them are not working.

Pls suggest.

1 year ago

PM_Dialog

Hi There,

The ble_app_security example uses the SPI Flash in order to store the bonding information. You can use either i2C or SPI interface.

Please run your project with the debugger attached and try to find where it gets crashed.

Thanks, PM_Dialog