|
36 | 36 | *
|
37 | 37 | */
|
38 | 38 |
|
39 |
| -#include "flash_api.h" |
| 39 | +#if DEVICE_FLASH |
| 40 | + |
| 41 | +#include "hal/flash_api.h" |
| 42 | +#include "hal/lp_ticker_api.h" |
| 43 | + |
| 44 | +#include "nrf_drv_common.h" |
40 | 45 | #include "nrf_nvmc.h"
|
41 | 46 | #include "nrf_soc.h"
|
42 |
| -#include "nrf_sdm.h" |
43 | 47 |
|
44 |
| -#if DEVICE_FLASH |
| 48 | +#define WORD_WRITE_TIMEOUT_US (1 * 1000) // Max. value from datasheet: 338 us |
| 49 | +#define PAGE_ERASE_TIMEOUT_US (200 * 1000) // Max. value from datasheet: 89.7 ms |
| 50 | + |
| 51 | +/* Macro for testing if the SoftDevice is active, regardless of whether the |
| 52 | + * application is build with the SoftDevice or not. |
| 53 | + */ |
| 54 | +#if defined(SOFTDEVICE_PRESENT) |
| 55 | +#include "nrf_sdm.h" |
| 56 | +static uint8_t wrapper(void) { |
| 57 | + uint8_t softdevice_is_enabled; |
| 58 | + ret_code_t result = sd_softdevice_is_enabled(&softdevice_is_enabled); |
| 59 | + return ((result == NRF_SUCCESS) && (softdevice_is_enabled == 1)); |
| 60 | +} |
| 61 | +#define NRF_HAL_SD_IS_ENABLED() wrapper() |
| 62 | +#else |
| 63 | +#define NRF_HAL_SD_IS_ENABLED() 0 |
| 64 | +#endif |
45 | 65 |
|
46 | 66 | int32_t flash_init(flash_t *obj)
|
47 | 67 | {
|
48 | 68 | (void)(obj);
|
49 |
| - uint8_t sd_enabled; |
50 |
| - if ((sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) && sd_enabled == 1) { |
51 |
| - return -1; |
| 69 | + |
| 70 | + /* Initialize low power ticker. Used for timeouts. */ |
| 71 | + static bool first_init = true; |
| 72 | + |
| 73 | + if (first_init) { |
| 74 | + first_init = false; |
| 75 | + lp_ticker_init(); |
52 | 76 | }
|
| 77 | + |
53 | 78 | return 0;
|
54 | 79 | }
|
55 | 80 |
|
56 | 81 | int32_t flash_free(flash_t *obj)
|
57 | 82 | {
|
58 | 83 | (void)(obj);
|
| 84 | + |
59 | 85 | return 0;
|
60 | 86 | }
|
61 | 87 |
|
62 | 88 | int32_t flash_erase_sector(flash_t *obj, uint32_t address)
|
63 | 89 | {
|
64 | 90 | (void)(obj);
|
65 |
| - uint8_t sd_enabled; |
66 |
| - if ((sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) && sd_enabled == 1) { |
67 |
| - return -1; |
| 91 | + |
| 92 | + /* Return value defaults to error. */ |
| 93 | + uint32_t result = NRF_ERROR_BUSY; |
| 94 | + |
| 95 | + if (NRF_HAL_SD_IS_ENABLED()) { |
| 96 | + |
| 97 | + /* Convert address to page number. */ |
| 98 | + uint32_t page_number = address / NRF_FICR->CODEPAGESIZE; |
| 99 | + |
| 100 | + /* Setup stop watch for timeout. */ |
| 101 | + uint32_t start_us = lp_ticker_read(); |
| 102 | + uint32_t now_us = start_us; |
| 103 | + |
| 104 | + /* Retry if flash is busy until timeout is reached. */ |
| 105 | + while (((now_us - start_us) < PAGE_ERASE_TIMEOUT_US) && |
| 106 | + (result == NRF_ERROR_BUSY)) { |
| 107 | + |
| 108 | + result = sd_flash_page_erase(page_number); |
| 109 | + |
| 110 | + /* Read timeout timer. */ |
| 111 | + now_us = lp_ticker_read(); |
| 112 | + } |
| 113 | + |
| 114 | + } else { |
| 115 | + |
| 116 | + /* Raw API doesn't return error code, assume success. */ |
| 117 | + nrf_nvmc_page_erase(address); |
| 118 | + result = NRF_SUCCESS; |
68 | 119 | }
|
69 |
| - nrf_nvmc_page_erase(address); |
70 |
| - return 0; |
| 120 | + |
| 121 | + /* Convert Nordic error code to mbed HAL error code. */ |
| 122 | + return (result == NRF_SUCCESS) ? 0 : -1; |
71 | 123 | }
|
72 | 124 |
|
73 | 125 | int32_t flash_program_page(flash_t *obj, uint32_t address, const uint8_t *data, uint32_t size)
|
74 | 126 | {
|
75 |
| - uint8_t sd_enabled; |
76 |
| - if ((sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) && sd_enabled == 1) { |
77 |
| - return -1; |
| 127 | + (void)(obj); |
| 128 | + |
| 129 | + /* Return value defaults to error. */ |
| 130 | + uint32_t result = NRF_ERROR_BUSY; |
| 131 | + |
| 132 | + /* Convert size to words. */ |
| 133 | + uint32_t words = size / sizeof(uint32_t); |
| 134 | + |
| 135 | + if (NRF_HAL_SD_IS_ENABLED()) { |
| 136 | + |
| 137 | + /* Setup stop watch for timeout. */ |
| 138 | + uint32_t start_us = lp_ticker_read(); |
| 139 | + uint32_t now_us = start_us; |
| 140 | + |
| 141 | + /* Retry if flash is busy until timeout is reached. */ |
| 142 | + while (((now_us - start_us) < (words * WORD_WRITE_TIMEOUT_US)) && |
| 143 | + (result == NRF_ERROR_BUSY)) { |
| 144 | + |
| 145 | + result = sd_flash_write((uint32_t *) address, (const uint32_t *) data, words); |
| 146 | + |
| 147 | + /* Read timeout timer. */ |
| 148 | + now_us = lp_ticker_read(); |
| 149 | + } |
| 150 | + |
| 151 | + } else { |
| 152 | + /* We will use *_words function to speed up flashing code. Word means 32bit -> 4B |
| 153 | + * or sizeof(uint32_t). |
| 154 | + */ |
| 155 | + nrf_nvmc_write_words(address, (const uint32_t *) data, words); |
| 156 | + result = NRF_SUCCESS; |
78 | 157 | }
|
79 |
| - /* We will use *_words function to speed up flashing code. Word means 32bit -> 4B |
80 |
| - * or sizeof(uint32_t). |
81 |
| - */ |
82 |
| - nrf_nvmc_write_words(address, (const uint32_t *) data, (size / sizeof(uint32_t))); |
83 |
| - return 0; |
| 158 | + |
| 159 | + /* Convert Nordic error code to mbed HAL error code. */ |
| 160 | + return (result == NRF_SUCCESS) ? 0 : -1; |
84 | 161 | }
|
85 | 162 |
|
86 | 163 | uint32_t flash_get_size(const flash_t *obj)
|
87 | 164 | {
|
88 | 165 | (void)(obj);
|
| 166 | + |
89 | 167 | /* Just count flash size. */
|
90 | 168 | return NRF_FICR->CODESIZE * NRF_FICR->CODEPAGESIZE;
|
91 | 169 | }
|
92 | 170 |
|
93 | 171 | uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address)
|
94 | 172 | {
|
95 | 173 | (void)(obj);
|
| 174 | + |
96 | 175 | /* Test if passed address is in flash space. */
|
97 | 176 | if (address < flash_get_size(obj)) {
|
98 | 177 | return NRF_FICR->CODEPAGESIZE;
|
99 | 178 | }
|
| 179 | + |
100 | 180 | /* Something goes wrong, return invalid size error code. */
|
101 | 181 | return MBED_FLASH_INVALID_SIZE;
|
102 | 182 | }
|
103 | 183 |
|
104 | 184 | uint32_t flash_get_page_size(const flash_t *obj)
|
105 | 185 | {
|
106 | 186 | (void)(obj);
|
107 |
| - return NRF_FICR->CODEPAGESIZE; |
| 187 | + |
| 188 | + /* Return minimum writeable size. Note that this is different from the erase page size. */ |
| 189 | + return 4; |
108 | 190 | }
|
109 | 191 |
|
110 | 192 | uint32_t flash_get_start_address(const flash_t *obj)
|
111 | 193 | {
|
| 194 | + (void)(obj); |
| 195 | + |
112 | 196 | return 0;
|
113 | 197 | }
|
114 | 198 |
|
|
0 commit comments