123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973 |
- /**
- * \file
- *
- * \brief FLASHC driver for AVR32 UC3.
- *
- * Copyright (c) 2009-2018 Microchip Technology Inc. and its subsidiaries.
- *
- * \asf_license_start
- *
- * \page License
- *
- * Subject to your compliance with these terms, you may use Microchip
- * software and any derivatives exclusively with Microchip products.
- * It is your responsibility to comply with third party license terms applicable
- * to your use of third party software (including open source software) that
- * may accompany Microchip software.
- *
- * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
- * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
- * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
- * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
- * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
- * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
- * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
- * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
- * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
- * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
- * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
- *
- * \asf_license_stop
- *
- */
- /*
- * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
- */
- #include <avr32/io.h>
- #include <stddef.h>
- #include "compiler.h"
- #include "flashc.h"
- /*! \name FLASHC Writable Bit-Field Registers
- */
- //! @{
- typedef union {
- unsigned long fcr;
- avr32_flashc_fcr_t FCR;
- } u_avr32_flashc_fcr_t;
- typedef union {
- unsigned long fcmd;
- avr32_flashc_fcmd_t FCMD;
- } u_avr32_flashc_fcmd_t;
- //! @}
- /*! \name Flash Properties
- */
- //! @{
- unsigned int flashc_get_flash_size(void)
- {
- #if (AVR32_FLASHC_H_VERSION >= 300)
- const uint16_t FLASH_SIZE[] = {
- 4,
- 8,
- 16,
- 32,
- 48,
- 64,
- 96,
- 128,
- 192,
- 256,
- 384,
- 512,
- 768,
- 1024,
- 2048,
- };
- return ((unsigned int)FLASH_SIZE[(AVR32_FLASHC.pr & AVR32_FLASHC_PR_FSZ_MASK)
- >> AVR32_FLASHC_PR_FSZ_OFFSET])<<10;
- #else // in older flashc version, FSZ is located in FSR register
- const uint16_t FLASH_SIZE[] = {
- 32,
- 64,
- 128,
- 256,
- 384,
- 512,
- 768,
- 1024,
- };
- return ((unsigned int)FLASH_SIZE[(AVR32_FLASHC.fsr & AVR32_FLASHC_FSR_FSZ_MASK)
- >> AVR32_FLASHC_FSR_FSZ_OFFSET]) << 10;
- #endif
- }
- unsigned int flashc_get_page_count(void)
- {
- return flashc_get_flash_size() / AVR32_FLASHC_PAGE_SIZE;
- }
- unsigned int flashc_get_page_count_per_region(void)
- {
- return flashc_get_page_count() / AVR32_FLASHC_REGIONS;
- }
- unsigned int flashc_get_page_region(int page_number)
- {
- return ((page_number >= 0) ? page_number
- : flashc_get_page_number()) / flashc_get_page_count_per_region();
- }
- unsigned int flashc_get_region_first_page_number(unsigned int region)
- {
- return region * flashc_get_page_count_per_region();
- }
- //! @}
- /*! \name FLASHC Control
- */
- //! @{
- unsigned int flashc_get_wait_state(void)
- {
- return (AVR32_FLASHC.fcr & AVR32_FLASHC_FCR_FWS_MASK) >> AVR32_FLASHC_FCR_FWS_OFFSET;
- }
- void flashc_set_wait_state(unsigned int wait_state)
- {
- u_avr32_flashc_fcr_t u_avr32_flashc_fcr = {AVR32_FLASHC.fcr};
- u_avr32_flashc_fcr.FCR.fws = wait_state;
- AVR32_FLASHC.fcr = u_avr32_flashc_fcr.fcr;
- }
- void flashc_set_bus_freq(unsigned int cpu_f_hz)
- {
- if (cpu_f_hz >= AVR32_FLASHC_FWS_0_MAX_FREQ) {
- // Set 1 WS.
- flashc_set_wait_state(1);
- } else {
- // Set 0 WS.
- flashc_set_wait_state(0);
- }
- }
- bool flashc_is_ready_int_enabled(void)
- {
- return ((AVR32_FLASHC.fcr & AVR32_FLASHC_FCR_FRDY_MASK) != 0);
- }
- void flashc_enable_ready_int(bool enable)
- {
- u_avr32_flashc_fcr_t u_avr32_flashc_fcr = {AVR32_FLASHC.fcr};
- u_avr32_flashc_fcr.FCR.frdy = (enable != false);
- AVR32_FLASHC.fcr = u_avr32_flashc_fcr.fcr;
- }
- bool flashc_is_lock_error_int_enabled(void)
- {
- return ((AVR32_FLASHC.fcr & AVR32_FLASHC_FCR_LOCKE_MASK) != 0);
- }
- void flashc_enable_lock_error_int(bool enable)
- {
- u_avr32_flashc_fcr_t u_avr32_flashc_fcr = {AVR32_FLASHC.fcr};
- u_avr32_flashc_fcr.FCR.locke = (enable != false);
- AVR32_FLASHC.fcr = u_avr32_flashc_fcr.fcr;
- }
- bool flashc_is_prog_error_int_enabled(void)
- {
- return ((AVR32_FLASHC.fcr & AVR32_FLASHC_FCR_PROGE_MASK) != 0);
- }
- void flashc_enable_prog_error_int(bool enable)
- {
- u_avr32_flashc_fcr_t u_avr32_flashc_fcr = {AVR32_FLASHC.fcr};
- u_avr32_flashc_fcr.FCR.proge = (enable != false);
- AVR32_FLASHC.fcr = u_avr32_flashc_fcr.fcr;
- }
- //! @}
- /*! \name FLASHC Status
- */
- //! @{
- bool flashc_is_ready(void)
- {
- return ((AVR32_FLASHC.fsr & AVR32_FLASHC_FSR_FRDY_MASK) != 0);
- }
- void flashc_default_wait_until_ready(void)
- {
- while (!flashc_is_ready());
- }
- void (*volatile flashc_wait_until_ready)(void) = flashc_default_wait_until_ready;
- /*! \brief Gets the error status of the FLASHC.
- *
- * \return The error status of the FLASHC built up from
- * \c AVR32_FLASHC_FSR_LOCKE_MASK and \c AVR32_FLASHC_FSR_PROGE_MASK.
- *
- * \warning This hardware error status is cleared by all functions reading the
- * Flash Status Register (FSR). This function is therefore not part of
- * the driver's API which instead presents \ref flashc_is_lock_error
- * and \ref flashc_is_programming_error.
- */
- static unsigned int flashc_get_error_status(void)
- {
- return AVR32_FLASHC.fsr & (AVR32_FLASHC_FSR_LOCKE_MASK |
- AVR32_FLASHC_FSR_PROGE_MASK);
- }
- //! Sticky error status of the FLASHC.
- //! This variable is updated by functions that issue FLASHC commands. It
- //! contains the cumulated FLASHC error status of all the FLASHC commands issued
- //! by a function.
- static unsigned int flashc_error_status = 0;
- bool flashc_is_lock_error(void)
- {
- return ((flashc_error_status & AVR32_FLASHC_FSR_LOCKE_MASK) != 0);
- }
- bool flashc_is_programming_error(void)
- {
- return ((flashc_error_status & AVR32_FLASHC_FSR_PROGE_MASK) != 0);
- }
- //! @}
- /*! \name FLASHC Command Control
- */
- //! @{
- unsigned int flashc_get_command(void)
- {
- return (AVR32_FLASHC.fcmd & AVR32_FLASHC_FCMD_CMD_MASK) >> AVR32_FLASHC_FCMD_CMD_OFFSET;
- }
- unsigned int flashc_get_page_number(void)
- {
- return (AVR32_FLASHC.fcmd & AVR32_FLASHC_FCMD_PAGEN_MASK) >> AVR32_FLASHC_FCMD_PAGEN_OFFSET;
- }
- void flashc_issue_command(unsigned int command, int page_number)
- {
- u_avr32_flashc_fcmd_t u_avr32_flashc_fcmd;
- flashc_wait_until_ready();
- u_avr32_flashc_fcmd.fcmd = AVR32_FLASHC.fcmd;
- u_avr32_flashc_fcmd.FCMD.cmd = command;
- if (page_number >= 0) {
- u_avr32_flashc_fcmd.FCMD.pagen = page_number;
- }
- u_avr32_flashc_fcmd.FCMD.key = AVR32_FLASHC_FCMD_KEY_KEY;
- AVR32_FLASHC.fcmd = u_avr32_flashc_fcmd.fcmd;
- flashc_error_status = flashc_get_error_status();
- flashc_wait_until_ready();
- }
- //! @}
- /*! \name FLASHC Global Commands
- */
- //! @{
- void flashc_no_operation(void)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_NOP, -1);
- }
- void flashc_erase_all(void)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_EA, -1);
- }
- //! @}
- /*! \name FLASHC Protection Mechanisms
- */
- //! @{
- bool flashc_is_security_bit_active(void)
- {
- return ((AVR32_FLASHC.fsr & AVR32_FLASHC_FSR_SECURITY_MASK) != 0);
- }
- void flashc_activate_security_bit(void)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_SSB, -1);
- }
- unsigned int flashc_get_bootloader_protected_size(void)
- {
- unsigned int bootprot = (1 << AVR32_FLASHC_FGPFRLO_BOOTPROT_SIZE) - 1 -
- flashc_read_gp_fuse_bitfield(AVR32_FLASHC_FGPFRLO_BOOTPROT_OFFSET,
- AVR32_FLASHC_FGPFRLO_BOOTPROT_SIZE);
- return (bootprot) ? AVR32_FLASHC_PAGE_SIZE << bootprot : 0;
- }
- unsigned int flashc_set_bootloader_protected_size(unsigned int bootprot_size)
- {
- flashc_set_gp_fuse_bitfield(AVR32_FLASHC_FGPFRLO_BOOTPROT_OFFSET,
- AVR32_FLASHC_FGPFRLO_BOOTPROT_SIZE,
- (1 << AVR32_FLASHC_FGPFRLO_BOOTPROT_SIZE) - 1 -
- ((bootprot_size) ?
- 32 - clz((((min(max(bootprot_size, AVR32_FLASHC_PAGE_SIZE << 1),
- AVR32_FLASHC_PAGE_SIZE <<
- ((1 << AVR32_FLASHC_FGPFRLO_BOOTPROT_SIZE) - 1)) +
- AVR32_FLASHC_PAGE_SIZE - 1) /
- AVR32_FLASHC_PAGE_SIZE) << 1) - 1) - 1 :
- 0));
- return flashc_get_bootloader_protected_size();
- }
- bool flashc_is_external_privileged_fetch_locked(void)
- {
- return (!flashc_read_gp_fuse_bit(AVR32_FLASHC_FGPFRLO_EPFL_OFFSET));
- }
- void flashc_lock_external_privileged_fetch(bool lock)
- {
- flashc_set_gp_fuse_bit(AVR32_FLASHC_FGPFRLO_EPFL_OFFSET, !lock);
- }
- bool flashc_is_page_region_locked(int page_number)
- {
- return flashc_is_region_locked(flashc_get_page_region(page_number));
- }
- bool flashc_is_region_locked(unsigned int region)
- {
- return ((AVR32_FLASHC.fsr & AVR32_FLASHC_FSR_LOCK0_MASK << (region & (AVR32_FLASHC_REGIONS - 1))) != 0);
- }
- void flashc_lock_page_region(int page_number, bool lock)
- {
- flashc_issue_command((lock) ? AVR32_FLASHC_FCMD_CMD_LP : AVR32_FLASHC_FCMD_CMD_UP, page_number);
- }
- void flashc_lock_region(unsigned int region, bool lock)
- {
- flashc_lock_page_region(flashc_get_region_first_page_number(region), lock);
- }
- void flashc_lock_all_regions(bool lock)
- {
- unsigned int error_status = 0;
- unsigned int region = AVR32_FLASHC_REGIONS;
- while (region) {
- flashc_lock_region(--region, lock);
- error_status |= flashc_error_status;
- }
- flashc_error_status = error_status;
- }
- //! @}
- /*! \name Access to General-Purpose Fuses
- */
- //! @{
- bool flashc_read_gp_fuse_bit(unsigned int gp_fuse_bit)
- {
- return ((flashc_read_all_gp_fuses() & 1ULL << (gp_fuse_bit & 0x3F)) != 0);
- }
- uint64_t flashc_read_gp_fuse_bitfield(unsigned int pos, unsigned int width)
- {
- return flashc_read_all_gp_fuses() >> (pos & 0x3F) & ((1ULL << min(width, 64)) - 1);
- }
- uint8_t flashc_read_gp_fuse_byte(unsigned int gp_fuse_byte)
- {
- return flashc_read_all_gp_fuses() >> ((gp_fuse_byte & 0x07) << 3);
- }
- uint64_t flashc_read_all_gp_fuses(void)
- {
- return AVR32_FLASHC.fgpfrlo | (uint64_t)AVR32_FLASHC.fgpfrhi << 32;
- }
- bool flashc_erase_gp_fuse_bit(unsigned int gp_fuse_bit, bool check)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_EGPB, gp_fuse_bit & 0x3F);
- return (check) ? flashc_read_gp_fuse_bit(gp_fuse_bit) : true;
- }
- bool flashc_erase_gp_fuse_bitfield(unsigned int pos, unsigned int width, bool check)
- {
- unsigned int error_status = 0;
- unsigned int gp_fuse_bit;
- pos &= 0x3F;
- width = min(width, 64);
- for (gp_fuse_bit = pos; gp_fuse_bit < pos + width; gp_fuse_bit++) {
- flashc_erase_gp_fuse_bit(gp_fuse_bit, false);
- error_status |= flashc_error_status;
- }
- flashc_error_status = error_status;
- return (check) ? (flashc_read_gp_fuse_bitfield(pos, width) == (1ULL << width) - 1) : true;
- }
- bool flashc_erase_gp_fuse_byte(unsigned int gp_fuse_byte, bool check)
- {
- unsigned int error_status;
- unsigned int current_gp_fuse_byte;
- uint64_t value = flashc_read_all_gp_fuses();
- flashc_erase_all_gp_fuses(false);
- error_status = flashc_error_status;
- for (current_gp_fuse_byte = 0; current_gp_fuse_byte < 8; current_gp_fuse_byte++, value >>= 8) {
- if (current_gp_fuse_byte != gp_fuse_byte) {
- flashc_write_gp_fuse_byte(current_gp_fuse_byte, value);
- error_status |= flashc_error_status;
- }
- }
- flashc_error_status = error_status;
- return (check) ? (flashc_read_gp_fuse_byte(gp_fuse_byte) == 0xFF) : true;
- }
- bool flashc_erase_all_gp_fuses(bool check)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_EAGPF, -1);
- return (check) ? (flashc_read_all_gp_fuses() == 0xFFFFFFFFFFFFFFFFULL) : true;
- }
- void flashc_write_gp_fuse_bit(unsigned int gp_fuse_bit, bool value)
- {
- if (!value) {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_WGPB, gp_fuse_bit & 0x3F);
- }
- }
- void flashc_write_gp_fuse_bitfield(unsigned int pos, unsigned int width, uint64_t value)
- {
- unsigned int error_status = 0;
- unsigned int gp_fuse_bit;
- pos &= 0x3F;
- width = min(width, 64);
- for (gp_fuse_bit = pos; gp_fuse_bit < pos + width; gp_fuse_bit++, value >>= 1) {
- flashc_write_gp_fuse_bit(gp_fuse_bit, value & 0x01);
- error_status |= flashc_error_status;
- }
- flashc_error_status = error_status;
- }
- void flashc_write_gp_fuse_byte(unsigned int gp_fuse_byte, uint8_t value)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_PGPFB, (gp_fuse_byte & 0x07) | value << 3);
- }
- void flashc_write_all_gp_fuses(uint64_t value)
- {
- unsigned int error_status = 0;
- unsigned int gp_fuse_byte;
- for (gp_fuse_byte = 0; gp_fuse_byte < 8; gp_fuse_byte++, value >>= 8) {
- flashc_write_gp_fuse_byte(gp_fuse_byte, value);
- error_status |= flashc_error_status;
- }
- flashc_error_status = error_status;
- }
- void flashc_set_gp_fuse_bit(unsigned int gp_fuse_bit, bool value)
- {
- if (value) {
- flashc_erase_gp_fuse_bit(gp_fuse_bit, false);
- } else {
- flashc_write_gp_fuse_bit(gp_fuse_bit, false);
- }
- }
- void flashc_set_gp_fuse_bitfield(unsigned int pos, unsigned int width, uint64_t value)
- {
- unsigned int error_status = 0;
- unsigned int gp_fuse_bit;
- pos &= 0x3F;
- width = min(width, 64);
- for (gp_fuse_bit = pos; gp_fuse_bit < pos + width; gp_fuse_bit++, value >>= 1) {
- flashc_set_gp_fuse_bit(gp_fuse_bit, value & 0x01);
- error_status |= flashc_error_status;
- }
- flashc_error_status = error_status;
- }
- void flashc_set_gp_fuse_byte(unsigned int gp_fuse_byte, uint8_t value)
- {
- unsigned int error_status;
- switch (value) {
- case 0xFF:
- flashc_erase_gp_fuse_byte(gp_fuse_byte, false);
- break;
- case 0x00:
- flashc_write_gp_fuse_byte(gp_fuse_byte, 0x00);
- break;
- default:
- flashc_erase_gp_fuse_byte(gp_fuse_byte, false);
- error_status = flashc_error_status;
- flashc_write_gp_fuse_byte(gp_fuse_byte, value);
- flashc_error_status |= error_status;
- break;
- }
- }
- void flashc_set_all_gp_fuses(uint64_t value)
- {
- unsigned int error_status;
- switch (value) {
- case 0xFFFFFFFFFFFFFFFFULL:
- flashc_erase_all_gp_fuses(false);
- break;
- case 0x0000000000000000ULL:
- flashc_write_all_gp_fuses(0x0000000000000000ULL);
- break;
- default:
- flashc_erase_all_gp_fuses(false);
- error_status = flashc_error_status;
- flashc_write_all_gp_fuses(value);
- flashc_error_status |= error_status;
- break;
- }
- }
- //! @}
- /*! \name Access to Flash Pages
- */
- //! @{
- void flashc_clear_page_buffer(void)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_CPB, -1);
- }
- bool flashc_is_page_erased(void)
- {
- return ((AVR32_FLASHC.fsr & AVR32_FLASHC_FSR_QPRR_MASK) != 0);
- }
- bool flashc_quick_page_read(int page_number)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_QPR, page_number);
- return flashc_is_page_erased();
- }
- bool flashc_erase_page(int page_number, bool check)
- {
- bool page_erased = true;
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_EP, page_number);
- if (check) {
- unsigned int error_status = flashc_error_status;
- page_erased = flashc_quick_page_read(-1);
- flashc_error_status |= error_status;
- }
- return page_erased;
- }
- bool flashc_erase_all_pages(bool check)
- {
- bool all_pages_erased = true;
- unsigned int error_status = 0;
- unsigned int page_number = flashc_get_page_count();
- while (page_number) {
- all_pages_erased &= flashc_erase_page(--page_number, check);
- error_status |= flashc_error_status;
- }
- flashc_error_status = error_status;
- return all_pages_erased;
- }
- void flashc_write_page(int page_number)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_WP, page_number);
- }
- bool flashc_quick_user_page_read(void)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_QPRUP, -1);
- return flashc_is_page_erased();
- }
- bool flashc_erase_user_page(bool check)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_EUP, -1);
- return (check) ? flashc_quick_user_page_read() : true;
- }
- void flashc_write_user_page(void)
- {
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_WUP, -1);
- }
- volatile void *flashc_memset8(volatile void *dst, uint8_t src, size_t nbytes, bool erase)
- {
- return flashc_memset16(dst, src | (uint16_t)src << 8, nbytes, erase);
- }
- volatile void *flashc_memset16(volatile void *dst, uint16_t src, size_t nbytes, bool erase)
- {
- return flashc_memset32(dst, src | (uint32_t)src << 16, nbytes, erase);
- }
- volatile void *flashc_memset32(volatile void *dst, uint32_t src, size_t nbytes, bool erase)
- {
- return flashc_memset64(dst, src | (uint64_t)src << 32, nbytes, erase);
- }
- volatile void *flashc_memset64(volatile void *dst, uint64_t src, size_t nbytes, bool erase)
- {
- // Use aggregated pointers to have several alignments available for a same address.
- UnionCVPtr flash_array_end;
- UnionVPtr dest;
- Union64 source = {0};
- StructCVPtr dest_end;
- UnionCVPtr flash_page_source_end;
- bool incomplete_flash_page_end;
- Union64 flash_dword;
- UnionVPtr tmp;
- unsigned int error_status = 0;
- unsigned int i;
- // Reformat arguments.
- flash_array_end.u8ptr = AVR32_FLASH + flashc_get_flash_size();
- dest.u8ptr = dst;
- for (i = (Get_align((uint32_t)dest.u8ptr, sizeof(uint64_t)) - 1) & (sizeof(uint64_t) - 1);
- src; i = (i - 1) & (sizeof(uint64_t) - 1)) {
- source.u8[i] = src;
- src >>= 8;
- }
- dest_end.u8ptr = dest.u8ptr + nbytes;
- // If destination is outside flash, go to next flash page if any.
- if (dest.u8ptr < AVR32_FLASH) {
- dest.u8ptr = AVR32_FLASH;
- } else if (flash_array_end.u8ptr <= dest.u8ptr && dest.u8ptr < AVR32_FLASHC_USER_PAGE) {
- dest.u8ptr = AVR32_FLASHC_USER_PAGE;
- }
- // If end of destination is outside flash, move it to the end of the previous flash page if any.
- if (dest_end.u8ptr > AVR32_FLASHC_USER_PAGE + AVR32_FLASHC_USER_PAGE_SIZE) {
- dest_end.u8ptr = AVR32_FLASHC_USER_PAGE + AVR32_FLASHC_USER_PAGE_SIZE;
- } else if (AVR32_FLASHC_USER_PAGE >= dest_end.u8ptr && dest_end.u8ptr > flash_array_end.u8ptr) {
- dest_end.u8ptr = flash_array_end.u8ptr;
- }
- // Align each end of destination pointer with its natural boundary.
- dest_end.u16ptr = (uint16_t *)Align_down((uint32_t)dest_end.u8ptr, sizeof(uint16_t));
- dest_end.u32ptr = (uint32_t *)Align_down((uint32_t)dest_end.u16ptr, sizeof(uint32_t));
- dest_end.u64ptr = (uint64_t *)Align_down((uint32_t)dest_end.u32ptr, sizeof(uint64_t));
- // While end of destination is not reached...
- while (dest.u8ptr < dest_end.u8ptr) {
- // Clear the page buffer in order to prepare data for a flash page write.
- flashc_clear_page_buffer();
- error_status |= flashc_error_status;
- // Determine where the source data will end in the current flash page.
- flash_page_source_end.u64ptr =
- (uint64_t *)min((uint32_t)dest_end.u64ptr,
- Align_down((uint32_t)dest.u8ptr, AVR32_FLASHC_PAGE_SIZE) + AVR32_FLASHC_PAGE_SIZE);
- // Determine if the current destination page has an incomplete end.
- incomplete_flash_page_end = (Align_down((uint32_t)dest.u8ptr, AVR32_FLASHC_PAGE_SIZE) >=
- Align_down((uint32_t)dest_end.u8ptr, AVR32_FLASHC_PAGE_SIZE));
- // Use a flash double-word buffer to manage unaligned accesses.
- flash_dword.u64 = source.u64;
- // If destination does not point to the beginning of the current flash page...
- if (!Test_align((uint32_t)dest.u8ptr, AVR32_FLASHC_PAGE_SIZE)) {
- // Fill the beginning of the page buffer with the current flash page data.
- // This is required by the hardware, even if page erase is not requested,
- // in order to be able to write successfully to erased parts of flash
- // pages that have already been written to.
- for (tmp.u8ptr = (uint8_t *)Align_down((uint32_t)dest.u8ptr, AVR32_FLASHC_PAGE_SIZE);
- tmp.u64ptr < (uint64_t *)Align_down((uint32_t)dest.u8ptr, sizeof(uint64_t));
- tmp.u64ptr++) {
- *tmp.u64ptr = *tmp.u64ptr;
- }
- // If destination is not 64-bit aligned...
- if (!Test_align((uint32_t)dest.u8ptr, sizeof(uint64_t))) {
- // Fill the beginning of the flash double-word buffer with the current
- // flash page data.
- // This is required by the hardware, even if page erase is not
- // requested, in order to be able to write successfully to erased parts
- // of flash pages that have already been written to.
- for (i = 0; i < Get_align((uint32_t)dest.u8ptr, sizeof(uint64_t)); i++) {
- flash_dword.u8[i] = *tmp.u8ptr++;
- }
- // Align the destination pointer with its 64-bit boundary.
- dest.u64ptr = (uint64_t *)Align_down((uint32_t)dest.u8ptr, sizeof(uint64_t));
- // If the current destination double-word is not the last one...
- if (dest.u64ptr < dest_end.u64ptr) {
- // Write the flash double-word buffer to the page buffer and reinitialize it.
- *dest.u64ptr++ = flash_dword.u64;
- flash_dword.u64 = source.u64;
- }
- }
- }
- // Write the source data to the page buffer with 64-bit alignment.
- for (i = flash_page_source_end.u64ptr - dest.u64ptr; i; i--) {
- *dest.u64ptr++ = source.u64;
- }
- // If the current destination page has an incomplete end...
- if (incomplete_flash_page_end) {
- // This is required by the hardware, even if page erase is not requested,
- // in order to be able to write successfully to erased parts of flash
- // pages that have already been written to.
- {
- tmp.u8ptr = (volatile uint8_t *)dest_end.u8ptr;
- // If end of destination is not 64-bit aligned...
- if (!Test_align((uint32_t)dest_end.u8ptr, sizeof(uint64_t))) {
- // Fill the end of the flash double-word buffer with the current flash page data.
- for (i = Get_align((uint32_t)dest_end.u8ptr, sizeof(uint64_t)); i < sizeof(uint64_t); i++)
- flash_dword.u8[i] = *tmp.u8ptr++;
- // Write the flash double-word buffer to the page buffer.
- *dest.u64ptr++ = flash_dword.u64;
- }
- // Fill the end of the page buffer with the current flash page data.
- for (; !Test_align((uint32_t)tmp.u64ptr, AVR32_FLASHC_PAGE_SIZE); tmp.u64ptr++) {
- *tmp.u64ptr = *tmp.u64ptr;
- }
- }
- }
- // If the current flash page is in the flash array...
- if (dest.u8ptr <= AVR32_FLASHC_USER_PAGE) {
- // Erase the current page if requested and write it from the page buffer.
- if (erase) {
- flashc_erase_page(-1, false);
- error_status |= flashc_error_status;
- }
- flashc_write_page(-1);
- error_status |= flashc_error_status;
- // If the end of the flash array is reached, go to the User page.
- if (dest.u8ptr >= flash_array_end.u8ptr) {
- dest.u8ptr = AVR32_FLASHC_USER_PAGE;
- }
- } else {
- // Erase the User page if requested and write it from the page buffer.
- if (erase) {
- flashc_erase_user_page(false);
- error_status |= flashc_error_status;
- }
- flashc_write_user_page();
- error_status |= flashc_error_status;
- }
- }
- // Update the FLASHC error status.
- flashc_error_status = error_status;
- // Return the initial destination pointer as the standard memset function does.
- return dst;
- }
- volatile void *flashc_memcpy(volatile void *dst, const void *src, size_t nbytes, bool erase)
- {
- uint16_t page_pos;
- Union64 flash_dword;
- uint8_t i;
- bool b_user_page;
- unsigned int error_status = 0;
- uint8_t* flash_add;
- uint8_t* dest_add=(uint8_t*)dst;
- const uint8_t* src_buf=(const uint8_t*)src;
- // Copy area must be in flash array or flash user page
- Assert( (((uint8_t *)dst >= AVR32_FLASH)
- && (((uint8_t *)dst + nbytes) <= (AVR32_FLASH + flashc_get_flash_size())))
- || (((uint8_t *)dst >= AVR32_FLASHC_USER_PAGE)
- && (((uint8_t *)dst + nbytes) <= (AVR32_FLASHC_USER_PAGE + AVR32_FLASHC_USER_PAGE_SIZE))) );
- b_user_page = (volatile uint8_t *)dst >= AVR32_FLASHC_USER_PAGE;
- flash_add = (uint8_t*)((uint32_t)dest_add - ((uint32_t)dest_add % AVR32_FLASHC_PAGE_SIZE));
- while (nbytes) {
- // Clear the page buffer in order to prepare data for a flash page write.
- flashc_clear_page_buffer();
- error_status |= flashc_error_status;
- // Loop in the page
- for (page_pos=0; page_pos<AVR32_FLASHC_PAGE_SIZE; page_pos+=sizeof(uint64_t) ) {
- // Read the flash double-word buffer
- flash_dword.u64 = *(volatile uint64_t*)flash_add;
- // Update double-word if necessary
- for (i = 0; i < sizeof(uint64_t); i++) {
- if (nbytes && (flash_add == dest_add)) {
- // Update page with data source
- flash_dword.u8[i] = *src_buf++;
- dest_add++;
- nbytes--;
- }
- flash_add++;
- }
- // Write the flash double-word buffer to the page buffer.
- *(volatile uint64_t*)((uint32_t)flash_add - sizeof(uint64_t))= flash_dword.u64;
- }
- // Erase the current page if requested and write it from the page buffer.
- if (erase) {
- (b_user_page)? flashc_erase_user_page(false) : flashc_erase_page(-1, false);
- error_status |= flashc_error_status;
- }
- // Write the page
- (b_user_page)? flashc_write_user_page() : flashc_write_page(-1);
- error_status |= flashc_error_status;
- }
- // Update the FLASHC error status.
- flashc_error_status = error_status;
- // Return the initial destination pointer as the standard memcpy function does.
- return dst;
- }
- #if UC3C
- void flashc_set_flash_waitstate_and_readmode(unsigned long cpu_f_hz)
- {
- //! Device-specific data
- #undef AVR32_FLASHC_FWS_0_MAX_FREQ
- #undef AVR32_FLASHC_FWS_1_MAX_FREQ
- #undef AVR32_FLASHC_HSEN_FWS_0_MAX_FREQ
- #undef AVR32_FLASHC_HSEN_FWS_1_MAX_FREQ
- #define AVR32_FLASHC_FWS_0_MAX_FREQ 33000000
- #define AVR32_FLASHC_FWS_1_MAX_FREQ 66000000
- #define AVR32_FLASHC_HSEN_FWS_0_MAX_FREQ 33000000
- #define AVR32_FLASHC_HSEN_FWS_1_MAX_FREQ 72000000
- // These defines are missing from or wrong in the toolchain header files uc3cxxx.h
- // Put a Bugzilla
- if (cpu_f_hz > AVR32_FLASHC_HSEN_FWS_0_MAX_FREQ) { // > 33MHz
- // Set a wait-state
- flashc_set_wait_state(1);
- if (cpu_f_hz <= AVR32_FLASHC_FWS_1_MAX_FREQ) { // <= 66MHz and >33Mhz
- // Disable the high-speed read mode.
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSDIS, -1);
- } else { // > 66Mhz
- // Enable the high-speed read mode.
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSEN, -1);
- }
- } else { // <= 33 MHz
- // Disable wait-state
- flashc_set_wait_state(0);
- // Disable the high-speed read mode.
- flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSDIS, -1);
- }
- }
- #endif // UC3C device-specific implementation
- //! @}
|