Jurica Resetar / aconno_flash
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers aconno_flash.cpp Source File

aconno_flash.cpp

00001 /**
00002  *  Made by Jurica Resetar @ aconno
00003  *  ResetarJurica@gmail.com
00004  *  More info @ aconno.de
00005  *
00006  */
00007 
00008  /*
00009   * Copyright (c) 2017 Nordic Semiconductor ASA
00010   * All rights reserved.
00011   *
00012   * Redistribution and use in source and binary forms, with or without modification,
00013   * are permitted provided that the following conditions are met:
00014   *
00015   *   1. Redistributions of source code must retain the above copyright notice, this list
00016   *      of conditions and the following disclaimer.
00017   *
00018   *   2. Redistributions in binary form, except as embedded into a Nordic Semiconductor ASA
00019   *      integrated circuit in a product or a software update for such product, must reproduce
00020   *      the above copyright notice, this list of conditions and the following disclaimer in
00021   *      the documentation and/or other materials provided with the distribution.
00022   *
00023   *   3. Neither the name of Nordic Semiconductor ASA nor the names of its contributors may be
00024   *      used to endorse or promote products derived from this software without specific prior
00025   *      written permission.
00026   *
00027   *   4. This software, with or without modification, must only be used with a
00028   *      Nordic Semiconductor ASA integrated circuit.
00029   *
00030   *   5. Any software provided in binary or object form under this license must not be reverse
00031   *      engineered, decompiled, modified and/or disassembled.
00032   *
00033   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00034   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00035   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00036   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00037   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00038   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00039   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00040   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00041   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00042   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00043   *
00044   */
00045 
00046 #if DEVICE_FLASH
00047 
00048 #include "aconno_flash.h"
00049 #include "hal/flash_api.h"
00050 #include "hal/lp_ticker_api.h"
00051 
00052 #include "nrf_drv_common.h"
00053 #include "nrf_nvmc.h"
00054 #include "nrf_soc.h"
00055 #include <string.h>
00056 
00057 // Max. value from datasheet: 338 us
00058 // // Constant increased by the author experimentaly
00059 #define WORD_WRITE_TIMEOUT_US (1 * 100000)
00060 // Max. value from datasheet: 89.7 ms
00061 // Constant increased by the author experimentaly
00062 #define PAGE_ERASE_TIMEOUT_US (200 * 10000)
00063 
00064 /* Macro for testing if the SoftDevice is active, regardless of whether the
00065 * application is build with the SoftDevice or not.
00066 */
00067 #if defined(SOFTDEVICE_PRESENT)
00068 #include "nrf_sdm.h"
00069 
00070 static uint8_t wrapper(void) {
00071     uint8_t softdevice_is_enabled;
00072     ret_code_t result = sd_softdevice_is_enabled(&softdevice_is_enabled);
00073     return ((result == NRF_SUCCESS) && (softdevice_is_enabled == 1));
00074 }
00075 
00076 #define NRF_HAL_SD_IS_ENABLED() wrapper()
00077 #else
00078 #define NRF_HAL_SD_IS_ENABLED() 0
00079 #endif
00080 
00081 int32_t aconno_flash_init(flash_t *obj)
00082 {
00083     (void)(obj);
00084 
00085     /* Initialize low power ticker. Used for timeouts. */
00086     static bool first_init = true;
00087 
00088     if(first_init)
00089     {
00090         first_init = false;
00091         lp_ticker_init();
00092      }
00093     return 0;
00094 }
00095 
00096 int32_t aconno_flash_free(flash_t *obj)
00097 {
00098     (void)(obj);
00099 
00100     return 0;
00101 }
00102 
00103 int32_t aconno_flash_erase_sector(flash_t *obj, uint32_t address)
00104 {
00105     (void)(obj);
00106 
00107     /* Return value defaults to error. */
00108     uint32_t result = NRF_ERROR_BUSY;
00109 
00110      if(NRF_HAL_SD_IS_ENABLED())
00111      {
00112         /* Convert address to page number. */
00113         uint32_t page_number = address / NRF_FICR->CODEPAGESIZE;
00114 
00115         /* Setup stop watch for timeout. */
00116         uint32_t start_us = lp_ticker_read();
00117         uint32_t now_us = start_us;
00118 
00119         /* Retry if flash is busy until timeout is reached. */
00120         while(((now_us - start_us) < PAGE_ERASE_TIMEOUT_US) &&
00121                 (result == NRF_ERROR_BUSY)){
00122 
00123             result = sd_flash_page_erase(page_number);
00124             /* Read timeout timer. */
00125             now_us = lp_ticker_read();
00126         }
00127     }
00128     else
00129     {
00130         /* Raw API doesn't return error code, assume success. */
00131         nrf_nvmc_page_erase(address);
00132         result = NRF_SUCCESS;
00133     }
00134 
00135     /* Convert Nordic error code to mbed HAL error code. */
00136     return (result == NRF_SUCCESS) ? 0 : -1;
00137 }
00138 
00139 int32_t aconno_flash_read(flash_t *obj, uint32_t address, uint8_t *data, uint32_t size)
00140 {
00141     memcpy(data, (const void *)address, size);
00142     return 0;
00143 }
00144 
00145 int32_t aconno_flash_program_page(flash_t *obj, uint32_t address, const uint8_t *data, uint32_t size)
00146 {
00147     (void)(obj);
00148 
00149     /* Return value defaults to error. */
00150     uint32_t result = NRF_ERROR_BUSY;
00151 
00152     /* Convert size to words. */
00153     uint32_t words = size / sizeof(uint32_t);
00154 
00155     if(NRF_HAL_SD_IS_ENABLED()){
00156         /* Setup stop watch for timeout. */
00157         uint32_t start_us = lp_ticker_read();
00158         uint32_t now_us = start_us;
00159 
00160         /* Retry if flash is busy until timeout is reached. */
00161         while(((now_us - start_us) < (words * WORD_WRITE_TIMEOUT_US)) &&
00162             (result == NRF_ERROR_BUSY)){
00163                 result = sd_flash_write((uint32_t *) address, (const uint32_t *) data, words);
00164                 /* Read timeout timer. */
00165                 now_us = lp_ticker_read();
00166         }
00167     }
00168     else
00169     {
00170         /* We will use *_words function to speed up flashing code.
00171         *  Word means 32bit -> 4B or sizeof(uint32_t). */
00172         nrf_nvmc_write_words(address, (const uint32_t *) data, words);
00173         result = NRF_SUCCESS;
00174     }
00175 
00176     /* Convert Nordic error code to mbed HAL error code. */
00177     return (result == NRF_SUCCESS) ? 0 : -1;
00178 }
00179 
00180 uint32_t aconno_flash_get_size(const flash_t *obj)
00181 {
00182     (void)(obj);
00183 
00184     /* Just count flash size. */
00185     return NRF_FICR->CODESIZE * NRF_FICR->CODEPAGESIZE;
00186 }
00187 
00188 uint32_t aconno_flash_get_sector_size(const flash_t *obj, uint32_t address)
00189 {
00190     (void)(obj);
00191 
00192     /* Test if passed address is in flash space. */
00193     if (address < aconno_flash_get_size(obj)) {
00194         return NRF_FICR->CODEPAGESIZE;
00195     }
00196 
00197     /* Something goes wrong, return invalid size error code. */
00198     return MBED_FLASH_INVALID_SIZE;
00199 }
00200 
00201 uint32_t aconno_flash_get_page_size(const flash_t *obj)
00202 {
00203     (void)(obj);
00204     /* Return minimum writeable size. Note that this is
00205     different from the erase page size. */
00206     return 4;
00207 }
00208 
00209 uint32_t aconno_flash_get_start_address(const flash_t *obj)
00210 {
00211     (void)(obj);
00212 
00213     return 0;
00214 }
00215 
00216 /**
00217  *  Just leave the following function's declarations here!
00218  *  It's total mess if you try to put them somewhere else (mbed stuff...)
00219  */
00220 void nrf_nvmc_page_erase(uint32_t address)
00221 {
00222    // Enable erase.
00223    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een;
00224    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00225    {
00226    }
00227 
00228    // Erase the page
00229    NRF_NVMC->ERASEPAGE = address;
00230    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00231    {
00232    }
00233 
00234    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
00235    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00236    {
00237    }
00238 }
00239 
00240 void nrf_nvmc_write_byte(uint32_t address, uint8_t value)
00241 {
00242    uint32_t byte_shift = address & (uint32_t)0x03;
00243    uint32_t address32 = address & ~byte_shift; // Address to the word this byte is in.
00244    uint32_t value32 = (*(uint32_t*)address32 & ~((uint32_t)0xFF << (byte_shift << (uint32_t)3)));
00245    value32 = value32 + ((uint32_t)value << (byte_shift << 3));
00246 
00247    // Enable write.
00248    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
00249    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00250    {
00251    }
00252 
00253    *(uint32_t*)address32 = value32;
00254    while(NRF_NVMC->READY == NVMC_READY_READY_Busy)
00255    {
00256    }
00257 
00258    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
00259    {
00260    }
00261 }
00262 
00263 void nrf_nvmc_write_word(uint32_t address, uint32_t value)
00264 {
00265    // Enable write.
00266    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
00267    while (NRF_NVMC->READY == NVMC_READY_READY_Busy){
00268    }
00269 
00270    *(uint32_t*)address = value;
00271    while (NRF_NVMC->READY == NVMC_READY_READY_Busy){
00272    }
00273 
00274    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
00275    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00276    {
00277    }
00278 }
00279 
00280 void nrf_nvmc_write_bytes(uint32_t address, const uint8_t * src, uint32_t num_bytes)
00281 {
00282    uint32_t i;
00283    for(i=0;i<num_bytes;i++)
00284    {
00285       nrf_nvmc_write_byte(address+i,src[i]);
00286    }
00287 }
00288 
00289 void nrf_nvmc_write_words(uint32_t address, const uint32_t * src, uint32_t num_words)
00290 {
00291    uint32_t i;
00292 
00293    // Enable write.
00294    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
00295    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00296    {
00297    }
00298 
00299    for(i=0;i<num_words;i++)
00300    {
00301      ((uint32_t*)address)[i] = src[i];
00302      while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00303      {
00304      }
00305    }
00306 
00307    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
00308    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
00309    {
00310    }
00311 }
00312 
00313 #endif
00314 /** @}*/