| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- /*!
- * Copyright (C) 2007 by egnite Software GmbH. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- */
- /*!
- * \file avrtarget.c
- * \brief External AVR device programming.
- *
- * \verbatim
- *
- * $Log$
- * Revision 1.3 2009/01/17 11:26:46 haraldkipp
- * Getting rid of two remaining BSD types in favor of stdint.
- * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
- *
- * Revision 1.2 2008/08/11 06:59:41 haraldkipp
- * BSD types replaced by stdint types (feature request #1282721).
- *
- * Revision 1.1 2007/04/12 09:01:38 haraldkipp
- * New API allows to program external AVR devices.
- *
- *
- * \endverbatim
- */
- #include <sys/timer.h>
- #include <dev/avrtarget.h>
- /*!
- * \addtogroup xgAvrTarget
- */
- /*@{*/
- #ifndef AVRTARGET_CHIPERASE_TIMEOUT
- /*!
- * \brief Maximum time (in milliseconds) to wait for chip erase done.
- */
- #define AVRTARGET_CHIPERASE_TIMEOUT 200
- #endif
- #ifndef AVRTARGET_PAGEWRITE_TIMEOUT
- /*!
- * \brief Maximum time (in milliseconds) to wait for page write done.
- */
- #define AVRTARGET_PAGEWRITE_TIMEOUT 10
- #endif
- /*!
- * \brief Safe fuse programming mask.
- *
- * If a bit is set in this mask, the corresponding fuse should
- * never be programmed to 0.
- *
- * Used in AvrTargetFusesWriteSafe() to avoid dead chips. However,
- * it is still possible to break hardware. Triple check any new
- * fuse configuration.
- *
- * This unsigned long value is interpreted as follows:
- *
- * - Least significant byte is fuse low byte.
- * - Second byte is fuse high byte.
- * - Third byte is fuse extended byte.
- * - Most significant byte is not used.
- */
- #define AVR_FUSES_NEVER_PROG 0x00F88062UL
- /*!
- * \brief Safe fuse unprogramming mask.
- *
- * If a bit is set in this mask, the corresponding fuse should
- * never be left unprogrammed (set to 1).
- *
- * Used in AvrTargetFusesWriteSafe() to avoid dead chips. However,
- * it is still possible to break hardware. Triple check any new
- * fuse configuration.
- *
- * This unsigned long value is interpreted as follows:
- *
- * - Least significant byte is fuse low byte.
- * - Second byte is fuse high byte.
- * - Third byte is fuse extended byte.
- * - Most significant byte is not used.
- */
- #define AVR_FUSES_ALWAYS_PROG 0x0000201DUL
- #ifndef AVRTARGET_SPI_MODE
- #define AVRTARGET_SPI_MODE 0
- #endif
- #ifndef AVRTARGET_SPI_RATE
- #define AVRTARGET_SPI_RATE 500000
- #endif
- #if defined(AVRTARGET_SPI0_DEVICE) /* SPI device. */
- #include <dev/sppif0.h>
- #if defined(AVRTARGET_SELECT_ACTIVE_HIGH)
- #define TargetReset(act) Sppi0ChipReset(AVRTARGET_SPI0_DEVICE, act)
- #else
- #define TargetReset(act) Sppi0ChipReset(AVRTARGET_SPI0_DEVICE, !act)
- #endif
- #define SpiSetMode() Sppi0SetMode(AVRTARGET_SPI0_DEVICE, AVRTARGET_SPI_MODE)
- #define SpiSetSpeed() Sppi0SetSpeed(AVRTARGET_SPI0_DEVICE, AVRTARGET_SPI_RATE)
- #if defined(AVRTARGET_SELECT_ACTIVE_HIGH)
- #define SpiSelect() Sppi0SelectDevice(AVRTARGET_SPI0_DEVICE)
- #define SpiDeselect() Sppi0DeselectDevice(AVRTARGET_SPI0_DEVICE)
- #else
- #define SpiSelect() Sppi0NegSelectDevice(AVRTARGET_SPI0_DEVICE)
- #define SpiDeselect() Sppi0NegDeselectDevice(AVRTARGET_SPI0_DEVICE)
- #endif
- #define SpiByte Sppi0Byte
- #elif defined(AVRTARGET_SBBI0_DEVICE) /* SPI device. */
- #include <dev/sbbif0.h>
- #if defined(AVRTARGET_SELECT_ACTIVE_HIGH)
- #define TargetReset(act) Sbbi0ChipReset(AVRTARGET_SBBI0_DEVICE, act)
- #else
- #define TargetReset(act) Sbbi0ChipReset(AVRTARGET_SBBI0_DEVICE, !act)
- #endif
- #define SpiSetMode() Sbbi0SetMode(AVRTARGET_SBBI0_DEVICE, AVRTARGET_SPI_MODE)
- #define SpiSetSpeed() Sbbi0SetSpeed(AVRTARGET_SBBI0_DEVICE, AVRTARGET_SPI_RATE)
- #if defined(AVRTARGET_SELECT_ACTIVE_HIGH)
- #define SpiSelect() Sbbi0SelectDevice(AVRTARGET_SBBI0_DEVICE)
- #define SpiDeselect() Sbbi0DeselectDevice(AVRTARGET_SBBI0_DEVICE)
- #else
- #define SpiSelect() Sbbi0NegSelectDevice(AVRTARGET_SBBI0_DEVICE)
- #define SpiDeselect() Sbbi0NegDeselectDevice(AVRTARGET_SBBI0_DEVICE)
- #endif
- #define SpiByte Sbbi0Byte
- #elif defined(AVRTARGET_SBBI1_DEVICE) /* SPI device. */
- #include <dev/sbbif1.h>
- #if defined(AVRTARGET_SELECT_ACTIVE_HIGH)
- #define TargetReset(act) Sbbi1ChipReset(AVRTARGET_SBBI1_DEVICE, act)
- #else
- #define TargetReset(act) Sbbi1ChipReset(AVRTARGET_SBBI1_DEVICE, !act)
- #endif
- #define SpiSetMode() Sbbi1SetMode(AVRTARGET_SBBI1_DEVICE, AVRTARGET_SPI_MODE)
- #define SpiSetSpeed() Sbbi1SetSpeed(AVRTARGET_SBBI1_DEVICE, AVRTARGET_SPI_RATE)
- #if defined(AVRTARGET_SELECT_ACTIVE_HIGH)
- #define SpiSelect() Sbbi1SelectDevice(AVRTARGET_SBBI1_DEVICE)
- #define SpiDeselect() Sbbi1DeselectDevice(AVRTARGET_SBBI1_DEVICE)
- #else
- #define SpiSelect() Sbbi1NegSelectDevice(AVRTARGET_SBBI1_DEVICE)
- #define SpiDeselect() Sbbi1NegDeselectDevice(AVRTARGET_SBBI1_DEVICE)
- #endif
- #define SpiByte Sbbi1Byte
- #elif defined(AVRTARGET_SBBI2_DEVICE) /* SPI device. */
- #include <dev/sbbif2.h>
- #if defined(AVRTARGET_SELECT_ACTIVE_HIGH)
- #define TargetReset(act) Sbbi2ChipReset(AVRTARGET_SBBI2_DEVICE, act)
- #else
- #define TargetReset(act) Sbbi2ChipReset(AVRTARGET_SBBI2_DEVICE, !act)
- #endif
- #define SpiSetMode() Sbbi2SetMode(AVRTARGET_SBBI2_DEVICE, AVRTARGET_SPI_MODE)
- #define SpiSetSpeed() Sbbi2SetSpeed(AVRTARGET_SBBI2_DEVICE, AVRTARGET_SPI_RATE)
- #if defined(AVRTARGET_SELECT_ACTIVE_HIGH)
- #define SpiSelect() Sbbi2SelectDevice(AVRTARGET_SBBI2_DEVICE)
- #define SpiDeselect() Sbbi2DeselectDevice(AVRTARGET_SBBI2_DEVICE)
- #else
- #define SpiSelect() Sbbi2NegSelectDevice(AVRTARGET_SBBI2_DEVICE)
- #define SpiDeselect() Sbbi2NegDeselectDevice(AVRTARGET_SBBI2_DEVICE)
- #endif
- #define SpiByte Sbbi2Byte
- #elif defined(AVRTARGET_SBBI3_DEVICE) /* SPI device. */
- #include <dev/sbbif3.h>
- #if defined(AVRTARGET_SELECT_ACTIVE_HIGH)
- #define TargetReset(act) Sbbi3ChipReset(AVRTARGET_SBBI3_DEVICE, act)
- #else
- #define TargetReset(act) Sbbi3ChipReset(AVRTARGET_SBBI3_DEVICE, !act)
- #endif
- #define SpiSetMode() Sbbi3SetMode(AVRTARGET_SBBI3_DEVICE, AVRTARGET_SPI_MODE)
- #define SpiSetSpeed() Sbbi3SetSpeed(AVRTARGET_SBBI3_DEVICE, AVRTARGET_SPI_RATE)
- #if defined(AVRTARGET_SELECT_ACTIVE_HIGH)
- #define SpiSelect() Sbbi3SelectDevice(AVRTARGET_SBBI3_DEVICE)
- #define SpiDeselect() Sbbi3DeselectDevice(AVRTARGET_SBBI3_DEVICE)
- #else
- #define SpiSelect() Sbbi3NegSelectDevice(AVRTARGET_SBBI3_DEVICE)
- #define SpiDeselect() Sbbi3NegDeselectDevice(AVRTARGET_SBBI3_DEVICE)
- #endif
- #define SpiByte Sbbi3Byte
- #else /* SPI device. */
- #define AVRTARGET_NO_SPI_DEVICE
- #endif /* SPI device. */
- /*!
- * \brief Initialize programming interface.
- *
- * Sets the configured SPI mode and rate. This must be called before
- * using any other routine in this module.
- *
- * \return 0 on success, -1 otherwise.
- */
- int AvrTargetInit(void)
- {
- #if defined(AVRTARGET_NO_SPI_DEVICE)
- return -1;
- #else
- if (SpiSetMode()) {
- return -1;
- }
- SpiSetSpeed();
- SpiDeselect();
- return 0;
- #endif
- }
- /*!
- * \brief Set or clear the chip select line.
- *
- * Must be called before sending programming commands to the target device,
- * even if no chip selects are implemented by the hardware. Beside activating
- * an optional chip select, this routine will also properly initialize the
- * SPI hardware.
- *
- * \param act When 0, the chip will be deactivated and the serial peripheral
- * interface may be used to communicate with another device.
- * When not 0, the SPI bus is allocated for the attached AVR target.
- */
- void AvrTargetSelect(ureg_t act)
- {
- #if !defined(AVRTARGET_NO_SPI_DEVICE)
- if (act) {
- SpiSelect();
- } else {
- SpiDeselect();
- }
- #endif
- }
- /*!
- * \brief Set or release the target's reset line.
- *
- * The target must be held in reset state during programming.
- *
- * \param on When not 0, the reset line will be activated.
- */
- void AvrTargetReset(ureg_t act)
- {
- #if !defined(AVRTARGET_NO_SPI_DEVICE)
- TargetReset(act);
- #endif
- }
- /*!
- * \brief Send programming command and return response.
- *
- * \param cmd 4-byte command.
- *
- * \return 4-byte response.
- */
- uint32_t AvrTargetCmd(uint32_t cmd)
- {
- uint32_t rc = 0;
- #if !defined(AVRTARGET_NO_SPI_DEVICE)
- ureg_t i;
- for (i = 0; i < 4; i++) {
- rc <<= 8;
- rc |= SpiByte((uint8_t) (cmd >> 24));
- cmd <<= 8;
- }
- #endif
- return rc;
- }
- /*!
- * \brief Enable target's programming mode.
- *
- * \return 0 on success, -1 otherwise.
- */
- int AvrTargetProgEnable(void)
- {
- #if defined(AVRTARGET_NO_SPI_DEVICE)
- return -1;
- #else
- if ((uint8_t) (AvrTargetCmd(AVRCMD_PROG_ENABLE) >> 8) != 0x53) {
- return -1;
- }
- return 0;
- #endif
- }
- /*!
- * \brief Retrieve the target's signature.
- *
- * \return Signature in the 3 least significant bytes.
- */
- uint32_t AvrTargetSignature(void)
- {
- uint32_t rc = 0;
- #if !defined(AVRTARGET_NO_SPI_DEVICE)
- ureg_t i;
- for (i = 0; i < 3; i++) {
- rc <<= 8;
- rc |= (uint8_t) AvrTargetCmd(AVRCMD_READ_SIGNATURE_BYTE | ((uint32_t) i << 8));
- }
- #endif
- return rc;
- }
- /*!
- * \brief Retrieve the target's fuses.
- *
- * \return Fuse bits in the 3 least significant bytes.
- */
- uint32_t AvrTargetFusesRead(void)
- {
- uint32_t rc = 0;
- rc = (uint8_t) AvrTargetCmd(AVRCMD_READ_FUSE_EXT_BITS);
- rc <<= 8;
- rc |= (uint8_t) AvrTargetCmd(AVRCMD_READ_FUSE_HI_BITS);
- rc <<= 8;
- rc |= (uint8_t) AvrTargetCmd(AVRCMD_READ_FUSE_BITS);
- return rc;
- }
- /*!
- * \brief Program the target's fuses in a safe way.
- *
- * Fuses with corresponding bits set in \ref AVR_FUSES_NEVER_PROG will
- * never be programmed. Fuses with corresponding bits set in
- * \ref AVR_FUSES_ALWAYS_PROG will always be programmed.
- *
- * \param fuses Fuse bits are expected in the 3 least significant bytes,
- * Lower fuses in the LSB, followed by the high fuses and
- * last no least the extended fuses.
- */
- uint32_t AvrTargetFusesWriteSafe(uint32_t fuses)
- {
- uint32_t rc;
- fuses |= AVR_FUSES_NEVER_PROG;
- fuses &= ~AVR_FUSES_ALWAYS_PROG;
- rc = fuses;
- AvrTargetCmd(AVRCMD_WRITE_FUSE_BITS | (uint8_t)fuses);
- fuses >>= 8;
- AvrTargetCmd(AVRCMD_WRITE_FUSE_HI_BITS | (uint8_t)fuses);
- fuses >>= 8;
- AvrTargetCmd(AVRCMD_WRITE_FUSE_EXT_BITS | (uint8_t)fuses);
- fuses >>= 8;
- return rc;
- }
- /*!
- * \brief Poll target for becoming ready.
- *
- * May switch to another thread while waiting. After switching back to
- * the calling thread, the SPI is re-selected.
- *
- * \param tmo Maximum number of milliseconds to wait.
- *
- * \return 0 on success, -1 on time out.
- */
- int AvrTargetPollReady(unsigned int tmo)
- {
- #if !defined(AVRTARGET_NO_SPI_DEVICE)
- while (AvrTargetCmd(AVRCMD_POLL_READY) & 1UL) {
- if (tmo-- == 0) {
- return -1;
- }
- NutSleep(1);
- /* We may have lost the SPI. */
- SpiSelect();
- }
- #endif
- return 0;
- }
- /*!
- * \brief Erase the target chip.
- *
- * Be aware, that this routine calls AvrTargetPollReady(), which may
- * initiate a context switch while waiting for the erase to finish.
- *
- * \return 0 on success, -1 on time out.
- */
- int AvrTargetChipErase(void)
- {
- AvrTargetCmd(AVRCMD_CHIP_ERASE);
- return AvrTargetPollReady(AVRTARGET_CHIPERASE_TIMEOUT);
- }
- /*!
- * \brief Load target's program memory page buffer.
- *
- * \param page Program memory page number.
- * \param data Points to the data.
- *
- */
- void AvrTargetPageLoad(uint32_t page, const uint8_t * data)
- {
- ureg_t bc;
- page <<= 6;
- for (bc = 0; bc < (AVRTARGET_PAGESIZE / 2); bc++) {
- AvrTargetCmd(AVRCMD_LOAD_PROG_MEM_PAGE_LO | (page << 8) | *data);
- data++;
- AvrTargetCmd(AVRCMD_LOAD_PROG_MEM_PAGE_HI | (page << 8) | *data);
- data++;
- page++;
- }
- }
- /*!
- * \brief Write page buffer contents to program memory.
- *
- * Calls AvrTargetPollReady(), which may initiate a context switch
- * while waiting for the page write to finish.
- *
- * \param page Program memory page number.
- *
- * \return 0 on success, -1 on time out.
- */
- int AvrTargetPageWrite(uint32_t page)
- {
- AvrTargetCmd(AVRCMD_WRITE_PROG_MEM_PAGE | (page << 14));
- return AvrTargetPollReady(AVRTARGET_PAGEWRITE_TIMEOUT);
- }
- /*!
- * \brief Verify program memory page contents.
- *
- * \param page Program memory page number.
- * \param data Points to a buffer with the expected contents.
- *
- * \return 0 if the buffer contents equals the memory page contents or
- * -1 if it doesn't.
- */
- int AvrTargetPageVerify(uint32_t page, const uint8_t * data)
- {
- uint32_t waddr = page << 6;
- ureg_t bc;
- for (bc = 0; bc < (AVRTARGET_PAGESIZE / 2); bc++) {
- if ((uint8_t) AvrTargetCmd(AVRCMD_READ_PROG_MEM_LO | (waddr << 8)) != *data++) {
- return -1;
- }
- if ((uint8_t) AvrTargetCmd(AVRCMD_READ_PROG_MEM_HI | (waddr << 8)) != *data++) {
- return -1;
- }
- waddr++;
- }
- return 0;
- }
- /*@}*/
|