@@ -10,153 +10,4 @@ uint32_t availableRAM(void) {
1010 return &top - (char *)sbrk (0 ); // Top of stack minus end of heap
1111}
1212
13- // NVM (Non-Volatile Memory, i.e. flash) functions -------------------------
14-
15- #define FLASH_PAGE_SIZE (8 << NVMCTRL->PARAM.bit.PSZ)
16- #define FLASH_NUM_PAGES NVMCTRL->PARAM.bit.NVMP
17- #define FLASH_SIZE (FLASH_PAGE_SIZE * FLASH_NUM_PAGES)
18- #define FLASH_BLOCK_SIZE (FLASH_PAGE_SIZE * 16 ) // Datasheet 25.6.2
19-
20- extern uint32_t __etext; // CODE END. Symbol exported from linker script
21- static uint8_t *flashAddress = NULL ; // Initted on first use below
22-
23- uint32_t availableNVM (void ) {
24- if (flashAddress == NULL ) {
25- // On first call, initialize flashAddress to first block boundary
26- // following program storage. Code is uploaded page-at-a-time and
27- // any trailing bytes in the last program block may be gibberish,
28- // so we can't make use of that for ourselves.
29- flashAddress = (uint8_t *)&__etext; // OK to overwrite the '0' there
30- if ((uint32_t )flashAddress % FLASH_BLOCK_SIZE) {
31- flashAddress = &flashAddress[FLASH_BLOCK_SIZE -
32- ((uint32_t )flashAddress % FLASH_BLOCK_SIZE)];
33- }
34- } else {
35- // On subsequent calls, round up to next quadword (16 byte) boundary,
36- // try packing some data into the trailing bytes of the last-used flash
37- // block! Saves up to (8K-16) bytes flash per call.
38- if ((uint32_t )flashAddress & 15 ) {
39- flashAddress = &flashAddress[16 - ((uint32_t )flashAddress & 15 )];
40- }
41- }
42- return FLASH_SIZE - (uint32_t )flashAddress;
43- }
44-
45- static inline void wait_ready (void ) {
46- while (!NVMCTRL->STATUS .bit .READY );
47- }
48-
49- // Write a block of data to the NEXT AVAILABLE position in flash memory
50- // (NOT a specific location). Returns pointer to stored data, NULL if
51- // insufficient space or error.
52- uint8_t *writeDataToFlash (uint8_t *ramAddress, uint32_t len) {
53-
54- // availableNVM(), aside from reporting the amount of free flash memory,
55- // also adjusts flashAddress to the first/next available usable boundary.
56- // No need to do that manually here.
57- if (len > availableNVM ()) {
58- Serial.println (" Too large!" );
59- return NULL ;
60- }
61-
62- uint16_t saveCache = NVMCTRL->CTRLA .reg ; // Cache in Rev a silicon
63- NVMCTRL->CTRLA .bit .CACHEDIS0 = true ; // isn't reliable when
64- NVMCTRL->CTRLA .bit .CACHEDIS1 = true ; // writing to NVM.
65-
66- // Set manual write mode - only needed once, not in loop
67- NVMCTRL->CTRLA .bit .WMODE = NVMCTRL_CTRLA_WMODE_MAN;
68-
69- // Clear page buffer, only needed once, quadword write also clears it
70- NVMCTRL->CTRLB .reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_PBC;
71-
72- for (uint8_t tries = 0 ;;) { // Repeat write sequence until success or limit
73-
74- uint8_t *src = (uint8_t *)ramAddress; // Maintain passed-in pointers,
75- uint32_t *dst = (uint32_t *)flashAddress; // modify these instead.
76- int32_t bytesThisPass, bytesToGo = len;
77-
78- Serial.print (" Storing" );
79- wait_ready (); // Wait for any NVM write op in progress
80-
81- while (bytesToGo > 0 ) {
82- yield ();
83- // Because dst (via flashAddress) is always quadword-aligned at this
84- // point, and flash blocks are known to be a quadword-multiple size,
85- // this comparison is reasonable for checking for start of block...
86- if (!((uint32_t )dst % FLASH_BLOCK_SIZE)) { // At block boundary
87- // If ANY changed data within the entire block, it must be erased
88- bytesThisPass = min (FLASH_BLOCK_SIZE, bytesToGo);
89- if (memcmp (src, dst, bytesThisPass)) { // >0 if different
90- Serial.write (' -' ); // minus = erasing
91- wait_ready ();
92- NVMCTRL->ADDR .reg = (uint32_t )dst; // Destination address in flash
93- NVMCTRL->CTRLB .reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_EB;
94- } else { // Skip entire block
95- Serial.print (" >>" ); // >> = skipping, already stored
96- bytesToGo -= bytesThisPass;
97- src += FLASH_BLOCK_SIZE; // Advance to next block
98- dst += FLASH_BLOCK_SIZE / 4 ;
99- continue ;
100- }
101- }
102-
103- // Examine next quadword, write only if needed (reduce flash wear)
104- bytesThisPass = min (16 , bytesToGo);
105- if (memcmp (src, dst, bytesThisPass)) { // >0 if different
106- if (!((uint32_t )dst & 2047 )) Serial.write (' .' ); // One . per 2KB
107- // src might not be 32-bit aligned and must be read byte-at-a-time.
108- // dst write ops MUST be 32-bit! Won't work with memcpy().
109- dst[0 ] = src[ 0 ] | (src[ 1 ]<<8 ) | (src[ 2 ]<<16 ) | (src[ 3 ]<<24 );
110- dst[1 ] = src[ 4 ] | (src[ 5 ]<<8 ) | (src[ 6 ]<<16 ) | (src[ 7 ]<<24 );
111- dst[2 ] = src[ 8 ] | (src[ 9 ]<<8 ) | (src[10 ]<<16 ) | (src[11 ]<<24 );
112- dst[3 ] = src[12 ] | (src[13 ]<<8 ) | (src[14 ]<<16 ) | (src[15 ]<<24 );
113- // Trigger the quadword write
114- wait_ready ();
115- NVMCTRL->ADDR .reg = (uint32_t )dst;
116- NVMCTRL->CTRLB .reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_WQW;
117- }
118- bytesToGo -= bytesThisPass;
119- src += 16 ; // Advance to next quadword
120- dst += 4 ;
121- }
122-
123- wait_ready (); // Wait for last write to finish
124-
125- Serial.print (" verify..." ); Serial.flush ();
126- if (memcmp (ramAddress, flashAddress, len)) { // nonzero if mismatch
127- if (++tries >= 4 ) {
128- Serial.println (" ...proceeding anyway" );
129- break ; // Give up, run with the data we have
130- }
131- // If we didn't start at a block boundary...
132- if (uint32_t q = (uint32_t )flashAddress % FLASH_BLOCK_SIZE) {
133- // Get index of first changed byte
134- uint32_t n;
135- for (n=0 ; (ramAddress[n] == flashAddress[n]) &&
136- (n <= FLASH_BLOCK_SIZE); n++);
137- // ...and if first mismatched byte is within the region before
138- // the first block boundary...
139- q = FLASH_BLOCK_SIZE - q; // Bytes in partial 1st block
140- if (n < q) {
141- // ...then flashAddress MUST be advanced to the next block
142- // boundary before we retry, reason being that we CAN'T erase
143- // the initial partial block (it may be preceded by other data).
144- flashAddress = &flashAddress[q];
145- }
146- }
147- Serial.println (" ...retrying..." ); Serial.flush ();
148- } else {
149- Serial.println (" OK" );
150- break ;
151- }
152- }
153-
154- NVMCTRL->CTRLA .reg = saveCache; // Restore NVM cache settings
155-
156- // Return value will be start of newly-written data in flash
157- uint8_t *returnVal = flashAddress;
158- // Move next flash address past new data
159- // No need to align to next boundary, done at top of next call
160- flashAddress += len;
161- return returnVal;
162- }
13+ // All the flash stuff has now been merged into Arcada library.
0 commit comments