nrf_flash_loader.cpp


1
#include <cstdint>
2
#include <initializer_list>
3
4
#include "driver/flash_loader_defs.hpp"
5
6
#define NRF_FLASH_LOADER_DEBUG 0
7
8
#ifdef __cplusplus
9
  #define   __I     volatile             /*!< Defines 'read only' permissions */
10
#else
11
  #define   __I     volatile const       /*!< Defines 'read only' permissions */
12
#endif
13
#define     __O     volatile             /*!< Defines 'write only' permissions */
14
#define     __IO    volatile             /*!< Defines 'read / write' permissions */
15
16
/* following defines should be used for structure members */
17
#define     __IM     volatile const      /*! Defines 'read only' structure member permissions */
18
#define     __OM     volatile            /*! Defines 'write only' structure member permissions */
19
#define     __IOM    volatile            /*! Defines 'read / write' structure member permissions */
20
21
/* Bit 0 : Disable the protection mechanism for NVM regions while in debug interface mode. This register will only disable the protection mechanism if the device is in debug interface mode. */
22
#define BPROT_DISABLEINDEBUG_DISABLEINDEBUG_Pos (0UL) /*!< Position of DISABLEINDEBUG field. */
23
#define BPROT_DISABLEINDEBUG_DISABLEINDEBUG_Msk (0x1UL << BPROT_DISABLEINDEBUG_DISABLEINDEBUG_Pos) /*!< Bit mask of DISABLEINDEBUG field. */
24
#define BPROT_DISABLEINDEBUG_DISABLEINDEBUG_Enabled (0UL) /*!< Enable in debug */
25
#define BPROT_DISABLEINDEBUG_DISABLEINDEBUG_Disabled (1UL) /*!< Disable in debug */
26
27
/* Peripheral: NVMC */
28
/* Description: Non Volatile Memory Controller */
29
30
/* Register: NVMC_READY */
31
/* Description: Ready flag */
32
33
/* Bit 0 : NVMC is ready or busy */
34
#define NVMC_READY_READY_Pos (0UL) /*!< Position of READY field. */
35
#define NVMC_READY_READY_Msk (0x1UL << NVMC_READY_READY_Pos) /*!< Bit mask of READY field. */
36
#define NVMC_READY_READY_Busy (0UL) /*!< NVMC is busy (on-going write or erase operation) */
37
#define NVMC_READY_READY_Ready (1UL) /*!< NVMC is ready */
38
39
/* Register: NVMC_CONFIG */
40
/* Description: Configuration register */
41
42
/* Bits 1..0 : Program memory access mode. It is strongly recommended to only activate erase and write modes when they are actively used. Enabling write or erase will invalidate the cache and keep it invalidated. */
43
#define NVMC_CONFIG_WEN_Pos (0UL) /*!< Position of WEN field. */
44
#define NVMC_CONFIG_WEN_Msk (0x3UL << NVMC_CONFIG_WEN_Pos) /*!< Bit mask of WEN field. */
45
#define NVMC_CONFIG_WEN_Ren (0UL) /*!< Read only access */
46
#define NVMC_CONFIG_WEN_Wen (1UL) /*!< Write Enabled */
47
#define NVMC_CONFIG_WEN_Een (2UL) /*!< Erase enabled */
48
49
/* Register: NVMC_ERASEPAGE */
50
/* Description: Register for erasing a page in Code area */
51
52
/* Bits 31..0 : Register for starting erase of a page in Code area */
53
#define NVMC_ERASEPAGE_ERASEPAGE_Pos (0UL) /*!< Position of ERASEPAGE field. */
54
#define NVMC_ERASEPAGE_ERASEPAGE_Msk (0xFFFFFFFFUL << NVMC_ERASEPAGE_ERASEPAGE_Pos) /*!< Bit mask of ERASEPAGE field. */
55
56
/* Register: NVMC_ERASEPCR1 */
57
/* Description: Deprecated register -  Register for erasing a page in Code area. Equivalent to ERASEPAGE. */
58
59
/* Bits 31..0 : Register for erasing a page in Code area. Equivalent to ERASEPAGE. */
60
#define NVMC_ERASEPCR1_ERASEPCR1_Pos (0UL) /*!< Position of ERASEPCR1 field. */
61
#define NVMC_ERASEPCR1_ERASEPCR1_Msk (0xFFFFFFFFUL << NVMC_ERASEPCR1_ERASEPCR1_Pos) /*!< Bit mask of ERASEPCR1 field. */
62
63
/* Register: NVMC_ERASEALL */
64
/* Description: Register for erasing all non-volatile user memory */
65
66
/* Bit 0 : Erase all non-volatile memory including UICR registers. Note that code erase has to be enabled by CONFIG.EEN before the UICR can be erased. */
67
#define NVMC_ERASEALL_ERASEALL_Pos (0UL) /*!< Position of ERASEALL field. */
68
#define NVMC_ERASEALL_ERASEALL_Msk (0x1UL << NVMC_ERASEALL_ERASEALL_Pos) /*!< Bit mask of ERASEALL field. */
69
#define NVMC_ERASEALL_ERASEALL_NoOperation (0UL) /*!< No operation */
70
#define NVMC_ERASEALL_ERASEALL_Erase (1UL) /*!< Start chip erase */
71
72
/* Register: NVMC_ERASEPCR0 */
73
/* Description: Deprecated register -  Register for erasing a page in Code area. Equivalent to ERASEPAGE. */
74
75
/* Bits 31..0 : Register for starting erase of a page in Code area. Equivalent to ERASEPAGE. */
76
#define NVMC_ERASEPCR0_ERASEPCR0_Pos (0UL) /*!< Position of ERASEPCR0 field. */
77
#define NVMC_ERASEPCR0_ERASEPCR0_Msk (0xFFFFFFFFUL << NVMC_ERASEPCR0_ERASEPCR0_Pos) /*!< Bit mask of ERASEPCR0 field. */
78
79
/* Register: NVMC_ERASEUICR */
80
/* Description: Register for erasing User Information Configuration Registers */
81
82
/* Bit 0 : Register starting erase of all User Information Configuration Registers. Note that code erase has to be enabled by CONFIG.EEN before the UICR can be erased. */
83
#define NVMC_ERASEUICR_ERASEUICR_Pos (0UL) /*!< Position of ERASEUICR field. */
84
#define NVMC_ERASEUICR_ERASEUICR_Msk (0x1UL << NVMC_ERASEUICR_ERASEUICR_Pos) /*!< Bit mask of ERASEUICR field. */
85
#define NVMC_ERASEUICR_ERASEUICR_NoOperation (0UL) /*!< No operation */
86
#define NVMC_ERASEUICR_ERASEUICR_Erase (1UL) /*!< Start erase of UICR */
87
88
/* Register: NVMC_ICACHECNF */
89
/* Description: I-Code cache configuration register. */
90
91
/* Bit 8 : Cache profiling enable */
92
#define NVMC_ICACHECNF_CACHEPROFEN_Pos (8UL) /*!< Position of CACHEPROFEN field. */
93
#define NVMC_ICACHECNF_CACHEPROFEN_Msk (0x1UL << NVMC_ICACHECNF_CACHEPROFEN_Pos) /*!< Bit mask of CACHEPROFEN field. */
94
#define NVMC_ICACHECNF_CACHEPROFEN_Disabled (0UL) /*!< Disable cache profiling */
95
#define NVMC_ICACHECNF_CACHEPROFEN_Enabled (1UL) /*!< Enable cache profiling */
96
97
/* Bit 0 : Cache enable */
98
#define NVMC_ICACHECNF_CACHEEN_Pos (0UL) /*!< Position of CACHEEN field. */
99
#define NVMC_ICACHECNF_CACHEEN_Msk (0x1UL << NVMC_ICACHECNF_CACHEEN_Pos) /*!< Bit mask of CACHEEN field. */
100
#define NVMC_ICACHECNF_CACHEEN_Disabled (0UL) /*!< Disable cache. Invalidates all cache entries. */
101
#define NVMC_ICACHECNF_CACHEEN_Enabled (1UL) /*!< Enable cache */
102
103
/* Register: NVMC_IHIT */
104
/* Description: I-Code cache hit counter. */
105
106
/* Bits 31..0 : Number of cache hits */
107
#define NVMC_IHIT_HITS_Pos (0UL) /*!< Position of HITS field. */
108
#define NVMC_IHIT_HITS_Msk (0xFFFFFFFFUL << NVMC_IHIT_HITS_Pos) /*!< Bit mask of HITS field. */
109
110
/* Register: NVMC_IMISS */
111
/* Description: I-Code cache miss counter. */
112
113
/* Bits 31..0 : Number of cache misses */
114
#define NVMC_IMISS_MISSES_Pos (0UL) /*!< Position of MISSES field. */
115
#define NVMC_IMISS_MISSES_Msk (0xFFFFFFFFUL << NVMC_IMISS_MISSES_Pos) /*!< Bit mask of MISSES field. */
116
117
__attribute__((always_inline)) static inline void __ISB(void)
118
{
119
  __asm volatile ("isb 0xF":::"memory");
120
}
121
122
123
/**
124
  \brief   Data Synchronization Barrier
125
  \details Acts as a special kind of Data Memory Barrier.
126
           It completes when all explicit memory accesses before this instruction complete.
127
 */
