Patched version of nrf51822 FOTA compatible driver, with GPTIO disabled, as it clashed with the mbed definitions...

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 /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
00002  *
00003  * The information contained herein is property of Nordic Semiconductor ASA.
00004  * Terms and conditions of usage are described in detail in NORDIC
00005  * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
00006  *
00007  * Licensees are granted free, non-transferable use of the information. NO
00008  * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
00009  * the file.
00010  *
00011  */
00012 
00013 #include "ble_flash.h "
00014 #include <stdlib.h>
00015 #include <stdint.h>
00016 #include <string.h>
00017 #include "nrf_soc.h"
00018 #include "nordic_common.h"
00019 #include "nrf_error.h"
00020 #include "nrf.h"
00021 #include "nrf51_bitfields.h"
00022 #include "app_util.h "
00023 
00024 
00025 static volatile bool m_radio_active = false;  /**< TRUE if radio is active (or about to become active), FALSE otherwise. */
00026 
00027 
00028 uint16_t ble_flash_crc16_compute(uint8_t * p_data, uint16_t size, uint16_t * p_crc)
00029 {
00030     uint16_t i;
00031     uint16_t crc = (p_crc == NULL) ? 0xffff : *p_crc;
00032 
00033     for (i = 0; i < size; i++)
00034     {
00035         crc  = (unsigned char)(crc >> 8) | (crc << 8);
00036         crc ^= p_data[i];
00037         crc ^= (unsigned char)(crc & 0xff) >> 4;
00038         crc ^= (crc << 8) << 4;
00039         crc ^= ((crc & 0xff) << 4) << 1;
00040     }
00041     return crc;
00042 }
00043 
00044 
00045 /**@brief Function for erasing a page in flash.
00046  * 
00047  * @param[in]  p_page  Pointer to first word in page to be erased.
00048  */
00049 static void flash_page_erase(uint32_t * p_page)
00050 {
00051     // Turn on flash erase enable and wait until the NVMC is ready.
00052     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos);
00053     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00054     {
00055         // Do nothing.
00056     }
00057 
00058     // Erase page.
00059     NRF_NVMC->ERASEPAGE = (uint32_t)p_page;
00060     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00061     {
00062         // Do nothing.
00063     }
00064 
00065     // Turn off flash erase enable and wait until the NVMC is ready.
00066     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
00067     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00068     {
00069         // Do nothing
00070     }
00071 }
00072 
00073 
00074 /**@brief Function for writing one word to flash. Unprotected write, which can interfere with radio communication.
00075  *
00076  * @details This function DOES NOT use the m_radio_active variable, but will force the write even
00077  *          when the radio is active. To be used only from @ref ble_flash_page_write.
00078  *
00079  * @note Flash location to be written must have been erased previously.
00080  *
00081  * @param[in]  p_address   Pointer to flash location to be written.
00082  * @param[in]  value       Value to write to flash.
00083  */
00084 static void flash_word_unprotected_write(uint32_t * p_address, uint32_t value)
00085 {
00086     // Turn on flash write enable and wait until the NVMC is ready.
00087     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
00088     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00089     {
00090         // Do nothing.
00091     }
00092     *p_address = value;
00093     
00094     // Wait flash write to finish
00095     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00096     {
00097         // Do nothing.
00098     }
00099 
00100     // Turn off flash write enable and wait until the NVMC is ready.
00101     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
00102     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00103     {
00104         // Do nothing.
00105     }
00106 }
00107 
00108 
00109 /**@brief Function for writing one word to flash.
00110  *
00111  * @note Flash location to be written must have been erased previously.
00112  *
00113  * @param[in]  p_address   Pointer to flash location to be written.
00114  * @param[in]  value       Value to write to flash.
00115  */
00116 static void flash_word_write(uint32_t * p_address, uint32_t value)
00117 {
00118     // If radio is active, wait for it to become inactive.
00119     while (m_radio_active)
00120     {
00121         // Do nothing (just wait for radio to become inactive).
00122         (void) sd_app_evt_wait();
00123     }
00124 
00125     // Turn on flash write enable and wait until the NVMC is ready.
00126     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
00127     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00128     {
00129         // Do nothing.
00130     }
00131 
00132     *p_address = value;
00133     // Wait flash write to finish
00134     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00135     {
00136         // Do nothing.
00137     }
00138     // Turn off flash write enable and wait until the NVMC is ready.
00139     NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
00140     while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00141     {
00142         // Do nothing
00143     }
00144 }
00145 
00146 
00147 uint32_t ble_flash_word_write(uint32_t * p_address, uint32_t value)
00148 {
00149     flash_word_write(p_address, value);
00150     return NRF_SUCCESS;
00151 }
00152 
00153 
00154 uint32_t ble_flash_block_write(uint32_t * p_address, uint32_t * p_in_array, uint16_t word_count)
00155 {
00156     uint16_t i;
00157 
00158     for (i = 0; i < word_count; i++)
00159     {
00160         flash_word_write(p_address, p_in_array[i]);
00161         p_address++;
00162     }
00163 
00164     return NRF_SUCCESS;
00165 }
00166 
00167 
00168 uint32_t ble_flash_page_erase(uint8_t page_num)
00169 {
00170     uint32_t * p_page = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);
00171     flash_page_erase(p_page);
00172 
00173     return NRF_SUCCESS;
00174 }
00175 
00176 
00177 uint32_t ble_flash_page_write(uint8_t page_num, uint32_t * p_in_array, uint8_t word_count)
00178 {
00179     int        i;
00180     uint32_t * p_page;
00181     uint32_t * p_curr_addr;
00182     uint16_t   in_data_crc;
00183     uint16_t   flash_crc;
00184     uint32_t   flash_header;
00185 
00186     p_page      = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);
00187     p_curr_addr = p_page;
00188 
00189     // Calculate CRC of the data to write.
00190     in_data_crc = ble_flash_crc16_compute((uint8_t *)p_in_array,
00191                                           word_count * sizeof(uint32_t),
00192                                           NULL);
00193 
00194     // Compare the calculated to the one in flash.
00195     flash_header = *p_curr_addr;
00196     flash_crc    = (uint16_t)flash_header;
00197 
00198     if (flash_crc == in_data_crc)
00199     {
00200         // Data is the same as the data already stored in flash, return without modifying flash.
00201         return NRF_SUCCESS;
00202     }
00203 
00204     // Erase flash page
00205     flash_page_erase(p_page);
00206 
00207     // Reserve space for magic number (for detecting if flash content is valid).
00208     p_curr_addr++;
00209 
00210     // Reserve space for saving word_count.
00211     p_curr_addr++;
00212 
00213     // Write data
00214     for (i = 0; i < word_count; i++)
00215     {
00216         flash_word_unprotected_write(p_curr_addr, p_in_array[i]);
00217         p_curr_addr++;
00218     }
00219 
00220     // Write number of elements.
00221     flash_word_write(p_page + 1, (uint32_t)(word_count));
00222 
00223     // Write magic number and CRC to indicate that flash content is valid.
00224     flash_header = BLE_FLASH_MAGIC_NUMBER | (uint32_t)in_data_crc;
00225     flash_word_write(p_page, flash_header);
00226 
00227     return NRF_SUCCESS;
00228 }
00229 
00230 
00231 uint32_t ble_flash_page_read(uint8_t page_num, uint32_t * p_out_array, uint8_t * p_word_count)
00232 {
00233     int        byte_count;
00234     uint32_t * p_page;
00235     uint32_t * p_curr_addr;
00236     uint32_t   flash_header;
00237     uint32_t   calc_header;
00238     uint16_t   calc_crc;
00239     uint32_t   tmp;
00240 
00241     p_page      = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);    
00242     p_curr_addr = p_page;
00243 
00244     // Check if block is valid
00245     flash_header = *p_curr_addr;
00246     tmp = flash_header & 0xFFFF0000;
00247     if (tmp != BLE_FLASH_MAGIC_NUMBER)
00248     {
00249         *p_word_count = 0;
00250         return NRF_ERROR_NOT_FOUND;
00251     }
00252     p_curr_addr++;
00253 
00254     // Read number of elements
00255     *p_word_count = (uint8_t)(*(p_curr_addr));
00256     p_curr_addr++;
00257 
00258     // Read data
00259     byte_count = (*p_word_count) * sizeof(uint32_t);
00260     memcpy(p_out_array, p_curr_addr, byte_count);
00261 
00262     // Check CRC
00263     calc_crc = ble_flash_crc16_compute((uint8_t *)p_out_array,
00264                                        (*p_word_count) * sizeof(uint32_t),
00265                                        NULL);
00266     calc_header = BLE_FLASH_MAGIC_NUMBER | (uint32_t)calc_crc;
00267 
00268     if (calc_header != flash_header)
00269     {
00270         return NRF_ERROR_NOT_FOUND;
00271     }
00272 
00273     return NRF_SUCCESS;
00274 }
00275 
00276 
00277 uint32_t ble_flash_page_addr(uint8_t page_num, uint32_t ** pp_page_addr)
00278 {
00279     *pp_page_addr = (uint32_t *)(BLE_FLASH_PAGE_SIZE * page_num);
00280     return NRF_SUCCESS;
00281 }
00282 
00283 
00284 void ble_flash_on_radio_active_evt(bool radio_active)
00285 {
00286     m_radio_active = radio_active;
00287 }