fork

Fork of nRF51822 by Nordic Semiconductor

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ble_flash.c Source File

ble_flash.c

00001 /*
00002  * Copyright (c) Nordic Semiconductor ASA
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without modification,
00006  * are permitted provided that the following conditions are met:
00007  *
00008  *   1. Redistributions of source code must retain the above copyright notice, this
00009  *   list of conditions and the following disclaimer.
00010  *
00011  *   2. Redistributions in binary form must reproduce the above copyright notice, this
00012  *   list of conditions and the following disclaimer in the documentation and/or
00013  *   other materials provided with the distribution.
00014  *
00015  *   3. Neither the name of Nordic Semiconductor ASA nor the names of other
00016  *   contributors to this software may be used to endorse or promote products
00017  *   derived from this software without specific prior written permission.
00018  *
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00021  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00022  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00023  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00024  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00025  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00026  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00027  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  *
00031  */
00032 
00033 #include "ble_flash.h "
00034 #include <stdlib.h>
00035 #include <stdint.h>
00036 #include <string.h>
00037 #include "nrf_soc.h"
00038 #include "nordic_common.h"
00039 #include "nrf_error.h"
00040 #include "nrf.h"
00041 #include "nrf51_bitfields.h"
00042 #include "app_util.h"
00043 
00044 
00045 static volatile bool m_radio_active = false;  /**< TRUE if radio is active (or about to become active), FALSE otherwise. */
00046 
00047 
00048 uint16_t ble_flash_crc16_compute(uint8_t * p_data, uint16_t size, uint16_t * p_crc)
00049 {
00050     uint16_t i;
00051     uint16_t crc = (p_crc == NULL) ? 0xffff : *p_crc;
00052 
00053     for (i = 0; i < size; i++)
00054     {
00055         crc  = (unsigned char)(crc >> 8) | (crc << 8);
00056         crc ^= p_data[i];
00057         crc ^= (unsigned char)(crc & 0xff) >> 4;
00058         crc ^= (crc << 8) << 4;
00059         crc ^= ((crc & 0xff) << 4) << 1;
00060     }
00061     return crc;
00062 }
00063 
00064 
00065 /**@brief Function for erasing a page in flash.
00066  * 
00067  * @param[in]  p_page  Pointer to first word in page to be erased.
00068  */
00069 static void flash_page_erase(uint32_t * p_page)
00070 {
00071     // Turn on flash erase enable and wait until the NVMC is ready.
00072     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos);
00073     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00074     {
00075         // Do nothing.
00076     }
00077 
00078     // Erase page.
00079     NRF_NVMC->ERASEPAGE = (uint32_t)p_page;
00080     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00081     {
00082         // Do nothing.
00083     }
00084 
00085     // Turn off flash erase enable and wait until the NVMC is ready.
00086     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
00087     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00088     {
00089         // Do nothing
00090     }
00091 }
00092 
00093 
00094 /**@brief Function for writing one word to flash. Unprotected write, which can interfere with radio communication.
00095  *
00096  * @details This function DOES NOT use the m_radio_active variable, but will force the write even
00097  *          when the radio is active. To be used only from @ref ble_flash_page_write.
00098  *
00099  * @note Flash location to be written must have been erased previously.
00100  *
00101  * @param[in]  p_address   Pointer to flash location to be written.
00102  * @param[in]  value       Value to write to flash.
00103  */
00104 static void flash_word_unprotected_write(uint32_t * p_address, uint32_t value)
00105 {
00106     // Turn on flash write enable and wait until the NVMC is ready.
00107     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
00108     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00109     {
00110         // Do nothing.
00111     }
00112     *p_address = value;
00113     
00114     // Wait flash write to finish
00115     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00116     {
00117         // Do nothing.
00118     }
00119 
00120     // Turn off flash write enable and wait until the NVMC is ready.
00121     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
00122     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00123     {
00124         // Do nothing.
00125     }
00126 }
00127 
00128 
00129 /**@brief Function for writing one word to flash.
00130  *
00131  * @note Flash location to be written must have been erased previously.
00132  *
00133  * @param[in]  p_address   Pointer to flash location to be written.
00134  * @param[in]  value       Value to write to flash.
00135  */
00136 static void flash_word_write(uint32_t * p_address, uint32_t value)
00137 {
00138     // If radio is active, wait for it to become inactive.
00139     while (m_radio_active)
00140     {
00141         // Do nothing (just wait for radio to become inactive).
00142         (void) sd_app_evt_wait();
00143     }
00144 
00145     // Turn on flash write enable and wait until the NVMC is ready.
00146     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
00147     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00148     {
00149         // Do nothing.
00150     }
00151 
00152     *p_address = value;
00153     // Wait flash write to finish
00154     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00155     {
00156         // Do nothing.
00157     }
00158     // Turn off flash write enable and wait until the NVMC is ready.
00159     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
00160     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00161     {
00162         // Do nothing
00163     }
00164 }
00165 
00166 
00167 uint32_t ble_flash_word_write(uint32_t * p_address, uint32_t value)
00168 {
00169     flash_word_write(p_address, value);
00170     return NRF_SUCCESS;
00171 }
00172 
00173 
00174 uint32_t ble_flash_block_write(uint32_t * p_address, uint32_t * p_in_array, uint16_t word_count)
00175 {
00176     uint16_t i;
00177 
00178     for (i = 0; i < word_count; i++)
00179     {
00180         flash_word_write(p_address, p_in_array[i]);
00181         p_address++;
00182     }
00183 
00184     return NRF_SUCCESS;
00185 }
00186 
00187 
00188 uint32_t ble_flash_page_erase(uint8_t page_num)
00189 {
00190     uint32_t * p_page = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);
00191     flash_page_erase(p_page);
00192 
00193     return NRF_SUCCESS;
00194 }
00195 
00196 
00197 uint32_t ble_flash_page_write(uint8_t page_num, uint32_t * p_in_array, uint8_t word_count)
00198 {
00199     int        i;
00200     uint32_t * p_page;
00201     uint32_t * p_curr_addr;
00202     uint16_t   in_data_crc;
00203     uint16_t   flash_crc;
00204     uint32_t   flash_header;
00205 
00206     p_page      = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);
00207     p_curr_addr = p_page;
00208 
00209     // Calculate CRC of the data to write.
00210     in_data_crc = ble_flash_crc16_compute((uint8_t *)p_in_array,
00211                                           word_count * sizeof(uint32_t),
00212                                           NULL);
00213 
00214     // Compare the calculated to the one in flash.
00215     flash_header = *p_curr_addr;
00216     flash_crc    = (uint16_t)flash_header;
00217 
00218     if (flash_crc == in_data_crc)
00219     {
00220         // Data is the same as the data already stored in flash, return without modifying flash.
00221         return NRF_SUCCESS;
00222     }
00223 
00224     // Erase flash page
00225     flash_page_erase(p_page);
00226 
00227     // Reserve space for magic number (for detecting if flash content is valid).
00228     p_curr_addr++;
00229 
00230     // Reserve space for saving word_count.
00231     p_curr_addr++;
00232 
00233     // Write data
00234     for (i = 0; i < word_count; i++)
00235     {
00236         flash_word_unprotected_write(p_curr_addr, p_in_array[i]);
00237         p_curr_addr++;
00238     }
00239 
00240     // Write number of elements.
00241     flash_word_write(p_page + 1, (uint32_t)(word_count));
00242 
00243     // Write magic number and CRC to indicate that flash content is valid.
00244     flash_header = BLE_FLASH_MAGIC_NUMBER | (uint32_t)in_data_crc;
00245     flash_word_write(p_page, flash_header);
00246 
00247     return NRF_SUCCESS;
00248 }
00249 
00250 
00251 uint32_t ble_flash_page_read(uint8_t page_num, uint32_t * p_out_array, uint8_t * p_word_count)
00252 {
00253     int        byte_count;
00254     uint32_t * p_page;
00255     uint32_t * p_curr_addr;
00256     uint32_t   flash_header;
00257     uint32_t   calc_header;
00258     uint16_t   calc_crc;
00259     uint32_t   tmp;
00260 
00261     p_page      = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);    
00262     p_curr_addr = p_page;
00263 
00264     // Check if block is valid
00265     flash_header = *p_curr_addr;
00266     tmp = flash_header & 0xFFFF0000;
00267     if (tmp != BLE_FLASH_MAGIC_NUMBER)
00268     {
00269         *p_word_count = 0;
00270         return NRF_ERROR_NOT_FOUND;
00271     }
00272     p_curr_addr++;
00273 
00274     // Read number of elements
00275     *p_word_count = (uint8_t)(*(p_curr_addr));
00276     p_curr_addr++;
00277 
00278     // Read data
00279     byte_count = (*p_word_count) * sizeof(uint32_t);
00280     memcpy(p_out_array, p_curr_addr, byte_count);
00281 
00282     // Check CRC
00283     calc_crc = ble_flash_crc16_compute((uint8_t *)p_out_array,
00284                                        (*p_word_count) * sizeof(uint32_t),
00285                                        NULL);
00286     calc_header = BLE_FLASH_MAGIC_NUMBER | (uint32_t)calc_crc;
00287 
00288     if (calc_header != flash_header)
00289     {
00290         return NRF_ERROR_NOT_FOUND;
00291     }
00292 
00293     return NRF_SUCCESS;
00294 }
00295 
00296 
00297 uint32_t ble_flash_page_addr(uint8_t page_num, uint32_t ** pp_page_addr)
00298 {
00299     *pp_page_addr = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);
00300     return NRF_SUCCESS;
00301 }
00302 
00303 
00304 void ble_flash_on_radio_active_evt(bool radio_active)
00305 {
00306     m_radio_active = radio_active;
00307 }