128
__attribute__((always_inline)) static inline void __DSB(void)
129
{
130
  __asm volatile ("dsb 0xF":::"memory");
131
}
132
133
/**
134
  * @brief Block Protect (BPROT)
135
  */
136
137
typedef struct {                                /*!< (@ 0x40000000) BPROT Structure                                            */
138
  __IM  uint32_t  RESERVED[384];
139
  __IOM uint32_t  CONFIG0;                      /*!< (@ 0x00000600) Block protect configuration register 0                     */
140
  __IOM uint32_t  CONFIG1;                      /*!< (@ 0x00000604) Block protect configuration register 1                     */
141
  __IOM uint32_t  DISABLEINDEBUG;               /*!< (@ 0x00000608) Disable protection mechanism in debug interface
142
                                                                    mode                                                       */
143
  __IOM uint32_t  UNUSED0;                      /*!< (@ 0x0000060C) Unspecified                                                */
144
  __IOM uint32_t  CONFIG2;                      /*!< (@ 0x00000610) Block protect configuration register 2                     */
145
  __IOM uint32_t  CONFIG3;                      /*!< (@ 0x00000614) Block protect configuration register 3                     */
146
} NRF_BPROT_Type;                               /*!< Size = 1560 (0x618)                                                       */
147
148
/**
149
  * @brief Non Volatile Memory Controller (NVMC)
150
  */
