| Xmega IEC60730 Class B Library 1.0 |

All Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
classb_crc_hw.c
Go to the documentation of this file.
1 /**
2 * \file
3 *
4 * \brief Driver for 16- and 32-bit CRC using CRC hardware module.
5 *
6 * Copyright (C) 2012 Atmel Corporation. All rights reserved.
7 *
8 * \page License
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 *
20 * 3. The name of Atmel may not be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * 4. This software may only be redistributed and used in connection with an
24 * Atmel AVR product.
25 *
26 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
29 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
30 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
36 * DAMAGE.
37 */
38
39 #include "classb_crc_hw.h"
40
41 //! \ingroup classb_crc_hw
42 //@{
43
44 /******************* CRC DRIVER Common ******************/
45
46 #if defined(CLASSB_CRC_USE_HW) || defined(__DOXYGEN__)
47
48
49 //! \internal
50 //!
51 //! \brief Initial CRC value to use on next CRC calculation.
52 uint32_t crc_initial_value = 0;
53
54
55 /**
56 * \internal
57 *
58 * \brief Non-Volatile Memory Execute Specific Command
59 *
60 * This function sets a command in the NVM.CMD register, then performs an
61 * execute command by writing the CMDEX bit to the NVM.CTRLA register.
62 *
63 * \note The function saves and restores the NVM.CMD register, but if this
64 * function is called from an interrupt, interrupts must be disabled
65 * before this function is called.
66 *
67 * \param nvm_command NVM Command to execute.
68 */
69 static inline void nvm_issue_command(NVM_CMD_t nvm_command)
70 {
71 uint8_t old_cmd;
72
73 old_cmd = NVM.CMD;
74 NVM.CMD = nvm_command;
75
76 CCP = CCP_IOREG_gc;
77 NVM.CTRLA = NVM_CMDEX_bm;
78
79 NVM.CMD = old_cmd;
80 }
81
82 /**
83 * \internal
84 *
85 * \brief Check if the CRC module is busy
86 *
87 * This function can be used to see if a CRC checksum generation is completed.
88 *
89 * \retval true if module is busy
90 * \retval false if module is not busy
91 *
92 */
93 static inline bool crc_is_busy(void)
94 {
95 return ((CRC_STATUS & CRC_BUSY_bm) == CRC_BUSY_bm);
96 }
97
98 /**
99 * \internal
100 *
101 * \brief Add one byte of data to CRC performed on I/O interface
102 *
103 * This function writes a byte to the DATAIN register. Each time this function
104 * is called, the checksum is calculated for the new data appended to all
105 * previous data written since the \ref crc_io_checksum_byte_start was called.
106 * A new checksum is ready one clock cycle after the DATAIN register is
107 * written.
108 *
109 * \param data data to perform CRC on
110 *
111 */
112 void crc_io_checksum_byte_add(uint8_t data)
113 {
114 CRC_DATAIN = data;
115 }
116
117 /**
118 * \internal
119 *
120 * \brief Reset CRC module and set CHECKSUM to initial value
121 *
122 * The CRC registers will be reset one peripheral clock cycle after the
123 * RESET[1] bit is set. The initial value is reset to 0 after loading it into
124 * the CHECKSUM registers.
125 *
126 */
127 static inline void crc_reset(void)
128 {
129 // Reset module
130 CRC_CTRL |= CRC_RESET_RESET0_gc;
131
132 // Set initial checksum value
133 CRC.CHECKSUM0 = crc_initial_value & 0xFF;
134 CRC.CHECKSUM1 = (crc_initial_value >> 8) & 0xFF;
135 CRC.CHECKSUM2 = (crc_initial_value >> 16) & 0xFF;
136 CRC.CHECKSUM3 = (crc_initial_value >> 24) & 0xFF;
137
138 crc_initial_value = 0;
139 }
140
141
142 /**
143 * \internal
144 *
145 * \brief Read CRC-16 checksum
146 *
147 * This function returns the computed CRC-16 checksum.
148 *
149 * \return checksum checksum value
150 */
151 static inline uint16_t crc16_checksum_read(void)
152 {
153 uint16_t checksum;
154 checksum = 0;
155 checksum = ((uint16_t)CRC_CHECKSUM0 & 0x00FF);
156 checksum |= (((uint16_t)CRC_CHECKSUM1 << 8) & 0xFF00);
157
158 return checksum;
159 }
160
161 /**
162 * \internal
163 *
164 * \brief Read CRC-32 checksum
165 *
166 * This function extracts the CRC-32 checksum from the registers.
167 *
168 * \note In IEEE 802.3 CRC-32 the checksum is bit reversed
169 * and complemented.
170 *
171 * \return checksum checksum value
172 */
173 static inline uint32_t crc32_checksum_read(void)
174 {
175 uint32_t checksum;
176
177 checksum = ((uint32_t)CRC_CHECKSUM0 & 0x000000FF);
178 checksum |= (((uint32_t)CRC_CHECKSUM1 << 8) & 0x0000FF00);
179 checksum |= (((uint32_t)CRC_CHECKSUM2 << 16) & 0x00FF0000);
180 checksum |= (((uint32_t)CRC_CHECKSUM3 << 24) & 0xFF000000);
181
182 return checksum;
183 }
184
185 /**
186 * \internal
187 *
188 * \brief Read checksum
189 *
190 * This function waits until the CRC conversion is complete and returns
191 * either the 32 bit or 16 bit checksum as a 32 bit value.
192 *
193 * \note This function must not be called before a IO CRC calculation is
194 * completed or a FLASH or DMA CRC calculation is started, as this will cause
195 * it to wait for the BUSY flag to be cleared forever.
196 *
197 * \return checksum checksum value
198 */
199 static inline uint32_t crc_checksum_read(void)
200 {
201 // Wait until the CRC conversion is finished
202 while (crc_is_busy()) {
203 // Do nothing
204 }
205
206 // Check if we have a 32 or 16 bit checksum and return the correct one
207 if ((CRC_CTRL & CRC_CRC32_bm) == CRC_CRC32_bm) {
208 return crc32_checksum_read();
209 } else {
210 return crc16_checksum_read();
211 }
212 }
213
214 /**
215 * \internal
216 *
217 * \brief Set data source for the CRC module after reset
218 *
219 * The selected source is locked until either the CRC generation is completed
220 * or the CRC module is reset.
221 * CRC generation complete is generated and signaled from the selected source
222 * when used with the DMA controller or flash memory.
223 * To disable the CRC module, use CRC_SOURCE_DISABLE_gc as source.
224 *
225 * \param source the data source for the CRC module
226 */
227 static inline void crc_set_source(CRC_SOURCE_t source)
228 {
229 CRC_CTRL &= ~CRC_SOURCE_gm;
230 CRC_CTRL |= source;
231 }
232
233
234
235 /**
236 * \internal
237 *
238 * \brief Disable the CRC module
239 *
240 */
241 static inline void crc_disable(void)
242 {
243 crc_set_source(CRC_SOURCE_DISABLE_gc);
244 }
245
246 /**
247 * \internal
248 *
249 * \brief Complete CRC calculation by reading checksum and disabling module
250 *
251 * \return checksum checksum value
252 */
253 static inline uint32_t crc_checksum_complete(void)
254 {
255 uint32_t checksum;
256
257 // Read checksum
258 checksum = crc_checksum_read();
259
260 // Disable CRC module
261 crc_disable();
262
263 // Return checksum
264 return checksum;
265 }
266
267
268 /**
269 * \internal
270 *
271 * \brief Set initial CRC value for next CRC calculation
272 *
273 * \note Value is reset to 0 when CRC calculation completes.
274 *
275 * \param value Initial CRC value
276 */
277 void crc_set_initial_value(uint32_t value)
278 {
279 crc_initial_value = value;
280 }
281
282
283 /**
284 * \internal
285 *
286 * \brief Calculate the CRC checksum for data in a buffer
287 *
288 * This function initializes the CRC module, calculates the checksum for the
289 * selected number of bytes in a data buffer, disables the module and returns
290 * the calculated checksum.
291 *
292 * \param data data buffer to perform CRC on
293 * \param len the number of bytes to perform CRC on
294 * \param crc_16_32 enum to indicate whether CRC-32 or CRC-16 shall be used
295 *
296 * \return checksum checksum
297 */
298 uint32_t crc_io_checksum(void *data, uint16_t len, enum crc_16_32_t crc_16_32)
299 {
300 // Initialize CRC calculations on I/O interface
301 crc_io_checksum_byte_start(crc_16_32);
302
303 // Write data to DATAIN register
304 while (len--) {
305 crc_io_checksum_byte_add(*(uint8_t*)data);
306 data = (uint8_t*)data + 1;
307 }
308
309 // Return checksum
310 return crc_io_checksum_byte_stop();
311 }
312
313
314 /**
315 * \internal
316 *
317 * \brief Enable CRC-32
318 *
319 * This function will set the CRC-32 polynomial to be used to generate
320 * the checksum.
321 *
322 * \note This cannot be changed while the busy flag is set.
323 *
324 */
325 static inline void crc_32_enable(void)
326 {
327 CRC_CTRL |= CRC_CRC32_bm;
328 }
329
330
331 /**
332 * \internal
333 *
334 * \brief Reset CRC module and set source to I/O interface
335 *
336 * This function initializes the CRC module, and \ref crc_io_checksum_byte_add
337 * can be used to add bytes to calculate checksum for. When any number of bytes
338 * have been added, the \ref crc_io_checksum_byte_stop can be called to disable
339 * the module and get the calculated checksum.
340 *
341 * \param crc_16_32 enum to indicate whether CRC-32 or CRC-16 shall be used
342 */
343 void crc_io_checksum_byte_start(enum crc_16_32_t crc_16_32)
344 {
345 // Initialize CRC calculations on I/O interface
346 crc_reset();
347 // Enable CRC-32 if chosen
348 if (crc_16_32 == CRC_32BIT) {
349 crc_32_enable();
350 }
351 // Enable CRC module using the I/O interface
352 crc_set_source(CRC_SOURCE_IO_gc);
353 }
354
355 /**
356 * \internal
357 *
358 * \brief Disable CRC module and return checksum
359 *
360 * This function stops the CRC calculation for bytes added with the \ref
361 * crc_io_checksum_byte_add and returns the calculated checksum.
362 *
363 * \retval checksum checksum
364 *
365 */
366 uint32_t crc_io_checksum_byte_stop(void)
367 {
368 // Signal CRC complete
369 CRC_STATUS |= CRC_BUSY_bm;
370
371 // Stop CRC and return checksum
372 return crc_checksum_complete();
373 }
374
375
376 #endif // defined(CLASSB_CRC_USE_HW)
377
378
379 /******************* CRC16 Functions ******************/
380
381 #if (defined(CLASSB_CRC_USE_HW) && defined(CLASSB_CRC_16_BIT)) || defined(__DOXYGEN__)
382
383
384 /*! \brief Compute 16-bit CRC for EEPROM address range using hardware CRC module.
385 *
386 * This function returns the 16-bit CRC of the specified EEPROM address range.
387 *
388 * \param origDataptr Address of EEPROM location to start CRC computation at.
389 * \param numBytes Number of bytes of the data.
390 * \param pchecksum Pointer to the checksum stored in EEPROM.
391 *
392 * \note No sanity checking of addresses is done.
393 */
394 uint16_t CLASSB_CRC16_EEPROM_HW (eepromptr_t origDataptr, crcbytenum_t numBytes, eeprom_uint16ptr_t pchecksum)
395 {
396 eeprom_uint8ptr_t dataptr = origDataptr;
397
398 crc_set_initial_value(CRC16_INITIAL_REMAINDER);
399
400 // Ensure that EEPROM is memory mapped.
401 CLASSB_EEMAP_BEGIN();
402 dataptr += MAPPED_EEPROM_START;
403
404 uint32_t checksum = crc_io_checksum((void*)dataptr, numBytes, CRC_16BIT);
405
406
407 #if defined(__ICCAVR__)
408 // Disable memory mapping of EEPROM, if necessary.
409 CLASSB_EEMAP_END();
410 // Compare checksums and handle error if necessary.
411 if ( checksum != *pchecksum)
412 CLASSB_ERROR_HANDLER_CRC();
413 #elif defined(__GNUC__)
414 // Compare checksums and handle error if necessary.
415 if ( checksum != *(eeprom_uint16ptr_t)(MAPPED_EEPROM_START + (uintptr_t) pchecksum))
416 CLASSB_ERROR_HANDLER_CRC();
417 // Disable memory mapping of EEPROM, if necessary.
418 CLASSB_EEMAP_END();
419 #endif
420
421
422
423 // Return 16 bits
424 return (checksum & 0x0000FFFF);
425 }
426
427
428 /*! \brief Compute 16-bit CRC for Flash address range using hardware CRC module.
429 *
430 * This function returns the 16-bit CRC of the specified Flash address range.
431 *
432 * \param origDataptr Address of Flash location to start CRC computation at.
433 * \param numBytes Number of bytes of the data.
434 * \param pchecksum Pointer to the checksum stored in EEPROM.
435 *
436 * \note 16-bit flash CRC is much slower than 32-bit for flash checking.
437 * \note No sanity checking of addresses is done.
438 */
439 uint16_t CLASSB_CRC16_Flash_HW (flashptr_t origDataptr, crcbytenum_t numBytes, eeprom_uint16ptr_t pchecksum )
440 {
441 flash_uint8ptr_t dataptr = origDataptr;
442 uint8_t dataTemp;
443
444 crc_set_initial_value(CRC16_INITIAL_REMAINDER);
445
446 crc_io_checksum_byte_start(CRC_16BIT);
447
448 // Compute CRC for the specified data.
449 for (; numBytes != 0; numBytes--) {
450 #if (PROGMEM_SIZE >= 0x10000UL)
451 dataTemp = PROGMEM_READ_BYTE_FAR(dataptr++);
452 #else
453 dataTemp = PROGMEM_READ_BYTE(dataptr++);
454 #endif
455
456 crc_io_checksum_byte_add(dataTemp);
457 }
458
459 uint32_t checksum = crc_io_checksum_byte_stop();
460
461 #if defined(__ICCAVR__)
462 // Compare checksums and handle error if necessary.
463 if ( checksum != *pchecksum)
464 CLASSB_ERROR_HANDLER_CRC();
465 #elif defined(__GCC__)
466 // Ensure that EEPROM is memory mapped.
467 CLASSB_EEMAP_BEGIN();
468 // Compare checksums and handle error if necessary.
469 if ( checksum != *(eeprom_uint16ptr_t)(MAPPED_EEPROM_START + (uintptr_t) pchecksum))
470 CLASSB_ERROR_HANDLER_CRC();
471 // Disable memory mapping of EEPROM, if necessary.
472 CLASSB_EEMAP_END();
473 #endif
474
475 return (checksum & 0x0000FFFF);
476 }
477
478
479
480
481 /**
482 * \internal
483 *
484 * \brief Appends a CRC value to the given pointer
485 *
486 * Taking the checksum of the value and the appended data will result in zero.
487 *
488 * \note At least two bytes must be reserved at the given pointer location.
489 *
490 * \param value CRC value to append
491 * \param ptr pointer to 2 byte memory location to store value.
492 *
493 */
494 void crc16_append_value(uint16_t value, void *ptr)
495 {
496 *(uint8_t*)ptr = (value >> 8);
497 *((uint8_t*)ptr+1) = value;
498 }
499
500 #endif // defined(CLASSB_CRC_USE_HW) && defined(CLASSB_CRC_16_BIT)
501
502
503 /******************* CRC32 Functions ******************/
504
505 #if (defined(CLASSB_CRC_USE_HW) && defined(CLASSB_CRC_32_BIT)) || defined(__DOXYGEN__)
506
507 /**
508 * \brief Compute 32-bit CRC for EEPROM address range using hardware CRC module.
509 *
510 * This function returns the 32-bit CRC of the specified EEPROM address range.
511 *
512 * \param origDataptr Address of EEPROM location to start CRC computation at.
513 * \param numBytes Number of bytes of the data.
514 * \param pchecksum Pointer to the checksum stored in EEPROM.
515 *
516 * \note No sanity checking of addresses is done.
517 */
518 uint32_t CLASSB_CRC32_EEPROM_HW (eepromptr_t origDataptr, crcbytenum_t numBytes, eeprom_uint32ptr_t pchecksum)
519 {
520 eeprom_uint8ptr_t dataptr = origDataptr;
521 crc_set_initial_value(CRC32_INITIAL_REMAINDER);
522
523 // Ensure that EEPROM is memory mapped.
524 CLASSB_EEMAP_BEGIN();
525 dataptr += MAPPED_EEPROM_START;
526
527 uint32_t checksum = crc_io_checksum((void*)dataptr, numBytes, CRC_32BIT);
528
529 #if defined(__ICCAVR__)
530 // Disable memory mapping of EEPROM, if necessary.
531 CLASSB_EEMAP_END();
532 // Compare checksums and handle error if necessary.
533 if ( checksum != *pchecksum)
534 CLASSB_ERROR_HANDLER_CRC();
535 #elif defined(__GCC__)
536 // Compare checksums and handle error if necessary.
537 if ( checksum != *(eeprom_uint32ptr_t)(MAPPED_EEPROM_START + (uintptr_t) pchecksum))
538 CLASSB_ERROR_HANDLER_CRC();
539 // Disable memory mapping of EEPROM, if necessary.
540 CLASSB_EEMAP_END();
541 #endif
542
543
544
545 return (checksum);
546 }
547
548
549 /** \brief Compute 32-bit CRC for Flash address range using hardware CRC module.
550 *
551 * This function returns the 32-bit CRC of the specified Flash address range.
552 *
553 * \param crc_type Type of CRC computation: \ref CRC_FLASH_RANGE, \ref CRC_BOOT or \ref CRC_APP.
554 * \param origDataptr Address of Flash location to start CRC computation at.
555 * \param numBytes Number of bytes of the data.
556 * \param pchecksum Pointer to the checksum stored in EEPROM.
557 *
558 * \note No sanity checking of addresses is done.
559 */
560 uint32_t CLASSB_CRC32_Flash_HW (NVM_CMD_t crc_type, flashptr_t origDataptr, crcbytenum_t numBytes, eeprom_uint32ptr_t pchecksum)
561 {
562 flash_uint8ptr_t dataptr = origDataptr;
563 crc_set_initial_value(CRC32_INITIAL_REMAINDER);
564
565 // Compute CRC for the specified data.
566 uint32_t checksum = crc_flash_checksum(crc_type, (flash_addr_t)dataptr, numBytes);
567
568 #if defined(__ICCAVR__)
569 // Compare checksums and handle error if necessary.
570 if ( checksum != *pchecksum)
571 CLASSB_ERROR_HANDLER_CRC();
572 #elif defined(__GNUC__)
573 // Ensure that EEPROM is memory mapped.
574 CLASSB_EEMAP_BEGIN();
575 // Compare checksums and handle error if necessary.
576 if ( checksum != *(eeprom_uint32ptr_t)(MAPPED_EEPROM_START + (uintptr_t) pchecksum))
577 CLASSB_ERROR_HANDLER_CRC();
578 // Disable memory mapping of EEPROM, if necessary.
579 CLASSB_EEMAP_END();
580 #endif
581
582 return(checksum);
583 }
584
585
586 /**
587 * \internal
588 *
589 * \brief Get and append data to generate checksum zero with CRC32
590 *
591 * This function calculates checksum value to append to the data after
592 * generating its checksum.
593 * The value is written to given pointer as little endian.
594 * Taking the checksum of the data appended will result in checksum zero.
595 *
596 * \note At least four bytes must be reserved at the given pointer location.
597 *
598 * \param value the value to convert to append value
599 * \param ptr pointer to 4 byte memory location to store the value.
600 *
601 */
602 void crc32_append_value(uint32_t value, void *ptr)
603 {
604 *(uint8_t*)ptr = value & 0xFF;
605 *((uint8_t*)ptr+1) = (value >> 8) & 0xFF;
606 *((uint8_t*)ptr+2) = (value >> 16) & 0xFF;
607 *((uint8_t*)ptr+3) = (value >> 24) & 0xFF;
608 }
609
610
611 /**
612 * \internal
613 *
614 * \brief Perform a CRC-32 calculation on the entire flash memory, on only
615 * the application section, on only the boot section, or on a selectable range
616 * of the flash memory.
617 *
618 * This function setups the type of CRC to perform and configures the memory
619 * range to perform the CRC on, and starts the CRC via the NVM module.
620 * When the calculation is done, the function disables the CRC module and
621 * returns the checksum.
622 * For CRC on the boot or application section, start address and length are not
623 * needed.
624 *
625 * \note In the flash range mode, an even number of bytes is read. If the user
626 * selects a range with an odd number of bytes, an extra byte will be read, and
627 * the checksum will not correspond to the selected range.
628 *
629 * \param crc_type what kind of CRC to do perform on the nvm module: \ref
630 * CRC_FLASH_RANGE, \ref CRC_BOOT or \ref CRC_APP
631 * \param flash_addr address of first byte in flash to perform CRC on
632 * \param length number of bytes to perform CRC on
633 *
634 * \return checksum CRC-32 checksum
635 */
636 uint32_t crc_flash_checksum(NVM_CMD_t crc_type, flash_addr_t flash_addr, uint32_t length)
637 {
638 if ((length == 0) && (crc_type == CRC_FLASH_RANGE))
639 return 0;
640
641 if (! ((crc_type != CRC_FLASH_RANGE) || (crc_type != CRC_BOOT) ||
642 (crc_type != CRC_APP)) )
643 return 0;
644
645 // Initialize CRC for flash
646 crc_reset();
647 // Set CRC32 enable bit to ensure correct reading of the resulting checksum
648 crc_32_enable();
649 crc_set_source(CRC_SOURCE_FLASH_gc);
650
651 if (crc_type == CRC_FLASH_RANGE) {
652 nvm_issue_flash_range_crc(flash_addr, flash_addr + length - 1);
653 } else {
654 nvm_issue_command(crc_type);
655 }
656
657 // Disable CRC and return checksum
658 return crc_checksum_complete();
659 }
660
661
662 /**
663 * \internal
664 *
665 * \brief Issue flash range CRC command
666 *
667 * This function sets the FLASH range CRC command in the NVM.CMD register.
668 * It then loads the start and end byte address of the part of FLASH to
669 * generate a CRC-32 for into the ADDR and DATA registers and finally performs
670 * the execute command.
671 *
672 * \note Should only be called from the CRC module. The function saves and
673 * restores the NVM.CMD register, but if this
674 * function is called from an interrupt, interrupts must be disabled
675 * before this function is called.
676 *
677 * \param start_addr end byte address
678 * \param end_addr start byte address
679 */
680 void nvm_issue_flash_range_crc(flash_addr_t start_addr, flash_addr_t end_addr)
681 {
682 uint8_t old_cmd;
683 // Save current nvm command
684 old_cmd = NVM.CMD;
685
686 // Load the NVM CMD register with the Flash Range CRC command
687 NVM.CMD = NVM_CMD_FLASH_RANGE_CRC_gc;
688
689 // Load the start byte address in the NVM Address Register
690 NVM.ADDR0 = start_addr & 0xFF;
691 NVM.ADDR1 = (start_addr >> 8) & 0xFF;
692 #if (PROGMEM_SIZE >= 0x10000UL)
693 NVM.ADDR2 = (start_addr >> 16) & 0xFF;
694 #endif
695
696 // Load the end byte address in NVM Data Register
697 NVM.DATA0 = end_addr & 0xFF;
698 NVM.DATA1 = (end_addr >> 8) & 0xFF;
699 #if (PROGMEM_SIZE >= 0x10000UL)
700 NVM.DATA2 = (end_addr >> 16) & 0xFF;
701 #endif
702
703 // Execute command
704 CCP = CCP_IOREG_gc;
705 NVM.CTRLA = NVM_CMDEX_bm;
706
707 // Restore command register
708 NVM.CMD = old_cmd;
709 }
710
711 #endif //defined(CLASSB_CRC_USE_HW) && defined(CLASSB_CRC_32_BIT)
712
713 //@}
714