Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of nRF51822 by
nordic-sdk/components/drivers_nrf/ble_flash/ble_flash.c
- Committer:
- rgrover1
- Date:
- 2015-07-06
- Revision:
- 371:8f7d2137727a
- Parent:
- 370:295f76db798e
File content as of revision 371:8f7d2137727a:
/*
* Copyright (c) Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "ble_flash.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "nrf_soc.h"
#include "nordic_common.h"
#include "nrf_error.h"
#include "nrf.h"
#include "nrf51_bitfields.h"
#include "app_util.h"
static volatile bool m_radio_active = false; /**< TRUE if radio is active (or about to become active), FALSE otherwise. */
uint16_t ble_flash_crc16_compute(uint8_t * p_data, uint16_t size, uint16_t * p_crc)
{
uint16_t i;
uint16_t crc = (p_crc == NULL) ? 0xffff : *p_crc;
for (i = 0; i < size; i++)
{
crc = (unsigned char)(crc >> 8) | (crc << 8);
crc ^= p_data[i];
crc ^= (unsigned char)(crc & 0xff) >> 4;
crc ^= (crc << 8) << 4;
crc ^= ((crc & 0xff) << 4) << 1;
}
return crc;
}
/**@brief Function for erasing a page in flash.
*
* @param[in] p_page Pointer to first word in page to be erased.
*/
static void flash_page_erase(uint32_t * p_page)
{
// Turn on flash erase enable and wait until the NVMC is ready.
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos);
while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
{
// Do nothing.
}
// Erase page.
NRF_NVMC->ERASEPAGE = (uint32_t)p_page;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
{
// Do nothing.
}
// Turn off flash erase enable and wait until the NVMC is ready.
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
{
// Do nothing
}
}
/**@brief Function for writing one word to flash. Unprotected write, which can interfere with radio communication.
*
* @details This function DOES NOT use the m_radio_active variable, but will force the write even
* when the radio is active. To be used only from @ref ble_flash_page_write.
*
* @note Flash location to be written must have been erased previously.
*
* @param[in] p_address Pointer to flash location to be written.
* @param[in] value Value to write to flash.
*/
static void flash_word_unprotected_write(uint32_t * p_address, uint32_t value)
{
// Turn on flash write enable and wait until the NVMC is ready.
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
{
// Do nothing.
}
*p_address = value;
// Wait flash write to finish
while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
{
// Do nothing.
}
// Turn off flash write enable and wait until the NVMC is ready.
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
{
// Do nothing.
}
}
/**@brief Function for writing one word to flash.
*
* @note Flash location to be written must have been erased previously.
*
* @param[in] p_address Pointer to flash location to be written.
* @param[in] value Value to write to flash.
*/
static void flash_word_write(uint32_t * p_address, uint32_t value)
{
// If radio is active, wait for it to become inactive.
while (m_radio_active)
{
// Do nothing (just wait for radio to become inactive).
(void) sd_app_evt_wait();
}
// Turn on flash write enable and wait until the NVMC is ready.
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
{
// Do nothing.
}
*p_address = value;
// Wait flash write to finish
while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
{
// Do nothing.
}
// Turn off flash write enable and wait until the NVMC is ready.
NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
{
// Do nothing
}
}
uint32_t ble_flash_word_write(uint32_t * p_address, uint32_t value)
{
flash_word_write(p_address, value);
return NRF_SUCCESS;
}
uint32_t ble_flash_block_write(uint32_t * p_address, uint32_t * p_in_array, uint16_t word_count)
{
uint16_t i;
for (i = 0; i < word_count; i++)
{
flash_word_write(p_address, p_in_array[i]);
p_address++;
}
return NRF_SUCCESS;
}
uint32_t ble_flash_page_erase(uint8_t page_num)
{
uint32_t * p_page = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);
flash_page_erase(p_page);
return NRF_SUCCESS;
}
uint32_t ble_flash_page_write(uint8_t page_num, uint32_t * p_in_array, uint8_t word_count)
{
int i;
uint32_t * p_page;
uint32_t * p_curr_addr;
uint16_t in_data_crc;
uint16_t flash_crc;
uint32_t flash_header;
p_page = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);
p_curr_addr = p_page;
// Calculate CRC of the data to write.
in_data_crc = ble_flash_crc16_compute((uint8_t *)p_in_array,
word_count * sizeof(uint32_t),
NULL);
// Compare the calculated to the one in flash.
flash_header = *p_curr_addr;
flash_crc = (uint16_t)flash_header;
if (flash_crc == in_data_crc)
{
// Data is the same as the data already stored in flash, return without modifying flash.
return NRF_SUCCESS;
}
// Erase flash page
flash_page_erase(p_page);
// Reserve space for magic number (for detecting if flash content is valid).
p_curr_addr++;
// Reserve space for saving word_count.
p_curr_addr++;
// Write data
for (i = 0; i < word_count; i++)
{
flash_word_unprotected_write(p_curr_addr, p_in_array[i]);
p_curr_addr++;
}
// Write number of elements.
flash_word_write(p_page + 1, (uint32_t)(word_count));
// Write magic number and CRC to indicate that flash content is valid.
flash_header = BLE_FLASH_MAGIC_NUMBER | (uint32_t)in_data_crc;
flash_word_write(p_page, flash_header);
return NRF_SUCCESS;
}
uint32_t ble_flash_page_read(uint8_t page_num, uint32_t * p_out_array, uint8_t * p_word_count)
{
int byte_count;
uint32_t * p_page;
uint32_t * p_curr_addr;
uint32_t flash_header;
uint32_t calc_header;
uint16_t calc_crc;
uint32_t tmp;
p_page = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);
p_curr_addr = p_page;
// Check if block is valid
flash_header = *p_curr_addr;
tmp = flash_header & 0xFFFF0000;
if (tmp != BLE_FLASH_MAGIC_NUMBER)
{
*p_word_count = 0;
return NRF_ERROR_NOT_FOUND;
}
p_curr_addr++;
// Read number of elements
*p_word_count = (uint8_t)(*(p_curr_addr));
p_curr_addr++;
// Read data
byte_count = (*p_word_count) * sizeof(uint32_t);
memcpy(p_out_array, p_curr_addr, byte_count);
// Check CRC
calc_crc = ble_flash_crc16_compute((uint8_t *)p_out_array,
(*p_word_count) * sizeof(uint32_t),
NULL);
calc_header = BLE_FLASH_MAGIC_NUMBER | (uint32_t)calc_crc;
if (calc_header != flash_header)
{
return NRF_ERROR_NOT_FOUND;
}
return NRF_SUCCESS;
}
uint32_t ble_flash_page_addr(uint8_t page_num, uint32_t ** pp_page_addr)
{
*pp_page_addr = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);
return NRF_SUCCESS;
}
void ble_flash_on_radio_active_evt(bool radio_active)
{
m_radio_active = radio_active;
}