151
152
typedef struct {                                /*!< (@ 0x4001E000) NVMC Structure                                             */
153
  __IM  uint32_t  RESERVED[256];
154
  __IM  uint32_t  READY;                        /*!< (@ 0x00000400) Ready flag                                                 */
155
  __IM  uint32_t  RESERVED1[64];
156
  __IOM uint32_t  CONFIG;                       /*!< (@ 0x00000504) Configuration register                                     */
157
158
  union {
159
    __IOM uint32_t ERASEPAGE;                   /*!< (@ 0x00000508) Register for erasing a page in Code area                   */
160
    __IOM uint32_t ERASEPCR1;                   /*!< (@ 0x00000508) Deprecated register - Register for erasing a
161
                                                                    page in Code area. Equivalent to ERASEPAGE.                */
162
  };
163
  __IOM uint32_t  ERASEALL;                     /*!< (@ 0x0000050C) Register for erasing all non-volatile user memory          */
164
  __IOM uint32_t  ERASEPCR0;                    /*!< (@ 0x00000510) Deprecated register - Register for erasing a
165
                                                                    page in Code area. Equivalent to ERASEPAGE.                */
166
  __IOM uint32_t  ERASEUICR;                    /*!< (@ 0x00000514) Register for erasing User Information Configuration
167
                                                                    Registers                                                  */
168
  __IM  uint32_t  RESERVED2[10];
169
  __IOM uint32_t  ICACHECNF;                    /*!< (@ 0x00000540) I-Code cache configuration register.                       */
170
  __IM  uint32_t  RESERVED3;
171
  __IOM uint32_t  IHIT;                         /*!< (@ 0x00000548) I-Code cache hit counter.                                  */
172
  __IOM uint32_t  IMISS;                        /*!< (@ 0x0000054C) I-Code cache miss counter.                                 */
173
} NRF_NVMC_Type;                                /*!< Size = 1360 (0x550)                                                       */
174
175
typedef struct {                                /*!< (@ 0x50000000) P0 Structure                                               */
176
  __IM  uint32_t  RESERVED[321];
177
  __IOM uint32_t  OUT;                          /*!< (@ 0x00000504) Write GPIO port                                            */
178
  __IOM uint32_t  OUTSET;                       /*!< (@ 0x00000508) Set individual bits in GPIO port                           */
179
  __IOM uint32_t  OUTCLR;                       /*!< (@ 0x0000050C) Clear individual bits in GPIO port                         */
180
  __IM  uint32_t  IN;                           /*!< (@ 0x00000510) Read GPIO port                                             */
181
  __IOM uint32_t  DIR;                          /*!< (@ 0x00000514) Direction of GPIO pins                                     */
182
  __IOM uint32_t  DIRSET;                       /*!< (@ 0x00000518) DIR set register                                           */
183
  __IOM uint32_t  DIRCLR;                       /*!< (@ 0x0000051C) DIR clear register                                         */
184
  __IOM uint32_t  LATCH;                        /*!< (@ 0x00000520) Latch register indicating what GPIO pins that
185
                                                                    have met the criteria set in the PIN_CNF[n].SENSE
186
                                                                    registers                                                  */
187
  __IOM uint32_t  DETECTMODE;                   /*!< (@ 0x00000524) Select between default DETECT signal behaviour
188
                                                                    and LDETECT mode                                           */
189
  __IM  uint32_t  RESERVED1[118];
190
  __IOM uint32_t  PIN_CNF[32];                  /*!< (@ 0x00000700) Description collection[0]: Configuration of GPIO
191
                                                                    pins                                                       */
192
} NRF_GPIO_Type;                                /*!< Size = 1920 (0x780)                                                       */
193
194
#define NRF_NVMC_BASE               0x4001E000UL
195
#define NRF_BPROT_BASE              0x40000000UL
196
#define NRF_P0_BASE                 0x50000000UL
197
198
#define NRF_NVMC                    ((NRF_NVMC_Type*)          NRF_NVMC_BASE)
199
#define NRF_BPROT                   ((NRF_BPROT_Type*)         NRF_BPROT_BASE)
200
#define NRF_P0                      ((NRF_GPIO_Type*)          NRF_P0_BASE)
201
#define NRF_GPIO                    ((NRF_GPIO_Type*)          NRF_P0_BASE)
202
203
/* Register: GPIO_PIN_CNF */
204
/* Description: Description collection[0]:  Configuration of GPIO pins */
205
206
/* Bits 17..16 : Pin sensing mechanism */
207
#define GPIO_PIN_CNF_SENSE_Pos (16UL) /*!< Position of SENSE field. */
208
#define GPIO_PIN_CNF_SENSE_Msk (0x3UL << GPIO_PIN_CNF_SENSE_Pos) /*!< Bit mask of SENSE field. */
209
#define GPIO_PIN_CNF_SENSE_Disabled (0UL) /*!< Disabled */
210
#define GPIO_PIN_CNF_SENSE_High (2UL) /*!< Sense for high level */
211
#define GPIO_PIN_CNF_SENSE_Low (3UL) /*!< Sense for low level */
212
213
/* Bits 10..8 : Drive configuration */
214
#define GPIO_PIN_CNF_DRIVE_Pos (8UL) /*!< Position of DRIVE field. */
215
#define GPIO_PIN_CNF_DRIVE_Msk (0x7UL << GPIO_PIN_CNF_DRIVE_Pos) /*!< Bit mask of DRIVE field. */
216
#define GPIO_PIN_CNF_DRIVE_S0S1 (0UL) /*!< Standard '0', standard '1' */
217
#define GPIO_PIN_CNF_DRIVE_H0S1 (1UL) /*!< High drive '0', standard '1' */
218
#define GPIO_PIN_CNF_DRIVE_S0H1 (2UL) /*!< Standard '0', high drive '1' */
219
#define GPIO_PIN_CNF_DRIVE_H0H1 (3UL) /*!< High drive '0', high 'drive '1'' */
220
#define GPIO_PIN_CNF_DRIVE_D0S1 (4UL) /*!< Disconnect '0' standard '1' (normally used for wired-or connections) */
221
#define GPIO_PIN_CNF_DRIVE_D0H1 (5UL) /*!< Disconnect '0', high drive '1' (normally used for wired-or connections) */
222
#define GPIO_PIN_CNF_DRIVE_S0D1 (6UL) /*!< Standard '0'. disconnect '1' (normally used for wired-and connections) */
223
#define GPIO_PIN_CNF_DRIVE_H0D1 (7UL) /*!< High drive '0', disconnect '1' (normally used for wired-and connections) */
224
225
/* Bits 3..2 : Pull configuration */
226
#define GPIO_PIN_CNF_PULL_Pos (2UL) /*!< Position of PULL field. */
227
#define GPIO_PIN_CNF_PULL_Msk (0x3UL << GPIO_PIN_CNF_PULL_Pos) /*!< Bit mask of PULL field. */
228
#define GPIO_PIN_CNF_PULL_Disabled (0UL) /*!< No pull */
229
#define GPIO_PIN_CNF_PULL_Pulldown (1UL) /*!< Pull down on pin */
230
#define GPIO_PIN_CNF_PULL_Pullup (3UL) /*!< Pull up on pin */
231
232
/* Bit 1 : Connect or disconnect input buffer */
233
#define GPIO_PIN_CNF_INPUT_Pos (1UL) /*!< Position of INPUT field. */
234
#define GPIO_PIN_CNF_INPUT_Msk (0x1UL << GPIO_PIN_CNF_INPUT_Pos) /*!< Bit mask of INPUT field. */
235
#define GPIO_PIN_CNF_INPUT_Connect (0UL) /*!< Connect input buffer */
236
#define GPIO_PIN_CNF_INPUT_Disconnect (1UL) /*!< Disconnect input buffer */
237
238
/* Bit 0 : Pin direction. Same physical register as DIR register */
239
#define GPIO_PIN_CNF_DIR_Pos (0UL) /*!< Position of DIR field. */
240
#define GPIO_PIN_CNF_DIR_Msk (0x1UL << GPIO_PIN_CNF_DIR_Pos) /*!< Bit mask of DIR field. */
241
#define GPIO_PIN_CNF_DIR_Input (0UL) /*!< Configure pin as an input pin */
242
#define GPIO_PIN_CNF_DIR_Output (1UL) /*!< Configure pin as an output pin */
243
244
#if NRF_FLASH_LOADER_DEBUG
245
  static constexpr std::uint32_t debug_pin0 = 19;
