|
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