246
  static constexpr std::uint32_t debug_pin1 = 20;
247
  static constexpr std::uint32_t debug_pin2 = 22;
248
  static constexpr std::uint32_t debug_pin3 = 23;
249
  static constexpr std::uint32_t all_debug_pin_mask =
250
      ( 1 << debug_pin0 ) |
251
      ( 1 << debug_pin1 ) |
252
      ( 1 << debug_pin2 ) |
253
      ( 1 << debug_pin3 );
254
#endif
255
256
static constexpr std::uint32_t    flash_driver_result_ok = 0;
257
static constexpr std::uint32_t    flash_driver_result_error = 1;
258
259
/**
260
 * @brief writes a page of flash memory
261
 *
262
 * @param word_count size of flash memory / 4
263
 * @param target_address start address of flash memory
264
 * @param content_address start address, containing the content to be flashed
265
 */
266
extern "C" std::uint32_t flash_loader(
267
            std::uint32_t function,
268
            std::uint32_t word_count,
269
            std::uint32_t target_address,
270
            std::uint32_t content_address )
271
{
272
    bool result = true;
273
274
#   if NRF_FLASH_LOADER_DEBUG
275
      for ( auto pin: { debug_pin0, debug_pin1, debug_pin2, debug_pin3 } )
276
          NRF_GPIO->PIN_CNF[ pin ] =
277
              ( GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos ) |
278
              ( GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos );
279
280
      NRF_GPIO->OUTSET = 1 << debug_pin0;
281
#   endif
282
283
    // disable cache
284
    NRF_NVMC->ICACHECNF = 0;
285
    // Disable Blockprotection
286
    NRF_BPROT->DISABLEINDEBUG = BPROT_DISABLEINDEBUG_DISABLEINDEBUG_Msk;
287
288
    if ( static_cast< driver::flash_loader_function >( function ) == driver::flash_loader_function::erase_all )
289
    {
290
#       if NRF_FLASH_LOADER_DEBUG
291
            NRF_GPIO->OUTSET = 1 << debug_pin1;
292
#       endif
293
294
        NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een;
295
        __ISB();
296
        __DSB();
297
298
        NRF_NVMC->ERASEALL = NVMC_ERASEALL_ERASEALL_Erase;
299
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
300
            ;
301
302
#       if NRF_FLASH_LOADER_DEBUG
303
            NRF_GPIO->OUTCLR = 1 << debug_pin1;
304
            NRF_GPIO->OUTCLR = 1 << debug_pin0;
305
#       endif
306
307
        return flash_driver_result_ok;
308
    }
309
310
    if ( static_cast< driver::flash_loader_function >( function ) == driver::flash_loader_function::flash_and_erase_block )
311
    {
312
#       if NRF_FLASH_LOADER_DEBUG
313
            NRF_GPIO->OUTSET = 1 << debug_pin2;
314
#       endif
315
316
        NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een;
317
        __ISB();
318
        __DSB();
319
320
        NRF_NVMC->ERASEPAGE = target_address;
321
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
322
            ;
323
324
#       if NRF_FLASH_LOADER_DEBUG
325
            NRF_GPIO->OUTCLR = 1 << debug_pin2;
326
#       endif
327
    }
328
329
    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
330
    __ISB();
331
    __DSB();
332
333
    for ( ; word_count && result; --word_count )
334
    {
335
        *reinterpret_cast< std::uint32_t* >( target_address ) =
336
            *reinterpret_cast< const std::uint32_t* >( content_address );
337
338
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
339
            ;
340
341
        result = *reinterpret_cast< std::uint32_t* >( target_address ) ==
342
            *reinterpret_cast< const std::uint32_t* >( content_address );
343
344
        target_address += 4;
345
        content_address += 4;
346
    }
347
348
    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
349
    __ISB();
350
    __DSB();
351
352
#   if NRF_FLASH_LOADER_DEBUG
353
        NRF_GPIO->OUTCLR = 1 << debug_pin0;
354
#   endif
355
356
    return result ? flash_driver_result_ok : flash_driver_result_error;
357
}