From 93717e43b38348821b32cd476c1ab87b1bed9edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Redon?= Date: Sun, 8 Jul 2018 13:26:15 +0200 Subject: [PATCH] set linux end of line Change-Id: I5200f0d6f39b0641cac26a4109a3cd33e8474b9b --- .../libchip_sam3s/include/efc.h | 226 +- .../libchip_sam3s/include/flashd.h | 158 +- .../libchip_sam3s/source/USBD_HAL.c | 3424 ++++++++--------- .../libchip_sam3s/source/efc.c | 580 +-- .../libchip_sam3s/source/exceptions.c | 1010 ++--- .../libchip_sam3s/source/flashd.c | 1034 ++--- .../libchip_sam3s/source/pio.c | 906 ++--- .../libchip_sam3s/source/pio_it.c | 630 +-- .../libchip_sam3s/source/pmc.c | 336 +- .../libchip_sam3s/source/spi.c | 704 ++-- .../libchip_sam3s/source/tc.c | 350 +- .../libchip_sam3s/source/usart.c | 820 ++-- .../libchip_sam3s/source/wdt.c | 264 +- .../common/source/board_cstartup_gnu.c | 416 +- .../libboard/common/source/board_lowlevel.c | 432 +-- .../libboard/common/source/uart_console.c | 852 ++-- 16 files changed, 6071 insertions(+), 6071 deletions(-) diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/include/efc.h b/firmware/atmel_softpack_libraries/libchip_sam3s/include/efc.h index 0a99633d..faafd477 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/include/efc.h +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/include/efc.h @@ -1,113 +1,113 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** - * \file - * - * \section Purpose - * - * Interface for configuration the Enhanced Embedded Flash Controller (EEFC) peripheral. - * - * \section Usage - * - * -# Enable/disable %flash ready interrupt sources using EFC_EnableFrdyIt() - * and EFC_DisableFrdyIt(). - * -# Translates the given address into which EEFC, page and offset values - * for difference density %flash memory using EFC_TranslateAddress(). - * -# Computes the address of a %flash access given the EFC, page and offset - * for difference density %flash memory using EFC_ComputeAddress(). - * -# Start the executing command with EFC_StartCommand() - * -# Retrieve the current status of the EFC using EFC_GetStatus(). - * -# Retrieve the result of the last executed command with EFC_GetResult(). - */ - -#ifndef _EEFC_ -#define _EEFC_ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ -#include "chip.h" - -#include - -/*---------------------------------------------------------------------------- - * Definitions - *----------------------------------------------------------------------------*/ -/* EFC command */ -#define EFC_FCMD_GETD 0x00 -#define EFC_FCMD_WP 0x01 -#define EFC_FCMD_WPL 0x02 -#define EFC_FCMD_EWP 0x03 -#define EFC_FCMD_EWPL 0x04 -#define EFC_FCMD_EA 0x05 -#define EFC_FCMD_SLB 0x08 -#define EFC_FCMD_CLB 0x09 -#define EFC_FCMD_GLB 0x0A -#define EFC_FCMD_SFB 0x0B -#define EFC_FCMD_CFB 0x0C -#define EFC_FCMD_GFB 0x0D -#define EFC_FCMD_STUI 0x0E /* Start unique ID */ -#define EFC_FCMD_SPUI 0x0F /* Stop unique ID */ - -/* The IAP function entry addreass */ -#define CHIP_FLASH_IAP_ADDRESS (0x00800008) - -#ifdef __cplusplus - extern "C" { -#endif - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ - -extern void EFC_EnableFrdyIt( Efc* efc ) ; - -extern void EFC_DisableFrdyIt( Efc* efc ) ; - -extern void EFC_SetWaitState( Efc* efc, uint8_t cycles ) ; - -extern void EFC_TranslateAddress( Efc** pEfc, uint32_t dwAddress, uint16_t *pwPage, uint16_t *pwOffset ) ; - -extern void EFC_ComputeAddress( Efc* efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress ) ; - -extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument ) ; - -extern uint32_t EFC_PerformCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument, uint32_t dwUseIAP ) ; - -extern uint32_t EFC_GetStatus( Efc* efc ) ; - -extern uint32_t EFC_GetResult( Efc* efc ) ; - -#ifdef __cplusplus -} -#endif - -#endif /* #ifndef _EEFC_ */ - +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** + * \file + * + * \section Purpose + * + * Interface for configuration the Enhanced Embedded Flash Controller (EEFC) peripheral. + * + * \section Usage + * + * -# Enable/disable %flash ready interrupt sources using EFC_EnableFrdyIt() + * and EFC_DisableFrdyIt(). + * -# Translates the given address into which EEFC, page and offset values + * for difference density %flash memory using EFC_TranslateAddress(). + * -# Computes the address of a %flash access given the EFC, page and offset + * for difference density %flash memory using EFC_ComputeAddress(). + * -# Start the executing command with EFC_StartCommand() + * -# Retrieve the current status of the EFC using EFC_GetStatus(). + * -# Retrieve the result of the last executed command with EFC_GetResult(). + */ + +#ifndef _EEFC_ +#define _EEFC_ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ +#include "chip.h" + +#include + +/*---------------------------------------------------------------------------- + * Definitions + *----------------------------------------------------------------------------*/ +/* EFC command */ +#define EFC_FCMD_GETD 0x00 +#define EFC_FCMD_WP 0x01 +#define EFC_FCMD_WPL 0x02 +#define EFC_FCMD_EWP 0x03 +#define EFC_FCMD_EWPL 0x04 +#define EFC_FCMD_EA 0x05 +#define EFC_FCMD_SLB 0x08 +#define EFC_FCMD_CLB 0x09 +#define EFC_FCMD_GLB 0x0A +#define EFC_FCMD_SFB 0x0B +#define EFC_FCMD_CFB 0x0C +#define EFC_FCMD_GFB 0x0D +#define EFC_FCMD_STUI 0x0E /* Start unique ID */ +#define EFC_FCMD_SPUI 0x0F /* Stop unique ID */ + +/* The IAP function entry addreass */ +#define CHIP_FLASH_IAP_ADDRESS (0x00800008) + +#ifdef __cplusplus + extern "C" { +#endif + +/*---------------------------------------------------------------------------- + * Exported functions + *----------------------------------------------------------------------------*/ + +extern void EFC_EnableFrdyIt( Efc* efc ) ; + +extern void EFC_DisableFrdyIt( Efc* efc ) ; + +extern void EFC_SetWaitState( Efc* efc, uint8_t cycles ) ; + +extern void EFC_TranslateAddress( Efc** pEfc, uint32_t dwAddress, uint16_t *pwPage, uint16_t *pwOffset ) ; + +extern void EFC_ComputeAddress( Efc* efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress ) ; + +extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument ) ; + +extern uint32_t EFC_PerformCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument, uint32_t dwUseIAP ) ; + +extern uint32_t EFC_GetStatus( Efc* efc ) ; + +extern uint32_t EFC_GetResult( Efc* efc ) ; + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef _EEFC_ */ + diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/include/flashd.h b/firmware/atmel_softpack_libraries/libchip_sam3s/include/flashd.h index e58ba029..f4bece4c 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/include/flashd.h +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/include/flashd.h @@ -1,79 +1,79 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- -*/ - -/** - * \file - * - * The flash driver provides the unified interface for flash program operations. - * - */ - -#ifndef _FLASHD_ -#define _FLASHD_ - -#include - -#ifdef __cplusplus - extern "C" { -#endif - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ - -extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP ) ; - -extern uint32_t FLASHD_Erase( uint32_t dwAddress ) ; - -extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize ) ; - -extern uint32_t FLASHD_Lock( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) ; - -extern uint32_t FLASHD_Unlock( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) ; - -extern uint32_t FLASHD_IsLocked( uint32_t dwStart, uint32_t dwEnd ) ; - -extern uint32_t FLASHD_SetGPNVM( uint8_t gpnvm ) ; - -extern uint32_t FLASHD_ClearGPNVM( uint8_t gpnvm ) ; - -extern uint32_t FLASHD_IsGPNVMSet( uint8_t gpnvm ) ; - -#define FLASHD_IsSecurityBitSet() FLASHD_IsGPNVMSet( 0 ) - -#define FLASHD_SetSecurityBit() FLASHD_SetGPNVM( 0 ) - -extern uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID ) ; - -#ifdef __cplusplus -} -#endif - -#endif /* #ifndef _FLASHD_ */ - +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- +*/ + +/** + * \file + * + * The flash driver provides the unified interface for flash program operations. + * + */ + +#ifndef _FLASHD_ +#define _FLASHD_ + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/*---------------------------------------------------------------------------- + * Exported functions + *----------------------------------------------------------------------------*/ + +extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP ) ; + +extern uint32_t FLASHD_Erase( uint32_t dwAddress ) ; + +extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize ) ; + +extern uint32_t FLASHD_Lock( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) ; + +extern uint32_t FLASHD_Unlock( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) ; + +extern uint32_t FLASHD_IsLocked( uint32_t dwStart, uint32_t dwEnd ) ; + +extern uint32_t FLASHD_SetGPNVM( uint8_t gpnvm ) ; + +extern uint32_t FLASHD_ClearGPNVM( uint8_t gpnvm ) ; + +extern uint32_t FLASHD_IsGPNVMSet( uint8_t gpnvm ) ; + +#define FLASHD_IsSecurityBitSet() FLASHD_IsGPNVMSet( 0 ) + +#define FLASHD_SetSecurityBit() FLASHD_SetGPNVM( 0 ) + +extern uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID ) ; + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef _FLASHD_ */ + diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c index 3fa4c64b..2f566023 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c @@ -1,1712 +1,1712 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2008, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** - - \file - - \section Purpose - - Implementation of USB device functions on a UDP controller. - - See \ref usbd_api_method USBD API Methods. -*/ - -/** \addtogroup usbd_hal - *@{*/ - -/*--------------------------------------------------------------------------- - * Headers - *---------------------------------------------------------------------------*/ - -#ifdef TRACE_LEVEL -#undef TRACE_LEVEL -#endif -#define TRACE_LEVEL TRACE_LEVEL_WARNING - -#include "chip.h" -#include "USBD_HAL.h" -#include - -#include -#include -#include - -/*--------------------------------------------------------------------------- - * Definitions - *---------------------------------------------------------------------------*/ - -/** Indicates chip has an UDP Full Speed. */ -#define CHIP_USB_UDP - -/** Indicates chip has an internal pull-up. */ -#define CHIP_USB_PULLUP_INTERNAL - -/** Number of USB endpoints */ -#define CHIP_USB_NUMENDPOINTS 8 - -/** Endpoints max paxcket size */ -#define CHIP_USB_ENDPOINTS_MAXPACKETSIZE(i) \ - ((i == 0) ? 64 : \ - ((i == 1) ? 64 : \ - ((i == 2) ? 64 : \ - ((i == 3) ? 64 : \ - ((i == 4) ? 512 : \ - ((i == 5) ? 512 : \ - ((i == 6) ? 64 : \ - ((i == 7) ? 64 : 0 )))))))) - -/** Endpoints Number of Bank */ -#define CHIP_USB_ENDPOINTS_BANKS(i) \ - ((i == 0) ? 1 : \ - ((i == 1) ? 2 : \ - ((i == 2) ? 2 : \ - ((i == 3) ? 1 : \ - ((i == 4) ? 2 : \ - ((i == 5) ? 2 : \ - ((i == 6) ? 2 : \ - ((i == 7) ? 2 : 0 )))))))) - -/** - * \section UDP_registers_sec "UDP Register field values" - * - * This section lists the initialize values of UDP registers. - * - * \subsection Values - * - UDP_RXDATA - */ -/** Bit mask for both banks of the UDP_CSR register. */ -#define UDP_CSR_RXDATA_BK (UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1) - -/** - * \section endpoint_states_sec "UDP Endpoint states" - * - * This page lists the endpoint states. - * - * \subsection States - * - UDP_ENDPOINT_DISABLED - * - UDP_ENDPOINT_HALTED - * - UDP_ENDPOINT_IDLE - * - UDP_ENDPOINT_SENDING - * - UDP_ENDPOINT_RECEIVING - * - UDP_ENDPOINT_SENDINGM - * - UDP_ENDPOINT_RECEIVINGM - */ - -/** Endpoint states: Endpoint is disabled */ -#define UDP_ENDPOINT_DISABLED 0 -/** Endpoint states: Endpoint is halted (i.e. STALLs every request) */ -#define UDP_ENDPOINT_HALTED 1 -/** Endpoint states: Endpoint is idle (i.e. ready for transmission) */ -#define UDP_ENDPOINT_IDLE 2 -/** Endpoint states: Endpoint is sending data */ -#define UDP_ENDPOINT_SENDING 3 -/** Endpoint states: Endpoint is receiving data */ -#define UDP_ENDPOINT_RECEIVING 4 -/** Endpoint states: Endpoint is sending MBL */ -#define UDP_ENDPOINT_SENDINGM 5 -/** Endpoint states: Endpoint is receiving MBL */ -#define UDP_ENDPOINT_RECEIVINGM 6 - -/** - * \section udp_csr_register_access_sec "UDP CSR register access" - * - * This page lists the macros to access UDP CSR register. - * - * \comment - * In a preemptive environment, set or clear the flag and wait for a time of - * 1 UDPCK clock cycle and 1 peripheral clock cycle. However, RX_DATA_BK0, - * TXPKTRDY, RX_DATA_BK1 require wait times of 3 UDPCK clock cycles and - * 5 peripheral clock cycles before accessing DPR. - * See datasheet - * - * !Macros - * - CLEAR_CSR - * - SET_CSR - */ - -#if defined ( __CC_ARM ) - #define nop() {volatile int h; for(h=0;h<10;h++){}} -#elif defined ( __ICCARM__ ) - #include - #define nop() (__no_operation()) -#elif defined ( __GNUC__ ) - #define nop() __asm__ __volatile__ ( "nop" ) -#endif - - -/** Bitmap for all status bits in CSR. */ -#define REG_NO_EFFECT_1_ALL UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1 \ - |UDP_CSR_STALLSENTISOERROR | UDP_CSR_RXSETUP \ - |UDP_CSR_TXCOMP - -/** - * Sets the specified bit(s) in the UDP_CSR register. - * - * \param endpoint The endpoint number of the CSR to process. - * \param flags The bitmap to set to 1. - */ -#define SET_CSR(endpoint, flags) \ - { \ - volatile uint32_t reg; \ - int32_t nop_count ; \ - reg = UDP->UDP_CSR[endpoint] ; \ - reg |= REG_NO_EFFECT_1_ALL; \ - reg |= (flags); \ - UDP->UDP_CSR[endpoint] = reg; \ - for( nop_count=0; nop_count<15; nop_count++ ) {\ - nop();\ - }\ - } - -/** - * Clears the specified bit(s) in the UDP_CSR register. - * - * \param endpoint The endpoint number of the CSR to process. - * \param flags The bitmap to clear to 0. - */ -#define CLEAR_CSR(endpoint, flags) \ -{ \ - volatile uint32_t reg; \ - int32_t nop_count ; \ - reg = UDP->UDP_CSR[endpoint]; \ - reg |= REG_NO_EFFECT_1_ALL; \ - reg &= ~((uint32_t)(flags)); \ - UDP->UDP_CSR[endpoint] = reg; \ - for( nop_count=0; nop_count<15; nop_count++ ) {\ - nop();\ - }\ -} - - -/** Get Number of buffer in Multi-Buffer-List - * \param i input index - * \param o output index - * \param size list size - */ -#define MBL_NbBuffer(i, o, size) (((i)>(o))?((i)-(o)):((i)+(size)-(o))) - -/** Buffer list is full */ -#define MBL_FULL 1 -/** Buffer list is null */ -#define MBL_NULL 2 - -/*--------------------------------------------------------------------------- - * Types - *---------------------------------------------------------------------------*/ - -/** Describes header for UDP endpoint transfer. */ -typedef struct { - /** Optional callback to invoke when the transfer completes. */ - void* fCallback; - /** Optional argument to the callback function. */ - void* pArgument; - /** Transfer type */ - uint8_t transType; -} TransferHeader; - -/** Describes a transfer on a UDP endpoint. */ -typedef struct { - - /** Optional callback to invoke when the transfer completes. */ - TransferCallback fCallback; - /** Optional argument to the callback function. */ - void *pArgument; - /** Transfer type */ - uint16_t transType; - /** Number of bytes which have been written into the UDP internal FIFO - * buffers. */ - int16_t buffered; - /** Pointer to a data buffer used for emission/reception. */ - uint8_t *pData; - /** Number of bytes which have been sent/received. */ - int32_t transferred; - /** Number of bytes which have not been buffered/transferred yet. */ - int32_t remaining; -} Transfer; - -/** Describes Multi Buffer List transfer on a UDP endpoint. */ -typedef struct { - /** Optional callback to invoke when the transfer completes. */ - MblTransferCallback fCallback; - /** Optional argument to the callback function. */ - void *pArgument; - /** Transfer type */ - volatile uint8_t transType; - /** List state (OK, FULL, NULL) (run time) */ - uint8_t listState; - /** Multi-Buffer List size */ - uint16_t listSize; - /** Pointer to multi-buffer list */ - USBDTransferBuffer *pMbl; - /** Offset number of buffers to start transfer */ - uint16_t offsetSize; - /** Current processing buffer index (run time) */ - uint16_t outCurr; - /** Loast loaded buffer index (run time) */ - uint16_t outLast; - /** Current buffer for input (run time) */ - uint16_t inCurr; -} MblTransfer; - -/** - * Describes the state of an endpoint of the UDP controller. - */ -typedef struct { - - /* CSR */ - //uint32_t CSR; - /** Current endpoint state. */ - volatile uint8_t state; - /** Current reception bank (0 or 1). */ - volatile uint8_t bank; - /** Maximum packet size for the endpoint. */ - volatile uint16_t size; - /** Describes an ongoing transfer (if current state is either - * UDP_ENDPOINT_SENDING or UDP_ENDPOINT_RECEIVING) */ - union { - TransferHeader transHdr; - Transfer singleTransfer; - MblTransfer mblTransfer; - } transfer; -} Endpoint; - -/*--------------------------------------------------------------------------- - * Internal variables - *---------------------------------------------------------------------------*/ - -/** Holds the internal state for each endpoint of the UDP. */ -static Endpoint endpoints[CHIP_USB_NUMENDPOINTS]; - -/*--------------------------------------------------------------------------- - * Internal Functions - *---------------------------------------------------------------------------*/ - -/** - * Enables the clock of the UDP peripheral. - * \return 1 if peripheral status changed. - */ -static uint8_t UDP_EnablePeripheralClock(void) -{ - if (!PMC_IsPeriphEnabled(ID_UDP)) { - PMC_EnablePeripheral(ID_UDP); - return 1; - } - return 0; -} - -/** - * Disables the UDP peripheral clock. - */ -static inline void UDP_DisablePeripheralClock(void) -{ - PMC_DisablePeripheral(ID_UDP); -} - -/** - * Enables the 48MHz USB clock. - */ -static inline void UDP_EnableUsbClock(void) -{ - REG_PMC_SCER = PMC_SCER_UDP; -} - -/** - * Disables the 48MHz USB clock. - */ -static inline void UDP_DisableUsbClock(void) -{ - REG_PMC_SCDR = PMC_SCER_UDP; -} - -/** - * Enables the UDP transceiver. - */ -static inline void UDP_EnableTransceiver(void) -{ - UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_TXVDIS; -} - -/** - * Disables the UDP transceiver. - */ -static inline void UDP_DisableTransceiver(void) -{ - UDP->UDP_TXVC |= UDP_TXVC_TXVDIS; -} - -/** - * Handles a completed transfer on the given endpoint, invoking the - * configured callback if any. - * \param bEndpoint Number of the endpoint for which the transfer has completed. - * \param bStatus Status code returned by the transfer operation - */ -static void UDP_EndOfTransfer(uint8_t bEndpoint, uint8_t bStatus) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - - // Check that endpoint was sending or receiving data - if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING) - || (pEndpoint->state == UDP_ENDPOINT_SENDING)) { - - Transfer *pTransfer = (Transfer *)&(pEndpoint->transfer); - uint32_t transferred = pTransfer->transferred; - uint32_t remaining = pTransfer->remaining + pTransfer->buffered; - - TRACE_DEBUG_WP("EoT "); - - /* Endpoint returns in Idle state */ - pEndpoint->state = UDP_ENDPOINT_IDLE; - /* Reset descriptor values */ - pTransfer->pData = 0; - pTransfer->transferred = -1; - pTransfer->buffered = -1; - pTransfer->remaining = -1; - - // Invoke callback is present - if (pTransfer->fCallback != 0) { - - ((TransferCallback) pTransfer->fCallback) - (pTransfer->pArgument, - bStatus, - transferred, - remaining); - } - else { - TRACE_DEBUG_WP("NoCB "); - } - } - else if ( (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM) - || (pEndpoint->state == UDP_ENDPOINT_SENDINGM) ) { - - MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); - - TRACE_DEBUG_WP("EoMT "); - - /* Endpoint returns in Idle state */ - pEndpoint->state = UDP_ENDPOINT_IDLE; - /* Reset transfer descriptor */ - if (pTransfer->transType) { - MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer); - pMblt->listState = 0; - pMblt->outCurr = pMblt->inCurr = pMblt->outLast = 0; - } - /* Invoke callback */ - if (pTransfer->fCallback != 0) { - - ((MblTransferCallback) pTransfer->fCallback) - (pTransfer->pArgument, - bStatus); - } - else { - TRACE_DEBUG_WP("NoCB "); - } - } -} - -/** - * Clears the correct reception flag (bank 0 or bank 1) of an endpoint - * \param bEndpoint Index of endpoint - */ -static void UDP_ClearRxFlag(uint8_t bEndpoint) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - - // Clear flag and change banks - if (pEndpoint->bank == 0) { - - CLEAR_CSR(bEndpoint, UDP_CSR_RX_DATA_BK0); - // Swap bank if in dual-fifo mode - if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) { - - pEndpoint->bank = 1; - } - } - else { - - CLEAR_CSR(bEndpoint, UDP_CSR_RX_DATA_BK1); - pEndpoint->bank = 0; - } -} - -/** - * Update multi-buffer-transfer descriptors. - * \param pTransfer Pointer to instance MblTransfer. - * \param size Size of bytes that processed. - * \param forceEnd Force the buffer END. - * \return 1 if current buffer ended. - */ -static uint8_t UDP_MblUpdate(MblTransfer *pTransfer, - USBDTransferBuffer * pBi, - uint16_t size, - uint8_t forceEnd) -{ - /* Update transfer descriptor */ - pBi->remaining -= size; - /* Check if list NULL */ - if (pTransfer->listState == MBL_NULL) { - return 1; - } - /* Check if current buffer ended */ - if (pBi->remaining == 0 || forceEnd || size == 0) { - - /* Process to next buffer */ - if ((++ pTransfer->outCurr) == pTransfer->listSize) - pTransfer->outCurr = 0; - /* Check buffer NULL case */ - if (pTransfer->outCurr == pTransfer->inCurr) - pTransfer->listState = MBL_NULL; - else { - pTransfer->listState = 0; - /* Continue transfer, prepare for next operation */ - pBi = &pTransfer->pMbl[pTransfer->outCurr]; - pBi->buffered = 0; - pBi->transferred = 0; - pBi->remaining = pBi->size; - } - return 1; - } - return 0; -} - -/** - * Transfers a data payload from the current tranfer buffer to the endpoint - * FIFO - * \param bEndpoint Number of the endpoint which is sending data. - */ -static uint8_t UDP_MblWriteFifo(uint8_t bEndpoint) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); - USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->outCurr]); - int32_t size; - - volatile uint8_t * pBytes; - volatile uint8_t bufferEnd = 1; - - /* Get the number of bytes to send */ - size = pEndpoint->size; - if (size > pBi->remaining) size = pBi->remaining; - - TRACE_DEBUG_WP("w%d.%" PRId32 " ", pTransfer->outCurr, size); - - /* Record last accessed buffer */ - pTransfer->outLast = pTransfer->outCurr; - - pBytes = &(pBi->pBuffer[pBi->transferred + pBi->buffered]); - pBi->buffered += size; - bufferEnd = UDP_MblUpdate(pTransfer, pBi, size, 0); - - /* Write packet in the FIFO buffer */ - if (size) { - int32_t c8 = size >> 3; - int32_t c1 = size & 0x7; - for (; c8; c8 --) { - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - } - for (; c1; c1 --) { - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - } - } - return bufferEnd; -} - -/** - * Transfers a data payload from the current tranfer buffer to the endpoint - * FIFO - * \param bEndpoint Number of the endpoint which is sending data. - */ -static void UDP_WritePayload(uint8_t bEndpoint) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); - int32_t size; - - // Get the number of bytes to send - size = pEndpoint->size; - if (size > pTransfer->remaining) { - - size = pTransfer->remaining; - } - - // Update transfer descriptor information - pTransfer->buffered += size; - pTransfer->remaining -= size; - - // Write packet in the FIFO buffer - while (size > 0) { - - UDP->UDP_FDR[bEndpoint] = *(pTransfer->pData); - pTransfer->pData++; - size--; - } -} - - -/** - * Transfers a data payload from an endpoint FIFO to the current transfer buffer - * \param bEndpoint Endpoint number. - * \param wPacketSize Size of received data packet - */ -static void UDP_ReadPayload(uint8_t bEndpoint, int32_t wPacketSize) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); - - // Check that the requested size is not bigger than the remaining transfer - if (wPacketSize > pTransfer->remaining) { - - pTransfer->buffered += wPacketSize - pTransfer->remaining; - wPacketSize = pTransfer->remaining; - } - - // Update transfer descriptor information - pTransfer->remaining -= wPacketSize; - pTransfer->transferred += wPacketSize; - - // Retrieve packet - while (wPacketSize > 0) { - - *(pTransfer->pData) = (uint8_t) UDP->UDP_FDR[bEndpoint]; - pTransfer->pData++; - wPacketSize--; - } -} - -/** - * Received SETUP packet from endpoint 0 FIFO - * \param pRequest Generic USB SETUP request sent over Control endpoints - */ -static void UDP_ReadRequest(USBGenericRequest *pRequest) -{ - uint8_t *pData = (uint8_t *)pRequest; - uint32_t i; - - // Copy packet - for (i = 0; i < 8; i++) { - - *pData = (uint8_t) UDP->UDP_FDR[0]; - pData++; - } -} - -/** - * Checks if an ongoing transfer on an endpoint has been completed. - * \param bEndpoint Endpoint number. - * \return 1 if the current transfer on the given endpoint is complete; - * otherwise 0. - */ -static uint8_t UDP_IsTransferFinished(uint8_t bEndpoint) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); - - // Check if it is a Control endpoint - // -> Control endpoint must always finish their transfer with a zero-length - // packet - if ((UDP->UDP_CSR[bEndpoint] & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL) { - - return (pTransfer->buffered < pEndpoint->size); - } - // Other endpoints only need to transfer all the data - else { - - return (pTransfer->buffered <= pEndpoint->size) - && (pTransfer->remaining == 0); - } -} - -/** - * Endpoint interrupt handler. - * Handle IN/OUT transfers, received SETUP packets and STALLing - * \param bEndpoint Index of endpoint - */ -static void UDP_EndpointHandler(uint8_t bEndpoint) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); - MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer); - uint32_t status = UDP->UDP_CSR[bEndpoint]; - uint16_t wPacketSize; - USBGenericRequest request; - - TRACE_DEBUG_WP("E%d ", bEndpoint); - TRACE_DEBUG_WP("st:0x%" PRIX32 " ", status); - - // Handle interrupts - // IN packet sent - if ((status & UDP_CSR_TXCOMP) != 0) { - - TRACE_DEBUG_WP("Wr "); - - // Check that endpoint was in MBL Sending state - if (pEndpoint->state == UDP_ENDPOINT_SENDINGM) { - - USBDTransferBuffer * pMbli = &(pMblt->pMbl[pMblt->outLast]); - uint8_t bufferEnd = 0; - - TRACE_DEBUG_WP("TxM%d.%d ", pMblt->listState, pMbli->buffered); - - // End of transfer ? - if (pMblt->listState == MBL_NULL && pMbli->buffered == 0) { - - pMbli->transferred += pMbli->buffered; - pMbli->buffered = 0; - - // Disable interrupt - UDP->UDP_IDR = 1 << bEndpoint; - UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); - CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); - } - else { - - // Transfer remaining data - TRACE_DEBUG_WP("%d ", pEndpoint->size); - - if (pMbli->buffered > pEndpoint->size) { - pMbli->transferred += pEndpoint->size; - pMbli->buffered -= pEndpoint->size; - } - else { - pMbli->transferred += pMbli->buffered; - pMbli->buffered = 0; - } - - // Send next packet - if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) { - - // No double buffering - bufferEnd = UDP_MblWriteFifo(bEndpoint); - SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); - CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); - } - else { - // Double buffering - SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); - CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); - bufferEnd = UDP_MblWriteFifo(bEndpoint); - } - - if (bufferEnd && pMblt->fCallback) { - ((MblTransferCallback) pTransfer->fCallback) - (pTransfer->pArgument, - USBD_STATUS_PARTIAL_DONE); - } - } - } - // Check that endpoint was in Sending state - else if (pEndpoint->state == UDP_ENDPOINT_SENDING) { - - // End of transfer ? - if (UDP_IsTransferFinished(bEndpoint)) { - - pTransfer->transferred += pTransfer->buffered; - pTransfer->buffered = 0; - - // Disable interrupt if this is not a control endpoint - if ((status & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) { - - UDP->UDP_IDR = 1 << bEndpoint; - } - - UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); - CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); - } - else { - - // Transfer remaining data - TRACE_DEBUG_WP(" %d ", pEndpoint->size); - - pTransfer->transferred += pEndpoint->size; - pTransfer->buffered -= pEndpoint->size; - - // Send next packet - if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) { - - // No double buffering - UDP_WritePayload(bEndpoint); - SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); - CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); - } - else { - // Double buffering - SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); - CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); - UDP_WritePayload(bEndpoint); - } - } - } - else { - // Acknowledge interrupt - TRACE_ERROR("Error Wr%d, %x\n\r", bEndpoint, pEndpoint->state); - CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); - } - } - - // OUT packet received - if ((status & UDP_CSR_RXDATA_BK) != 0) { - - TRACE_DEBUG_WP("Rd "); - - // Check that the endpoint is in Receiving state - if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) { - - // Check if an ACK has been received on a Control endpoint - if (((status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL) - && ((status & UDP_CSR_RXBYTECNT_Msk) == 0)) { - - // Acknowledge the data and finish the current transfer - UDP_ClearRxFlag(bEndpoint); - UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); - } - // Check if the data has been STALLed - else if ((status & UDP_CSR_FORCESTALL) != 0) { - - // Discard STALLed data - TRACE_DEBUG_WP("Discard "); - UDP_ClearRxFlag(bEndpoint); - } - // NAK the data - else { - - TRACE_DEBUG_WP("Nak "); - UDP->UDP_IDR = 1 << bEndpoint; - } - } - // Endpoint is in Read state - else { - - // Retrieve data and store it into the current transfer buffer - wPacketSize = (uint16_t) (status >> 16); - TRACE_DEBUG_WP("%d ", wPacketSize); - UDP_ReadPayload(bEndpoint, wPacketSize); - UDP_ClearRxFlag(bEndpoint); - - // Check if the transfer is finished - if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) { - - // Disable interrupt if this is not a control endpoint - if ((status & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) { - - UDP->UDP_IDR = 1 << bEndpoint; - } - UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); - } - } - } - - // STALL sent - if ((status & UDP_CSR_STALLSENTISOERROR) != 0) { - - CLEAR_CSR(bEndpoint, UDP_CSR_STALLSENTISOERROR); - - if ( (status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_ISO_IN - || (status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_ISO_OUT ) { - - TRACE_WARNING("Isoe [%d] ", bEndpoint); - UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED); - } - else { - - TRACE_WARNING("Sta 0x%X [%d] ", (int)status, bEndpoint); - - if (pEndpoint->state != UDP_ENDPOINT_HALTED) { - - TRACE_WARNING( "_ " ); - // If the endpoint is not halted, clear the STALL condition - CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL); - } - } - } - - // SETUP packet received - if ((status & UDP_CSR_RXSETUP) != 0) { - - TRACE_DEBUG_WP("Stp "); - - // If a transfer was pending, complete it - // Handles the case where during the status phase of a control write - // transfer, the host receives the device ZLP and ack it, but the ack - // is not received by the device - if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING) - || (pEndpoint->state == UDP_ENDPOINT_SENDING)) { - - UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); - } - // Copy the setup packet - UDP_ReadRequest(&request); - - // Set the DIR bit before clearing RXSETUP in Control IN sequence - if (USBGenericRequest_GetDirection(&request) == USBGenericRequest_IN) { - - SET_CSR(bEndpoint, UDP_CSR_DIR); - } - // Acknowledge setup packet - CLEAR_CSR(bEndpoint, UDP_CSR_RXSETUP); - - // Forward the request to the upper layer - USBD_RequestHandler(0, &request); - } - -} - -/** - * Sends data through a USB endpoint. Sets up the transfer descriptor, - * writes one or two data payloads (depending on the number of FIFO bank - * for the endpoint) and then starts the actual transfer. The operation is - * complete when all the data has been sent. - * - * *If the size of the buffer is greater than the size of the endpoint - * (or twice the size if the endpoint has two FIFO banks), then the buffer - * must be kept allocated until the transfer is finished*. This means that - * it is not possible to declare it on the stack (i.e. as a local variable - * of a function which returns after starting a transfer). - * - * \param pEndpoint Pointer to Endpoint struct. - * \param pData Pointer to a buffer with the data to send. - * \param dLength Size of the data buffer. - * \return USBD_STATUS_SUCCESS if the transfer has been started; - * otherwise, the corresponding error status code. - */ -static inline uint8_t UDP_Write(uint8_t bEndpoint, - const void *pData, - uint32_t dLength) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); - - /* Check that the endpoint is in Idle state */ - if (pEndpoint->state != UDP_ENDPOINT_IDLE) { - - return USBD_STATUS_LOCKED; - } - TRACE_DEBUG_WP("Write%d(%" PRIu32 ") ", bEndpoint, dLength); - -/* int i; - for (i = 0; i < dLength; i++) { - if (!(i%16)) { - printf("\n\r"); - } - printf("0x%x ", ((uint8_t*)pData)[i]); - } - printf("\n\r"); -*/ - - /* Setup the transfer descriptor */ - pTransfer->pData = (void *) pData; - pTransfer->remaining = dLength; - pTransfer->buffered = 0; - pTransfer->transferred = 0; - - /* Send the first packet */ - pEndpoint->state = UDP_ENDPOINT_SENDING; - while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY); - UDP_WritePayload(bEndpoint); - SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); - - /* If double buffering is enabled and there is data remaining, - prepare another packet */ - if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) && (pTransfer->remaining > 0)) { - - UDP_WritePayload(bEndpoint); - } - - /* Enable interrupt on endpoint */ - UDP->UDP_IER = 1 << bEndpoint; - - return USBD_STATUS_SUCCESS; -} - -/** - * Sends data through a USB endpoint. Sets up the transfer descriptor list, - * writes one or two data payloads (depending on the number of FIFO bank - * for the endpoint) and then starts the actual transfer. The operation is - * complete when all the transfer buffer in the list has been sent. - * - * *If the size of the buffer is greater than the size of the endpoint - * (or twice the size if the endpoint has two FIFO banks), then the buffer - * must be kept allocated until the transfer is finished*. This means that - * it is not possible to declare it on the stack (i.e. as a local variable - * of a function which returns after starting a transfer). - * - * \param pEndpoint Pointer to Endpoint struct. - * \param pData Pointer to a buffer with the data to send. - * \param dLength Size of the data buffer. - * \return USBD_STATUS_SUCCESS if the transfer has been started; - * otherwise, the corresponding error status code. - */ -static inline uint8_t UDP_AddWr(uint8_t bEndpoint, - const void *pData, - uint32_t dLength) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - MblTransfer *pMbl = (MblTransfer*)&(pEndpoint->transfer); - USBDTransferBuffer *pTx; - - /* Check parameter */ - if (dLength >= 0x10000) - return USBD_STATUS_INVALID_PARAMETER; - - /* Data in progressing */ - if (pEndpoint->state > UDP_ENDPOINT_IDLE) { - /* If list full */ - if (pMbl->listState == MBL_FULL) { - return USBD_STATUS_LOCKED; - } - } - - TRACE_DEBUG_WP("AddW%d(%" PRIu32 ") ", bEndpoint, dLength); - - /* Add buffer to buffer list and update index */ - pTx = &(pMbl->pMbl[pMbl->inCurr]); - pTx->pBuffer = (uint8_t*)pData; - pTx->size = pTx->remaining = dLength; - pTx->transferred = pTx->buffered = 0; - /* Update input index */ - if (pMbl->inCurr >= (pMbl->listSize-1)) pMbl->inCurr = 0; - else pMbl->inCurr ++; - if (pMbl->inCurr == pMbl->outCurr) pMbl->listState = MBL_FULL; - else pMbl->listState = 0; - /* Start sending when offset achieved */ - if (MBL_NbBuffer(pMbl->inCurr, pMbl->outCurr, pMbl->listSize) - >= pMbl->offsetSize - && pEndpoint->state == UDP_ENDPOINT_IDLE) { - TRACE_DEBUG_WP("StartT "); - /* Change state */ - pEndpoint->state = UDP_ENDPOINT_SENDINGM; - while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY); - /* Send first packet */ - UDP_MblWriteFifo(bEndpoint); - SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); - /* If double buffering is enabled and there is remaining, continue */ - if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) - && pMbl->pMbl[pMbl->outCurr].remaining) { - UDP_MblWriteFifo(bEndpoint); - } - /* Enable interrupt on endpoint */ - UDP->UDP_IER = 1 << bEndpoint; - } - - return USBD_STATUS_SUCCESS; -} - -/** - * Reads incoming data on an USB endpoint This methods sets the transfer - * descriptor and activate the endpoint interrupt. The actual transfer is - * then carried out by the endpoint interrupt handler. The Read operation - * finishes either when the buffer is full, or a short packet (inferior to - * endpoint maximum size) is received. - * - * *The buffer must be kept allocated until the transfer is finished*. - * \param bEndpoint Endpoint number. - * \param pData Pointer to a data buffer. - * \param dLength Size of the data buffer in bytes. - * \return USBD_STATUS_SUCCESS if the read operation has been started; - * otherwise, the corresponding error code. - */ -static inline uint8_t UDP_Read(uint8_t bEndpoint, - void *pData, - uint32_t dLength) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); - - /* Return if the endpoint is not in IDLE state */ - if (pEndpoint->state != UDP_ENDPOINT_IDLE) { - - return USBD_STATUS_LOCKED; - } - - /* Endpoint enters Receiving state */ - pEndpoint->state = UDP_ENDPOINT_RECEIVING; - TRACE_DEBUG_WP("Read%d(%" PRIu32 ") ", bEndpoint, dLength); - -/* int i; - for (i = 0; i < dLength; i++) { - if (!(i%16)) { - printf("\n\r"); - } - printf("0x%x ", ((uint8_t*)pData)[i]); - } - printf("\n\r"); -*/ - - /* Set the transfer descriptor */ - pTransfer->pData = pData; - pTransfer->remaining = dLength; - pTransfer->buffered = 0; - pTransfer->transferred = 0; - - /* Enable interrupt on endpoint */ - UDP->UDP_IER = 1 << bEndpoint; - - return USBD_STATUS_SUCCESS; -} - - -/*--------------------------------------------------------------------------- - * Exported functions - *---------------------------------------------------------------------------*/ - -/** - * USBD (UDP) interrupt handler - * Manages device resume, suspend, end of bus reset. - * Forwards endpoint events to the appropriate handler. - */ -void USBD_IrqHandler(void) -{ - uint32_t status; - int32_t eptnum = 0; - - /* Enable peripheral ? */ - //UDP_EnablePeripheralClock(); - - /* Get interrupt status - Some interrupts may get masked depending on the device state */ - status = UDP->UDP_ISR; - status &= UDP->UDP_IMR; - - TRACE_DEBUG("status; 0x%" PRIx32 , status); - - if (USBD_GetState() < USBD_STATE_POWERED) { - - status &= UDP_ICR_WAKEUP | UDP_ICR_RXRSM; - UDP->UDP_ICR = ~status; - } - - /* Return immediately if there is no interrupt to service */ - if (status == 0) { - - TRACE_DEBUG_WP(".\n\r"); - return; - } - - /* Toggle USB LED if the device is active */ - if (USBD_GetState() >= USBD_STATE_POWERED) { - - //LED_Set(USBD_LEDUSB); - } - - /* Service interrupts */ - - /** / Start Of Frame (SOF) */ - //if (ISSET(dStatus, UDP_ISR_SOFINT)) { - // - // TRACE_DEBUG("SOF"); - // - // // Invoke the SOF callback - // USB_StartOfFrameCallback(pUsb); - // - // // Acknowledge interrupt - // UDP->UDP_ICR = UDP_ICR_SOFINT; - // dStatus &= ~UDP_ISR_SOFINT; - //} - /* Resume (Wakeup) */ - if ((status & (UDP_ISR_WAKEUP | UDP_ISR_RXRSM)) != 0) { - - TRACE_INFO_WP("Res "); - /* Clear and disable resume interrupts */ - UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP; - UDP->UDP_IDR = UDP_IDR_WAKEUP | UDP_IDR_RXRSM; - /* Do resome operations */ - USBD_ResumeHandler(); - } - - /* Suspend - This interrupt is always treated last (hence the '==') */ - if (status == UDP_ISR_RXSUSP) { - - TRACE_INFO_WP("Susp "); - /* Enable wakeup */ - UDP->UDP_IER = UDP_IER_WAKEUP | UDP_IER_RXRSM; - /* Acknowledge interrupt */ - UDP->UDP_ICR = UDP_ICR_RXSUSP; - /* Do suspend operations */ - USBD_SuspendHandler(); - } - /* End of bus reset */ - else if ((status & UDP_ISR_ENDBUSRES) != 0) { - - TRACE_INFO_WP("EoBRes "); - -#if defined(BOARD_USB_DFU) -#if defined(APPLICATION_dfu) - /* if we are currently in the DFU bootloader, and we are beyond - * the MANIFEST stage, we shall switch to the normal - * application */ - if (g_dfu->past_manifest) - USBDFU_SwitchToApp(); -#else - /* if we are currently in the main application, and we are in - * appDETACH state, switch into the DFU bootloader */ - if (g_dfu->state == DFU_STATE_appDETACH) - DFURT_SwitchToDFU(); -#endif /* APPLICATION_dfu */ -#endif /* BOARD_USB_DFU */ - - /* Flush and enable the Suspend interrupt */ - UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP; - UDP->UDP_IER = UDP_IER_RXSUSP; - - /* Do RESET operations */ - USBD_ResetHandler(); - - /* Acknowledge end of bus reset interrupt */ - UDP->UDP_ICR = UDP_ICR_ENDBUSRES; - } - /* Endpoint interrupts */ - else { - - status &= ((1 << CHIP_USB_NUMENDPOINTS) - 1); - while (status != 0) { - - /* Check if endpoint has a pending interrupt */ - if ((status & (1 << eptnum)) != 0) { - - UDP_EndpointHandler(eptnum); - status &= ~(1 << eptnum); - - if (status != 0) { - - TRACE_INFO_WP("\n\r - "); - } - } - eptnum++; - } - } - - /* Toggle LED back to its previous state */ - TRACE_DEBUG_WP("!"); - TRACE_INFO_WP("\n\r"); - if (USBD_GetState() >= USBD_STATE_POWERED) { - - //LED_Clear(USBD_LEDUSB); - } -} - -/** - * \brief Reset endpoints and disable them. - * -# Terminate transfer if there is any, with given status; - * -# Reset the endpoint & disable it. - * \param bmEPs Bitmap for endpoints to reset. - * \param bStatus Status passed to terminate transfer on endpoint. - * \param bKeepCfg 1 to keep old endpoint configuration. - * \note Use USBD_HAL_ConfigureEP() to configure and enable endpoint - if not keeping old configuration. - * \sa USBD_HAL_ConfigureEP(). - */ -void USBD_HAL_ResetEPs(uint32_t bmEPs, uint8_t bStatus, uint8_t bKeepCfg) -{ - Endpoint *pEndpoint; - uint32_t tmp = bmEPs & ((1<UDP_IDR = epBit; - /* Kill pending TXPKTREADY */ - CLEAR_CSR(ep, UDP_CSR_TXPKTRDY); - - /* Reset transfer information */ - pEndpoint = &(endpoints[ep]); - /* Reset endpoint state */ - pEndpoint->bank = 0; - /* Endpoint configure */ - epCfg = UDP->UDP_CSR[ep]; - /* Reset endpoint */ - UDP->UDP_RST_EP |= epBit; - UDP->UDP_RST_EP &= ~epBit; - /* Restore configure */ - if (bKeepCfg) { - //SET_CSR(ep, pEndpoint->CSR); - SET_CSR(ep, epCfg); - } - else { - //pEndpoint->CSR = 0; - pEndpoint->state = UDP_ENDPOINT_DISABLED; - } - - /* Terminate transfer on this EP */ - UDP_EndOfTransfer(ep, bStatus); - } - epBit <<= 1; - } - /* Reset EPs */ - // UDP->UDP_RST_EP |= bmEPs; - // UDP->UDP_RST_EP &= ~bmEPs; -} - -/** - * Cancel pending READ/WRITE - * \param bmEPs Bitmap for endpoints to reset. - * \note EP callback is invoked with USBD_STATUS_CANCELED. - */ -void USBD_HAL_CancelIo(uint32_t bmEPs) -{ - uint32_t tmp = bmEPs & ((1<UDP_IDR = epBit; - /* Kill pending TXPKTREADY */ - CLEAR_CSR(ep, UDP_CSR_TXPKTRDY); - - /* Terminate transfer on this EP */ - UDP_EndOfTransfer(ep, USBD_STATUS_CANCELED); - } - epBit <<= 1; - } -} - -/** - * Configures an endpoint according to its endpoint Descriptor. - * \param pDescriptor Pointer to an endpoint descriptor. - */ -uint8_t USBD_HAL_ConfigureEP(const USBEndpointDescriptor *pDescriptor) -{ - Endpoint *pEndpoint; - uint8_t bEndpoint; - uint8_t bType; - uint8_t bEndpointDir; - - /* NULL descriptor -> Control endpoint 0 in default */ - if (pDescriptor == 0) { - bEndpoint = 0; - pEndpoint = &(endpoints[bEndpoint]); - bType= USBEndpointDescriptor_CONTROL; - bEndpointDir = 0; - pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0); - } - /* Device descriptor -> Specific Control EP */ - else if (pDescriptor->bDescriptorType == USBGenericDescriptor_DEVICE) { - bEndpoint = 0; - pEndpoint = &(endpoints[bEndpoint]); - bType = USBEndpointDescriptor_CONTROL; - bEndpointDir = 0; - pEndpoint->size = ((USBDeviceDescriptor *)pDescriptor)->bMaxPacketSize0; - } - /* Not endpoint descriptor, ERROR! */ - else if (pDescriptor->bDescriptorType != USBGenericDescriptor_ENDPOINT) { - return 0xFF; - } - else { - bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor); - pEndpoint = &(endpoints[bEndpoint]); - bType = USBEndpointDescriptor_GetType(pDescriptor); - bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor); - pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor); - } - - /* Abort the current transfer is the endpoint was configured and in - Write or Read state */ - if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING) - || (pEndpoint->state == UDP_ENDPOINT_SENDING) - || (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM) - || (pEndpoint->state == UDP_ENDPOINT_SENDINGM)) { - UDP_EndOfTransfer(bEndpoint, USBD_STATUS_RESET); - } - pEndpoint->state = UDP_ENDPOINT_IDLE; - - /* Reset Endpoint Fifos */ - UDP->UDP_RST_EP |= (1 << bEndpoint); - UDP->UDP_RST_EP &= ~(1 << bEndpoint); - - /* Configure endpoint */ - SET_CSR(bEndpoint, (uint32_t)UDP_CSR_EPEDS - | (bType << 8) | (bEndpointDir << 10)); - if (bType != USBEndpointDescriptor_CONTROL) { - - } - else { - - UDP->UDP_IER = (1 << bEndpoint); - } - - TRACE_INFO_WP("CfgEp%d ", bEndpoint); - return bEndpoint; -} - -/** - * Set callback for a USB endpoint for transfer (read/write). - * - * \param bEP Endpoint number. - * \param fCallback Optional callback function to invoke when the transfer is - * complete. - * \param pCbData Optional pointer to data to the callback function. - * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED if endpoint is busy. - */ -uint8_t USBD_HAL_SetTransferCallback(uint8_t bEP, - TransferCallback fCallback, - void *pCbData) -{ - Endpoint *pEndpoint = &(endpoints[bEP]); - TransferHeader *pTransfer = (TransferHeader*)&(pEndpoint->transfer); - /* Check that the endpoint is not transferring */ - if (pEndpoint->state > UDP_ENDPOINT_IDLE) { - return USBD_STATUS_LOCKED; - } - TRACE_DEBUG_WP("sXfrCb "); - /* Setup the transfer callback and extension data */ - pTransfer->fCallback = (void*)fCallback; - pTransfer->pArgument = pCbData; - return USBD_STATUS_SUCCESS; -} - -/** - * Configure an endpoint to use multi-buffer-list transfer mode. - * The buffers can be added by _Read/_Write function. - * \param pMbList Pointer to a multi-buffer list used, NULL to disable MBL. - * \param mblSize Multi-buffer list size (number of buffers can be queued) - * \param startOffset When number of buffer achieve this offset transfer start - */ -uint8_t USBD_HAL_SetupMblTransfer( uint8_t bEndpoint, - USBDTransferBuffer* pMbList, - uint16_t mblSize, - uint16_t startOffset) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - MblTransfer *pXfr = (MblTransfer*)&(pEndpoint->transfer); - uint16_t i; - /* Check that the endpoint is not transferring */ - if (pEndpoint->state > UDP_ENDPOINT_IDLE) { - return USBD_STATUS_LOCKED; - } - TRACE_DEBUG_WP("sMblXfr "); - /* Enable Multi-Buffer Transfer List */ - if (pMbList) { - /* Reset list items */ - for (i = 0; i < mblSize; i --) { - pMbList[i].pBuffer = NULL; - pMbList[i].size = 0; - pMbList[i].transferred = 0; - pMbList[i].buffered = 0; - pMbList[i].remaining = 0; - } - /* Setup transfer */ - pXfr->transType = 1; - pXfr->listState = 0; /* OK */ - pXfr->listSize = mblSize; - pXfr->pMbl = pMbList; - pXfr->outCurr = pXfr->outLast = 0; - pXfr->inCurr = 0; - pXfr->offsetSize = startOffset; - } - /* Disable Multi-Buffer Transfer */ - else { - pXfr->transType = 0; - pXfr->pMbl = NULL; - pXfr->listSize = 0; - pXfr->offsetSize = 1; - } - return USBD_STATUS_SUCCESS; -} - -/** - * Sends data through a USB endpoint. Sets up the transfer descriptor, - * writes one or two data payloads (depending on the number of FIFO bank - * for the endpoint) and then starts the actual transfer. The operation is - * complete when all the data has been sent. - * - * *If the size of the buffer is greater than the size of the endpoint - * (or twice the size if the endpoint has two FIFO banks), then the buffer - * must be kept allocated until the transfer is finished*. This means that - * it is not possible to declare it on the stack (i.e. as a local variable - * of a function which returns after starting a transfer). - * - * \param bEndpoint Endpoint number. - * \param pData Pointer to a buffer with the data to send. - * \param dLength Size of the data buffer. - * \return USBD_STATUS_SUCCESS if the transfer has been started; - * otherwise, the corresponding error status code. - */ -uint8_t USBD_HAL_Write( uint8_t bEndpoint, - const void *pData, - uint32_t dLength) -{ - if (endpoints[bEndpoint].transfer.transHdr.transType) - return UDP_AddWr(bEndpoint, pData, dLength); - else - return UDP_Write(bEndpoint, pData, dLength); -} - -/** - * Reads incoming data on an USB endpoint This methods sets the transfer - * descriptor and activate the endpoint interrupt. The actual transfer is - * then carried out by the endpoint interrupt handler. The Read operation - * finishes either when the buffer is full, or a short packet (inferior to - * endpoint maximum size) is received. - * - * *The buffer must be kept allocated until the transfer is finished*. - * \param bEndpoint Endpoint number. - * \param pData Pointer to a data buffer. - * \param dLength Size of the data buffer in bytes. - * \return USBD_STATUS_SUCCESS if the read operation has been started; - * otherwise, the corresponding error code. - */ -uint8_t USBD_HAL_Read(uint8_t bEndpoint, - void *pData, - uint32_t dLength) -{ - if (endpoints[bEndpoint].transfer.transHdr.transType) - return USBD_STATUS_SW_NOT_SUPPORTED; - else - return UDP_Read(bEndpoint, pData, dLength); -} - -/** - * \brief Enable Pull-up, connect. - * - * -# Enable HW access if needed - * -# Enable Pull-Up - * -# Disable HW access if needed - */ -void USBD_HAL_Connect(void) -{ - uint8_t dis = UDP_EnablePeripheralClock(); - UDP->UDP_TXVC |= UDP_TXVC_PUON; - if (dis) UDP_DisablePeripheralClock(); -} - -/** - * \brief Disable Pull-up, disconnect. - * - * -# Enable HW access if needed - * -# Disable PULL-Up - * -# Disable HW access if needed - */ -void USBD_HAL_Disconnect(void) -{ - uint8_t dis = UDP_EnablePeripheralClock(); - UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_PUON; - if (dis) UDP_DisablePeripheralClock(); -} - -/** - * Starts a remote wake-up procedure. - */ -void USBD_HAL_RemoteWakeUp(void) -{ - UDP_EnablePeripheralClock(); - UDP_EnableUsbClock(); - UDP_EnableTransceiver(); - - TRACE_INFO_WP("RWUp "); - - // Activates a remote wakeup (edge on ESR), then clear ESR - UDP->UDP_GLB_STAT |= UDP_GLB_STAT_ESR; - UDP->UDP_GLB_STAT &= ~(uint32_t)UDP_GLB_STAT_ESR; -} - -/** - * Sets the device address to the given value. - * \param address New device address. - */ -void USBD_HAL_SetAddress(uint8_t address) -{ - /* Set address */ - UDP->UDP_FADDR = UDP_FADDR_FEN | (address & UDP_FADDR_FADD_Msk); - /* If the address is 0, the device returns to the Default state */ - if (address == 0) UDP->UDP_GLB_STAT = 0; - /* If the address is non-zero, the device enters the Address state */ - else UDP->UDP_GLB_STAT = UDP_GLB_STAT_FADDEN; -} - -/** - * Sets the current device configuration. - * \param cfgnum - Configuration number to set. - */ -void USBD_HAL_SetConfiguration(uint8_t cfgnum) -{ - /* If the configuration number if non-zero, the device enters the - Configured state */ - if (cfgnum != 0) UDP->UDP_GLB_STAT |= UDP_GLB_STAT_CONFG; - /* If the configuration number is zero, the device goes back to the Address - state */ - else { - UDP->UDP_GLB_STAT = UDP_FADDR_FEN; - } -} - -/** - * Initializes the USB HW Access driver. - */ -void USBD_HAL_Init(void) -{ - TRACE_DEBUG("%s\n\r", "USBD_HAL_Init"); - - /* Must before USB & TXVC access! */ - UDP_EnablePeripheralClock(); - - /* Reset & disable endpoints */ - USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0); - - /* Configure the pull-up on D+ and disconnect it */ - UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_PUON; - - UDP_EnableUsbClock(); - - UDP->UDP_IDR = 0xFE; - UDP->UDP_IER = UDP_IER_WAKEUP; -} - -/** - * Causes the given endpoint to acknowledge the next packet it receives - * with a STALL handshake except setup request. - * \param bEP Endpoint number. - * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED. - */ -uint8_t USBD_HAL_Stall(uint8_t bEP) -{ - Endpoint *pEndpoint = &(endpoints[bEP]); - - /* Check that endpoint is in Idle state */ - if (pEndpoint->state != UDP_ENDPOINT_IDLE) { - TRACE_WARNING("UDP_Stall: EP%d locked\n\r", bEP); - return USBD_STATUS_LOCKED; - } - /* STALL endpoint */ - SET_CSR(bEP, UDP_CSR_FORCESTALL); - TRACE_DEBUG_WP("Stall%d ", bEP); - return USBD_STATUS_SUCCESS; -} - -/** - * Sets/Clear/Get the HALT state on the endpoint. - * In HALT state, the endpoint should keep stalling any packet. - * \param bEndpoint Endpoint number. - * \param ctl Control code CLR/HALT/READ. - * 0: Clear HALT state; - * 1: Set HALT state; - * .: Return HALT status. - * \return USBD_STATUS_INVALID_PARAMETER if endpoint not exist, - * otherwise endpoint halt status. - */ -uint8_t USBD_HAL_Halt(uint8_t bEndpoint, uint8_t ctl) -{ - Endpoint *pEndpoint = &(endpoints[bEndpoint]); - uint8_t status = 0; - - /* SET Halt */ - if (ctl == 1) { - /* Check that endpoint is enabled and not already in Halt state */ - if ((pEndpoint->state != UDP_ENDPOINT_DISABLED) - && (pEndpoint->state != UDP_ENDPOINT_HALTED)) { - - TRACE_DEBUG_WP("Halt%d ", bEndpoint); - - /* Abort the current transfer if necessary */ - UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED); - - /* Put endpoint into Halt state */ - SET_CSR(bEndpoint, UDP_CSR_FORCESTALL); - pEndpoint->state = UDP_ENDPOINT_HALTED; - - /* Enable the endpoint interrupt */ - UDP->UDP_IER = 1 << bEndpoint; - } - } - /* CLEAR Halt */ - else if (ctl == 0) { - /* Check if the endpoint is halted */ - //if (pEndpoint->state != UDP_ENDPOINT_DISABLED) { - if (pEndpoint->state == UDP_ENDPOINT_HALTED) { - - TRACE_DEBUG_WP("Unhalt%d ", bEndpoint); - - /* Return endpoint to Idle state */ - pEndpoint->state = UDP_ENDPOINT_IDLE; - - /* Clear FORCESTALL flag */ - CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL); - - /* Reset Endpoint Fifos, beware this is a 2 steps operation */ - UDP->UDP_RST_EP |= 1 << bEndpoint; - UDP->UDP_RST_EP &= ~(1 << bEndpoint); - } - } - - /* Return Halt status */ - if (pEndpoint->state == UDP_ENDPOINT_HALTED) { - status = 1; - } - return( status ); -} - -/** - * Indicates if the device is running in high or full-speed. Always returns 0 - * since UDP does not support high-speed mode. - */ -uint8_t USBD_HAL_IsHighSpeed(void) -{ - return 0; -} - -/** - * Suspend USB Device HW Interface - * - * -# Disable transceiver - * -# Disable USB Clock - * -# Disable USB Peripheral - */ -void USBD_HAL_Suspend(void) -{ - /* The device enters the Suspended state */ - UDP_DisableTransceiver(); - UDP_DisableUsbClock(); - UDP_DisablePeripheralClock(); -} - -/** - * Activate USB Device HW Interface - * -# Enable USB Peripheral - * -# Enable USB Clock - * -# Enable transceiver - */ -void USBD_HAL_Activate(void) -{ - UDP_EnablePeripheralClock(); - UDP_EnableUsbClock(); - UDP_EnableTransceiver(); -} - -/**@}*/ - +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** + + \file + + \section Purpose + + Implementation of USB device functions on a UDP controller. + + See \ref usbd_api_method USBD API Methods. +*/ + +/** \addtogroup usbd_hal + *@{*/ + +/*--------------------------------------------------------------------------- + * Headers + *---------------------------------------------------------------------------*/ + +#ifdef TRACE_LEVEL +#undef TRACE_LEVEL +#endif +#define TRACE_LEVEL TRACE_LEVEL_WARNING + +#include "chip.h" +#include "USBD_HAL.h" +#include + +#include +#include +#include + +/*--------------------------------------------------------------------------- + * Definitions + *---------------------------------------------------------------------------*/ + +/** Indicates chip has an UDP Full Speed. */ +#define CHIP_USB_UDP + +/** Indicates chip has an internal pull-up. */ +#define CHIP_USB_PULLUP_INTERNAL + +/** Number of USB endpoints */ +#define CHIP_USB_NUMENDPOINTS 8 + +/** Endpoints max paxcket size */ +#define CHIP_USB_ENDPOINTS_MAXPACKETSIZE(i) \ + ((i == 0) ? 64 : \ + ((i == 1) ? 64 : \ + ((i == 2) ? 64 : \ + ((i == 3) ? 64 : \ + ((i == 4) ? 512 : \ + ((i == 5) ? 512 : \ + ((i == 6) ? 64 : \ + ((i == 7) ? 64 : 0 )))))))) + +/** Endpoints Number of Bank */ +#define CHIP_USB_ENDPOINTS_BANKS(i) \ + ((i == 0) ? 1 : \ + ((i == 1) ? 2 : \ + ((i == 2) ? 2 : \ + ((i == 3) ? 1 : \ + ((i == 4) ? 2 : \ + ((i == 5) ? 2 : \ + ((i == 6) ? 2 : \ + ((i == 7) ? 2 : 0 )))))))) + +/** + * \section UDP_registers_sec "UDP Register field values" + * + * This section lists the initialize values of UDP registers. + * + * \subsection Values + * - UDP_RXDATA + */ +/** Bit mask for both banks of the UDP_CSR register. */ +#define UDP_CSR_RXDATA_BK (UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1) + +/** + * \section endpoint_states_sec "UDP Endpoint states" + * + * This page lists the endpoint states. + * + * \subsection States + * - UDP_ENDPOINT_DISABLED + * - UDP_ENDPOINT_HALTED + * - UDP_ENDPOINT_IDLE + * - UDP_ENDPOINT_SENDING + * - UDP_ENDPOINT_RECEIVING + * - UDP_ENDPOINT_SENDINGM + * - UDP_ENDPOINT_RECEIVINGM + */ + +/** Endpoint states: Endpoint is disabled */ +#define UDP_ENDPOINT_DISABLED 0 +/** Endpoint states: Endpoint is halted (i.e. STALLs every request) */ +#define UDP_ENDPOINT_HALTED 1 +/** Endpoint states: Endpoint is idle (i.e. ready for transmission) */ +#define UDP_ENDPOINT_IDLE 2 +/** Endpoint states: Endpoint is sending data */ +#define UDP_ENDPOINT_SENDING 3 +/** Endpoint states: Endpoint is receiving data */ +#define UDP_ENDPOINT_RECEIVING 4 +/** Endpoint states: Endpoint is sending MBL */ +#define UDP_ENDPOINT_SENDINGM 5 +/** Endpoint states: Endpoint is receiving MBL */ +#define UDP_ENDPOINT_RECEIVINGM 6 + +/** + * \section udp_csr_register_access_sec "UDP CSR register access" + * + * This page lists the macros to access UDP CSR register. + * + * \comment + * In a preemptive environment, set or clear the flag and wait for a time of + * 1 UDPCK clock cycle and 1 peripheral clock cycle. However, RX_DATA_BK0, + * TXPKTRDY, RX_DATA_BK1 require wait times of 3 UDPCK clock cycles and + * 5 peripheral clock cycles before accessing DPR. + * See datasheet + * + * !Macros + * - CLEAR_CSR + * - SET_CSR + */ + +#if defined ( __CC_ARM ) + #define nop() {volatile int h; for(h=0;h<10;h++){}} +#elif defined ( __ICCARM__ ) + #include + #define nop() (__no_operation()) +#elif defined ( __GNUC__ ) + #define nop() __asm__ __volatile__ ( "nop" ) +#endif + + +/** Bitmap for all status bits in CSR. */ +#define REG_NO_EFFECT_1_ALL UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1 \ + |UDP_CSR_STALLSENTISOERROR | UDP_CSR_RXSETUP \ + |UDP_CSR_TXCOMP + +/** + * Sets the specified bit(s) in the UDP_CSR register. + * + * \param endpoint The endpoint number of the CSR to process. + * \param flags The bitmap to set to 1. + */ +#define SET_CSR(endpoint, flags) \ + { \ + volatile uint32_t reg; \ + int32_t nop_count ; \ + reg = UDP->UDP_CSR[endpoint] ; \ + reg |= REG_NO_EFFECT_1_ALL; \ + reg |= (flags); \ + UDP->UDP_CSR[endpoint] = reg; \ + for( nop_count=0; nop_count<15; nop_count++ ) {\ + nop();\ + }\ + } + +/** + * Clears the specified bit(s) in the UDP_CSR register. + * + * \param endpoint The endpoint number of the CSR to process. + * \param flags The bitmap to clear to 0. + */ +#define CLEAR_CSR(endpoint, flags) \ +{ \ + volatile uint32_t reg; \ + int32_t nop_count ; \ + reg = UDP->UDP_CSR[endpoint]; \ + reg |= REG_NO_EFFECT_1_ALL; \ + reg &= ~((uint32_t)(flags)); \ + UDP->UDP_CSR[endpoint] = reg; \ + for( nop_count=0; nop_count<15; nop_count++ ) {\ + nop();\ + }\ +} + + +/** Get Number of buffer in Multi-Buffer-List + * \param i input index + * \param o output index + * \param size list size + */ +#define MBL_NbBuffer(i, o, size) (((i)>(o))?((i)-(o)):((i)+(size)-(o))) + +/** Buffer list is full */ +#define MBL_FULL 1 +/** Buffer list is null */ +#define MBL_NULL 2 + +/*--------------------------------------------------------------------------- + * Types + *---------------------------------------------------------------------------*/ + +/** Describes header for UDP endpoint transfer. */ +typedef struct { + /** Optional callback to invoke when the transfer completes. */ + void* fCallback; + /** Optional argument to the callback function. */ + void* pArgument; + /** Transfer type */ + uint8_t transType; +} TransferHeader; + +/** Describes a transfer on a UDP endpoint. */ +typedef struct { + + /** Optional callback to invoke when the transfer completes. */ + TransferCallback fCallback; + /** Optional argument to the callback function. */ + void *pArgument; + /** Transfer type */ + uint16_t transType; + /** Number of bytes which have been written into the UDP internal FIFO + * buffers. */ + int16_t buffered; + /** Pointer to a data buffer used for emission/reception. */ + uint8_t *pData; + /** Number of bytes which have been sent/received. */ + int32_t transferred; + /** Number of bytes which have not been buffered/transferred yet. */ + int32_t remaining; +} Transfer; + +/** Describes Multi Buffer List transfer on a UDP endpoint. */ +typedef struct { + /** Optional callback to invoke when the transfer completes. */ + MblTransferCallback fCallback; + /** Optional argument to the callback function. */ + void *pArgument; + /** Transfer type */ + volatile uint8_t transType; + /** List state (OK, FULL, NULL) (run time) */ + uint8_t listState; + /** Multi-Buffer List size */ + uint16_t listSize; + /** Pointer to multi-buffer list */ + USBDTransferBuffer *pMbl; + /** Offset number of buffers to start transfer */ + uint16_t offsetSize; + /** Current processing buffer index (run time) */ + uint16_t outCurr; + /** Loast loaded buffer index (run time) */ + uint16_t outLast; + /** Current buffer for input (run time) */ + uint16_t inCurr; +} MblTransfer; + +/** + * Describes the state of an endpoint of the UDP controller. + */ +typedef struct { + + /* CSR */ + //uint32_t CSR; + /** Current endpoint state. */ + volatile uint8_t state; + /** Current reception bank (0 or 1). */ + volatile uint8_t bank; + /** Maximum packet size for the endpoint. */ + volatile uint16_t size; + /** Describes an ongoing transfer (if current state is either + * UDP_ENDPOINT_SENDING or UDP_ENDPOINT_RECEIVING) */ + union { + TransferHeader transHdr; + Transfer singleTransfer; + MblTransfer mblTransfer; + } transfer; +} Endpoint; + +/*--------------------------------------------------------------------------- + * Internal variables + *---------------------------------------------------------------------------*/ + +/** Holds the internal state for each endpoint of the UDP. */ +static Endpoint endpoints[CHIP_USB_NUMENDPOINTS]; + +/*--------------------------------------------------------------------------- + * Internal Functions + *---------------------------------------------------------------------------*/ + +/** + * Enables the clock of the UDP peripheral. + * \return 1 if peripheral status changed. + */ +static uint8_t UDP_EnablePeripheralClock(void) +{ + if (!PMC_IsPeriphEnabled(ID_UDP)) { + PMC_EnablePeripheral(ID_UDP); + return 1; + } + return 0; +} + +/** + * Disables the UDP peripheral clock. + */ +static inline void UDP_DisablePeripheralClock(void) +{ + PMC_DisablePeripheral(ID_UDP); +} + +/** + * Enables the 48MHz USB clock. + */ +static inline void UDP_EnableUsbClock(void) +{ + REG_PMC_SCER = PMC_SCER_UDP; +} + +/** + * Disables the 48MHz USB clock. + */ +static inline void UDP_DisableUsbClock(void) +{ + REG_PMC_SCDR = PMC_SCER_UDP; +} + +/** + * Enables the UDP transceiver. + */ +static inline void UDP_EnableTransceiver(void) +{ + UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_TXVDIS; +} + +/** + * Disables the UDP transceiver. + */ +static inline void UDP_DisableTransceiver(void) +{ + UDP->UDP_TXVC |= UDP_TXVC_TXVDIS; +} + +/** + * Handles a completed transfer on the given endpoint, invoking the + * configured callback if any. + * \param bEndpoint Number of the endpoint for which the transfer has completed. + * \param bStatus Status code returned by the transfer operation + */ +static void UDP_EndOfTransfer(uint8_t bEndpoint, uint8_t bStatus) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // Check that endpoint was sending or receiving data + if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING)) { + + Transfer *pTransfer = (Transfer *)&(pEndpoint->transfer); + uint32_t transferred = pTransfer->transferred; + uint32_t remaining = pTransfer->remaining + pTransfer->buffered; + + TRACE_DEBUG_WP("EoT "); + + /* Endpoint returns in Idle state */ + pEndpoint->state = UDP_ENDPOINT_IDLE; + /* Reset descriptor values */ + pTransfer->pData = 0; + pTransfer->transferred = -1; + pTransfer->buffered = -1; + pTransfer->remaining = -1; + + // Invoke callback is present + if (pTransfer->fCallback != 0) { + + ((TransferCallback) pTransfer->fCallback) + (pTransfer->pArgument, + bStatus, + transferred, + remaining); + } + else { + TRACE_DEBUG_WP("NoCB "); + } + } + else if ( (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM) + || (pEndpoint->state == UDP_ENDPOINT_SENDINGM) ) { + + MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); + + TRACE_DEBUG_WP("EoMT "); + + /* Endpoint returns in Idle state */ + pEndpoint->state = UDP_ENDPOINT_IDLE; + /* Reset transfer descriptor */ + if (pTransfer->transType) { + MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer); + pMblt->listState = 0; + pMblt->outCurr = pMblt->inCurr = pMblt->outLast = 0; + } + /* Invoke callback */ + if (pTransfer->fCallback != 0) { + + ((MblTransferCallback) pTransfer->fCallback) + (pTransfer->pArgument, + bStatus); + } + else { + TRACE_DEBUG_WP("NoCB "); + } + } +} + +/** + * Clears the correct reception flag (bank 0 or bank 1) of an endpoint + * \param bEndpoint Index of endpoint + */ +static void UDP_ClearRxFlag(uint8_t bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + // Clear flag and change banks + if (pEndpoint->bank == 0) { + + CLEAR_CSR(bEndpoint, UDP_CSR_RX_DATA_BK0); + // Swap bank if in dual-fifo mode + if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) { + + pEndpoint->bank = 1; + } + } + else { + + CLEAR_CSR(bEndpoint, UDP_CSR_RX_DATA_BK1); + pEndpoint->bank = 0; + } +} + +/** + * Update multi-buffer-transfer descriptors. + * \param pTransfer Pointer to instance MblTransfer. + * \param size Size of bytes that processed. + * \param forceEnd Force the buffer END. + * \return 1 if current buffer ended. + */ +static uint8_t UDP_MblUpdate(MblTransfer *pTransfer, + USBDTransferBuffer * pBi, + uint16_t size, + uint8_t forceEnd) +{ + /* Update transfer descriptor */ + pBi->remaining -= size; + /* Check if list NULL */ + if (pTransfer->listState == MBL_NULL) { + return 1; + } + /* Check if current buffer ended */ + if (pBi->remaining == 0 || forceEnd || size == 0) { + + /* Process to next buffer */ + if ((++ pTransfer->outCurr) == pTransfer->listSize) + pTransfer->outCurr = 0; + /* Check buffer NULL case */ + if (pTransfer->outCurr == pTransfer->inCurr) + pTransfer->listState = MBL_NULL; + else { + pTransfer->listState = 0; + /* Continue transfer, prepare for next operation */ + pBi = &pTransfer->pMbl[pTransfer->outCurr]; + pBi->buffered = 0; + pBi->transferred = 0; + pBi->remaining = pBi->size; + } + return 1; + } + return 0; +} + +/** + * Transfers a data payload from the current tranfer buffer to the endpoint + * FIFO + * \param bEndpoint Number of the endpoint which is sending data. + */ +static uint8_t UDP_MblWriteFifo(uint8_t bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer); + USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->outCurr]); + int32_t size; + + volatile uint8_t * pBytes; + volatile uint8_t bufferEnd = 1; + + /* Get the number of bytes to send */ + size = pEndpoint->size; + if (size > pBi->remaining) size = pBi->remaining; + + TRACE_DEBUG_WP("w%d.%" PRId32 " ", pTransfer->outCurr, size); + + /* Record last accessed buffer */ + pTransfer->outLast = pTransfer->outCurr; + + pBytes = &(pBi->pBuffer[pBi->transferred + pBi->buffered]); + pBi->buffered += size; + bufferEnd = UDP_MblUpdate(pTransfer, pBi, size, 0); + + /* Write packet in the FIFO buffer */ + if (size) { + int32_t c8 = size >> 3; + int32_t c1 = size & 0x7; + for (; c8; c8 --) { + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + } + for (; c1; c1 --) { + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + } + } + return bufferEnd; +} + +/** + * Transfers a data payload from the current tranfer buffer to the endpoint + * FIFO + * \param bEndpoint Number of the endpoint which is sending data. + */ +static void UDP_WritePayload(uint8_t bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + int32_t size; + + // Get the number of bytes to send + size = pEndpoint->size; + if (size > pTransfer->remaining) { + + size = pTransfer->remaining; + } + + // Update transfer descriptor information + pTransfer->buffered += size; + pTransfer->remaining -= size; + + // Write packet in the FIFO buffer + while (size > 0) { + + UDP->UDP_FDR[bEndpoint] = *(pTransfer->pData); + pTransfer->pData++; + size--; + } +} + + +/** + * Transfers a data payload from an endpoint FIFO to the current transfer buffer + * \param bEndpoint Endpoint number. + * \param wPacketSize Size of received data packet + */ +static void UDP_ReadPayload(uint8_t bEndpoint, int32_t wPacketSize) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + + // Check that the requested size is not bigger than the remaining transfer + if (wPacketSize > pTransfer->remaining) { + + pTransfer->buffered += wPacketSize - pTransfer->remaining; + wPacketSize = pTransfer->remaining; + } + + // Update transfer descriptor information + pTransfer->remaining -= wPacketSize; + pTransfer->transferred += wPacketSize; + + // Retrieve packet + while (wPacketSize > 0) { + + *(pTransfer->pData) = (uint8_t) UDP->UDP_FDR[bEndpoint]; + pTransfer->pData++; + wPacketSize--; + } +} + +/** + * Received SETUP packet from endpoint 0 FIFO + * \param pRequest Generic USB SETUP request sent over Control endpoints + */ +static void UDP_ReadRequest(USBGenericRequest *pRequest) +{ + uint8_t *pData = (uint8_t *)pRequest; + uint32_t i; + + // Copy packet + for (i = 0; i < 8; i++) { + + *pData = (uint8_t) UDP->UDP_FDR[0]; + pData++; + } +} + +/** + * Checks if an ongoing transfer on an endpoint has been completed. + * \param bEndpoint Endpoint number. + * \return 1 if the current transfer on the given endpoint is complete; + * otherwise 0. + */ +static uint8_t UDP_IsTransferFinished(uint8_t bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + + // Check if it is a Control endpoint + // -> Control endpoint must always finish their transfer with a zero-length + // packet + if ((UDP->UDP_CSR[bEndpoint] & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL) { + + return (pTransfer->buffered < pEndpoint->size); + } + // Other endpoints only need to transfer all the data + else { + + return (pTransfer->buffered <= pEndpoint->size) + && (pTransfer->remaining == 0); + } +} + +/** + * Endpoint interrupt handler. + * Handle IN/OUT transfers, received SETUP packets and STALLing + * \param bEndpoint Index of endpoint + */ +static void UDP_EndpointHandler(uint8_t bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer); + uint32_t status = UDP->UDP_CSR[bEndpoint]; + uint16_t wPacketSize; + USBGenericRequest request; + + TRACE_DEBUG_WP("E%d ", bEndpoint); + TRACE_DEBUG_WP("st:0x%" PRIX32 " ", status); + + // Handle interrupts + // IN packet sent + if ((status & UDP_CSR_TXCOMP) != 0) { + + TRACE_DEBUG_WP("Wr "); + + // Check that endpoint was in MBL Sending state + if (pEndpoint->state == UDP_ENDPOINT_SENDINGM) { + + USBDTransferBuffer * pMbli = &(pMblt->pMbl[pMblt->outLast]); + uint8_t bufferEnd = 0; + + TRACE_DEBUG_WP("TxM%d.%d ", pMblt->listState, pMbli->buffered); + + // End of transfer ? + if (pMblt->listState == MBL_NULL && pMbli->buffered == 0) { + + pMbli->transferred += pMbli->buffered; + pMbli->buffered = 0; + + // Disable interrupt + UDP->UDP_IDR = 1 << bEndpoint; + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); + } + else { + + // Transfer remaining data + TRACE_DEBUG_WP("%d ", pEndpoint->size); + + if (pMbli->buffered > pEndpoint->size) { + pMbli->transferred += pEndpoint->size; + pMbli->buffered -= pEndpoint->size; + } + else { + pMbli->transferred += pMbli->buffered; + pMbli->buffered = 0; + } + + // Send next packet + if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) { + + // No double buffering + bufferEnd = UDP_MblWriteFifo(bEndpoint); + SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); + CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); + } + else { + // Double buffering + SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); + CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); + bufferEnd = UDP_MblWriteFifo(bEndpoint); + } + + if (bufferEnd && pMblt->fCallback) { + ((MblTransferCallback) pTransfer->fCallback) + (pTransfer->pArgument, + USBD_STATUS_PARTIAL_DONE); + } + } + } + // Check that endpoint was in Sending state + else if (pEndpoint->state == UDP_ENDPOINT_SENDING) { + + // End of transfer ? + if (UDP_IsTransferFinished(bEndpoint)) { + + pTransfer->transferred += pTransfer->buffered; + pTransfer->buffered = 0; + + // Disable interrupt if this is not a control endpoint + if ((status & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) { + + UDP->UDP_IDR = 1 << bEndpoint; + } + + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); + } + else { + + // Transfer remaining data + TRACE_DEBUG_WP(" %d ", pEndpoint->size); + + pTransfer->transferred += pEndpoint->size; + pTransfer->buffered -= pEndpoint->size; + + // Send next packet + if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) { + + // No double buffering + UDP_WritePayload(bEndpoint); + SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); + CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); + } + else { + // Double buffering + SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); + CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); + UDP_WritePayload(bEndpoint); + } + } + } + else { + // Acknowledge interrupt + TRACE_ERROR("Error Wr%d, %x\n\r", bEndpoint, pEndpoint->state); + CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); + } + } + + // OUT packet received + if ((status & UDP_CSR_RXDATA_BK) != 0) { + + TRACE_DEBUG_WP("Rd "); + + // Check that the endpoint is in Receiving state + if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) { + + // Check if an ACK has been received on a Control endpoint + if (((status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL) + && ((status & UDP_CSR_RXBYTECNT_Msk) == 0)) { + + // Acknowledge the data and finish the current transfer + UDP_ClearRxFlag(bEndpoint); + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + // Check if the data has been STALLed + else if ((status & UDP_CSR_FORCESTALL) != 0) { + + // Discard STALLed data + TRACE_DEBUG_WP("Discard "); + UDP_ClearRxFlag(bEndpoint); + } + // NAK the data + else { + + TRACE_DEBUG_WP("Nak "); + UDP->UDP_IDR = 1 << bEndpoint; + } + } + // Endpoint is in Read state + else { + + // Retrieve data and store it into the current transfer buffer + wPacketSize = (uint16_t) (status >> 16); + TRACE_DEBUG_WP("%d ", wPacketSize); + UDP_ReadPayload(bEndpoint, wPacketSize); + UDP_ClearRxFlag(bEndpoint); + + // Check if the transfer is finished + if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) { + + // Disable interrupt if this is not a control endpoint + if ((status & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) { + + UDP->UDP_IDR = 1 << bEndpoint; + } + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + } + } + + // STALL sent + if ((status & UDP_CSR_STALLSENTISOERROR) != 0) { + + CLEAR_CSR(bEndpoint, UDP_CSR_STALLSENTISOERROR); + + if ( (status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_ISO_IN + || (status & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_ISO_OUT ) { + + TRACE_WARNING("Isoe [%d] ", bEndpoint); + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED); + } + else { + + TRACE_WARNING("Sta 0x%X [%d] ", (int)status, bEndpoint); + + if (pEndpoint->state != UDP_ENDPOINT_HALTED) { + + TRACE_WARNING( "_ " ); + // If the endpoint is not halted, clear the STALL condition + CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL); + } + } + } + + // SETUP packet received + if ((status & UDP_CSR_RXSETUP) != 0) { + + TRACE_DEBUG_WP("Stp "); + + // If a transfer was pending, complete it + // Handles the case where during the status phase of a control write + // transfer, the host receives the device ZLP and ack it, but the ack + // is not received by the device + if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING)) { + + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + // Copy the setup packet + UDP_ReadRequest(&request); + + // Set the DIR bit before clearing RXSETUP in Control IN sequence + if (USBGenericRequest_GetDirection(&request) == USBGenericRequest_IN) { + + SET_CSR(bEndpoint, UDP_CSR_DIR); + } + // Acknowledge setup packet + CLEAR_CSR(bEndpoint, UDP_CSR_RXSETUP); + + // Forward the request to the upper layer + USBD_RequestHandler(0, &request); + } + +} + +/** + * Sends data through a USB endpoint. Sets up the transfer descriptor, + * writes one or two data payloads (depending on the number of FIFO bank + * for the endpoint) and then starts the actual transfer. The operation is + * complete when all the data has been sent. + * + * *If the size of the buffer is greater than the size of the endpoint + * (or twice the size if the endpoint has two FIFO banks), then the buffer + * must be kept allocated until the transfer is finished*. This means that + * it is not possible to declare it on the stack (i.e. as a local variable + * of a function which returns after starting a transfer). + * + * \param pEndpoint Pointer to Endpoint struct. + * \param pData Pointer to a buffer with the data to send. + * \param dLength Size of the data buffer. + * \return USBD_STATUS_SUCCESS if the transfer has been started; + * otherwise, the corresponding error status code. + */ +static inline uint8_t UDP_Write(uint8_t bEndpoint, + const void *pData, + uint32_t dLength) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + + /* Check that the endpoint is in Idle state */ + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + return USBD_STATUS_LOCKED; + } + TRACE_DEBUG_WP("Write%d(%" PRIu32 ") ", bEndpoint, dLength); + +/* int i; + for (i = 0; i < dLength; i++) { + if (!(i%16)) { + printf("\n\r"); + } + printf("0x%x ", ((uint8_t*)pData)[i]); + } + printf("\n\r"); +*/ + + /* Setup the transfer descriptor */ + pTransfer->pData = (void *) pData; + pTransfer->remaining = dLength; + pTransfer->buffered = 0; + pTransfer->transferred = 0; + + /* Send the first packet */ + pEndpoint->state = UDP_ENDPOINT_SENDING; + while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY); + UDP_WritePayload(bEndpoint); + SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); + + /* If double buffering is enabled and there is data remaining, + prepare another packet */ + if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) && (pTransfer->remaining > 0)) { + + UDP_WritePayload(bEndpoint); + } + + /* Enable interrupt on endpoint */ + UDP->UDP_IER = 1 << bEndpoint; + + return USBD_STATUS_SUCCESS; +} + +/** + * Sends data through a USB endpoint. Sets up the transfer descriptor list, + * writes one or two data payloads (depending on the number of FIFO bank + * for the endpoint) and then starts the actual transfer. The operation is + * complete when all the transfer buffer in the list has been sent. + * + * *If the size of the buffer is greater than the size of the endpoint + * (or twice the size if the endpoint has two FIFO banks), then the buffer + * must be kept allocated until the transfer is finished*. This means that + * it is not possible to declare it on the stack (i.e. as a local variable + * of a function which returns after starting a transfer). + * + * \param pEndpoint Pointer to Endpoint struct. + * \param pData Pointer to a buffer with the data to send. + * \param dLength Size of the data buffer. + * \return USBD_STATUS_SUCCESS if the transfer has been started; + * otherwise, the corresponding error status code. + */ +static inline uint8_t UDP_AddWr(uint8_t bEndpoint, + const void *pData, + uint32_t dLength) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + MblTransfer *pMbl = (MblTransfer*)&(pEndpoint->transfer); + USBDTransferBuffer *pTx; + + /* Check parameter */ + if (dLength >= 0x10000) + return USBD_STATUS_INVALID_PARAMETER; + + /* Data in progressing */ + if (pEndpoint->state > UDP_ENDPOINT_IDLE) { + /* If list full */ + if (pMbl->listState == MBL_FULL) { + return USBD_STATUS_LOCKED; + } + } + + TRACE_DEBUG_WP("AddW%d(%" PRIu32 ") ", bEndpoint, dLength); + + /* Add buffer to buffer list and update index */ + pTx = &(pMbl->pMbl[pMbl->inCurr]); + pTx->pBuffer = (uint8_t*)pData; + pTx->size = pTx->remaining = dLength; + pTx->transferred = pTx->buffered = 0; + /* Update input index */ + if (pMbl->inCurr >= (pMbl->listSize-1)) pMbl->inCurr = 0; + else pMbl->inCurr ++; + if (pMbl->inCurr == pMbl->outCurr) pMbl->listState = MBL_FULL; + else pMbl->listState = 0; + /* Start sending when offset achieved */ + if (MBL_NbBuffer(pMbl->inCurr, pMbl->outCurr, pMbl->listSize) + >= pMbl->offsetSize + && pEndpoint->state == UDP_ENDPOINT_IDLE) { + TRACE_DEBUG_WP("StartT "); + /* Change state */ + pEndpoint->state = UDP_ENDPOINT_SENDINGM; + while((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY); + /* Send first packet */ + UDP_MblWriteFifo(bEndpoint); + SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); + /* If double buffering is enabled and there is remaining, continue */ + if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) + && pMbl->pMbl[pMbl->outCurr].remaining) { + UDP_MblWriteFifo(bEndpoint); + } + /* Enable interrupt on endpoint */ + UDP->UDP_IER = 1 << bEndpoint; + } + + return USBD_STATUS_SUCCESS; +} + +/** + * Reads incoming data on an USB endpoint This methods sets the transfer + * descriptor and activate the endpoint interrupt. The actual transfer is + * then carried out by the endpoint interrupt handler. The Read operation + * finishes either when the buffer is full, or a short packet (inferior to + * endpoint maximum size) is received. + * + * *The buffer must be kept allocated until the transfer is finished*. + * \param bEndpoint Endpoint number. + * \param pData Pointer to a data buffer. + * \param dLength Size of the data buffer in bytes. + * \return USBD_STATUS_SUCCESS if the read operation has been started; + * otherwise, the corresponding error code. + */ +static inline uint8_t UDP_Read(uint8_t bEndpoint, + void *pData, + uint32_t dLength) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer); + + /* Return if the endpoint is not in IDLE state */ + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + + return USBD_STATUS_LOCKED; + } + + /* Endpoint enters Receiving state */ + pEndpoint->state = UDP_ENDPOINT_RECEIVING; + TRACE_DEBUG_WP("Read%d(%" PRIu32 ") ", bEndpoint, dLength); + +/* int i; + for (i = 0; i < dLength; i++) { + if (!(i%16)) { + printf("\n\r"); + } + printf("0x%x ", ((uint8_t*)pData)[i]); + } + printf("\n\r"); +*/ + + /* Set the transfer descriptor */ + pTransfer->pData = pData; + pTransfer->remaining = dLength; + pTransfer->buffered = 0; + pTransfer->transferred = 0; + + /* Enable interrupt on endpoint */ + UDP->UDP_IER = 1 << bEndpoint; + + return USBD_STATUS_SUCCESS; +} + + +/*--------------------------------------------------------------------------- + * Exported functions + *---------------------------------------------------------------------------*/ + +/** + * USBD (UDP) interrupt handler + * Manages device resume, suspend, end of bus reset. + * Forwards endpoint events to the appropriate handler. + */ +void USBD_IrqHandler(void) +{ + uint32_t status; + int32_t eptnum = 0; + + /* Enable peripheral ? */ + //UDP_EnablePeripheralClock(); + + /* Get interrupt status + Some interrupts may get masked depending on the device state */ + status = UDP->UDP_ISR; + status &= UDP->UDP_IMR; + + TRACE_DEBUG("status; 0x%" PRIx32 , status); + + if (USBD_GetState() < USBD_STATE_POWERED) { + + status &= UDP_ICR_WAKEUP | UDP_ICR_RXRSM; + UDP->UDP_ICR = ~status; + } + + /* Return immediately if there is no interrupt to service */ + if (status == 0) { + + TRACE_DEBUG_WP(".\n\r"); + return; + } + + /* Toggle USB LED if the device is active */ + if (USBD_GetState() >= USBD_STATE_POWERED) { + + //LED_Set(USBD_LEDUSB); + } + + /* Service interrupts */ + + /** / Start Of Frame (SOF) */ + //if (ISSET(dStatus, UDP_ISR_SOFINT)) { + // + // TRACE_DEBUG("SOF"); + // + // // Invoke the SOF callback + // USB_StartOfFrameCallback(pUsb); + // + // // Acknowledge interrupt + // UDP->UDP_ICR = UDP_ICR_SOFINT; + // dStatus &= ~UDP_ISR_SOFINT; + //} + /* Resume (Wakeup) */ + if ((status & (UDP_ISR_WAKEUP | UDP_ISR_RXRSM)) != 0) { + + TRACE_INFO_WP("Res "); + /* Clear and disable resume interrupts */ + UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP; + UDP->UDP_IDR = UDP_IDR_WAKEUP | UDP_IDR_RXRSM; + /* Do resome operations */ + USBD_ResumeHandler(); + } + + /* Suspend + This interrupt is always treated last (hence the '==') */ + if (status == UDP_ISR_RXSUSP) { + + TRACE_INFO_WP("Susp "); + /* Enable wakeup */ + UDP->UDP_IER = UDP_IER_WAKEUP | UDP_IER_RXRSM; + /* Acknowledge interrupt */ + UDP->UDP_ICR = UDP_ICR_RXSUSP; + /* Do suspend operations */ + USBD_SuspendHandler(); + } + /* End of bus reset */ + else if ((status & UDP_ISR_ENDBUSRES) != 0) { + + TRACE_INFO_WP("EoBRes "); + +#if defined(BOARD_USB_DFU) +#if defined(APPLICATION_dfu) + /* if we are currently in the DFU bootloader, and we are beyond + * the MANIFEST stage, we shall switch to the normal + * application */ + if (g_dfu->past_manifest) + USBDFU_SwitchToApp(); +#else + /* if we are currently in the main application, and we are in + * appDETACH state, switch into the DFU bootloader */ + if (g_dfu->state == DFU_STATE_appDETACH) + DFURT_SwitchToDFU(); +#endif /* APPLICATION_dfu */ +#endif /* BOARD_USB_DFU */ + + /* Flush and enable the Suspend interrupt */ + UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP; + UDP->UDP_IER = UDP_IER_RXSUSP; + + /* Do RESET operations */ + USBD_ResetHandler(); + + /* Acknowledge end of bus reset interrupt */ + UDP->UDP_ICR = UDP_ICR_ENDBUSRES; + } + /* Endpoint interrupts */ + else { + + status &= ((1 << CHIP_USB_NUMENDPOINTS) - 1); + while (status != 0) { + + /* Check if endpoint has a pending interrupt */ + if ((status & (1 << eptnum)) != 0) { + + UDP_EndpointHandler(eptnum); + status &= ~(1 << eptnum); + + if (status != 0) { + + TRACE_INFO_WP("\n\r - "); + } + } + eptnum++; + } + } + + /* Toggle LED back to its previous state */ + TRACE_DEBUG_WP("!"); + TRACE_INFO_WP("\n\r"); + if (USBD_GetState() >= USBD_STATE_POWERED) { + + //LED_Clear(USBD_LEDUSB); + } +} + +/** + * \brief Reset endpoints and disable them. + * -# Terminate transfer if there is any, with given status; + * -# Reset the endpoint & disable it. + * \param bmEPs Bitmap for endpoints to reset. + * \param bStatus Status passed to terminate transfer on endpoint. + * \param bKeepCfg 1 to keep old endpoint configuration. + * \note Use USBD_HAL_ConfigureEP() to configure and enable endpoint + if not keeping old configuration. + * \sa USBD_HAL_ConfigureEP(). + */ +void USBD_HAL_ResetEPs(uint32_t bmEPs, uint8_t bStatus, uint8_t bKeepCfg) +{ + Endpoint *pEndpoint; + uint32_t tmp = bmEPs & ((1<UDP_IDR = epBit; + /* Kill pending TXPKTREADY */ + CLEAR_CSR(ep, UDP_CSR_TXPKTRDY); + + /* Reset transfer information */ + pEndpoint = &(endpoints[ep]); + /* Reset endpoint state */ + pEndpoint->bank = 0; + /* Endpoint configure */ + epCfg = UDP->UDP_CSR[ep]; + /* Reset endpoint */ + UDP->UDP_RST_EP |= epBit; + UDP->UDP_RST_EP &= ~epBit; + /* Restore configure */ + if (bKeepCfg) { + //SET_CSR(ep, pEndpoint->CSR); + SET_CSR(ep, epCfg); + } + else { + //pEndpoint->CSR = 0; + pEndpoint->state = UDP_ENDPOINT_DISABLED; + } + + /* Terminate transfer on this EP */ + UDP_EndOfTransfer(ep, bStatus); + } + epBit <<= 1; + } + /* Reset EPs */ + // UDP->UDP_RST_EP |= bmEPs; + // UDP->UDP_RST_EP &= ~bmEPs; +} + +/** + * Cancel pending READ/WRITE + * \param bmEPs Bitmap for endpoints to reset. + * \note EP callback is invoked with USBD_STATUS_CANCELED. + */ +void USBD_HAL_CancelIo(uint32_t bmEPs) +{ + uint32_t tmp = bmEPs & ((1<UDP_IDR = epBit; + /* Kill pending TXPKTREADY */ + CLEAR_CSR(ep, UDP_CSR_TXPKTRDY); + + /* Terminate transfer on this EP */ + UDP_EndOfTransfer(ep, USBD_STATUS_CANCELED); + } + epBit <<= 1; + } +} + +/** + * Configures an endpoint according to its endpoint Descriptor. + * \param pDescriptor Pointer to an endpoint descriptor. + */ +uint8_t USBD_HAL_ConfigureEP(const USBEndpointDescriptor *pDescriptor) +{ + Endpoint *pEndpoint; + uint8_t bEndpoint; + uint8_t bType; + uint8_t bEndpointDir; + + /* NULL descriptor -> Control endpoint 0 in default */ + if (pDescriptor == 0) { + bEndpoint = 0; + pEndpoint = &(endpoints[bEndpoint]); + bType= USBEndpointDescriptor_CONTROL; + bEndpointDir = 0; + pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0); + } + /* Device descriptor -> Specific Control EP */ + else if (pDescriptor->bDescriptorType == USBGenericDescriptor_DEVICE) { + bEndpoint = 0; + pEndpoint = &(endpoints[bEndpoint]); + bType = USBEndpointDescriptor_CONTROL; + bEndpointDir = 0; + pEndpoint->size = ((USBDeviceDescriptor *)pDescriptor)->bMaxPacketSize0; + } + /* Not endpoint descriptor, ERROR! */ + else if (pDescriptor->bDescriptorType != USBGenericDescriptor_ENDPOINT) { + return 0xFF; + } + else { + bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor); + pEndpoint = &(endpoints[bEndpoint]); + bType = USBEndpointDescriptor_GetType(pDescriptor); + bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor); + pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor); + } + + /* Abort the current transfer is the endpoint was configured and in + Write or Read state */ + if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING) + || (pEndpoint->state == UDP_ENDPOINT_SENDING) + || (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM) + || (pEndpoint->state == UDP_ENDPOINT_SENDINGM)) { + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_RESET); + } + pEndpoint->state = UDP_ENDPOINT_IDLE; + + /* Reset Endpoint Fifos */ + UDP->UDP_RST_EP |= (1 << bEndpoint); + UDP->UDP_RST_EP &= ~(1 << bEndpoint); + + /* Configure endpoint */ + SET_CSR(bEndpoint, (uint32_t)UDP_CSR_EPEDS + | (bType << 8) | (bEndpointDir << 10)); + if (bType != USBEndpointDescriptor_CONTROL) { + + } + else { + + UDP->UDP_IER = (1 << bEndpoint); + } + + TRACE_INFO_WP("CfgEp%d ", bEndpoint); + return bEndpoint; +} + +/** + * Set callback for a USB endpoint for transfer (read/write). + * + * \param bEP Endpoint number. + * \param fCallback Optional callback function to invoke when the transfer is + * complete. + * \param pCbData Optional pointer to data to the callback function. + * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED if endpoint is busy. + */ +uint8_t USBD_HAL_SetTransferCallback(uint8_t bEP, + TransferCallback fCallback, + void *pCbData) +{ + Endpoint *pEndpoint = &(endpoints[bEP]); + TransferHeader *pTransfer = (TransferHeader*)&(pEndpoint->transfer); + /* Check that the endpoint is not transferring */ + if (pEndpoint->state > UDP_ENDPOINT_IDLE) { + return USBD_STATUS_LOCKED; + } + TRACE_DEBUG_WP("sXfrCb "); + /* Setup the transfer callback and extension data */ + pTransfer->fCallback = (void*)fCallback; + pTransfer->pArgument = pCbData; + return USBD_STATUS_SUCCESS; +} + +/** + * Configure an endpoint to use multi-buffer-list transfer mode. + * The buffers can be added by _Read/_Write function. + * \param pMbList Pointer to a multi-buffer list used, NULL to disable MBL. + * \param mblSize Multi-buffer list size (number of buffers can be queued) + * \param startOffset When number of buffer achieve this offset transfer start + */ +uint8_t USBD_HAL_SetupMblTransfer( uint8_t bEndpoint, + USBDTransferBuffer* pMbList, + uint16_t mblSize, + uint16_t startOffset) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + MblTransfer *pXfr = (MblTransfer*)&(pEndpoint->transfer); + uint16_t i; + /* Check that the endpoint is not transferring */ + if (pEndpoint->state > UDP_ENDPOINT_IDLE) { + return USBD_STATUS_LOCKED; + } + TRACE_DEBUG_WP("sMblXfr "); + /* Enable Multi-Buffer Transfer List */ + if (pMbList) { + /* Reset list items */ + for (i = 0; i < mblSize; i --) { + pMbList[i].pBuffer = NULL; + pMbList[i].size = 0; + pMbList[i].transferred = 0; + pMbList[i].buffered = 0; + pMbList[i].remaining = 0; + } + /* Setup transfer */ + pXfr->transType = 1; + pXfr->listState = 0; /* OK */ + pXfr->listSize = mblSize; + pXfr->pMbl = pMbList; + pXfr->outCurr = pXfr->outLast = 0; + pXfr->inCurr = 0; + pXfr->offsetSize = startOffset; + } + /* Disable Multi-Buffer Transfer */ + else { + pXfr->transType = 0; + pXfr->pMbl = NULL; + pXfr->listSize = 0; + pXfr->offsetSize = 1; + } + return USBD_STATUS_SUCCESS; +} + +/** + * Sends data through a USB endpoint. Sets up the transfer descriptor, + * writes one or two data payloads (depending on the number of FIFO bank + * for the endpoint) and then starts the actual transfer. The operation is + * complete when all the data has been sent. + * + * *If the size of the buffer is greater than the size of the endpoint + * (or twice the size if the endpoint has two FIFO banks), then the buffer + * must be kept allocated until the transfer is finished*. This means that + * it is not possible to declare it on the stack (i.e. as a local variable + * of a function which returns after starting a transfer). + * + * \param bEndpoint Endpoint number. + * \param pData Pointer to a buffer with the data to send. + * \param dLength Size of the data buffer. + * \return USBD_STATUS_SUCCESS if the transfer has been started; + * otherwise, the corresponding error status code. + */ +uint8_t USBD_HAL_Write( uint8_t bEndpoint, + const void *pData, + uint32_t dLength) +{ + if (endpoints[bEndpoint].transfer.transHdr.transType) + return UDP_AddWr(bEndpoint, pData, dLength); + else + return UDP_Write(bEndpoint, pData, dLength); +} + +/** + * Reads incoming data on an USB endpoint This methods sets the transfer + * descriptor and activate the endpoint interrupt. The actual transfer is + * then carried out by the endpoint interrupt handler. The Read operation + * finishes either when the buffer is full, or a short packet (inferior to + * endpoint maximum size) is received. + * + * *The buffer must be kept allocated until the transfer is finished*. + * \param bEndpoint Endpoint number. + * \param pData Pointer to a data buffer. + * \param dLength Size of the data buffer in bytes. + * \return USBD_STATUS_SUCCESS if the read operation has been started; + * otherwise, the corresponding error code. + */ +uint8_t USBD_HAL_Read(uint8_t bEndpoint, + void *pData, + uint32_t dLength) +{ + if (endpoints[bEndpoint].transfer.transHdr.transType) + return USBD_STATUS_SW_NOT_SUPPORTED; + else + return UDP_Read(bEndpoint, pData, dLength); +} + +/** + * \brief Enable Pull-up, connect. + * + * -# Enable HW access if needed + * -# Enable Pull-Up + * -# Disable HW access if needed + */ +void USBD_HAL_Connect(void) +{ + uint8_t dis = UDP_EnablePeripheralClock(); + UDP->UDP_TXVC |= UDP_TXVC_PUON; + if (dis) UDP_DisablePeripheralClock(); +} + +/** + * \brief Disable Pull-up, disconnect. + * + * -# Enable HW access if needed + * -# Disable PULL-Up + * -# Disable HW access if needed + */ +void USBD_HAL_Disconnect(void) +{ + uint8_t dis = UDP_EnablePeripheralClock(); + UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_PUON; + if (dis) UDP_DisablePeripheralClock(); +} + +/** + * Starts a remote wake-up procedure. + */ +void USBD_HAL_RemoteWakeUp(void) +{ + UDP_EnablePeripheralClock(); + UDP_EnableUsbClock(); + UDP_EnableTransceiver(); + + TRACE_INFO_WP("RWUp "); + + // Activates a remote wakeup (edge on ESR), then clear ESR + UDP->UDP_GLB_STAT |= UDP_GLB_STAT_ESR; + UDP->UDP_GLB_STAT &= ~(uint32_t)UDP_GLB_STAT_ESR; +} + +/** + * Sets the device address to the given value. + * \param address New device address. + */ +void USBD_HAL_SetAddress(uint8_t address) +{ + /* Set address */ + UDP->UDP_FADDR = UDP_FADDR_FEN | (address & UDP_FADDR_FADD_Msk); + /* If the address is 0, the device returns to the Default state */ + if (address == 0) UDP->UDP_GLB_STAT = 0; + /* If the address is non-zero, the device enters the Address state */ + else UDP->UDP_GLB_STAT = UDP_GLB_STAT_FADDEN; +} + +/** + * Sets the current device configuration. + * \param cfgnum - Configuration number to set. + */ +void USBD_HAL_SetConfiguration(uint8_t cfgnum) +{ + /* If the configuration number if non-zero, the device enters the + Configured state */ + if (cfgnum != 0) UDP->UDP_GLB_STAT |= UDP_GLB_STAT_CONFG; + /* If the configuration number is zero, the device goes back to the Address + state */ + else { + UDP->UDP_GLB_STAT = UDP_FADDR_FEN; + } +} + +/** + * Initializes the USB HW Access driver. + */ +void USBD_HAL_Init(void) +{ + TRACE_DEBUG("%s\n\r", "USBD_HAL_Init"); + + /* Must before USB & TXVC access! */ + UDP_EnablePeripheralClock(); + + /* Reset & disable endpoints */ + USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0); + + /* Configure the pull-up on D+ and disconnect it */ + UDP->UDP_TXVC &= ~(uint32_t)UDP_TXVC_PUON; + + UDP_EnableUsbClock(); + + UDP->UDP_IDR = 0xFE; + UDP->UDP_IER = UDP_IER_WAKEUP; +} + +/** + * Causes the given endpoint to acknowledge the next packet it receives + * with a STALL handshake except setup request. + * \param bEP Endpoint number. + * \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED. + */ +uint8_t USBD_HAL_Stall(uint8_t bEP) +{ + Endpoint *pEndpoint = &(endpoints[bEP]); + + /* Check that endpoint is in Idle state */ + if (pEndpoint->state != UDP_ENDPOINT_IDLE) { + TRACE_WARNING("UDP_Stall: EP%d locked\n\r", bEP); + return USBD_STATUS_LOCKED; + } + /* STALL endpoint */ + SET_CSR(bEP, UDP_CSR_FORCESTALL); + TRACE_DEBUG_WP("Stall%d ", bEP); + return USBD_STATUS_SUCCESS; +} + +/** + * Sets/Clear/Get the HALT state on the endpoint. + * In HALT state, the endpoint should keep stalling any packet. + * \param bEndpoint Endpoint number. + * \param ctl Control code CLR/HALT/READ. + * 0: Clear HALT state; + * 1: Set HALT state; + * .: Return HALT status. + * \return USBD_STATUS_INVALID_PARAMETER if endpoint not exist, + * otherwise endpoint halt status. + */ +uint8_t USBD_HAL_Halt(uint8_t bEndpoint, uint8_t ctl) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + uint8_t status = 0; + + /* SET Halt */ + if (ctl == 1) { + /* Check that endpoint is enabled and not already in Halt state */ + if ((pEndpoint->state != UDP_ENDPOINT_DISABLED) + && (pEndpoint->state != UDP_ENDPOINT_HALTED)) { + + TRACE_DEBUG_WP("Halt%d ", bEndpoint); + + /* Abort the current transfer if necessary */ + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED); + + /* Put endpoint into Halt state */ + SET_CSR(bEndpoint, UDP_CSR_FORCESTALL); + pEndpoint->state = UDP_ENDPOINT_HALTED; + + /* Enable the endpoint interrupt */ + UDP->UDP_IER = 1 << bEndpoint; + } + } + /* CLEAR Halt */ + else if (ctl == 0) { + /* Check if the endpoint is halted */ + //if (pEndpoint->state != UDP_ENDPOINT_DISABLED) { + if (pEndpoint->state == UDP_ENDPOINT_HALTED) { + + TRACE_DEBUG_WP("Unhalt%d ", bEndpoint); + + /* Return endpoint to Idle state */ + pEndpoint->state = UDP_ENDPOINT_IDLE; + + /* Clear FORCESTALL flag */ + CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL); + + /* Reset Endpoint Fifos, beware this is a 2 steps operation */ + UDP->UDP_RST_EP |= 1 << bEndpoint; + UDP->UDP_RST_EP &= ~(1 << bEndpoint); + } + } + + /* Return Halt status */ + if (pEndpoint->state == UDP_ENDPOINT_HALTED) { + status = 1; + } + return( status ); +} + +/** + * Indicates if the device is running in high or full-speed. Always returns 0 + * since UDP does not support high-speed mode. + */ +uint8_t USBD_HAL_IsHighSpeed(void) +{ + return 0; +} + +/** + * Suspend USB Device HW Interface + * + * -# Disable transceiver + * -# Disable USB Clock + * -# Disable USB Peripheral + */ +void USBD_HAL_Suspend(void) +{ + /* The device enters the Suspended state */ + UDP_DisableTransceiver(); + UDP_DisableUsbClock(); + UDP_DisablePeripheralClock(); +} + +/** + * Activate USB Device HW Interface + * -# Enable USB Peripheral + * -# Enable USB Clock + * -# Enable transceiver + */ +void USBD_HAL_Activate(void) +{ + UDP_EnablePeripheralClock(); + UDP_EnableUsbClock(); + UDP_EnableTransceiver(); +} + +/**@}*/ + diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/efc.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/efc.c index b6a028e9..0c288e0d 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/efc.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/efc.c @@ -1,290 +1,290 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** \addtogroup efc_module Working with EEFC - * The EEFC driver provides the interface to configure and use the EEFC - * peripheral. - * - * The user needs to set the number of wait states depending on the frequency used.\n - * Configure number of cycles for flash read/write operations in the FWS field of EEFC_FMR. - * - * It offers a function to send flash command to EEFC and waits for the - * flash to be ready. - * - * To send flash command, the user could do in either of following way: - *
    - *
  • Write a correct key, command and argument in EEFC_FCR.
  • - *
  • Or, Use IAP (In Application Programming) function which is executed from - * ROM directly, this allows flash programming to be done by code running in flash.
  • - *
  • Once the command is achieved, it can be detected even by polling EEFC_FSR or interrupt. - *
- * - * The command argument could be a page number,GPNVM number or nothing, it depends on - * the command itself. Some useful functions in this driver could help user tranlate physical - * flash address into a page number and vice verse. - * - * For more accurate information, please look at the EEFC section of the - * Datasheet. - * - * Related files :\n - * \ref efc.c\n - * \ref efc.h.\n -*/ -/*@{*/ -/*@}*/ - - -/** - * \file - * - * Implementation of Enhanced Embedded Flash Controller (EEFC). - * - */ - - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ -#include "chip.h" -#include "efc.h" - -#include - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Enables the flash ready interrupt source on the EEFC peripheral. - * - * \param efc Pointer to a Efc instance - */ -extern void EFC_EnableFrdyIt( Efc* efc ) -{ - efc->EEFC_FMR |= EEFC_FMR_FRDY ; -} - -/** - * \brief Disables the flash ready interrupt source on the EEFC peripheral. - * - * \param efc Pointer to a Efc instance - */ - -extern void EFC_DisableFrdyIt( Efc* efc ) -{ - efc->EEFC_FMR &= ~((uint32_t)EEFC_FMR_FRDY) ; -} - - -/** - * \brief Set read/write wait state on the EEFC perpherial. - * - * \param efc Pointer to a Efc instance - * \param cycles the number of wait states in cycle. - */ - -extern void EFC_SetWaitState( Efc* efc, uint8_t ucCycles ) -{ - uint32_t dwValue ; - - dwValue = efc->EEFC_FMR ; - dwValue &= ~((uint32_t)EEFC_FMR_FWS_Msk) ; - dwValue |= EEFC_FMR_FWS(ucCycles); - efc->EEFC_FMR = dwValue ; -} - -/** - * \brief Returns the current status of the EEFC. - * - * \note Keep in mind that this function clears the value of some status bits (LOCKE, PROGE). - * - * \param efc Pointer to a Efc instance - */ -extern uint32_t EFC_GetStatus( Efc* efc ) -{ - return efc->EEFC_FSR ; -} - -/** - * \brief Returns the result of the last executed command. - * - * \param efc Pointer to a Efc instance - */ -extern uint32_t EFC_GetResult( Efc* efc ) -{ - return efc->EEFC_FRR ; -} - -/** - * \brief Translates the given address page and offset values. - * \note The resulting values are stored in the provided variables if they are not null. - * - * \param efc Pointer to a Efc instance - * \param address Address to translate. - * \param pPage First page accessed. - * \param pOffset Byte offset in first page. - */ -extern void EFC_TranslateAddress( Efc** ppEfc, uint32_t dwAddress, uint16_t* pwPage, uint16_t* pwOffset ) -{ - Efc *pEfc ; - uint16_t wPage ; - uint16_t wOffset ; - - assert( dwAddress >= IFLASH_ADDR ) ; - assert( dwAddress <= (IFLASH_ADDR + IFLASH_SIZE) ) ; - - pEfc = EFC ; - wPage = (dwAddress - IFLASH_ADDR) / IFLASH_PAGE_SIZE; - wOffset = (dwAddress - IFLASH_ADDR) % IFLASH_PAGE_SIZE; - - TRACE_DEBUG( "Translated 0x%08X to page=%d and offset=%d\n\r", dwAddress, wPage, wOffset ) ; - /* Store values */ - if ( pEfc ) - { - *ppEfc = pEfc ; - } - - if ( pwPage ) - { - *pwPage = wPage ; - } - - if ( pwOffset ) - { - *pwOffset = wOffset ; - } -} - -/** - * \brief Computes the address of a flash access given the page and offset. - * - * \param efc Pointer to a Efc instance - * \param page Page number. - * \param offset Byte offset inside page. - * \param pAddress Computed address (optional). - */ -extern void EFC_ComputeAddress( Efc *efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress ) -{ - uint32_t dwAddress ; - - assert( efc ) ; - assert( wPage <= IFLASH_NB_OF_PAGES ) ; - assert( wOffset < IFLASH_PAGE_SIZE ) ; - - /* Compute address */ - dwAddress = IFLASH_ADDR + wPage * IFLASH_PAGE_SIZE + wOffset ; - - /* Store result */ - if ( pdwAddress != NULL ) - { - *pdwAddress = dwAddress ; - } -} - -/** - * \brief Starts the executing the given command on the EEFC and returns as soon as the command is started. - * - * \note It does NOT set the FMCN field automatically. - * \param efc Pointer to a Efc instance - * \param command Command to execute. - * \param argument Command argument (should be 0 if not used). - */ -extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument ) -{ - /* Check command & argument */ - switch ( dwCommand ) - { - case EFC_FCMD_WP: - case EFC_FCMD_WPL: - case EFC_FCMD_EWP: - case EFC_FCMD_EWPL: - case EFC_FCMD_SLB: - case EFC_FCMD_CLB: - assert( dwArgument < IFLASH_NB_OF_PAGES ) ; - break ; - - case EFC_FCMD_SFB: - case EFC_FCMD_CFB: - assert( dwArgument < 2 ) ; - break; - - case EFC_FCMD_GETD: - case EFC_FCMD_EA: - case EFC_FCMD_GLB: - case EFC_FCMD_GFB: - case EFC_FCMD_STUI: - assert( dwArgument == 0 ) ; - break; - - default: assert( 0 ) ; - } - - /* Start command Embedded flash */ - assert( (efc->EEFC_FSR & EEFC_FMR_FRDY) == EEFC_FMR_FRDY ) ; - efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ; -} - -/** - * \brief Performs the given command and wait until its completion (or an error). - * - * \param efc Pointer to a Efc instance - * \param command Command to perform. - * \param argument Optional command argument. - * - * \return 0 if successful, otherwise returns an error code. - */ - -extern uint32_t EFC_PerformCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument, uint32_t dwUseIAP ) -{ - if ( dwUseIAP != 0 ) - { - /* Pointer on IAP function in ROM */ - static uint32_t (*IAP_PerformCommand)( uint32_t, uint32_t ) ; - - IAP_PerformCommand = (uint32_t (*)( uint32_t, uint32_t )) *((uint32_t*)CHIP_FLASH_IAP_ADDRESS ) ; - IAP_PerformCommand( 0, EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ) ; - - return (efc->EEFC_FSR & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)) ; - } - else - { - uint32_t dwStatus ; - - efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ; - do - { - dwStatus = efc->EEFC_FSR ; - } - while ( (dwStatus & EEFC_FSR_FRDY) != EEFC_FSR_FRDY ) ; - - return ( dwStatus & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE) ) ; - } -} - - +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** \addtogroup efc_module Working with EEFC + * The EEFC driver provides the interface to configure and use the EEFC + * peripheral. + * + * The user needs to set the number of wait states depending on the frequency used.\n + * Configure number of cycles for flash read/write operations in the FWS field of EEFC_FMR. + * + * It offers a function to send flash command to EEFC and waits for the + * flash to be ready. + * + * To send flash command, the user could do in either of following way: + *
    + *
  • Write a correct key, command and argument in EEFC_FCR.
  • + *
  • Or, Use IAP (In Application Programming) function which is executed from + * ROM directly, this allows flash programming to be done by code running in flash.
  • + *
  • Once the command is achieved, it can be detected even by polling EEFC_FSR or interrupt. + *
+ * + * The command argument could be a page number,GPNVM number or nothing, it depends on + * the command itself. Some useful functions in this driver could help user tranlate physical + * flash address into a page number and vice verse. + * + * For more accurate information, please look at the EEFC section of the + * Datasheet. + * + * Related files :\n + * \ref efc.c\n + * \ref efc.h.\n +*/ +/*@{*/ +/*@}*/ + + +/** + * \file + * + * Implementation of Enhanced Embedded Flash Controller (EEFC). + * + */ + + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ +#include "chip.h" +#include "efc.h" + +#include + +/*---------------------------------------------------------------------------- + * Exported functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Enables the flash ready interrupt source on the EEFC peripheral. + * + * \param efc Pointer to a Efc instance + */ +extern void EFC_EnableFrdyIt( Efc* efc ) +{ + efc->EEFC_FMR |= EEFC_FMR_FRDY ; +} + +/** + * \brief Disables the flash ready interrupt source on the EEFC peripheral. + * + * \param efc Pointer to a Efc instance + */ + +extern void EFC_DisableFrdyIt( Efc* efc ) +{ + efc->EEFC_FMR &= ~((uint32_t)EEFC_FMR_FRDY) ; +} + + +/** + * \brief Set read/write wait state on the EEFC perpherial. + * + * \param efc Pointer to a Efc instance + * \param cycles the number of wait states in cycle. + */ + +extern void EFC_SetWaitState( Efc* efc, uint8_t ucCycles ) +{ + uint32_t dwValue ; + + dwValue = efc->EEFC_FMR ; + dwValue &= ~((uint32_t)EEFC_FMR_FWS_Msk) ; + dwValue |= EEFC_FMR_FWS(ucCycles); + efc->EEFC_FMR = dwValue ; +} + +/** + * \brief Returns the current status of the EEFC. + * + * \note Keep in mind that this function clears the value of some status bits (LOCKE, PROGE). + * + * \param efc Pointer to a Efc instance + */ +extern uint32_t EFC_GetStatus( Efc* efc ) +{ + return efc->EEFC_FSR ; +} + +/** + * \brief Returns the result of the last executed command. + * + * \param efc Pointer to a Efc instance + */ +extern uint32_t EFC_GetResult( Efc* efc ) +{ + return efc->EEFC_FRR ; +} + +/** + * \brief Translates the given address page and offset values. + * \note The resulting values are stored in the provided variables if they are not null. + * + * \param efc Pointer to a Efc instance + * \param address Address to translate. + * \param pPage First page accessed. + * \param pOffset Byte offset in first page. + */ +extern void EFC_TranslateAddress( Efc** ppEfc, uint32_t dwAddress, uint16_t* pwPage, uint16_t* pwOffset ) +{ + Efc *pEfc ; + uint16_t wPage ; + uint16_t wOffset ; + + assert( dwAddress >= IFLASH_ADDR ) ; + assert( dwAddress <= (IFLASH_ADDR + IFLASH_SIZE) ) ; + + pEfc = EFC ; + wPage = (dwAddress - IFLASH_ADDR) / IFLASH_PAGE_SIZE; + wOffset = (dwAddress - IFLASH_ADDR) % IFLASH_PAGE_SIZE; + + TRACE_DEBUG( "Translated 0x%08X to page=%d and offset=%d\n\r", dwAddress, wPage, wOffset ) ; + /* Store values */ + if ( pEfc ) + { + *ppEfc = pEfc ; + } + + if ( pwPage ) + { + *pwPage = wPage ; + } + + if ( pwOffset ) + { + *pwOffset = wOffset ; + } +} + +/** + * \brief Computes the address of a flash access given the page and offset. + * + * \param efc Pointer to a Efc instance + * \param page Page number. + * \param offset Byte offset inside page. + * \param pAddress Computed address (optional). + */ +extern void EFC_ComputeAddress( Efc *efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress ) +{ + uint32_t dwAddress ; + + assert( efc ) ; + assert( wPage <= IFLASH_NB_OF_PAGES ) ; + assert( wOffset < IFLASH_PAGE_SIZE ) ; + + /* Compute address */ + dwAddress = IFLASH_ADDR + wPage * IFLASH_PAGE_SIZE + wOffset ; + + /* Store result */ + if ( pdwAddress != NULL ) + { + *pdwAddress = dwAddress ; + } +} + +/** + * \brief Starts the executing the given command on the EEFC and returns as soon as the command is started. + * + * \note It does NOT set the FMCN field automatically. + * \param efc Pointer to a Efc instance + * \param command Command to execute. + * \param argument Command argument (should be 0 if not used). + */ +extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument ) +{ + /* Check command & argument */ + switch ( dwCommand ) + { + case EFC_FCMD_WP: + case EFC_FCMD_WPL: + case EFC_FCMD_EWP: + case EFC_FCMD_EWPL: + case EFC_FCMD_SLB: + case EFC_FCMD_CLB: + assert( dwArgument < IFLASH_NB_OF_PAGES ) ; + break ; + + case EFC_FCMD_SFB: + case EFC_FCMD_CFB: + assert( dwArgument < 2 ) ; + break; + + case EFC_FCMD_GETD: + case EFC_FCMD_EA: + case EFC_FCMD_GLB: + case EFC_FCMD_GFB: + case EFC_FCMD_STUI: + assert( dwArgument == 0 ) ; + break; + + default: assert( 0 ) ; + } + + /* Start command Embedded flash */ + assert( (efc->EEFC_FSR & EEFC_FMR_FRDY) == EEFC_FMR_FRDY ) ; + efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ; +} + +/** + * \brief Performs the given command and wait until its completion (or an error). + * + * \param efc Pointer to a Efc instance + * \param command Command to perform. + * \param argument Optional command argument. + * + * \return 0 if successful, otherwise returns an error code. + */ + +extern uint32_t EFC_PerformCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument, uint32_t dwUseIAP ) +{ + if ( dwUseIAP != 0 ) + { + /* Pointer on IAP function in ROM */ + static uint32_t (*IAP_PerformCommand)( uint32_t, uint32_t ) ; + + IAP_PerformCommand = (uint32_t (*)( uint32_t, uint32_t )) *((uint32_t*)CHIP_FLASH_IAP_ADDRESS ) ; + IAP_PerformCommand( 0, EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ) ; + + return (efc->EEFC_FSR & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)) ; + } + else + { + uint32_t dwStatus ; + + efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ; + do + { + dwStatus = efc->EEFC_FSR ; + } + while ( (dwStatus & EEFC_FSR_FRDY) != EEFC_FSR_FRDY ) ; + + return ( dwStatus & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE) ) ; + } +} + + diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/exceptions.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/exceptions.c index 2cbf458f..74e0fbdf 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/exceptions.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/exceptions.c @@ -1,505 +1,505 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** - * \file - * This file contains the default exception handlers. - * - * \note - * The exception handler has weak aliases. - * As they are weak aliases, any function with the same name will override - * this definition. - */ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ - -#include "chip.h" - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Default interrupt handler for not used irq. - */ -void IrqHandlerNotUsed( void ) -{ - printf("NotUsed\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default NMI interrupt handler. - */ -WEAK void NMI_Handler( void ) -{ - printf("NMI\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default HardFault interrupt handler. - */ -struct hardfault_args { - unsigned long r0; - unsigned long r1; - unsigned long r2; - unsigned long r3; - unsigned long r12; - unsigned long lr; - unsigned long pc; - unsigned long psr; -}; - -void hard_fault_handler_c(struct hardfault_args *args) -{ - printf("\r\nHardFault\r\n"); - printf("R0=%08x, R1=%08x, R2=%08x, R3=%08x, R12=%08x\r\n", - args->r0, args->r1, args->r2, args->r3, args->r12); - printf("LR[R14]=%08x, PC[R15]=%08x, PSR=%08x\r\n", - args->lr, args->pc, args->psr); - printf("BFAR=%08x, CFSR=%08x, HFSR=%08x\r\n", - SCB->BFAR, SCB->CFSR, SCB->HFSR); - printf("DFSR=%08x, AFSR=%08x, SHCSR=%08x\r\n", - SCB->DFSR, SCB->CFSR, SCB->SHCSR); - - if (SCB->HFSR & 0x40000000) - printf("FORCED "); - if (SCB->HFSR & 0x00000002) - printf("VECTTBL "); - - uint32_t ufsr = SCB->CFSR >> 16; - if (ufsr & 0x0200) - printf("DIVBYZERO "); - if (ufsr & 0x0100) - printf("UNALIGNED "); - if (ufsr & 0x0008) - printf("NOCP "); - if (ufsr & 0x0004) - printf("INVPC "); - if (ufsr & 0x0002) - printf("INVSTATE "); - if (ufsr & 0x0001) - printf("UNDEFINSTR "); - - uint32_t bfsr = (SCB->CFSR >> 8) & 0xff; - if (bfsr & 0x80) - printf("BFARVALID "); - if (bfsr & 0x10) - printf("STKERR "); - if (bfsr & 0x08) - printf("UNSTKERR "); - if (bfsr & 0x04) - printf("IMPRECISERR "); - if (bfsr & 0x02) - printf("PRECISERR "); - if (bfsr & 0x01) - printf("IBUSERR "); - - uint32_t mmfsr = (SCB->CFSR & 0xff); - if (mmfsr & 0x80) - printf("MMARVALID "); - if (mmfsr & 0x10) - printf("MSTKERR "); - if (mmfsr & 0x08) - printf("MUNSTKERR "); - if (mmfsr & 0x02) - printf("DACCVIOL "); - if (mmfsr & 0x01) - printf("IACCVIOL "); - - while ( 1 ) ; -} - -__attribute__((naked)) -WEAK void HardFault_Handler( void ) -{ - __asm volatile( - ".syntax unified \n" - " tst lr, #4 \n" - " ite eq \n" - " mrseq r0, msp \n" - " mrsne r0, psp \n" - //" ldr r1, [r0, #24] \n" - " b hard_fault_handler_c\n" - ".syntax divided \n"); -} - -/** - * \brief Default MemManage interrupt handler. - */ -WEAK void MemManage_Handler( void ) -{ - printf("MemManage\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default BusFault interrupt handler. - */ -WEAK void BusFault_Handler( void ) -{ - printf("BusFault\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default UsageFault interrupt handler. - */ -WEAK void UsageFault_Handler( void ) -{ - printf("UsageFault\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default SVC interrupt handler. - */ -WEAK void SVC_Handler( void ) -{ - printf("SVC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default DebugMon interrupt handler. - */ -WEAK void DebugMon_Handler( void ) -{ - printf("DebugMon\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default PendSV interrupt handler. - */ -WEAK void PendSV_Handler( void ) -{ - printf("PendSV\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default SysTick interrupt handler. - */ -WEAK void SysTick_Handler( void ) -{ - printf("SysTick\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for Supply Controller. - */ -WEAK void SUPC_IrqHandler( void ) -{ - printf("SUPC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for Reset Controller. - */ -WEAK void RSTC_IrqHandler( void ) -{ - printf("RSTC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for Real Time Clock. - */ -WEAK void RTC_IrqHandler( void ) -{ - printf("RTC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for Real Time Timer. - */ -WEAK void RTT_IrqHandler( void ) -{ - printf("RTT\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for Watchdog Timer. - */ -WEAK void WDT_IrqHandler( void ) -{ - printf("WDT\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for PMC. - */ -WEAK void PMC_IrqHandler( void ) -{ - printf("PMC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for EEFC. - */ -WEAK void EEFC_IrqHandler( void ) -{ - printf("EEFC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for UART0. - */ -WEAK void UART0_IrqHandler( void ) -{ - printf("UART0\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for UART1. - */ -WEAK void UART1_IrqHandler( void ) -{ - printf("UART1\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for SMC. - */ -WEAK void SMC_IrqHandler( void ) -{ - printf("SMC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for PIOA Controller. - */ -WEAK void PIOA_IrqHandler( void ) -{ - printf("PIOA\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for PIOB Controller. - */ -WEAK void PIOB_IrqHandler( void ) -{ - printf("PIOB\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for PIOC Controller. - */ -WEAK void PIOC_IrqHandler( void ) -{ - printf("PIOC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for USART0. - */ -WEAK void USART0_IrqHandler( void ) -{ - printf("USART0\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for USART1. - */ -WEAK void USART1_IrqHandler( void ) -{ - printf("USART1\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for MCI. - */ -WEAK void MCI_IrqHandler( void ) -{ - printf("MCI\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for TWI0. - */ -WEAK void TWI0_IrqHandler( void ) -{ - printf("TWI0\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for TWI1. - */ -WEAK void TWI1_IrqHandler( void ) -{ - printf("TWI1\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for SPI. - */ -WEAK void SPI_IrqHandler( void ) -{ - printf("SPI\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for SSC. - */ -WEAK void SSC_IrqHandler( void ) -{ - printf("SSC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for TC0. - */ -WEAK void TC0_IrqHandler( void ) -{ - printf("TC0\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for TC1. - */ -WEAK void TC1_IrqHandler( void ) -{ - printf("TC1\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default interrupt handler for TC2. - */ -WEAK void TC2_IrqHandler( void ) -{ - printf("TC2\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default SUPC interrupt handler for TC3. - */ -WEAK void TC3_IrqHandler( void ) -{ - printf("TC3\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default SUPC interrupt handler for TC4. - */ -WEAK void TC4_IrqHandler( void ) -{ - printf("TC4\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default SUPC interrupt handler for TC5. - */ -WEAK void TC5_IrqHandler( void ) -{ - printf("TC5\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default SUPC interrupt handler for ADC. - */ -WEAK void ADC_IrqHandler( void ) -{ - printf("ADC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default SUPC interrupt handler for DAC. - */ -WEAK void DAC_IrqHandler( void ) -{ - printf("DAC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default SUPC interrupt handler for PWM. - */ -WEAK void PWM_IrqHandler( void ) -{ - printf("PWM\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default SUPC interrupt handler for CRCCU. - */ -WEAK void CRCCU_IrqHandler( void ) -{ - printf("CRCCU\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default SUPC interrupt handler for ACC. - */ -WEAK void ACC_IrqHandler( void ) -{ - printf("ACC\r\n"); - while ( 1 ) ; -} - -/** - * \brief Default SUPC interrupt handler for USBD. - */ -WEAK void USBD_IrqHandler( void ) -{ - printf("USBD\r\n"); - while ( 1 ) ; -} +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** + * \file + * This file contains the default exception handlers. + * + * \note + * The exception handler has weak aliases. + * As they are weak aliases, any function with the same name will override + * this definition. + */ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "chip.h" + +/*---------------------------------------------------------------------------- + * Exported functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Default interrupt handler for not used irq. + */ +void IrqHandlerNotUsed( void ) +{ + printf("NotUsed\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default NMI interrupt handler. + */ +WEAK void NMI_Handler( void ) +{ + printf("NMI\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default HardFault interrupt handler. + */ +struct hardfault_args { + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r12; + unsigned long lr; + unsigned long pc; + unsigned long psr; +}; + +void hard_fault_handler_c(struct hardfault_args *args) +{ + printf("\r\nHardFault\r\n"); + printf("R0=%08x, R1=%08x, R2=%08x, R3=%08x, R12=%08x\r\n", + args->r0, args->r1, args->r2, args->r3, args->r12); + printf("LR[R14]=%08x, PC[R15]=%08x, PSR=%08x\r\n", + args->lr, args->pc, args->psr); + printf("BFAR=%08x, CFSR=%08x, HFSR=%08x\r\n", + SCB->BFAR, SCB->CFSR, SCB->HFSR); + printf("DFSR=%08x, AFSR=%08x, SHCSR=%08x\r\n", + SCB->DFSR, SCB->CFSR, SCB->SHCSR); + + if (SCB->HFSR & 0x40000000) + printf("FORCED "); + if (SCB->HFSR & 0x00000002) + printf("VECTTBL "); + + uint32_t ufsr = SCB->CFSR >> 16; + if (ufsr & 0x0200) + printf("DIVBYZERO "); + if (ufsr & 0x0100) + printf("UNALIGNED "); + if (ufsr & 0x0008) + printf("NOCP "); + if (ufsr & 0x0004) + printf("INVPC "); + if (ufsr & 0x0002) + printf("INVSTATE "); + if (ufsr & 0x0001) + printf("UNDEFINSTR "); + + uint32_t bfsr = (SCB->CFSR >> 8) & 0xff; + if (bfsr & 0x80) + printf("BFARVALID "); + if (bfsr & 0x10) + printf("STKERR "); + if (bfsr & 0x08) + printf("UNSTKERR "); + if (bfsr & 0x04) + printf("IMPRECISERR "); + if (bfsr & 0x02) + printf("PRECISERR "); + if (bfsr & 0x01) + printf("IBUSERR "); + + uint32_t mmfsr = (SCB->CFSR & 0xff); + if (mmfsr & 0x80) + printf("MMARVALID "); + if (mmfsr & 0x10) + printf("MSTKERR "); + if (mmfsr & 0x08) + printf("MUNSTKERR "); + if (mmfsr & 0x02) + printf("DACCVIOL "); + if (mmfsr & 0x01) + printf("IACCVIOL "); + + while ( 1 ) ; +} + +__attribute__((naked)) +WEAK void HardFault_Handler( void ) +{ + __asm volatile( + ".syntax unified \n" + " tst lr, #4 \n" + " ite eq \n" + " mrseq r0, msp \n" + " mrsne r0, psp \n" + //" ldr r1, [r0, #24] \n" + " b hard_fault_handler_c\n" + ".syntax divided \n"); +} + +/** + * \brief Default MemManage interrupt handler. + */ +WEAK void MemManage_Handler( void ) +{ + printf("MemManage\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default BusFault interrupt handler. + */ +WEAK void BusFault_Handler( void ) +{ + printf("BusFault\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default UsageFault interrupt handler. + */ +WEAK void UsageFault_Handler( void ) +{ + printf("UsageFault\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default SVC interrupt handler. + */ +WEAK void SVC_Handler( void ) +{ + printf("SVC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default DebugMon interrupt handler. + */ +WEAK void DebugMon_Handler( void ) +{ + printf("DebugMon\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default PendSV interrupt handler. + */ +WEAK void PendSV_Handler( void ) +{ + printf("PendSV\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default SysTick interrupt handler. + */ +WEAK void SysTick_Handler( void ) +{ + printf("SysTick\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for Supply Controller. + */ +WEAK void SUPC_IrqHandler( void ) +{ + printf("SUPC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for Reset Controller. + */ +WEAK void RSTC_IrqHandler( void ) +{ + printf("RSTC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for Real Time Clock. + */ +WEAK void RTC_IrqHandler( void ) +{ + printf("RTC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for Real Time Timer. + */ +WEAK void RTT_IrqHandler( void ) +{ + printf("RTT\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for Watchdog Timer. + */ +WEAK void WDT_IrqHandler( void ) +{ + printf("WDT\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for PMC. + */ +WEAK void PMC_IrqHandler( void ) +{ + printf("PMC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for EEFC. + */ +WEAK void EEFC_IrqHandler( void ) +{ + printf("EEFC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for UART0. + */ +WEAK void UART0_IrqHandler( void ) +{ + printf("UART0\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for UART1. + */ +WEAK void UART1_IrqHandler( void ) +{ + printf("UART1\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for SMC. + */ +WEAK void SMC_IrqHandler( void ) +{ + printf("SMC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for PIOA Controller. + */ +WEAK void PIOA_IrqHandler( void ) +{ + printf("PIOA\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for PIOB Controller. + */ +WEAK void PIOB_IrqHandler( void ) +{ + printf("PIOB\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for PIOC Controller. + */ +WEAK void PIOC_IrqHandler( void ) +{ + printf("PIOC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for USART0. + */ +WEAK void USART0_IrqHandler( void ) +{ + printf("USART0\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for USART1. + */ +WEAK void USART1_IrqHandler( void ) +{ + printf("USART1\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for MCI. + */ +WEAK void MCI_IrqHandler( void ) +{ + printf("MCI\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for TWI0. + */ +WEAK void TWI0_IrqHandler( void ) +{ + printf("TWI0\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for TWI1. + */ +WEAK void TWI1_IrqHandler( void ) +{ + printf("TWI1\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for SPI. + */ +WEAK void SPI_IrqHandler( void ) +{ + printf("SPI\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for SSC. + */ +WEAK void SSC_IrqHandler( void ) +{ + printf("SSC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for TC0. + */ +WEAK void TC0_IrqHandler( void ) +{ + printf("TC0\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for TC1. + */ +WEAK void TC1_IrqHandler( void ) +{ + printf("TC1\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default interrupt handler for TC2. + */ +WEAK void TC2_IrqHandler( void ) +{ + printf("TC2\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default SUPC interrupt handler for TC3. + */ +WEAK void TC3_IrqHandler( void ) +{ + printf("TC3\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default SUPC interrupt handler for TC4. + */ +WEAK void TC4_IrqHandler( void ) +{ + printf("TC4\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default SUPC interrupt handler for TC5. + */ +WEAK void TC5_IrqHandler( void ) +{ + printf("TC5\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default SUPC interrupt handler for ADC. + */ +WEAK void ADC_IrqHandler( void ) +{ + printf("ADC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default SUPC interrupt handler for DAC. + */ +WEAK void DAC_IrqHandler( void ) +{ + printf("DAC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default SUPC interrupt handler for PWM. + */ +WEAK void PWM_IrqHandler( void ) +{ + printf("PWM\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default SUPC interrupt handler for CRCCU. + */ +WEAK void CRCCU_IrqHandler( void ) +{ + printf("CRCCU\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default SUPC interrupt handler for ACC. + */ +WEAK void ACC_IrqHandler( void ) +{ + printf("ACC\r\n"); + while ( 1 ) ; +} + +/** + * \brief Default SUPC interrupt handler for USBD. + */ +WEAK void USBD_IrqHandler( void ) +{ + printf("USBD\r\n"); + while ( 1 ) ; +} diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/flashd.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/flashd.c index e11c2abf..677ea309 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/flashd.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/flashd.c @@ -1,517 +1,517 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** \addtogroup flashd_module Flash Memory Interface - * The flash driver manages the programming, erasing, locking and unlocking sequences - * with dedicated commands. - * - * To implement flash programing operation, the user has to follow these few steps : - *
    - *
  • Configue flash wait states to initializes the flash.
  • - *
  • Checks whether a region to be programmed is locked.
  • - *
  • Unlocks the user region to be programmed if the region have locked before.
  • - *
  • Erases the user page before program (optional).
  • - *
  • Writes the user page from the page buffer.
  • - *
  • Locks the region of programmed area if any.
  • - *
- * - * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption. - * A check of this validity and padding for 32-bit alignment should be done in write algorithm. - - * Lock/unlock range associated with the user address range is automatically translated. - * - * This security bit can be enabled through the command "Set General Purpose NVM Bit 0". - * - * A 128-bit factory programmed unique ID could be read to serve several purposes. - * - * The driver accesses the flash memory by calling the lowlevel module provided in \ref efc_module. - * For more accurate information, please look at the EEFC section of the Datasheet. - * - * Related files :\n - * \ref flashd.c\n - * \ref flashd.h.\n - * \ref efc.c\n - * \ref efc.h.\n -*/ -/*@{*/ -/*@}*/ - - -/** - * \file - * - * The flash driver provides the unified interface for flash program operations. - * - */ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ -#include "chip.h" -#include "flashd.h" -#include "efc.h" - -#include -#include - -/*---------------------------------------------------------------------------- - * Local variables - *----------------------------------------------------------------------------*/ - -//static NO_INIT uint8_t _aucPageBuffer[IFLASH_PAGE_SIZE] ; -static NO_INIT uint32_t _adwPageBuffer[IFLASH_PAGE_SIZE/4] ; -static uint8_t* _aucPageBuffer = (uint8_t*)_adwPageBuffer; -static NO_INIT uint32_t _dwUseIAP ; - -/*---------------------------------------------------------------------------- - * Local macros - *----------------------------------------------------------------------------*/ - -#define min( a, b ) (((a) < (b)) ? (a) : (b)) - -/*---------------------------------------------------------------------------- - * Local functions - *----------------------------------------------------------------------------*/ - - -/** - * \brief Computes the lock range associated with the given address range. - * - * \param dwStart Start address of lock range. - * \param dwEnd End address of lock range. - * \param pdwActualStart Actual start address of lock range. - * \param pdwActualEnd Actual end address of lock range. - */ -static void ComputeLockRange( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) -{ - Efc* pStartEfc ; - Efc* pEndEfc ; - uint16_t wStartPage ; - uint16_t wEndPage ; - uint16_t wNumPagesInRegion ; - uint16_t wActualStartPage ; - uint16_t wActualEndPage ; - - // Convert start and end address in page numbers - EFC_TranslateAddress( &pStartEfc, dwStart, &wStartPage, 0 ) ; - EFC_TranslateAddress( &pEndEfc, dwEnd, &wEndPage, 0 ) ; - - // Find out the first page of the first region to lock - wNumPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ; - wActualStartPage = wStartPage - (wStartPage % wNumPagesInRegion) ; - wActualEndPage = wEndPage ; - - if ( (wEndPage % wNumPagesInRegion) != 0 ) - { - wActualEndPage += wNumPagesInRegion - (wEndPage % wNumPagesInRegion) ; - } - // Store actual page numbers - EFC_ComputeAddress( pStartEfc, wActualStartPage, 0, pdwActualStart ) ; - EFC_ComputeAddress( pEndEfc, wActualEndPage, 0, pdwActualEnd ) ; - TRACE_DEBUG( "Actual lock range is 0x%06X - 0x%06X\n\r", *pdwActualStart, *pdwActualEnd ) ; -} - - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Initializes the flash driver. - * - * \param mck Master clock frequency in Hz. - */ - -extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP ) -{ - EFC_DisableFrdyIt( EFC ) ; -#if 1 - /* See Revision A errata 46.1.1.3 */ - EFC_SetWaitState(EFC, 6); -#else - if ( (dwMCk/1000000) >= 64 ) - { - EFC_SetWaitState( EFC, 2 ) ; - } - else - { - if ( (dwMCk/1000000) >= 50 ) - { - EFC_SetWaitState( EFC, 1 ) ; - } - else - { - EFC_SetWaitState( EFC, 0 ) ; - } - } -#endif - _dwUseIAP=dwUseIAP ; -} - -/** - * \brief Erases the entire flash. - * - * \param address Flash start address. - * \return 0 if successful; otherwise returns an error code. - */ -extern uint32_t FLASHD_Erase( uint32_t dwAddress ) -{ - Efc* pEfc ; - uint16_t wPage ; - uint16_t wOffset ; - uint32_t dwError ; - - assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ; - - // Translate write address - EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ; - dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EA, 0, _dwUseIAP ) ; - - return dwError ; -} - -/** - * \brief Writes a data buffer in the internal flash - * - * \note This function works in polling mode, and thus only returns when the - * data has been effectively written. - * \param address Write address. - * \param pBuffer Data buffer. - * \param size Size of data buffer in bytes. - * \return 0 if successful, otherwise returns an error code. - */ -extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize ) -{ - Efc* pEfc ; - uint16_t page ; - uint16_t offset ; - uint32_t writeSize ; - uint32_t pageAddress ; - uint16_t padding ; - uint32_t dwError ; - uint32_t sizeTmp ; - uint32_t *pAlignedDestination ; - uint32_t *pAlignedSource ; - - assert( pvBuffer ) ; - assert( dwAddress >=IFLASH_ADDR ) ; - assert( (dwAddress + dwSize) <= (IFLASH_ADDR + IFLASH_SIZE) ) ; - - /* Translate write address */ - EFC_TranslateAddress( &pEfc, dwAddress, &page, &offset ) ; - - /* Write all pages */ - while ( dwSize > 0 ) - { - /* Copy data in temporary buffer to avoid alignment problems */ - writeSize = min((uint32_t)IFLASH_PAGE_SIZE - offset, dwSize ) ; - EFC_ComputeAddress(pEfc, page, 0, &pageAddress ) ; - padding = IFLASH_PAGE_SIZE - offset - writeSize ; - - /* Pre-buffer data */ - memcpy( _aucPageBuffer, (void *) pageAddress, offset); - - /* Buffer data */ - memcpy( _aucPageBuffer + offset, pvBuffer, writeSize); - - /* Post-buffer data */ - memcpy( _aucPageBuffer + offset + writeSize, (void *) (pageAddress + offset + writeSize), padding); - - /* Write page - * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption - */ - pAlignedDestination = (uint32_t*)pageAddress ; - pAlignedSource = (uint32_t*)_adwPageBuffer ; - sizeTmp = IFLASH_PAGE_SIZE ; - - while ( sizeTmp >= 4 ) - { - *pAlignedDestination++ = *pAlignedSource++; - sizeTmp -= 4; - } - - /* Send writing command */ - dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EWP, page, _dwUseIAP ) ; - if ( dwError ) - { - return dwError ; - } - - /* Progression */ - dwAddress += IFLASH_PAGE_SIZE ; - pvBuffer = (void *)((uint32_t) pvBuffer + writeSize) ; - dwSize -= writeSize ; - page++; - offset = 0; - } - - return 0 ; -} -/** - * \brief Locks all the regions in the given address range. The actual lock range is - * reported through two output parameters. - * - * \param start Start address of lock range. - * \param end End address of lock range. - * \param pActualStart Start address of the actual lock range (optional). - * \param pActualEnd End address of the actual lock range (optional). - * \return 0 if successful, otherwise returns an error code. - */ -extern uint32_t FLASHD_Lock( uint32_t start, uint32_t end, uint32_t *pActualStart, uint32_t *pActualEnd ) -{ - Efc *pEfc ; - uint32_t actualStart, actualEnd ; - uint16_t startPage, endPage ; - uint32_t dwError ; - uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE; - - /* Compute actual lock range and store it */ - ComputeLockRange( start, end, &actualStart, &actualEnd ) ; - if ( pActualStart != NULL ) - { - *pActualStart = actualStart ; - } - if ( pActualEnd != NULL ) - { - *pActualEnd = actualEnd; - } - - /* Compute page numbers */ - EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ; - EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ; - - /* Lock all pages */ - while ( startPage < endPage ) - { - dwError = EFC_PerformCommand( pEfc, EFC_FCMD_SLB, startPage, _dwUseIAP ) ; - if ( dwError ) - { - return dwError ; - } - startPage += numPagesInRegion; - } - - return 0 ; -} - -/** - * \brief Unlocks all the regions in the given address range. The actual unlock range is - * reported through two output parameters. - * \param start Start address of unlock range. - * \param end End address of unlock range. - * \param pActualStart Start address of the actual unlock range (optional). - * \param pActualEnd End address of the actual unlock range (optional). - * \return 0 if successful, otherwise returns an error code. - */ -extern uint32_t FLASHD_Unlock( uint32_t start, uint32_t end, uint32_t *pActualStart, uint32_t *pActualEnd ) -{ - Efc* pEfc ; - uint32_t actualStart, actualEnd ; - uint16_t startPage, endPage ; - uint32_t dwError ; - uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE; - - // Compute actual unlock range and store it - ComputeLockRange(start, end, &actualStart, &actualEnd); - if ( pActualStart != NULL ) - { - *pActualStart = actualStart ; - } - if ( pActualEnd != NULL ) - { - *pActualEnd = actualEnd ; - } - - // Compute page numbers - EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ; - EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ; - - // Unlock all pages - while ( startPage < endPage ) - { - dwError = EFC_PerformCommand( pEfc, EFC_FCMD_CLB, startPage, _dwUseIAP ) ; - if ( dwError ) - { - return dwError ; - } - startPage += numPagesInRegion ; - } - return 0 ; -} - -/** - * \brief Returns the number of locked regions inside the given address range. - * - * \param start Start address of range - * \param end End address of range. - */ -extern uint32_t FLASHD_IsLocked( uint32_t start, uint32_t end ) -{ - Efc *pEfc ; - uint16_t startPage, endPage ; - uint8_t startRegion, endRegion ; - uint32_t numPagesInRegion ; - uint32_t status ; - uint32_t dwError ; - uint32_t numLockedRegions = 0 ; - - assert( end >= start ) ; - assert( (start >=IFLASH_ADDR) && (end <= IFLASH_ADDR + IFLASH_SIZE) ) ; - - // Compute page numbers - EFC_TranslateAddress( &pEfc, start, &startPage, 0 ) ; - EFC_TranslateAddress( 0, end, &endPage, 0 ) ; - - // Compute region numbers - numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ; - startRegion = startPage / numPagesInRegion ; - endRegion = endPage / numPagesInRegion ; - if ((endPage % numPagesInRegion) != 0) - { - endRegion++ ; - } - - // Retrieve lock status - dwError = EFC_PerformCommand( pEfc, EFC_FCMD_GLB, 0, _dwUseIAP ) ; - assert( !dwError ) ; - status = EFC_GetResult( pEfc ) ; - - // Check status of each involved region - while ( startRegion < endRegion ) - { - if ( (status & (1 << startRegion)) != 0 ) - { - numLockedRegions++ ; - } - startRegion++ ; - } - - return numLockedRegions ; -} - -/** - * \brief Check if the given GPNVM bit is set or not. - * - * \param gpnvm GPNVM bit index. - * \returns 1 if the given GPNVM bit is currently set; otherwise returns 0. - */ -extern uint32_t FLASHD_IsGPNVMSet( uint8_t ucGPNVM ) -{ - uint32_t dwError ; - uint32_t dwStatus ; - - assert( ucGPNVM < 2 ) ; - - /* Get GPNVMs status */ - dwError = EFC_PerformCommand( EFC, EFC_FCMD_GFB, 0, _dwUseIAP ) ; - assert( !dwError ) ; - dwStatus = EFC_GetResult( EFC ) ; - - /* Check if GPNVM is set */ - if ( (dwStatus & (1 << ucGPNVM)) != 0 ) - { - return 1 ; - } - else - { - return 0 ; - } -} - -/** - * \brief Sets the selected GPNVM bit. - * - * \param gpnvm GPNVM bit index. - * \returns 0 if successful; otherwise returns an error code. - */ -extern uint32_t FLASHD_SetGPNVM( uint8_t ucGPNVM ) -{ - assert( ucGPNVM < 2 ) ; - - if ( !FLASHD_IsGPNVMSet( ucGPNVM ) ) - { - return EFC_PerformCommand( EFC, EFC_FCMD_SFB, ucGPNVM, _dwUseIAP ) ; - } - else - { - return 0 ; - } -} - -/** - * \brief Clears the selected GPNVM bit. - * - * \param gpnvm GPNVM bit index. - * \returns 0 if successful; otherwise returns an error code. - */ -extern uint32_t FLASHD_ClearGPNVM( uint8_t ucGPNVM ) -{ - assert( ucGPNVM < 2 ) ; - - if ( FLASHD_IsGPNVMSet( ucGPNVM ) ) - { - return EFC_PerformCommand( EFC, EFC_FCMD_CFB, ucGPNVM, _dwUseIAP ) ; - } - else - { - return 0 ; - } -} -/** - * \brief Read the unique ID. - * - * \param uniqueID pointer on a 4bytes char containing the unique ID value. - * \returns 0 if successful; otherwise returns an error code. - */ -extern uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID ) -{ - uint32_t dwError ; - - assert( pdwUniqueID != NULL ) ; - - pdwUniqueID[0] = 0 ; - pdwUniqueID[1] = 0 ; - pdwUniqueID[2] = 0 ; - pdwUniqueID[3] = 0 ; - - EFC_StartCommand( EFC, EFC_FCMD_STUI, 0 ) ; - - pdwUniqueID[0] = *(uint32_t*) IFLASH_ADDR; - pdwUniqueID[1] = *(uint32_t*)(IFLASH_ADDR + 4) ; - pdwUniqueID[2] = *(uint32_t*)(IFLASH_ADDR + 8) ; - pdwUniqueID[3] = *(uint32_t*)(IFLASH_ADDR + 12) ; - - dwError = EFC_PerformCommand( EFC, EFC_FCMD_SPUI, 0, _dwUseIAP ) ; - if ( dwError ) - { - return dwError ; - } - - return 0 ; -} +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** \addtogroup flashd_module Flash Memory Interface + * The flash driver manages the programming, erasing, locking and unlocking sequences + * with dedicated commands. + * + * To implement flash programing operation, the user has to follow these few steps : + *
    + *
  • Configue flash wait states to initializes the flash.
  • + *
  • Checks whether a region to be programmed is locked.
  • + *
  • Unlocks the user region to be programmed if the region have locked before.
  • + *
  • Erases the user page before program (optional).
  • + *
  • Writes the user page from the page buffer.
  • + *
  • Locks the region of programmed area if any.
  • + *
+ * + * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption. + * A check of this validity and padding for 32-bit alignment should be done in write algorithm. + + * Lock/unlock range associated with the user address range is automatically translated. + * + * This security bit can be enabled through the command "Set General Purpose NVM Bit 0". + * + * A 128-bit factory programmed unique ID could be read to serve several purposes. + * + * The driver accesses the flash memory by calling the lowlevel module provided in \ref efc_module. + * For more accurate information, please look at the EEFC section of the Datasheet. + * + * Related files :\n + * \ref flashd.c\n + * \ref flashd.h.\n + * \ref efc.c\n + * \ref efc.h.\n +*/ +/*@{*/ +/*@}*/ + + +/** + * \file + * + * The flash driver provides the unified interface for flash program operations. + * + */ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ +#include "chip.h" +#include "flashd.h" +#include "efc.h" + +#include +#include + +/*---------------------------------------------------------------------------- + * Local variables + *----------------------------------------------------------------------------*/ + +//static NO_INIT uint8_t _aucPageBuffer[IFLASH_PAGE_SIZE] ; +static NO_INIT uint32_t _adwPageBuffer[IFLASH_PAGE_SIZE/4] ; +static uint8_t* _aucPageBuffer = (uint8_t*)_adwPageBuffer; +static NO_INIT uint32_t _dwUseIAP ; + +/*---------------------------------------------------------------------------- + * Local macros + *----------------------------------------------------------------------------*/ + +#define min( a, b ) (((a) < (b)) ? (a) : (b)) + +/*---------------------------------------------------------------------------- + * Local functions + *----------------------------------------------------------------------------*/ + + +/** + * \brief Computes the lock range associated with the given address range. + * + * \param dwStart Start address of lock range. + * \param dwEnd End address of lock range. + * \param pdwActualStart Actual start address of lock range. + * \param pdwActualEnd Actual end address of lock range. + */ +static void ComputeLockRange( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) +{ + Efc* pStartEfc ; + Efc* pEndEfc ; + uint16_t wStartPage ; + uint16_t wEndPage ; + uint16_t wNumPagesInRegion ; + uint16_t wActualStartPage ; + uint16_t wActualEndPage ; + + // Convert start and end address in page numbers + EFC_TranslateAddress( &pStartEfc, dwStart, &wStartPage, 0 ) ; + EFC_TranslateAddress( &pEndEfc, dwEnd, &wEndPage, 0 ) ; + + // Find out the first page of the first region to lock + wNumPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ; + wActualStartPage = wStartPage - (wStartPage % wNumPagesInRegion) ; + wActualEndPage = wEndPage ; + + if ( (wEndPage % wNumPagesInRegion) != 0 ) + { + wActualEndPage += wNumPagesInRegion - (wEndPage % wNumPagesInRegion) ; + } + // Store actual page numbers + EFC_ComputeAddress( pStartEfc, wActualStartPage, 0, pdwActualStart ) ; + EFC_ComputeAddress( pEndEfc, wActualEndPage, 0, pdwActualEnd ) ; + TRACE_DEBUG( "Actual lock range is 0x%06X - 0x%06X\n\r", *pdwActualStart, *pdwActualEnd ) ; +} + + +/*---------------------------------------------------------------------------- + * Exported functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Initializes the flash driver. + * + * \param mck Master clock frequency in Hz. + */ + +extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP ) +{ + EFC_DisableFrdyIt( EFC ) ; +#if 1 + /* See Revision A errata 46.1.1.3 */ + EFC_SetWaitState(EFC, 6); +#else + if ( (dwMCk/1000000) >= 64 ) + { + EFC_SetWaitState( EFC, 2 ) ; + } + else + { + if ( (dwMCk/1000000) >= 50 ) + { + EFC_SetWaitState( EFC, 1 ) ; + } + else + { + EFC_SetWaitState( EFC, 0 ) ; + } + } +#endif + _dwUseIAP=dwUseIAP ; +} + +/** + * \brief Erases the entire flash. + * + * \param address Flash start address. + * \return 0 if successful; otherwise returns an error code. + */ +extern uint32_t FLASHD_Erase( uint32_t dwAddress ) +{ + Efc* pEfc ; + uint16_t wPage ; + uint16_t wOffset ; + uint32_t dwError ; + + assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ; + + // Translate write address + EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ; + dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EA, 0, _dwUseIAP ) ; + + return dwError ; +} + +/** + * \brief Writes a data buffer in the internal flash + * + * \note This function works in polling mode, and thus only returns when the + * data has been effectively written. + * \param address Write address. + * \param pBuffer Data buffer. + * \param size Size of data buffer in bytes. + * \return 0 if successful, otherwise returns an error code. + */ +extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize ) +{ + Efc* pEfc ; + uint16_t page ; + uint16_t offset ; + uint32_t writeSize ; + uint32_t pageAddress ; + uint16_t padding ; + uint32_t dwError ; + uint32_t sizeTmp ; + uint32_t *pAlignedDestination ; + uint32_t *pAlignedSource ; + + assert( pvBuffer ) ; + assert( dwAddress >=IFLASH_ADDR ) ; + assert( (dwAddress + dwSize) <= (IFLASH_ADDR + IFLASH_SIZE) ) ; + + /* Translate write address */ + EFC_TranslateAddress( &pEfc, dwAddress, &page, &offset ) ; + + /* Write all pages */ + while ( dwSize > 0 ) + { + /* Copy data in temporary buffer to avoid alignment problems */ + writeSize = min((uint32_t)IFLASH_PAGE_SIZE - offset, dwSize ) ; + EFC_ComputeAddress(pEfc, page, 0, &pageAddress ) ; + padding = IFLASH_PAGE_SIZE - offset - writeSize ; + + /* Pre-buffer data */ + memcpy( _aucPageBuffer, (void *) pageAddress, offset); + + /* Buffer data */ + memcpy( _aucPageBuffer + offset, pvBuffer, writeSize); + + /* Post-buffer data */ + memcpy( _aucPageBuffer + offset + writeSize, (void *) (pageAddress + offset + writeSize), padding); + + /* Write page + * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption + */ + pAlignedDestination = (uint32_t*)pageAddress ; + pAlignedSource = (uint32_t*)_adwPageBuffer ; + sizeTmp = IFLASH_PAGE_SIZE ; + + while ( sizeTmp >= 4 ) + { + *pAlignedDestination++ = *pAlignedSource++; + sizeTmp -= 4; + } + + /* Send writing command */ + dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EWP, page, _dwUseIAP ) ; + if ( dwError ) + { + return dwError ; + } + + /* Progression */ + dwAddress += IFLASH_PAGE_SIZE ; + pvBuffer = (void *)((uint32_t) pvBuffer + writeSize) ; + dwSize -= writeSize ; + page++; + offset = 0; + } + + return 0 ; +} +/** + * \brief Locks all the regions in the given address range. The actual lock range is + * reported through two output parameters. + * + * \param start Start address of lock range. + * \param end End address of lock range. + * \param pActualStart Start address of the actual lock range (optional). + * \param pActualEnd End address of the actual lock range (optional). + * \return 0 if successful, otherwise returns an error code. + */ +extern uint32_t FLASHD_Lock( uint32_t start, uint32_t end, uint32_t *pActualStart, uint32_t *pActualEnd ) +{ + Efc *pEfc ; + uint32_t actualStart, actualEnd ; + uint16_t startPage, endPage ; + uint32_t dwError ; + uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE; + + /* Compute actual lock range and store it */ + ComputeLockRange( start, end, &actualStart, &actualEnd ) ; + if ( pActualStart != NULL ) + { + *pActualStart = actualStart ; + } + if ( pActualEnd != NULL ) + { + *pActualEnd = actualEnd; + } + + /* Compute page numbers */ + EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ; + EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ; + + /* Lock all pages */ + while ( startPage < endPage ) + { + dwError = EFC_PerformCommand( pEfc, EFC_FCMD_SLB, startPage, _dwUseIAP ) ; + if ( dwError ) + { + return dwError ; + } + startPage += numPagesInRegion; + } + + return 0 ; +} + +/** + * \brief Unlocks all the regions in the given address range. The actual unlock range is + * reported through two output parameters. + * \param start Start address of unlock range. + * \param end End address of unlock range. + * \param pActualStart Start address of the actual unlock range (optional). + * \param pActualEnd End address of the actual unlock range (optional). + * \return 0 if successful, otherwise returns an error code. + */ +extern uint32_t FLASHD_Unlock( uint32_t start, uint32_t end, uint32_t *pActualStart, uint32_t *pActualEnd ) +{ + Efc* pEfc ; + uint32_t actualStart, actualEnd ; + uint16_t startPage, endPage ; + uint32_t dwError ; + uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE; + + // Compute actual unlock range and store it + ComputeLockRange(start, end, &actualStart, &actualEnd); + if ( pActualStart != NULL ) + { + *pActualStart = actualStart ; + } + if ( pActualEnd != NULL ) + { + *pActualEnd = actualEnd ; + } + + // Compute page numbers + EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ; + EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ; + + // Unlock all pages + while ( startPage < endPage ) + { + dwError = EFC_PerformCommand( pEfc, EFC_FCMD_CLB, startPage, _dwUseIAP ) ; + if ( dwError ) + { + return dwError ; + } + startPage += numPagesInRegion ; + } + return 0 ; +} + +/** + * \brief Returns the number of locked regions inside the given address range. + * + * \param start Start address of range + * \param end End address of range. + */ +extern uint32_t FLASHD_IsLocked( uint32_t start, uint32_t end ) +{ + Efc *pEfc ; + uint16_t startPage, endPage ; + uint8_t startRegion, endRegion ; + uint32_t numPagesInRegion ; + uint32_t status ; + uint32_t dwError ; + uint32_t numLockedRegions = 0 ; + + assert( end >= start ) ; + assert( (start >=IFLASH_ADDR) && (end <= IFLASH_ADDR + IFLASH_SIZE) ) ; + + // Compute page numbers + EFC_TranslateAddress( &pEfc, start, &startPage, 0 ) ; + EFC_TranslateAddress( 0, end, &endPage, 0 ) ; + + // Compute region numbers + numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ; + startRegion = startPage / numPagesInRegion ; + endRegion = endPage / numPagesInRegion ; + if ((endPage % numPagesInRegion) != 0) + { + endRegion++ ; + } + + // Retrieve lock status + dwError = EFC_PerformCommand( pEfc, EFC_FCMD_GLB, 0, _dwUseIAP ) ; + assert( !dwError ) ; + status = EFC_GetResult( pEfc ) ; + + // Check status of each involved region + while ( startRegion < endRegion ) + { + if ( (status & (1 << startRegion)) != 0 ) + { + numLockedRegions++ ; + } + startRegion++ ; + } + + return numLockedRegions ; +} + +/** + * \brief Check if the given GPNVM bit is set or not. + * + * \param gpnvm GPNVM bit index. + * \returns 1 if the given GPNVM bit is currently set; otherwise returns 0. + */ +extern uint32_t FLASHD_IsGPNVMSet( uint8_t ucGPNVM ) +{ + uint32_t dwError ; + uint32_t dwStatus ; + + assert( ucGPNVM < 2 ) ; + + /* Get GPNVMs status */ + dwError = EFC_PerformCommand( EFC, EFC_FCMD_GFB, 0, _dwUseIAP ) ; + assert( !dwError ) ; + dwStatus = EFC_GetResult( EFC ) ; + + /* Check if GPNVM is set */ + if ( (dwStatus & (1 << ucGPNVM)) != 0 ) + { + return 1 ; + } + else + { + return 0 ; + } +} + +/** + * \brief Sets the selected GPNVM bit. + * + * \param gpnvm GPNVM bit index. + * \returns 0 if successful; otherwise returns an error code. + */ +extern uint32_t FLASHD_SetGPNVM( uint8_t ucGPNVM ) +{ + assert( ucGPNVM < 2 ) ; + + if ( !FLASHD_IsGPNVMSet( ucGPNVM ) ) + { + return EFC_PerformCommand( EFC, EFC_FCMD_SFB, ucGPNVM, _dwUseIAP ) ; + } + else + { + return 0 ; + } +} + +/** + * \brief Clears the selected GPNVM bit. + * + * \param gpnvm GPNVM bit index. + * \returns 0 if successful; otherwise returns an error code. + */ +extern uint32_t FLASHD_ClearGPNVM( uint8_t ucGPNVM ) +{ + assert( ucGPNVM < 2 ) ; + + if ( FLASHD_IsGPNVMSet( ucGPNVM ) ) + { + return EFC_PerformCommand( EFC, EFC_FCMD_CFB, ucGPNVM, _dwUseIAP ) ; + } + else + { + return 0 ; + } +} +/** + * \brief Read the unique ID. + * + * \param uniqueID pointer on a 4bytes char containing the unique ID value. + * \returns 0 if successful; otherwise returns an error code. + */ +extern uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID ) +{ + uint32_t dwError ; + + assert( pdwUniqueID != NULL ) ; + + pdwUniqueID[0] = 0 ; + pdwUniqueID[1] = 0 ; + pdwUniqueID[2] = 0 ; + pdwUniqueID[3] = 0 ; + + EFC_StartCommand( EFC, EFC_FCMD_STUI, 0 ) ; + + pdwUniqueID[0] = *(uint32_t*) IFLASH_ADDR; + pdwUniqueID[1] = *(uint32_t*)(IFLASH_ADDR + 4) ; + pdwUniqueID[2] = *(uint32_t*)(IFLASH_ADDR + 8) ; + pdwUniqueID[3] = *(uint32_t*)(IFLASH_ADDR + 12) ; + + dwError = EFC_PerformCommand( EFC, EFC_FCMD_SPUI, 0, _dwUseIAP ) ; + if ( dwError ) + { + return dwError ; + } + + return 0 ; +} diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio.c index 49a6741c..caa9deae 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio.c @@ -1,453 +1,453 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2010, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** \file */ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ -#include "chip.h" -#include "pio.h" -#include "pmc.h" - -/*---------------------------------------------------------------------------- - * Local functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Configures one or more pin(s) of a PIO controller as being controlled by - * peripheral A. Optionally, the corresponding internal pull-up(s) can be enabled. - * - * \param pio Pointer to a PIO controller. - * \param mask Bitmask of one or more pin(s) to configure. - * \param enablePullUp Indicates if the pin(s) internal pull-up shall be - * configured. - */ -static void PIO_SetPeripheralA( - Pio *pio, - unsigned int mask, - unsigned char enablePullUp) -{ - unsigned int abcdsr; - /* Disable interrupts on the pin(s) */ - pio->PIO_IDR = mask; - - /* Enable the pull-up(s) if necessary */ - if (enablePullUp) { - pio->PIO_PUER = mask; - } - else { - - pio->PIO_PUDR = mask; - } - - abcdsr = pio->PIO_ABCDSR[0]; - pio->PIO_ABCDSR[0] &= (~mask & abcdsr); - abcdsr = pio->PIO_ABCDSR[1]; - pio->PIO_ABCDSR[1] &= (~mask & abcdsr); - pio->PIO_PDR = mask; -} - -/** - * \brief Configures one or more pin(s) of a PIO controller as being controlled by - * peripheral B. Optionally, the corresponding internal pull-up(s) can be enabled. - * - * \param pio Pointer to a PIO controller. - * \param mask Bitmask of one or more pin(s) to configure. - * \param enablePullUp Indicates if the pin(s) internal pull-up shall be - * configured. - */ -static void PIO_SetPeripheralB( - Pio *pio, - unsigned int mask, - unsigned char enablePullUp) -{ - unsigned int abcdsr; - /* Disable interrupts on the pin(s) */ - pio->PIO_IDR = mask; - - /* Enable the pull-up(s) if necessary */ - if (enablePullUp) { - - pio->PIO_PUER = mask; - } - else { - - pio->PIO_PUDR = mask; - } - - abcdsr = pio->PIO_ABCDSR[0]; - pio->PIO_ABCDSR[0] = (mask | abcdsr); - abcdsr = pio->PIO_ABCDSR[1]; - pio->PIO_ABCDSR[1] &= (~mask & abcdsr); - - pio->PIO_PDR = mask; -} - -/** - * \brief Configures one or more pin(s) of a PIO controller as being controlled by - * peripheral C. Optionally, the corresponding internal pull-up(s) can be enabled. - * - * \param pio Pointer to a PIO controller. - * \param mask Bitmask of one or more pin(s) to configure. - * \param enablePullUp Indicates if the pin(s) internal pull-up shall be - * configured. - */ -static void PIO_SetPeripheralC( - Pio *pio, - unsigned int mask, - unsigned char enablePullUp) -{ - unsigned int abcdsr; - /* Disable interrupts on the pin(s) */ - pio->PIO_IDR = mask; - - /* Enable the pull-up(s) if necessary */ - if (enablePullUp) { - - pio->PIO_PUER = mask; - } - else { - - pio->PIO_PUDR = mask; - } - - abcdsr = pio->PIO_ABCDSR[0]; - pio->PIO_ABCDSR[0] &= (~mask & abcdsr); - abcdsr = pio->PIO_ABCDSR[1]; - pio->PIO_ABCDSR[1] = (mask | abcdsr); - - pio->PIO_PDR = mask; -} - -/** - * \brief Configures one or more pin(s) of a PIO controller as being controlled by - * peripheral D. Optionally, the corresponding internal pull-up(s) can be enabled. - * - * \param pio Pointer to a PIO controller. - * \param mask Bitmask of one or more pin(s) to configure. - * \param enablePullUp Indicates if the pin(s) internal pull-up shall be - * configured. - */ -static void PIO_SetPeripheralD( - Pio *pio, - unsigned int mask, - unsigned char enablePullUp) -{ - unsigned int abcdsr; - /* Disable interrupts on the pin(s) */ - pio->PIO_IDR = mask; - - /* Enable the pull-up(s) if necessary */ - if (enablePullUp) { - - pio->PIO_PUER = mask; - } - else { - - pio->PIO_PUDR = mask; - } - - abcdsr = pio->PIO_ABCDSR[0]; - pio->PIO_ABCDSR[0] = (mask | abcdsr); - abcdsr = pio->PIO_ABCDSR[1]; - pio->PIO_ABCDSR[1] = (mask | abcdsr); - - pio->PIO_PDR = mask; -} - -/** - * \brief Configures one or more pin(s) or a PIO controller as inputs. Optionally, - * the corresponding internal pull-up(s) and glitch filter(s) can be enabled. - * - * \param pio Pointer to a PIO controller. - * \param mask Bitmask indicating which pin(s) to configure as input(s). - * \param enablePullUp Indicates if the internal pull-up(s) must be enabled. - * \param enableFilter Indicates if the glitch filter(s) must be enabled. - */ -static void PIO_SetInput( - Pio *pio, - unsigned int mask, - unsigned char attribute) -{ - /* Disable interrupts */ - pio->PIO_IDR = mask; - - /* Enable pull-up(s) if necessary */ - if (attribute & PIO_PULLUP) - pio->PIO_PUER = mask; - else - pio->PIO_PUDR = mask; - - /* Enable Input Filter if necessary */ - if (attribute & (PIO_DEGLITCH | PIO_DEBOUNCE)) - pio->PIO_IFER = mask; - else - pio->PIO_IFDR = mask; - - /* Enable de-glitch or de-bounce if necessary */ - if (attribute & PIO_DEGLITCH) - { - pio->PIO_IFSCDR = mask; - } - else - { - if (attribute & PIO_DEBOUNCE) - { - pio->PIO_IFSCER = mask; - } - } - - /* Configure pin as input */ - pio->PIO_ODR = mask; - pio->PIO_PER = mask; -} - -/** - * \brief Configures one or more pin(s) of a PIO controller as outputs, with the - * given default value. Optionally, the multi-drive feature can be enabled - * on the pin(s). - * - * \param pio Pointer to a PIO controller. - * \param mask Bitmask indicating which pin(s) to configure. - * \param defaultValue Default level on the pin(s). - * \param enableMultiDrive Indicates if the pin(s) shall be configured as - * open-drain. - * \param enablePullUp Indicates if the pin shall have its pull-up activated. - */ -static void PIO_SetOutput( - Pio *pio, - unsigned int mask, - unsigned char defaultValue, - unsigned char enableMultiDrive, - unsigned char enablePullUp) -{ - /* Disable interrupts */ - pio->PIO_IDR = mask; - - /* Enable pull-up(s) if necessary */ - if (enablePullUp) { - - pio->PIO_PUER = mask; - } - else { - - pio->PIO_PUDR = mask; - } - - /* Enable multi-drive if necessary */ - if (enableMultiDrive) { - - pio->PIO_MDER = mask; - } - else { - - pio->PIO_MDDR = mask; - } - - /* Set default value */ - if (defaultValue) { - - pio->PIO_SODR = mask; - } - else { - - pio->PIO_CODR = mask; - } - - /* Configure pin(s) as output(s) */ - pio->PIO_OER = mask; - pio->PIO_PER = mask; -} - -/*---------------------------------------------------------------------------- - * Global functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Configures a list of Pin instances, each of which can either hold a single - * pin or a group of pins, depending on the mask value; all pins are configured - * by this function. The size of the array must also be provided and is easily - * computed using PIO_LISTSIZE whenever its length is not known in advance. - * - * \param list Pointer to a list of Pin instances. - * \param size Size of the Pin list (calculated using PIO_LISTSIZE). - * - * \return 1 if the pins have been configured properly; otherwise 0. - */ -uint8_t PIO_Configure( const Pin *list, uint32_t size ) -{ - /* Configure pins */ - while ( size > 0 ) - { - switch ( list->type ) - { - - case PIO_PERIPH_A: - PIO_SetPeripheralA(list->pio, - list->mask, - (list->attribute & PIO_PULLUP) ? 1 : 0); - break; - - case PIO_PERIPH_B: - PIO_SetPeripheralB(list->pio, - list->mask, - (list->attribute & PIO_PULLUP) ? 1 : 0); - break; - - case PIO_PERIPH_C: - PIO_SetPeripheralC(list->pio, - list->mask, - (list->attribute & PIO_PULLUP) ? 1 : 0); - break; - - case PIO_PERIPH_D: - PIO_SetPeripheralD(list->pio, - list->mask, - (list->attribute & PIO_PULLUP) ? 1 : 0); - break; - case PIO_INPUT: - PMC_EnablePeripheral(list->id); - PIO_SetInput(list->pio, - list->mask, - list->attribute); - break; - - case PIO_OUTPUT_0: - case PIO_OUTPUT_1: - PIO_SetOutput(list->pio, - list->mask, - (list->type == PIO_OUTPUT_1), - (list->attribute & PIO_OPENDRAIN) ? 1 : 0, - (list->attribute & PIO_PULLUP) ? 1 : 0); - break; - - default: return 0; - } - - list++; - size--; - } - - return 1; -} - -/** - * \brief Sets a high output level on all the PIOs defined in the given Pin instance. - * This has no immediate effects on PIOs that are not output, but the PIO - * controller will memorize the value they are changed to outputs. - * - * \param pin Pointer to a Pin instance describing one or more pins. - */ -void PIO_Set(const Pin *pin) -{ - pin->pio->PIO_SODR = pin->mask; -} - -/** - * \brief Sets a low output level on all the PIOs defined in the given Pin instance. - * This has no immediate effects on PIOs that are not output, but the PIO - * controller will memorize the value they are changed to outputs. - * - * \param pin Pointer to a Pin instance describing one or more pins. - */ -void PIO_Clear(const Pin *pin) -{ - pin->pio->PIO_CODR = pin->mask; -} - -/** - * \brief Returns 1 if one or more PIO of the given Pin instance currently have - * a high level; otherwise returns 0. This method returns the actual value that - * is being read on the pin. To return the supposed output value of a pin, use - * PIO_GetOutputDataStatus() instead. - * - * \param pin Pointer to a Pin instance describing one or more pins. - * - * \return 1 if the Pin instance contains at least one PIO that currently has - * a high level; otherwise 0. - */ -unsigned char PIO_Get( const Pin *pin ) -{ - unsigned int reg ; - - if ( (pin->type == PIO_OUTPUT_0) || (pin->type == PIO_OUTPUT_1) ) - { - reg = pin->pio->PIO_ODSR ; - } - else - { - reg = pin->pio->PIO_PDSR ; - } - - if ( (reg & pin->mask) == 0 ) - { - return 0 ; - } - else - { - return 1 ; - } -} - -/** - * \brief Returns 1 if one or more PIO of the given Pin are configured to output a - * high level (even if they are not output). - * To get the actual value of the pin, use PIO_Get() instead. - * - * \param pin Pointer to a Pin instance describing one or more pins. - * - * \return 1 if the Pin instance contains at least one PIO that is configured - * to output a high level; otherwise 0. - */ -unsigned char PIO_GetOutputDataStatus(const Pin *pin) -{ - if ((pin->pio->PIO_ODSR & pin->mask) == 0) { - - return 0; - } - else { - - return 1; - } -} - -/* - * \brief Configures Glitch or Debouncing filter for input. - * - * \param pin Pointer to a Pin instance describing one or more pins. - * \param cuttoff Cutt off frequency for debounce filter. - */ -void PIO_SetDebounceFilter( const Pin *pin, uint32_t cuttoff ) -{ - Pio *pio = pin->pio; - - pio->PIO_IFSCER = pin->mask; /* set Debouncing, 0 bit field no effect */ - pio->PIO_SCDR = ((32678/(2*(cuttoff))) - 1) & 0x3FFF; /* the lowest 14 bits work */ -} +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2010, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** \file */ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ +#include "chip.h" +#include "pio.h" +#include "pmc.h" + +/*---------------------------------------------------------------------------- + * Local functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Configures one or more pin(s) of a PIO controller as being controlled by + * peripheral A. Optionally, the corresponding internal pull-up(s) can be enabled. + * + * \param pio Pointer to a PIO controller. + * \param mask Bitmask of one or more pin(s) to configure. + * \param enablePullUp Indicates if the pin(s) internal pull-up shall be + * configured. + */ +static void PIO_SetPeripheralA( + Pio *pio, + unsigned int mask, + unsigned char enablePullUp) +{ + unsigned int abcdsr; + /* Disable interrupts on the pin(s) */ + pio->PIO_IDR = mask; + + /* Enable the pull-up(s) if necessary */ + if (enablePullUp) { + pio->PIO_PUER = mask; + } + else { + + pio->PIO_PUDR = mask; + } + + abcdsr = pio->PIO_ABCDSR[0]; + pio->PIO_ABCDSR[0] &= (~mask & abcdsr); + abcdsr = pio->PIO_ABCDSR[1]; + pio->PIO_ABCDSR[1] &= (~mask & abcdsr); + pio->PIO_PDR = mask; +} + +/** + * \brief Configures one or more pin(s) of a PIO controller as being controlled by + * peripheral B. Optionally, the corresponding internal pull-up(s) can be enabled. + * + * \param pio Pointer to a PIO controller. + * \param mask Bitmask of one or more pin(s) to configure. + * \param enablePullUp Indicates if the pin(s) internal pull-up shall be + * configured. + */ +static void PIO_SetPeripheralB( + Pio *pio, + unsigned int mask, + unsigned char enablePullUp) +{ + unsigned int abcdsr; + /* Disable interrupts on the pin(s) */ + pio->PIO_IDR = mask; + + /* Enable the pull-up(s) if necessary */ + if (enablePullUp) { + + pio->PIO_PUER = mask; + } + else { + + pio->PIO_PUDR = mask; + } + + abcdsr = pio->PIO_ABCDSR[0]; + pio->PIO_ABCDSR[0] = (mask | abcdsr); + abcdsr = pio->PIO_ABCDSR[1]; + pio->PIO_ABCDSR[1] &= (~mask & abcdsr); + + pio->PIO_PDR = mask; +} + +/** + * \brief Configures one or more pin(s) of a PIO controller as being controlled by + * peripheral C. Optionally, the corresponding internal pull-up(s) can be enabled. + * + * \param pio Pointer to a PIO controller. + * \param mask Bitmask of one or more pin(s) to configure. + * \param enablePullUp Indicates if the pin(s) internal pull-up shall be + * configured. + */ +static void PIO_SetPeripheralC( + Pio *pio, + unsigned int mask, + unsigned char enablePullUp) +{ + unsigned int abcdsr; + /* Disable interrupts on the pin(s) */ + pio->PIO_IDR = mask; + + /* Enable the pull-up(s) if necessary */ + if (enablePullUp) { + + pio->PIO_PUER = mask; + } + else { + + pio->PIO_PUDR = mask; + } + + abcdsr = pio->PIO_ABCDSR[0]; + pio->PIO_ABCDSR[0] &= (~mask & abcdsr); + abcdsr = pio->PIO_ABCDSR[1]; + pio->PIO_ABCDSR[1] = (mask | abcdsr); + + pio->PIO_PDR = mask; +} + +/** + * \brief Configures one or more pin(s) of a PIO controller as being controlled by + * peripheral D. Optionally, the corresponding internal pull-up(s) can be enabled. + * + * \param pio Pointer to a PIO controller. + * \param mask Bitmask of one or more pin(s) to configure. + * \param enablePullUp Indicates if the pin(s) internal pull-up shall be + * configured. + */ +static void PIO_SetPeripheralD( + Pio *pio, + unsigned int mask, + unsigned char enablePullUp) +{ + unsigned int abcdsr; + /* Disable interrupts on the pin(s) */ + pio->PIO_IDR = mask; + + /* Enable the pull-up(s) if necessary */ + if (enablePullUp) { + + pio->PIO_PUER = mask; + } + else { + + pio->PIO_PUDR = mask; + } + + abcdsr = pio->PIO_ABCDSR[0]; + pio->PIO_ABCDSR[0] = (mask | abcdsr); + abcdsr = pio->PIO_ABCDSR[1]; + pio->PIO_ABCDSR[1] = (mask | abcdsr); + + pio->PIO_PDR = mask; +} + +/** + * \brief Configures one or more pin(s) or a PIO controller as inputs. Optionally, + * the corresponding internal pull-up(s) and glitch filter(s) can be enabled. + * + * \param pio Pointer to a PIO controller. + * \param mask Bitmask indicating which pin(s) to configure as input(s). + * \param enablePullUp Indicates if the internal pull-up(s) must be enabled. + * \param enableFilter Indicates if the glitch filter(s) must be enabled. + */ +static void PIO_SetInput( + Pio *pio, + unsigned int mask, + unsigned char attribute) +{ + /* Disable interrupts */ + pio->PIO_IDR = mask; + + /* Enable pull-up(s) if necessary */ + if (attribute & PIO_PULLUP) + pio->PIO_PUER = mask; + else + pio->PIO_PUDR = mask; + + /* Enable Input Filter if necessary */ + if (attribute & (PIO_DEGLITCH | PIO_DEBOUNCE)) + pio->PIO_IFER = mask; + else + pio->PIO_IFDR = mask; + + /* Enable de-glitch or de-bounce if necessary */ + if (attribute & PIO_DEGLITCH) + { + pio->PIO_IFSCDR = mask; + } + else + { + if (attribute & PIO_DEBOUNCE) + { + pio->PIO_IFSCER = mask; + } + } + + /* Configure pin as input */ + pio->PIO_ODR = mask; + pio->PIO_PER = mask; +} + +/** + * \brief Configures one or more pin(s) of a PIO controller as outputs, with the + * given default value. Optionally, the multi-drive feature can be enabled + * on the pin(s). + * + * \param pio Pointer to a PIO controller. + * \param mask Bitmask indicating which pin(s) to configure. + * \param defaultValue Default level on the pin(s). + * \param enableMultiDrive Indicates if the pin(s) shall be configured as + * open-drain. + * \param enablePullUp Indicates if the pin shall have its pull-up activated. + */ +static void PIO_SetOutput( + Pio *pio, + unsigned int mask, + unsigned char defaultValue, + unsigned char enableMultiDrive, + unsigned char enablePullUp) +{ + /* Disable interrupts */ + pio->PIO_IDR = mask; + + /* Enable pull-up(s) if necessary */ + if (enablePullUp) { + + pio->PIO_PUER = mask; + } + else { + + pio->PIO_PUDR = mask; + } + + /* Enable multi-drive if necessary */ + if (enableMultiDrive) { + + pio->PIO_MDER = mask; + } + else { + + pio->PIO_MDDR = mask; + } + + /* Set default value */ + if (defaultValue) { + + pio->PIO_SODR = mask; + } + else { + + pio->PIO_CODR = mask; + } + + /* Configure pin(s) as output(s) */ + pio->PIO_OER = mask; + pio->PIO_PER = mask; +} + +/*---------------------------------------------------------------------------- + * Global functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Configures a list of Pin instances, each of which can either hold a single + * pin or a group of pins, depending on the mask value; all pins are configured + * by this function. The size of the array must also be provided and is easily + * computed using PIO_LISTSIZE whenever its length is not known in advance. + * + * \param list Pointer to a list of Pin instances. + * \param size Size of the Pin list (calculated using PIO_LISTSIZE). + * + * \return 1 if the pins have been configured properly; otherwise 0. + */ +uint8_t PIO_Configure( const Pin *list, uint32_t size ) +{ + /* Configure pins */ + while ( size > 0 ) + { + switch ( list->type ) + { + + case PIO_PERIPH_A: + PIO_SetPeripheralA(list->pio, + list->mask, + (list->attribute & PIO_PULLUP) ? 1 : 0); + break; + + case PIO_PERIPH_B: + PIO_SetPeripheralB(list->pio, + list->mask, + (list->attribute & PIO_PULLUP) ? 1 : 0); + break; + + case PIO_PERIPH_C: + PIO_SetPeripheralC(list->pio, + list->mask, + (list->attribute & PIO_PULLUP) ? 1 : 0); + break; + + case PIO_PERIPH_D: + PIO_SetPeripheralD(list->pio, + list->mask, + (list->attribute & PIO_PULLUP) ? 1 : 0); + break; + case PIO_INPUT: + PMC_EnablePeripheral(list->id); + PIO_SetInput(list->pio, + list->mask, + list->attribute); + break; + + case PIO_OUTPUT_0: + case PIO_OUTPUT_1: + PIO_SetOutput(list->pio, + list->mask, + (list->type == PIO_OUTPUT_1), + (list->attribute & PIO_OPENDRAIN) ? 1 : 0, + (list->attribute & PIO_PULLUP) ? 1 : 0); + break; + + default: return 0; + } + + list++; + size--; + } + + return 1; +} + +/** + * \brief Sets a high output level on all the PIOs defined in the given Pin instance. + * This has no immediate effects on PIOs that are not output, but the PIO + * controller will memorize the value they are changed to outputs. + * + * \param pin Pointer to a Pin instance describing one or more pins. + */ +void PIO_Set(const Pin *pin) +{ + pin->pio->PIO_SODR = pin->mask; +} + +/** + * \brief Sets a low output level on all the PIOs defined in the given Pin instance. + * This has no immediate effects on PIOs that are not output, but the PIO + * controller will memorize the value they are changed to outputs. + * + * \param pin Pointer to a Pin instance describing one or more pins. + */ +void PIO_Clear(const Pin *pin) +{ + pin->pio->PIO_CODR = pin->mask; +} + +/** + * \brief Returns 1 if one or more PIO of the given Pin instance currently have + * a high level; otherwise returns 0. This method returns the actual value that + * is being read on the pin. To return the supposed output value of a pin, use + * PIO_GetOutputDataStatus() instead. + * + * \param pin Pointer to a Pin instance describing one or more pins. + * + * \return 1 if the Pin instance contains at least one PIO that currently has + * a high level; otherwise 0. + */ +unsigned char PIO_Get( const Pin *pin ) +{ + unsigned int reg ; + + if ( (pin->type == PIO_OUTPUT_0) || (pin->type == PIO_OUTPUT_1) ) + { + reg = pin->pio->PIO_ODSR ; + } + else + { + reg = pin->pio->PIO_PDSR ; + } + + if ( (reg & pin->mask) == 0 ) + { + return 0 ; + } + else + { + return 1 ; + } +} + +/** + * \brief Returns 1 if one or more PIO of the given Pin are configured to output a + * high level (even if they are not output). + * To get the actual value of the pin, use PIO_Get() instead. + * + * \param pin Pointer to a Pin instance describing one or more pins. + * + * \return 1 if the Pin instance contains at least one PIO that is configured + * to output a high level; otherwise 0. + */ +unsigned char PIO_GetOutputDataStatus(const Pin *pin) +{ + if ((pin->pio->PIO_ODSR & pin->mask) == 0) { + + return 0; + } + else { + + return 1; + } +} + +/* + * \brief Configures Glitch or Debouncing filter for input. + * + * \param pin Pointer to a Pin instance describing one or more pins. + * \param cuttoff Cutt off frequency for debounce filter. + */ +void PIO_SetDebounceFilter( const Pin *pin, uint32_t cuttoff ) +{ + Pio *pio = pin->pio; + + pio->PIO_IFSCER = pin->mask; /* set Debouncing, 0 bit field no effect */ + pio->PIO_SCDR = ((32678/(2*(cuttoff))) - 1) & 0x3FFF; /* the lowest 14 bits work */ +} diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio_it.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio_it.c index 74e87dae..7feccd17 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio_it.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio_it.c @@ -1,315 +1,315 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2008, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/* - * \file - */ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ - -#include "chip.h" - -#include - -/*---------------------------------------------------------------------------- - * Local definitions - *----------------------------------------------------------------------------*/ - -/* Maximum number of interrupt sources that can be defined. This - * constant can be increased, but the current value is the smallest possible - * that will be compatible with all existing projects. */ -#define MAX_INTERRUPT_SOURCES 7 - -/*---------------------------------------------------------------------------- - * Local types - *----------------------------------------------------------------------------*/ - -/** - * Describes a PIO interrupt source, including the PIO instance triggering the - * interrupt and the associated interrupt handler. - */ -typedef struct _InterruptSource -{ - /* Pointer to the source pin instance. */ - const Pin *pPin; - - /* Interrupt handler. */ - void (*handler)( const Pin* ) ; -} InterruptSource ; - -/*---------------------------------------------------------------------------- - * Local variables - *----------------------------------------------------------------------------*/ - -/* List of interrupt sources. */ -static InterruptSource _aIntSources[MAX_INTERRUPT_SOURCES] ; - -/* Number of currently defined interrupt sources. */ -static uint32_t _dwNumSources = 0; - -/*---------------------------------------------------------------------------- - * Local Functions - *----------------------------------------------------------------------------*/ -/*----------------------------------------------------------------------------*/ -/** - * \brief Stub, to handling all PIO Capture interrupts, if not defined. - */ -/*----------------------------------------------------------------------------*/ -extern WEAK void PIO_CaptureHandler( void ) -{ -} - -/** - * \brief Handles all interrupts on the given PIO controller. - * \param id PIO controller ID. - * \param pPio PIO controller base address. - */ -extern void PioInterruptHandler( uint32_t id, Pio *pPio ) -{ - uint32_t status; - uint32_t i; - - /* Read PIO controller status */ - status = pPio->PIO_ISR; - status &= pPio->PIO_IMR; - - /* Check pending events */ - if ( status != 0 ) - { - TRACE_DEBUG( "PIO interrupt on PIO controller #%" PRIu32 "\n\r", id ) ; - - /* Find triggering source */ - i = 0; - while ( status != 0 ) - { - /* There cannot be an unconfigured source enabled. */ - assert(i < _dwNumSources); - - /* Source is configured on the same controller */ - if (_aIntSources[i].pPin->id == id) - { - /* Source has PIOs whose statuses have changed */ - if ( (status & _aIntSources[i].pPin->mask) != 0 ) - { - TRACE_DEBUG( "Interrupt source #%" PRIu32 " triggered\n\r", i ) ; - - _aIntSources[i].handler(_aIntSources[i].pPin); - status &= ~(_aIntSources[i].pPin->mask); - } - } - i++; - } - } -} - -/*---------------------------------------------------------------------------- - * Global Functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Parallel IO Controller A interrupt handler - * \Redefined PIOA interrupt handler for NVIC interrupt table. - */ -extern void PIOA_IrqHandler( void ) -{ - if ( PIOA->PIO_PCISR != 0 ) - { - PIO_CaptureHandler() ; - } - - PioInterruptHandler( ID_PIOA, PIOA ) ; -} - -/** - * \brief Parallel IO Controller B interrupt handler - * \Redefined PIOB interrupt handler for NVIC interrupt table. - */ -extern void PIOB_IrqHandler( void ) -{ - PioInterruptHandler( ID_PIOB, PIOB ) ; -} - -/** - * \brief Parallel IO Controller C interrupt handler - * \Redefined PIOC interrupt handler for NVIC interrupt table. - */ -extern void PIOC_IrqHandler( void ) -{ - PioInterruptHandler( ID_PIOC, PIOC ) ; -} - -/** - * \brief Initializes the PIO interrupt management logic - * - * The desired priority of PIO interrupts must be provided. - * Calling this function multiple times result in the reset of currently - * configured interrupts. - * - * \param priority PIO controller interrupts priority. - */ -extern void PIO_InitializeInterrupts( uint32_t dwPriority ) -{ - TRACE_DEBUG( "PIO_Initialize()\n\r" ) ; - - /* Reset sources */ - _dwNumSources = 0 ; - - /* Configure PIO interrupt sources */ - TRACE_DEBUG( "PIO_Initialize: Configuring PIOA\n\r" ) ; - PMC_EnablePeripheral( ID_PIOA ) ; - PIOA->PIO_ISR ; - PIOA->PIO_IDR = 0xFFFFFFFF ; - NVIC_DisableIRQ( PIOA_IRQn ) ; - NVIC_ClearPendingIRQ( PIOA_IRQn ) ; - NVIC_SetPriority( PIOA_IRQn, dwPriority ) ; - NVIC_EnableIRQ( PIOA_IRQn ) ; - - TRACE_DEBUG( "PIO_Initialize: Configuring PIOB\n\r" ) ; - PMC_EnablePeripheral( ID_PIOB ) ; - PIOB->PIO_ISR ; - PIOB->PIO_IDR = 0xFFFFFFFF ; - NVIC_DisableIRQ( PIOB_IRQn ) ; - NVIC_ClearPendingIRQ( PIOB_IRQn ) ; - NVIC_SetPriority( PIOB_IRQn, dwPriority ) ; - NVIC_EnableIRQ( PIOB_IRQn ) ; - - TRACE_DEBUG( "PIO_Initialize: Configuring PIOC\n\r" ) ; - PMC_EnablePeripheral( ID_PIOC ) ; - PIOC->PIO_ISR ; - PIOC->PIO_IDR = 0xFFFFFFFF ; - NVIC_DisableIRQ( PIOC_IRQn ) ; - NVIC_ClearPendingIRQ( PIOC_IRQn ) ; - NVIC_SetPriority( PIOC_IRQn, dwPriority ) ; - NVIC_EnableIRQ( PIOC_IRQn ) ; -} - -/** - * Configures a PIO or a group of PIO to generate an interrupt on status - * change. The provided interrupt handler will be called with the triggering - * pin as its parameter (enabling different pin instances to share the same - * handler). - * \param pPin Pointer to a Pin instance. - * \param handler Interrupt handler function pointer. - */ -extern void PIO_ConfigureIt( const Pin *pPin, void (*handler)( const Pin* ) ) -{ - Pio* pio ; - InterruptSource* pSource ; - - TRACE_DEBUG( "PIO_ConfigureIt()\n\r" ) ; - - assert( pPin ) ; - pio = pPin->pio ; - assert( _dwNumSources < MAX_INTERRUPT_SOURCES ) ; - - /* Define new source */ - TRACE_DEBUG( "PIO_ConfigureIt: Defining new source #%" PRIu32 ".\n\r", _dwNumSources ) ; - - pSource = &(_aIntSources[_dwNumSources]) ; - pSource->pPin = pPin ; - pSource->handler = handler ; - _dwNumSources++ ; - - /* PIO3 with additional interrupt support - * Configure additional interrupt mode registers */ - if ( pPin->attribute & PIO_IT_AIME ) - { - // enable additional interrupt mode - pio->PIO_AIMER = pPin->mask ; - - // if bit field of selected pin is 1, set as Rising Edge/High level detection event - if ( pPin->attribute & PIO_IT_RE_OR_HL ) - { - pio->PIO_REHLSR = pPin->mask ; - } - else - { - pio->PIO_FELLSR = pPin->mask; - } - - /* if bit field of selected pin is 1, set as edge detection source */ - if (pPin->attribute & PIO_IT_EDGE) - pio->PIO_ESR = pPin->mask; - else - pio->PIO_LSR = pPin->mask; - } - else - { - /* disable additional interrupt mode */ - pio->PIO_AIMDR = pPin->mask; - } -} - -/** - * Enables the given interrupt source if it has been configured. The status - * register of the corresponding PIO controller is cleared prior to enabling - * the interrupt. - * \param pPin Interrupt source to enable. - */ -extern void PIO_EnableIt( const Pin *pPin ) -{ - TRACE_DEBUG( "PIO_EnableIt()\n\r" ) ; - - assert( pPin != NULL ) ; - -#ifndef NOASSERT - uint32_t i = 0; - uint32_t dwFound = 0; - - while ( (i < _dwNumSources) && !dwFound ) - { - if ( _aIntSources[i].pPin == pPin ) - { - dwFound = 1 ; - } - i++ ; - } - assert( dwFound != 0 ) ; -#endif - - pPin->pio->PIO_ISR; - pPin->pio->PIO_IER = pPin->mask ; -} - -/** - * Disables a given interrupt source, with no added side effects. - * - * \param pPin Interrupt source to disable. - */ -extern void PIO_DisableIt( const Pin *pPin ) -{ - assert( pPin != NULL ) ; - - TRACE_DEBUG( "PIO_DisableIt()\n\r" ) ; - - pPin->pio->PIO_IDR = pPin->mask; -} - +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2008, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/* + * \file + */ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "chip.h" + +#include + +/*---------------------------------------------------------------------------- + * Local definitions + *----------------------------------------------------------------------------*/ + +/* Maximum number of interrupt sources that can be defined. This + * constant can be increased, but the current value is the smallest possible + * that will be compatible with all existing projects. */ +#define MAX_INTERRUPT_SOURCES 7 + +/*---------------------------------------------------------------------------- + * Local types + *----------------------------------------------------------------------------*/ + +/** + * Describes a PIO interrupt source, including the PIO instance triggering the + * interrupt and the associated interrupt handler. + */ +typedef struct _InterruptSource +{ + /* Pointer to the source pin instance. */ + const Pin *pPin; + + /* Interrupt handler. */ + void (*handler)( const Pin* ) ; +} InterruptSource ; + +/*---------------------------------------------------------------------------- + * Local variables + *----------------------------------------------------------------------------*/ + +/* List of interrupt sources. */ +static InterruptSource _aIntSources[MAX_INTERRUPT_SOURCES] ; + +/* Number of currently defined interrupt sources. */ +static uint32_t _dwNumSources = 0; + +/*---------------------------------------------------------------------------- + * Local Functions + *----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/** + * \brief Stub, to handling all PIO Capture interrupts, if not defined. + */ +/*----------------------------------------------------------------------------*/ +extern WEAK void PIO_CaptureHandler( void ) +{ +} + +/** + * \brief Handles all interrupts on the given PIO controller. + * \param id PIO controller ID. + * \param pPio PIO controller base address. + */ +extern void PioInterruptHandler( uint32_t id, Pio *pPio ) +{ + uint32_t status; + uint32_t i; + + /* Read PIO controller status */ + status = pPio->PIO_ISR; + status &= pPio->PIO_IMR; + + /* Check pending events */ + if ( status != 0 ) + { + TRACE_DEBUG( "PIO interrupt on PIO controller #%" PRIu32 "\n\r", id ) ; + + /* Find triggering source */ + i = 0; + while ( status != 0 ) + { + /* There cannot be an unconfigured source enabled. */ + assert(i < _dwNumSources); + + /* Source is configured on the same controller */ + if (_aIntSources[i].pPin->id == id) + { + /* Source has PIOs whose statuses have changed */ + if ( (status & _aIntSources[i].pPin->mask) != 0 ) + { + TRACE_DEBUG( "Interrupt source #%" PRIu32 " triggered\n\r", i ) ; + + _aIntSources[i].handler(_aIntSources[i].pPin); + status &= ~(_aIntSources[i].pPin->mask); + } + } + i++; + } + } +} + +/*---------------------------------------------------------------------------- + * Global Functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Parallel IO Controller A interrupt handler + * \Redefined PIOA interrupt handler for NVIC interrupt table. + */ +extern void PIOA_IrqHandler( void ) +{ + if ( PIOA->PIO_PCISR != 0 ) + { + PIO_CaptureHandler() ; + } + + PioInterruptHandler( ID_PIOA, PIOA ) ; +} + +/** + * \brief Parallel IO Controller B interrupt handler + * \Redefined PIOB interrupt handler for NVIC interrupt table. + */ +extern void PIOB_IrqHandler( void ) +{ + PioInterruptHandler( ID_PIOB, PIOB ) ; +} + +/** + * \brief Parallel IO Controller C interrupt handler + * \Redefined PIOC interrupt handler for NVIC interrupt table. + */ +extern void PIOC_IrqHandler( void ) +{ + PioInterruptHandler( ID_PIOC, PIOC ) ; +} + +/** + * \brief Initializes the PIO interrupt management logic + * + * The desired priority of PIO interrupts must be provided. + * Calling this function multiple times result in the reset of currently + * configured interrupts. + * + * \param priority PIO controller interrupts priority. + */ +extern void PIO_InitializeInterrupts( uint32_t dwPriority ) +{ + TRACE_DEBUG( "PIO_Initialize()\n\r" ) ; + + /* Reset sources */ + _dwNumSources = 0 ; + + /* Configure PIO interrupt sources */ + TRACE_DEBUG( "PIO_Initialize: Configuring PIOA\n\r" ) ; + PMC_EnablePeripheral( ID_PIOA ) ; + PIOA->PIO_ISR ; + PIOA->PIO_IDR = 0xFFFFFFFF ; + NVIC_DisableIRQ( PIOA_IRQn ) ; + NVIC_ClearPendingIRQ( PIOA_IRQn ) ; + NVIC_SetPriority( PIOA_IRQn, dwPriority ) ; + NVIC_EnableIRQ( PIOA_IRQn ) ; + + TRACE_DEBUG( "PIO_Initialize: Configuring PIOB\n\r" ) ; + PMC_EnablePeripheral( ID_PIOB ) ; + PIOB->PIO_ISR ; + PIOB->PIO_IDR = 0xFFFFFFFF ; + NVIC_DisableIRQ( PIOB_IRQn ) ; + NVIC_ClearPendingIRQ( PIOB_IRQn ) ; + NVIC_SetPriority( PIOB_IRQn, dwPriority ) ; + NVIC_EnableIRQ( PIOB_IRQn ) ; + + TRACE_DEBUG( "PIO_Initialize: Configuring PIOC\n\r" ) ; + PMC_EnablePeripheral( ID_PIOC ) ; + PIOC->PIO_ISR ; + PIOC->PIO_IDR = 0xFFFFFFFF ; + NVIC_DisableIRQ( PIOC_IRQn ) ; + NVIC_ClearPendingIRQ( PIOC_IRQn ) ; + NVIC_SetPriority( PIOC_IRQn, dwPriority ) ; + NVIC_EnableIRQ( PIOC_IRQn ) ; +} + +/** + * Configures a PIO or a group of PIO to generate an interrupt on status + * change. The provided interrupt handler will be called with the triggering + * pin as its parameter (enabling different pin instances to share the same + * handler). + * \param pPin Pointer to a Pin instance. + * \param handler Interrupt handler function pointer. + */ +extern void PIO_ConfigureIt( const Pin *pPin, void (*handler)( const Pin* ) ) +{ + Pio* pio ; + InterruptSource* pSource ; + + TRACE_DEBUG( "PIO_ConfigureIt()\n\r" ) ; + + assert( pPin ) ; + pio = pPin->pio ; + assert( _dwNumSources < MAX_INTERRUPT_SOURCES ) ; + + /* Define new source */ + TRACE_DEBUG( "PIO_ConfigureIt: Defining new source #%" PRIu32 ".\n\r", _dwNumSources ) ; + + pSource = &(_aIntSources[_dwNumSources]) ; + pSource->pPin = pPin ; + pSource->handler = handler ; + _dwNumSources++ ; + + /* PIO3 with additional interrupt support + * Configure additional interrupt mode registers */ + if ( pPin->attribute & PIO_IT_AIME ) + { + // enable additional interrupt mode + pio->PIO_AIMER = pPin->mask ; + + // if bit field of selected pin is 1, set as Rising Edge/High level detection event + if ( pPin->attribute & PIO_IT_RE_OR_HL ) + { + pio->PIO_REHLSR = pPin->mask ; + } + else + { + pio->PIO_FELLSR = pPin->mask; + } + + /* if bit field of selected pin is 1, set as edge detection source */ + if (pPin->attribute & PIO_IT_EDGE) + pio->PIO_ESR = pPin->mask; + else + pio->PIO_LSR = pPin->mask; + } + else + { + /* disable additional interrupt mode */ + pio->PIO_AIMDR = pPin->mask; + } +} + +/** + * Enables the given interrupt source if it has been configured. The status + * register of the corresponding PIO controller is cleared prior to enabling + * the interrupt. + * \param pPin Interrupt source to enable. + */ +extern void PIO_EnableIt( const Pin *pPin ) +{ + TRACE_DEBUG( "PIO_EnableIt()\n\r" ) ; + + assert( pPin != NULL ) ; + +#ifndef NOASSERT + uint32_t i = 0; + uint32_t dwFound = 0; + + while ( (i < _dwNumSources) && !dwFound ) + { + if ( _aIntSources[i].pPin == pPin ) + { + dwFound = 1 ; + } + i++ ; + } + assert( dwFound != 0 ) ; +#endif + + pPin->pio->PIO_ISR; + pPin->pio->PIO_IER = pPin->mask ; +} + +/** + * Disables a given interrupt source, with no added side effects. + * + * \param pPin Interrupt source to disable. + */ +extern void PIO_DisableIt( const Pin *pPin ) +{ + assert( pPin != NULL ) ; + + TRACE_DEBUG( "PIO_DisableIt()\n\r" ) ; + + pPin->pio->PIO_IDR = pPin->mask; +} + diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/pmc.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/pmc.c index fa4dde03..f372ebcb 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/pmc.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/pmc.c @@ -1,168 +1,168 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ - -#include "chip.h" -#include "trace.h" - -#include - -/*---------------------------------------------------------------------------- - * Local definitions - *----------------------------------------------------------------------------*/ - -#define MASK_STATUS0 0xFFFFFFFC -#define MASK_STATUS1 0xFFFFFFFF - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Enables the clock of a peripheral. The peripheral ID is used - * to identify which peripheral is targetted. - * - * \note The ID must NOT be shifted (i.e. 1 << ID_xxx). - * - * \param id Peripheral ID (ID_xxx). - */ -extern void PMC_EnablePeripheral( uint32_t dwId ) -{ - assert( dwId < 35 ) ; - - if ( dwId < 32 ) - { - if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId) ) - { - TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral" " %" PRIu32 " is already enabled\n\r", dwId ) ; - } - else - { - PMC->PMC_PCER0 = 1 << dwId ; - } - } - else - { - dwId -= 32; - if ((PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId)) - { - TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral" " %" PRIu32 " is already enabled\n\r", dwId + 32 ) ; - } - else - { - PMC->PMC_PCER1 = 1 << dwId ; - } - } -} - -/** - * \brief Disables the clock of a peripheral. The peripheral ID is used - * to identify which peripheral is targetted. - * - * \note The ID must NOT be shifted (i.e. 1 << ID_xxx). - * - * \param id Peripheral ID (ID_xxx). - */ -extern void PMC_DisablePeripheral( uint32_t dwId ) -{ - assert( dwId < 35 ) ; - - if ( dwId < 32 ) - { - if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) ) - { - TRACE_DEBUG("PMC_DisablePeripheral: clock of peripheral" " %" PRIu32 " is not enabled\n\r", dwId ) ; - } - else - { - PMC->PMC_PCDR0 = 1 << dwId ; - } - } - else - { - dwId -= 32 ; - if ( (PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) ) - { - TRACE_DEBUG( "PMC_DisablePeripheral: clock of peripheral" " %" PRIu32 " is not enabled\n\r", dwId + 32 ) ; - } - else - { - PMC->PMC_PCDR1 = 1 << dwId ; - } - } -} - -/** - * \brief Enable all the periph clock via PMC. - */ -extern void PMC_EnableAllPeripherals( void ) -{ - PMC->PMC_PCER0 = MASK_STATUS0 ; - while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != MASK_STATUS0 ) ; - - PMC->PMC_PCER1 = MASK_STATUS1 ; - while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != MASK_STATUS1 ) ; - - TRACE_DEBUG( "Enable all periph clocks\n\r" ) ; -} - -/** - * \brief Disable all the periph clock via PMC. - */ -extern void PMC_DisableAllPeripherals( void ) -{ - PMC->PMC_PCDR0 = MASK_STATUS0 ; - while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != 0 ) ; - - PMC->PMC_PCDR1 = MASK_STATUS1 ; - while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != 0 ) ; - - TRACE_DEBUG( "Disable all periph clocks\n\r" ) ; -} - -/** - * \brief Get Periph Status for the given peripheral ID. - * - * \param id Peripheral ID (ID_xxx). - */ -extern uint32_t PMC_IsPeriphEnabled( uint32_t dwId ) -{ - assert( dwId < 35 ) ; - - if ( dwId < 32 ) - { - return ( PMC->PMC_PCSR0 & (1 << dwId) ) ; - } - else { - return ( PMC->PMC_PCSR1 & (1 << (dwId - 32)) ) ; - } -} +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "chip.h" +#include "trace.h" + +#include + +/*---------------------------------------------------------------------------- + * Local definitions + *----------------------------------------------------------------------------*/ + +#define MASK_STATUS0 0xFFFFFFFC +#define MASK_STATUS1 0xFFFFFFFF + +/*---------------------------------------------------------------------------- + * Exported functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Enables the clock of a peripheral. The peripheral ID is used + * to identify which peripheral is targetted. + * + * \note The ID must NOT be shifted (i.e. 1 << ID_xxx). + * + * \param id Peripheral ID (ID_xxx). + */ +extern void PMC_EnablePeripheral( uint32_t dwId ) +{ + assert( dwId < 35 ) ; + + if ( dwId < 32 ) + { + if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId) ) + { + TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral" " %" PRIu32 " is already enabled\n\r", dwId ) ; + } + else + { + PMC->PMC_PCER0 = 1 << dwId ; + } + } + else + { + dwId -= 32; + if ((PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId)) + { + TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral" " %" PRIu32 " is already enabled\n\r", dwId + 32 ) ; + } + else + { + PMC->PMC_PCER1 = 1 << dwId ; + } + } +} + +/** + * \brief Disables the clock of a peripheral. The peripheral ID is used + * to identify which peripheral is targetted. + * + * \note The ID must NOT be shifted (i.e. 1 << ID_xxx). + * + * \param id Peripheral ID (ID_xxx). + */ +extern void PMC_DisablePeripheral( uint32_t dwId ) +{ + assert( dwId < 35 ) ; + + if ( dwId < 32 ) + { + if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) ) + { + TRACE_DEBUG("PMC_DisablePeripheral: clock of peripheral" " %" PRIu32 " is not enabled\n\r", dwId ) ; + } + else + { + PMC->PMC_PCDR0 = 1 << dwId ; + } + } + else + { + dwId -= 32 ; + if ( (PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) ) + { + TRACE_DEBUG( "PMC_DisablePeripheral: clock of peripheral" " %" PRIu32 " is not enabled\n\r", dwId + 32 ) ; + } + else + { + PMC->PMC_PCDR1 = 1 << dwId ; + } + } +} + +/** + * \brief Enable all the periph clock via PMC. + */ +extern void PMC_EnableAllPeripherals( void ) +{ + PMC->PMC_PCER0 = MASK_STATUS0 ; + while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != MASK_STATUS0 ) ; + + PMC->PMC_PCER1 = MASK_STATUS1 ; + while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != MASK_STATUS1 ) ; + + TRACE_DEBUG( "Enable all periph clocks\n\r" ) ; +} + +/** + * \brief Disable all the periph clock via PMC. + */ +extern void PMC_DisableAllPeripherals( void ) +{ + PMC->PMC_PCDR0 = MASK_STATUS0 ; + while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != 0 ) ; + + PMC->PMC_PCDR1 = MASK_STATUS1 ; + while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != 0 ) ; + + TRACE_DEBUG( "Disable all periph clocks\n\r" ) ; +} + +/** + * \brief Get Periph Status for the given peripheral ID. + * + * \param id Peripheral ID (ID_xxx). + */ +extern uint32_t PMC_IsPeriphEnabled( uint32_t dwId ) +{ + assert( dwId < 35 ) ; + + if ( dwId < 32 ) + { + return ( PMC->PMC_PCSR0 & (1 << dwId) ) ; + } + else { + return ( PMC->PMC_PCSR1 & (1 << (dwId - 32)) ) ; + } +} diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/spi.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/spi.c index 8e4b9652..7b37f218 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/spi.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/spi.c @@ -1,352 +1,352 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** \addtogroup spi_module Working with SPI - * The SPI driver provides the interface to configure and use the SPI - * peripheral. - * - * The Serial Peripheral Interface (SPI) circuit is a synchronous serial - * data link that provides communication with external devices in Master - * or Slave Mode. - * - * To use the SPI, the user has to follow these few steps: - * -# Enable the SPI pins required by the application (see pio.h). - * -# Configure the SPI using the \ref SPI_Configure(). This enables the - * peripheral clock. The mode register is loaded with the given value. - * -# Configure all the necessary chip selects with \ref SPI_ConfigureNPCS(). - * -# Enable the SPI by calling \ref SPI_Enable(). - * -# Send/receive data using \ref SPI_Write() and \ref SPI_Read(). Note that \ref SPI_Read() - * must be called after \ref SPI_Write() to retrieve the last value read. - * -# Send/receive data using the PDC with the \ref SPI_WriteBuffer() and - * \ref SPI_ReadBuffer() functions. - * -# Disable the SPI by calling \ref SPI_Disable(). - * - * For more accurate information, please look at the SPI section of the - * Datasheet. - * - * Related files :\n - * \ref spi.c\n - * \ref spi.h.\n -*/ -/*@{*/ -/*@}*/ - -/** - * \file - * - * Implementation of Serial Peripheral Interface (SPI) controller. - * - */ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ - -#include "chip.h" -#include "pmc.h" -#include "spi.h" - -#include - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Enables a SPI peripheral. - * - * \param spi Pointer to an Spi instance. - */ -extern void SPI_Enable( Spi* spi ) -{ - spi->SPI_CR = SPI_CR_SPIEN ; -} - -/** - * \brief Disables a SPI peripheral. - * - * \param spi Pointer to an Spi instance. - */ -extern void SPI_Disable( Spi* spi ) -{ - spi->SPI_CR = SPI_CR_SPIDIS ; -} - -/** - * \brief Enables one or more interrupt sources of a SPI peripheral. - * - * \param spi Pointer to an Spi instance. - * \param sources Bitwise OR of selected interrupt sources. - */ -extern void SPI_EnableIt( Spi* spi, uint32_t dwSources ) -{ - spi->SPI_IER = dwSources ; -} - -/** - * \brief Disables one or more interrupt sources of a SPI peripheral. - * - * \param spi Pointer to an Spi instance. - * \param sources Bitwise OR of selected interrupt sources. - */ -extern void SPI_DisableIt( Spi* spi, uint32_t dwSources ) -{ - spi->SPI_IDR = dwSources ; -} - -/** - * \brief Configures a SPI peripheral as specified. The configuration can be computed - * using several macros (see \ref spi_configuration_macros). - * - * \param spi Pointer to an Spi instance. - * \param id Peripheral ID of the SPI. - * \param configuration Value of the SPI configuration register. - */ -extern void SPI_Configure( Spi* spi, uint32_t dwId, uint32_t dwConfiguration ) -{ - PMC_EnablePeripheral( dwId ) ; - spi->SPI_CR = SPI_CR_SPIDIS ; - - /* Execute a software reset of the SPI twice */ - spi->SPI_CR = SPI_CR_SWRST ; - spi->SPI_CR = SPI_CR_SWRST ; - spi->SPI_MR = dwConfiguration ; -} - - -/** - * \brief Configures a chip select of a SPI peripheral. The chip select configuration - * is computed using several macros (see \ref spi_configuration_macros). - * - * \param spi Pointer to an Spi instance. - * \param npcs Chip select to configure (0, 1, 2 or 3). - * \param configuration Desired chip select configuration. - */ -void SPI_ConfigureNPCS( Spi* spi, uint32_t dwNpcs, uint32_t dwConfiguration ) -{ - spi->SPI_CSR[dwNpcs] = dwConfiguration ; -} - -/** - * \brief Get the current status register of the given SPI peripheral. - * \note This resets the internal value of the status register, so further - * read may yield different values. - * \param spi Pointer to a Spi instance. - * \return SPI status register. - */ -extern uint32_t SPI_GetStatus( Spi* spi ) -{ - return spi->SPI_SR ; -} - -/** - * \brief Reads and returns the last word of data received by a SPI peripheral. This - * method must be called after a successful SPI_Write call. - * - * \param spi Pointer to an Spi instance. - * - * \return readed data. - */ -extern uint32_t SPI_Read( Spi* spi ) -{ - while ( (spi->SPI_SR & SPI_SR_RDRF) == 0 ) ; - - return spi->SPI_RDR & 0xFFFF ; -} - -/** - * \brief Sends data through a SPI peripheral. If the SPI is configured to use a fixed - * peripheral select, the npcs value is meaningless. Otherwise, it identifies - * the component which shall be addressed. - * - * \param spi Pointer to an Spi instance. - * \param npcs Chip select of the component to address (0, 1, 2 or 3). - * \param data Word of data to send. - */ -extern void SPI_Write( Spi* spi, uint32_t dwNpcs, uint16_t wData ) -{ - /* Send data */ - while ( (spi->SPI_SR & SPI_SR_TXEMPTY) == 0 ) ; - spi->SPI_TDR = wData | SPI_PCS( dwNpcs ) ; - while ( (spi->SPI_SR & SPI_SR_TDRE) == 0 ) ; -} - -/** - * \brief Check if SPI transfer finish. - * - * \param spi Pointer to an Spi instance. - * - * \return Returns 1 if there is no pending write operation on the SPI; otherwise - * returns 0. - */ -extern uint32_t SPI_IsFinished( Spi* spi ) -{ - return ((spi->SPI_SR & SPI_SR_TXEMPTY) != 0) ; -} - -/** - * \brief Enable Spi PDC transmit - * \param spi Pointer to an Spi instance. -*/ -extern void SPI_PdcEnableTx( Spi* spi ) -{ - spi->SPI_PTCR = SPI_PTCR_TXTEN ; -} - -/** - * \brief Disable Spi PDC transmit - * \param spi Pointer to an Spi instance. -*/ -extern void SPI_PdcDisableTx( Spi* spi ) -{ - spi->SPI_PTCR = SPI_PTCR_TXTDIS ; -} - -/** - * \brief Enable Spi PDC receive - * \param spi Pointer to an Spi instance. -*/ -extern void SPI_PdcEnableRx( Spi* spi ) -{ - spi->SPI_PTCR = SPI_PTCR_RXTEN ; -} - -/** - * \brief Disable Spi PDC receive - * \param spi Pointer to an Spi instance. -*/ -extern void SPI_PdcDisableRx( Spi* spi ) -{ - spi->SPI_PTCR = SPI_PTCR_RXTDIS ; -} - -/** - * \brief Set PDC transmit and next transmit buffer address and size. - * - * \param spi Pointer to an Spi instance. - * \param txBuf PDC transmit buffer address. - * \param txCount Length in bytes of the transmit buffer. - * \param txNextBuf PDC next transmit buffer address. - * \param txNextCount Length in bytes of the next transmit buffer. - */ -extern void SPI_PdcSetTx( Spi* spi, void* pvTxBuf, uint32_t dwTxCount, void* pvTxNextBuf, uint32_t dwTxNextCount ) -{ - spi->SPI_TPR = (uint32_t)pvTxBuf ; - spi->SPI_TCR = dwTxCount ; - spi->SPI_TNPR = (uint32_t)pvTxNextBuf ; - spi->SPI_TNCR = dwTxNextCount ; -} - -/** - * \brief Set PDC receive and next receive buffer address and size. - * - * \param spi Pointer to an Spi instance. - * \param rxBuf PDC receive buffer address. - * \param rxCount Length in bytes of the receive buffer. - * \param rxNextBuf PDC next receive buffer address. - * \param rxNextCount Length in bytes of the next receive buffer. - */ -extern void SPI_PdcSetRx( Spi* spi, void* pvRxBuf, uint32_t dwRxCount, void* pvRxNextBuf, uint32_t dwRxNextCount ) -{ - spi->SPI_RPR = (uint32_t)pvRxBuf ; - spi->SPI_RCR = dwRxCount ; - spi->SPI_RNPR = (uint32_t)pvRxNextBuf ; - spi->SPI_RNCR = dwRxNextCount ; -} - -/** - * \brief Sends the contents of buffer through a SPI peripheral, using the PDC to - * take care of the transfer. - * - * \param spi Pointer to an Spi instance. - * \param buffer Data buffer to send. - * \param length Length of the data buffer. - */ -extern uint32_t SPI_WriteBuffer( Spi* spi, void* pvBuffer, uint32_t dwLength ) -{ - /* Check if first bank is free */ - if ( spi->SPI_TCR == 0 ) - { - spi->SPI_TPR = (uint32_t)pvBuffer ; - spi->SPI_TCR = dwLength ; - spi->SPI_PTCR = PERIPH_PTCR_TXTEN ; - - return 1 ; - } - /* Check if second bank is free */ - else - { - if ( spi->SPI_TNCR == 0 ) - { - spi->SPI_TNPR = (uint32_t)pvBuffer ; - spi->SPI_TNCR = dwLength ; - - return 1 ; - } - } - - /* No free banks */ - return 0 ; -} - -/** - * \brief Reads data from a SPI peripheral until the provided buffer is filled. This - * method does NOT need to be called after SPI_Write or SPI_WriteBuffer. - * - * \param spi Pointer to an Spi instance. - * \param buffer Data buffer to store incoming bytes. - * \param length Length in bytes of the data buffer. - */ -extern uint32_t SPI_ReadBuffer( Spi* spi, void *pvBuffer, uint32_t dwLength ) -{ - /* Check if the first bank is free */ - if ( spi->SPI_RCR == 0 ) - { - spi->SPI_RPR = (uint32_t)pvBuffer ; - spi->SPI_RCR = dwLength ; - spi->SPI_PTCR = PERIPH_PTCR_RXTEN ; - - return 1 ; - } - /* Check if second bank is free */ - else - { - if ( spi->SPI_RNCR == 0 ) - { - spi->SPI_RNPR = (uint32_t)pvBuffer ; - spi->SPI_RNCR = dwLength ; - return 1 ; - } - } - - /* No free bank */ - return 0 ; -} - - +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** \addtogroup spi_module Working with SPI + * The SPI driver provides the interface to configure and use the SPI + * peripheral. + * + * The Serial Peripheral Interface (SPI) circuit is a synchronous serial + * data link that provides communication with external devices in Master + * or Slave Mode. + * + * To use the SPI, the user has to follow these few steps: + * -# Enable the SPI pins required by the application (see pio.h). + * -# Configure the SPI using the \ref SPI_Configure(). This enables the + * peripheral clock. The mode register is loaded with the given value. + * -# Configure all the necessary chip selects with \ref SPI_ConfigureNPCS(). + * -# Enable the SPI by calling \ref SPI_Enable(). + * -# Send/receive data using \ref SPI_Write() and \ref SPI_Read(). Note that \ref SPI_Read() + * must be called after \ref SPI_Write() to retrieve the last value read. + * -# Send/receive data using the PDC with the \ref SPI_WriteBuffer() and + * \ref SPI_ReadBuffer() functions. + * -# Disable the SPI by calling \ref SPI_Disable(). + * + * For more accurate information, please look at the SPI section of the + * Datasheet. + * + * Related files :\n + * \ref spi.c\n + * \ref spi.h.\n +*/ +/*@{*/ +/*@}*/ + +/** + * \file + * + * Implementation of Serial Peripheral Interface (SPI) controller. + * + */ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "chip.h" +#include "pmc.h" +#include "spi.h" + +#include + +/*---------------------------------------------------------------------------- + * Exported functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Enables a SPI peripheral. + * + * \param spi Pointer to an Spi instance. + */ +extern void SPI_Enable( Spi* spi ) +{ + spi->SPI_CR = SPI_CR_SPIEN ; +} + +/** + * \brief Disables a SPI peripheral. + * + * \param spi Pointer to an Spi instance. + */ +extern void SPI_Disable( Spi* spi ) +{ + spi->SPI_CR = SPI_CR_SPIDIS ; +} + +/** + * \brief Enables one or more interrupt sources of a SPI peripheral. + * + * \param spi Pointer to an Spi instance. + * \param sources Bitwise OR of selected interrupt sources. + */ +extern void SPI_EnableIt( Spi* spi, uint32_t dwSources ) +{ + spi->SPI_IER = dwSources ; +} + +/** + * \brief Disables one or more interrupt sources of a SPI peripheral. + * + * \param spi Pointer to an Spi instance. + * \param sources Bitwise OR of selected interrupt sources. + */ +extern void SPI_DisableIt( Spi* spi, uint32_t dwSources ) +{ + spi->SPI_IDR = dwSources ; +} + +/** + * \brief Configures a SPI peripheral as specified. The configuration can be computed + * using several macros (see \ref spi_configuration_macros). + * + * \param spi Pointer to an Spi instance. + * \param id Peripheral ID of the SPI. + * \param configuration Value of the SPI configuration register. + */ +extern void SPI_Configure( Spi* spi, uint32_t dwId, uint32_t dwConfiguration ) +{ + PMC_EnablePeripheral( dwId ) ; + spi->SPI_CR = SPI_CR_SPIDIS ; + + /* Execute a software reset of the SPI twice */ + spi->SPI_CR = SPI_CR_SWRST ; + spi->SPI_CR = SPI_CR_SWRST ; + spi->SPI_MR = dwConfiguration ; +} + + +/** + * \brief Configures a chip select of a SPI peripheral. The chip select configuration + * is computed using several macros (see \ref spi_configuration_macros). + * + * \param spi Pointer to an Spi instance. + * \param npcs Chip select to configure (0, 1, 2 or 3). + * \param configuration Desired chip select configuration. + */ +void SPI_ConfigureNPCS( Spi* spi, uint32_t dwNpcs, uint32_t dwConfiguration ) +{ + spi->SPI_CSR[dwNpcs] = dwConfiguration ; +} + +/** + * \brief Get the current status register of the given SPI peripheral. + * \note This resets the internal value of the status register, so further + * read may yield different values. + * \param spi Pointer to a Spi instance. + * \return SPI status register. + */ +extern uint32_t SPI_GetStatus( Spi* spi ) +{ + return spi->SPI_SR ; +} + +/** + * \brief Reads and returns the last word of data received by a SPI peripheral. This + * method must be called after a successful SPI_Write call. + * + * \param spi Pointer to an Spi instance. + * + * \return readed data. + */ +extern uint32_t SPI_Read( Spi* spi ) +{ + while ( (spi->SPI_SR & SPI_SR_RDRF) == 0 ) ; + + return spi->SPI_RDR & 0xFFFF ; +} + +/** + * \brief Sends data through a SPI peripheral. If the SPI is configured to use a fixed + * peripheral select, the npcs value is meaningless. Otherwise, it identifies + * the component which shall be addressed. + * + * \param spi Pointer to an Spi instance. + * \param npcs Chip select of the component to address (0, 1, 2 or 3). + * \param data Word of data to send. + */ +extern void SPI_Write( Spi* spi, uint32_t dwNpcs, uint16_t wData ) +{ + /* Send data */ + while ( (spi->SPI_SR & SPI_SR_TXEMPTY) == 0 ) ; + spi->SPI_TDR = wData | SPI_PCS( dwNpcs ) ; + while ( (spi->SPI_SR & SPI_SR_TDRE) == 0 ) ; +} + +/** + * \brief Check if SPI transfer finish. + * + * \param spi Pointer to an Spi instance. + * + * \return Returns 1 if there is no pending write operation on the SPI; otherwise + * returns 0. + */ +extern uint32_t SPI_IsFinished( Spi* spi ) +{ + return ((spi->SPI_SR & SPI_SR_TXEMPTY) != 0) ; +} + +/** + * \brief Enable Spi PDC transmit + * \param spi Pointer to an Spi instance. +*/ +extern void SPI_PdcEnableTx( Spi* spi ) +{ + spi->SPI_PTCR = SPI_PTCR_TXTEN ; +} + +/** + * \brief Disable Spi PDC transmit + * \param spi Pointer to an Spi instance. +*/ +extern void SPI_PdcDisableTx( Spi* spi ) +{ + spi->SPI_PTCR = SPI_PTCR_TXTDIS ; +} + +/** + * \brief Enable Spi PDC receive + * \param spi Pointer to an Spi instance. +*/ +extern void SPI_PdcEnableRx( Spi* spi ) +{ + spi->SPI_PTCR = SPI_PTCR_RXTEN ; +} + +/** + * \brief Disable Spi PDC receive + * \param spi Pointer to an Spi instance. +*/ +extern void SPI_PdcDisableRx( Spi* spi ) +{ + spi->SPI_PTCR = SPI_PTCR_RXTDIS ; +} + +/** + * \brief Set PDC transmit and next transmit buffer address and size. + * + * \param spi Pointer to an Spi instance. + * \param txBuf PDC transmit buffer address. + * \param txCount Length in bytes of the transmit buffer. + * \param txNextBuf PDC next transmit buffer address. + * \param txNextCount Length in bytes of the next transmit buffer. + */ +extern void SPI_PdcSetTx( Spi* spi, void* pvTxBuf, uint32_t dwTxCount, void* pvTxNextBuf, uint32_t dwTxNextCount ) +{ + spi->SPI_TPR = (uint32_t)pvTxBuf ; + spi->SPI_TCR = dwTxCount ; + spi->SPI_TNPR = (uint32_t)pvTxNextBuf ; + spi->SPI_TNCR = dwTxNextCount ; +} + +/** + * \brief Set PDC receive and next receive buffer address and size. + * + * \param spi Pointer to an Spi instance. + * \param rxBuf PDC receive buffer address. + * \param rxCount Length in bytes of the receive buffer. + * \param rxNextBuf PDC next receive buffer address. + * \param rxNextCount Length in bytes of the next receive buffer. + */ +extern void SPI_PdcSetRx( Spi* spi, void* pvRxBuf, uint32_t dwRxCount, void* pvRxNextBuf, uint32_t dwRxNextCount ) +{ + spi->SPI_RPR = (uint32_t)pvRxBuf ; + spi->SPI_RCR = dwRxCount ; + spi->SPI_RNPR = (uint32_t)pvRxNextBuf ; + spi->SPI_RNCR = dwRxNextCount ; +} + +/** + * \brief Sends the contents of buffer through a SPI peripheral, using the PDC to + * take care of the transfer. + * + * \param spi Pointer to an Spi instance. + * \param buffer Data buffer to send. + * \param length Length of the data buffer. + */ +extern uint32_t SPI_WriteBuffer( Spi* spi, void* pvBuffer, uint32_t dwLength ) +{ + /* Check if first bank is free */ + if ( spi->SPI_TCR == 0 ) + { + spi->SPI_TPR = (uint32_t)pvBuffer ; + spi->SPI_TCR = dwLength ; + spi->SPI_PTCR = PERIPH_PTCR_TXTEN ; + + return 1 ; + } + /* Check if second bank is free */ + else + { + if ( spi->SPI_TNCR == 0 ) + { + spi->SPI_TNPR = (uint32_t)pvBuffer ; + spi->SPI_TNCR = dwLength ; + + return 1 ; + } + } + + /* No free banks */ + return 0 ; +} + +/** + * \brief Reads data from a SPI peripheral until the provided buffer is filled. This + * method does NOT need to be called after SPI_Write or SPI_WriteBuffer. + * + * \param spi Pointer to an Spi instance. + * \param buffer Data buffer to store incoming bytes. + * \param length Length in bytes of the data buffer. + */ +extern uint32_t SPI_ReadBuffer( Spi* spi, void *pvBuffer, uint32_t dwLength ) +{ + /* Check if the first bank is free */ + if ( spi->SPI_RCR == 0 ) + { + spi->SPI_RPR = (uint32_t)pvBuffer ; + spi->SPI_RCR = dwLength ; + spi->SPI_PTCR = PERIPH_PTCR_RXTEN ; + + return 1 ; + } + /* Check if second bank is free */ + else + { + if ( spi->SPI_RNCR == 0 ) + { + spi->SPI_RNPR = (uint32_t)pvBuffer ; + spi->SPI_RNCR = dwLength ; + return 1 ; + } + } + + /* No free bank */ + return 0 ; +} + + diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/tc.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/tc.c index 9cad5467..1fffe5a2 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/tc.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/tc.c @@ -1,175 +1,175 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** - * \file - * - * Implementation of Timer Counter (TC). - * - */ - -/*------------------------------------------------------------------------------ - * Headers - *------------------------------------------------------------------------------*/ - -#include "chip.h" - -#include - -/*------------------------------------------------------------------------------ - * Global functions - *------------------------------------------------------------------------------*/ - -/** - * \brief Configures a Timer Counter Channel - * - * Configures a Timer Counter to operate in the given mode. Timer is stopped - * after configuration and must be restarted with TC_Start(). All the - * interrupts of the timer are also disabled. - * - * \param pTc Pointer to a Tc instance. - * \param channel Channel number. - * \param mode Operating mode (TC_CMR value). - */ -extern void TC_Configure( Tc *pTc, uint32_t dwChannel, uint32_t dwMode ) -{ - TcChannel* pTcCh ; - - assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ; - pTcCh = pTc->TC_CHANNEL+dwChannel ; - - /* Disable TC clock */ - pTcCh->TC_CCR = TC_CCR_CLKDIS ; - - /* Disable interrupts */ - pTcCh->TC_IDR = 0xFFFFFFFF ; - - /* Clear status register */ - pTcCh->TC_SR ; - - /* Set mode */ - pTcCh->TC_CMR = dwMode ; -} - -/** - * \brief Reset and Start the TC Channel - * - * Enables the timer clock and performs a software reset to start the counting. - * - * \param pTc Pointer to a Tc instance. - * \param dwChannel Channel number. - */ -extern void TC_Start( Tc *pTc, uint32_t dwChannel ) -{ - TcChannel* pTcCh ; - - assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ; - - pTcCh = pTc->TC_CHANNEL+dwChannel ; - pTcCh->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG ; -} - -/** - * \brief Stop TC Channel - * - * Disables the timer clock, stopping the counting. - * - * \param pTc Pointer to a Tc instance. - * \param dwChannel Channel number. - */ -extern void TC_Stop(Tc *pTc, uint32_t dwChannel ) -{ - TcChannel* pTcCh ; - - assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ; - - pTcCh = pTc->TC_CHANNEL+dwChannel ; - pTcCh->TC_CCR = TC_CCR_CLKDIS ; -} - -/** - * \brief Find best MCK divisor - * - * Finds the best MCK divisor given the timer frequency and MCK. The result - * is guaranteed to satisfy the following equation: - * \code - * (MCK / (DIV * 65536)) <= freq <= (MCK / DIV) - * \endcode - * with DIV being the highest possible value. - * - * \param dwFreq Desired timer frequency. - * \param dwMCk Master clock frequency. - * \param dwDiv Divisor value. - * \param dwTcClks TCCLKS field value for divisor. - * \param dwBoardMCK Board clock frequency. - * - * \return 1 if a proper divisor has been found, otherwise 0. - */ -extern uint32_t TC_FindMckDivisor( uint32_t dwFreq, uint32_t dwMCk, uint32_t *dwDiv, uint32_t *dwTcClks, uint32_t dwBoardMCK ) -{ - const uint32_t adwDivisors[5] = { 2, 8, 32, 128, dwBoardMCK / 32768 } ; - - uint32_t dwIndex = 0 ; - - /* Satisfy lower bound */ - while ( dwFreq < ((dwMCk / adwDivisors[dwIndex]) / 65536) ) - { - dwIndex++ ; - - /* If no divisor can be found, return 0 */ - if ( dwIndex == (sizeof( adwDivisors )/sizeof( adwDivisors[0] )) ) - { - return 0 ; - } - } - - /* Try to maximize DIV while satisfying upper bound */ - while ( dwIndex < 4 ) - { - - if ( dwFreq > (dwMCk / adwDivisors[dwIndex + 1]) ) - { - break ; - } - dwIndex++ ; - } - - /* Store results */ - if ( dwDiv ) - { - *dwDiv = adwDivisors[dwIndex] ; - } - if ( dwTcClks ) - { - *dwTcClks = dwIndex ; - } - - return 1 ; -} - +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** + * \file + * + * Implementation of Timer Counter (TC). + * + */ + +/*------------------------------------------------------------------------------ + * Headers + *------------------------------------------------------------------------------*/ + +#include "chip.h" + +#include + +/*------------------------------------------------------------------------------ + * Global functions + *------------------------------------------------------------------------------*/ + +/** + * \brief Configures a Timer Counter Channel + * + * Configures a Timer Counter to operate in the given mode. Timer is stopped + * after configuration and must be restarted with TC_Start(). All the + * interrupts of the timer are also disabled. + * + * \param pTc Pointer to a Tc instance. + * \param channel Channel number. + * \param mode Operating mode (TC_CMR value). + */ +extern void TC_Configure( Tc *pTc, uint32_t dwChannel, uint32_t dwMode ) +{ + TcChannel* pTcCh ; + + assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ; + pTcCh = pTc->TC_CHANNEL+dwChannel ; + + /* Disable TC clock */ + pTcCh->TC_CCR = TC_CCR_CLKDIS ; + + /* Disable interrupts */ + pTcCh->TC_IDR = 0xFFFFFFFF ; + + /* Clear status register */ + pTcCh->TC_SR ; + + /* Set mode */ + pTcCh->TC_CMR = dwMode ; +} + +/** + * \brief Reset and Start the TC Channel + * + * Enables the timer clock and performs a software reset to start the counting. + * + * \param pTc Pointer to a Tc instance. + * \param dwChannel Channel number. + */ +extern void TC_Start( Tc *pTc, uint32_t dwChannel ) +{ + TcChannel* pTcCh ; + + assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ; + + pTcCh = pTc->TC_CHANNEL+dwChannel ; + pTcCh->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG ; +} + +/** + * \brief Stop TC Channel + * + * Disables the timer clock, stopping the counting. + * + * \param pTc Pointer to a Tc instance. + * \param dwChannel Channel number. + */ +extern void TC_Stop(Tc *pTc, uint32_t dwChannel ) +{ + TcChannel* pTcCh ; + + assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ; + + pTcCh = pTc->TC_CHANNEL+dwChannel ; + pTcCh->TC_CCR = TC_CCR_CLKDIS ; +} + +/** + * \brief Find best MCK divisor + * + * Finds the best MCK divisor given the timer frequency and MCK. The result + * is guaranteed to satisfy the following equation: + * \code + * (MCK / (DIV * 65536)) <= freq <= (MCK / DIV) + * \endcode + * with DIV being the highest possible value. + * + * \param dwFreq Desired timer frequency. + * \param dwMCk Master clock frequency. + * \param dwDiv Divisor value. + * \param dwTcClks TCCLKS field value for divisor. + * \param dwBoardMCK Board clock frequency. + * + * \return 1 if a proper divisor has been found, otherwise 0. + */ +extern uint32_t TC_FindMckDivisor( uint32_t dwFreq, uint32_t dwMCk, uint32_t *dwDiv, uint32_t *dwTcClks, uint32_t dwBoardMCK ) +{ + const uint32_t adwDivisors[5] = { 2, 8, 32, 128, dwBoardMCK / 32768 } ; + + uint32_t dwIndex = 0 ; + + /* Satisfy lower bound */ + while ( dwFreq < ((dwMCk / adwDivisors[dwIndex]) / 65536) ) + { + dwIndex++ ; + + /* If no divisor can be found, return 0 */ + if ( dwIndex == (sizeof( adwDivisors )/sizeof( adwDivisors[0] )) ) + { + return 0 ; + } + } + + /* Try to maximize DIV while satisfying upper bound */ + while ( dwIndex < 4 ) + { + + if ( dwFreq > (dwMCk / adwDivisors[dwIndex + 1]) ) + { + break ; + } + dwIndex++ ; + } + + /* Store results */ + if ( dwDiv ) + { + *dwDiv = adwDivisors[dwIndex] ; + } + if ( dwTcClks ) + { + *dwTcClks = dwIndex ; + } + + return 1 ; +} + diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/usart.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/usart.c index f1acb2fe..0cd2b47c 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/usart.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/usart.c @@ -1,410 +1,410 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** \addtogroup usart_module Working with USART - * The USART driver provides the interface to configure and use the USART peripheral.\n - * - * The USART supports several kinds of comminication modes such as full-duplex asynchronous/ - * synchronous serial commnunication,RS485 with driver control signal,ISO7816,SPI and Test modes. - * - * To start a USART transfer with \ref AT91SAM3S_PDC "PDC" support, the user could follow these steps: - *
    - *
  • Configure USART with expected mode and baudrate(see \ref USART_Configure), which could be done by: - * -# Resetting and disabling transmitter and receiver by setting US_CR(Control Register).
  • - * -# Conifguring the USART in a specific mode by setting USART_MODE bits in US_MR(Mode Register) - * -# Setting baudrate which is different from mode to mode. - - *
  • Enable transmitter or receiver respectively by set US_CR_TXEN or US_CR_RXEN in US_CR.
  • - *
  • Read from or write to the peripheral with \ref USART_ReadBuffer or \ref USART_WriteBuffer. - These operations could be done by polling or interruption.
  • - *
  • For polling, check the status bit US_CSR_ENDRX/US_CSR_RXBUFF (READ) or US_CSR_ENDTX/ - US_CSR_TXBUFE (WRITE).
  • - *
  • For interruption,"enable" the status bit through US_IER and - realize the hanler with USARTx_IrqHandler according to IRQ vector - table which is defined in board_cstartup_.c - To enable the interruption of USART,it should be configured with priority and enabled first through - NVIC .
  • - *
- * - * For more accurate information, please look at the USART section of the - * Datasheet. - * - * Related files :\n - * \ref usart.c\n - * \ref usart.h\n -*/ - - - -/** - * \file - * - * Implementation of USART (Universal Synchronous Asynchronous Receiver Transmitter) - * controller. - * - */ -/*------------------------------------------------------------------------------ - * Headers - *------------------------------------------------------------------------------*/ -#include "chip.h" -#include "trace.h" - -#include -#include - -/*---------------------------------------------------------------------------- - * Local definitions - *----------------------------------------------------------------------------*/ - - -/*------------------------------------------------------------------------------ - * Exported functions - *------------------------------------------------------------------------------*/ - -/** - * \brief Configures an USART peripheral with the specified parameters. - * - * - * \param usart Pointer to the USART peripheral to configure. - * \param mode Desired value for the USART mode register (see the datasheet). - * \param baudrate Baudrate at which the USART should operate (in Hz). - * \param masterClock Frequency of the system master clock (in Hz). - */ -void USART_Configure(Usart *usart, - uint32_t mode, - uint32_t baudrate, - uint32_t masterClock) -{ - /* Reset and disable receiver & transmitter*/ - usart->US_CR = US_CR_RSTRX | US_CR_RSTTX - | US_CR_RXDIS | US_CR_TXDIS; - - /* Configure mode*/ - usart->US_MR = mode; - - /* Configure baudrate*/ - /* Asynchronous, no oversampling*/ - if ( ((mode & US_MR_SYNC) == 0) && ((mode & US_MR_OVER) == 0) ) - { - usart->US_BRGR = (masterClock / baudrate) / 16; - } - - if( ((mode & US_MR_USART_MODE_SPI_MASTER) == US_MR_USART_MODE_SPI_MASTER) - || ((mode & US_MR_SYNC) == US_MR_SYNC)) - { - if( (mode & US_MR_USCLKS_Msk) == US_MR_USCLKS_MCK) - { - usart->US_BRGR = masterClock / baudrate; - } - else - { - if ( (mode & US_MR_USCLKS_DIV) == US_MR_USCLKS_DIV) - { - usart->US_BRGR = masterClock / baudrate / 8; - } - } - } - /* TODO other modes*/ -} -/** - * \brief Enables or disables the transmitter of an USART peripheral. - * - * - * \param usart Pointer to an USART peripheral - * \param enabled If true, the transmitter is enabled; otherwise it is - * disabled. - */ -void USART_SetTransmitterEnabled(Usart *usart, uint8_t enabled) -{ - if (enabled) { - - usart->US_CR = US_CR_TXEN; - } - else { - - usart->US_CR = US_CR_TXDIS; - } -} - -/** - * \brief Enables or disables the receiver of an USART peripheral - * - * - * \param usart Pointer to an USART peripheral - * \param enabled If true, the receiver is enabled; otherwise it is disabled. - */ -void USART_SetReceiverEnabled(Usart *usart, - uint8_t enabled) -{ - if (enabled) { - - usart->US_CR = US_CR_RXEN; - } - else { - - usart->US_CR = US_CR_RXDIS; - } -} - -/** - * \brief Sends one packet of data through the specified USART peripheral. This - * function operates synchronously, so it only returns when the data has been - * actually sent. - * - * - * \param usart Pointer to an USART peripheral. - * \param data Data to send including 9nth bit and sync field if necessary (in - * the same format as the US_THR register in the datasheet). - * \param timeOut Time out value (0 = no timeout). - */ -void USART_Write( - Usart *usart, - uint16_t data, - volatile uint32_t timeOut) -{ - if (timeOut == 0) { - - while ((usart->US_CSR & US_CSR_TXEMPTY) == 0); - } - else { - - while ((usart->US_CSR & US_CSR_TXEMPTY) == 0) { - - if (timeOut == 0) { - - TRACE_ERROR("USART_Write: Timed out.\n\r"); - return; - } - timeOut--; - } - } - - usart->US_THR = data; -} - -/** - * \brief Sends the contents of a data buffer through the specified USART peripheral. - * This function returns immediately (1 if the buffer has been queued, 0 - * otherwise); poll the ENDTX and TXBUFE bits of the USART status register - * to check for the transfer completion. - * - * \param usart Pointer to an USART peripheral. - * \param buffer Pointer to the data buffer to send. - * \param size Size of the data buffer (in bytes). - */ -uint8_t USART_WriteBuffer( - Usart *usart, - void *buffer, - uint32_t size) -{ - /* Check if the first PDC bank is free*/ - if ((usart->US_TCR == 0) && (usart->US_TNCR == 0)) { - - usart->US_TPR = (uint32_t) buffer; - usart->US_TCR = size; - usart->US_PTCR = US_PTCR_TXTEN; - - return 1; - } - /* Check if the second PDC bank is free*/ - else if (usart->US_TNCR == 0) { - - usart->US_TNPR = (uint32_t) buffer; - usart->US_TNCR = size; - - return 1; - } - else { - - return 0; - } -} - - -/** - * \brief Reads and return a packet of data on the specified USART peripheral. This - * function operates asynchronously, so it waits until some data has been - * received. - * - * \param usart Pointer to an USART peripheral. - * \param timeOut Time out value (0 -> no timeout). - */ -uint16_t USART_Read( - Usart *usart, - volatile uint32_t timeOut) -{ - if (timeOut == 0) { - - while ((usart->US_CSR & US_CSR_RXRDY) == 0); - } - else { - - while ((usart->US_CSR & US_CSR_RXRDY) == 0) { - - if (timeOut == 0) { - - TRACE_ERROR( "USART_Read: Timed out.\n\r" ) ; - return 0; - } - timeOut--; - } - } - - return usart->US_RHR; -} - -/** - * \brief Reads data from an USART peripheral, filling the provided buffer until it - * becomes full. This function returns immediately with 1 if the buffer has - * been queued for transmission; otherwise 0. - * - * \param usart Pointer to an USART peripheral. - * \param buffer Pointer to the buffer where the received data will be stored. - * \param size Size of the data buffer (in bytes). - */ -uint8_t USART_ReadBuffer(Usart *usart, - void *buffer, - uint32_t size) -{ - /* Check if the first PDC bank is free*/ - if ((usart->US_RCR == 0) && (usart->US_RNCR == 0)) { - - usart->US_RPR = (uint32_t) buffer; - usart->US_RCR = size; - usart->US_PTCR = US_PTCR_RXTEN; - - return 1; - } - /* Check if the second PDC bank is free*/ - else if (usart->US_RNCR == 0) { - - usart->US_RNPR = (uint32_t) buffer; - usart->US_RNCR = size; - - return 1; - } - else { - - return 0; - } -} - -/** - * \brief Returns 1 if some data has been received and can be read from an USART; - * otherwise returns 0. - * - * \param usart Pointer to an Usart instance. - */ -uint8_t USART_IsDataAvailable(Usart *usart) -{ - if ((usart->US_CSR & US_CSR_RXRDY) != 0) { - - return 1; - } - else { - - return 0; - } -} - -/** - * \brief Sets the filter value for the IRDA demodulator. - * - * \param pUsart Pointer to an Usart instance. - * \param filter Filter value. - */ -void USART_SetIrdaFilter(Usart *pUsart, uint8_t filter) -{ - assert( pUsart != NULL ) ; - - pUsart->US_IF = filter; -} - -/** - * \brief Sends one packet of data through the specified USART peripheral. This - * function operates synchronously, so it only returns when the data has been - * actually sent. - * - * \param usart Pointer to an USART peripheral. - * \param c Character to send - */ -void USART_PutChar( - Usart *usart, - uint8_t c) -{ - /* Wait for the transmitter to be ready*/ - while ((usart->US_CSR & US_CSR_TXEMPTY) == 0); - - /* Send character*/ - usart->US_THR = c; - - /* Wait for the transfer to complete*/ - while ((usart->US_CSR & US_CSR_TXEMPTY) == 0); -} - -/** - * \brief Return 1 if a character can be read in USART - */ -uint32_t USART_IsRxReady(Usart *usart) -{ - return (usart->US_CSR & US_CSR_RXRDY); -} -/** - * \brief Get present status - */ -uint32_t USART_GetStatus(Usart *usart) -{ - return usart->US_CSR; -} -/** - * \brief Enable interrupt - */ -void USART_EnableIt(Usart *usart,uint32_t mode) -{ - usart->US_IER = mode; -} -/** - * \brief Disable interrupt - */ -void USART_DisableIt(Usart *usart,uint32_t mode) -{ - usart->US_IDR = mode; -} -/** - * \brief Reads and returns a character from the USART. - * - * \note This function is synchronous (i.e. uses polling). - * \param usart Pointer to an USART peripheral. - * \return Character received. - */ -uint8_t USART_GetChar(Usart *usart) -{ - while ((usart->US_CSR & US_CSR_RXRDY) == 0); - return usart->US_RHR; -} +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** \addtogroup usart_module Working with USART + * The USART driver provides the interface to configure and use the USART peripheral.\n + * + * The USART supports several kinds of comminication modes such as full-duplex asynchronous/ + * synchronous serial commnunication,RS485 with driver control signal,ISO7816,SPI and Test modes. + * + * To start a USART transfer with \ref AT91SAM3S_PDC "PDC" support, the user could follow these steps: + *
    + *
  • Configure USART with expected mode and baudrate(see \ref USART_Configure), which could be done by: + * -# Resetting and disabling transmitter and receiver by setting US_CR(Control Register).
  • + * -# Conifguring the USART in a specific mode by setting USART_MODE bits in US_MR(Mode Register) + * -# Setting baudrate which is different from mode to mode. + + *
  • Enable transmitter or receiver respectively by set US_CR_TXEN or US_CR_RXEN in US_CR.
  • + *
  • Read from or write to the peripheral with \ref USART_ReadBuffer or \ref USART_WriteBuffer. + These operations could be done by polling or interruption.
  • + *
  • For polling, check the status bit US_CSR_ENDRX/US_CSR_RXBUFF (READ) or US_CSR_ENDTX/ + US_CSR_TXBUFE (WRITE).
  • + *
  • For interruption,"enable" the status bit through US_IER and + realize the hanler with USARTx_IrqHandler according to IRQ vector + table which is defined in board_cstartup_.c + To enable the interruption of USART,it should be configured with priority and enabled first through + NVIC .
  • + *
+ * + * For more accurate information, please look at the USART section of the + * Datasheet. + * + * Related files :\n + * \ref usart.c\n + * \ref usart.h\n +*/ + + + +/** + * \file + * + * Implementation of USART (Universal Synchronous Asynchronous Receiver Transmitter) + * controller. + * + */ +/*------------------------------------------------------------------------------ + * Headers + *------------------------------------------------------------------------------*/ +#include "chip.h" +#include "trace.h" + +#include +#include + +/*---------------------------------------------------------------------------- + * Local definitions + *----------------------------------------------------------------------------*/ + + +/*------------------------------------------------------------------------------ + * Exported functions + *------------------------------------------------------------------------------*/ + +/** + * \brief Configures an USART peripheral with the specified parameters. + * + * + * \param usart Pointer to the USART peripheral to configure. + * \param mode Desired value for the USART mode register (see the datasheet). + * \param baudrate Baudrate at which the USART should operate (in Hz). + * \param masterClock Frequency of the system master clock (in Hz). + */ +void USART_Configure(Usart *usart, + uint32_t mode, + uint32_t baudrate, + uint32_t masterClock) +{ + /* Reset and disable receiver & transmitter*/ + usart->US_CR = US_CR_RSTRX | US_CR_RSTTX + | US_CR_RXDIS | US_CR_TXDIS; + + /* Configure mode*/ + usart->US_MR = mode; + + /* Configure baudrate*/ + /* Asynchronous, no oversampling*/ + if ( ((mode & US_MR_SYNC) == 0) && ((mode & US_MR_OVER) == 0) ) + { + usart->US_BRGR = (masterClock / baudrate) / 16; + } + + if( ((mode & US_MR_USART_MODE_SPI_MASTER) == US_MR_USART_MODE_SPI_MASTER) + || ((mode & US_MR_SYNC) == US_MR_SYNC)) + { + if( (mode & US_MR_USCLKS_Msk) == US_MR_USCLKS_MCK) + { + usart->US_BRGR = masterClock / baudrate; + } + else + { + if ( (mode & US_MR_USCLKS_DIV) == US_MR_USCLKS_DIV) + { + usart->US_BRGR = masterClock / baudrate / 8; + } + } + } + /* TODO other modes*/ +} +/** + * \brief Enables or disables the transmitter of an USART peripheral. + * + * + * \param usart Pointer to an USART peripheral + * \param enabled If true, the transmitter is enabled; otherwise it is + * disabled. + */ +void USART_SetTransmitterEnabled(Usart *usart, uint8_t enabled) +{ + if (enabled) { + + usart->US_CR = US_CR_TXEN; + } + else { + + usart->US_CR = US_CR_TXDIS; + } +} + +/** + * \brief Enables or disables the receiver of an USART peripheral + * + * + * \param usart Pointer to an USART peripheral + * \param enabled If true, the receiver is enabled; otherwise it is disabled. + */ +void USART_SetReceiverEnabled(Usart *usart, + uint8_t enabled) +{ + if (enabled) { + + usart->US_CR = US_CR_RXEN; + } + else { + + usart->US_CR = US_CR_RXDIS; + } +} + +/** + * \brief Sends one packet of data through the specified USART peripheral. This + * function operates synchronously, so it only returns when the data has been + * actually sent. + * + * + * \param usart Pointer to an USART peripheral. + * \param data Data to send including 9nth bit and sync field if necessary (in + * the same format as the US_THR register in the datasheet). + * \param timeOut Time out value (0 = no timeout). + */ +void USART_Write( + Usart *usart, + uint16_t data, + volatile uint32_t timeOut) +{ + if (timeOut == 0) { + + while ((usart->US_CSR & US_CSR_TXEMPTY) == 0); + } + else { + + while ((usart->US_CSR & US_CSR_TXEMPTY) == 0) { + + if (timeOut == 0) { + + TRACE_ERROR("USART_Write: Timed out.\n\r"); + return; + } + timeOut--; + } + } + + usart->US_THR = data; +} + +/** + * \brief Sends the contents of a data buffer through the specified USART peripheral. + * This function returns immediately (1 if the buffer has been queued, 0 + * otherwise); poll the ENDTX and TXBUFE bits of the USART status register + * to check for the transfer completion. + * + * \param usart Pointer to an USART peripheral. + * \param buffer Pointer to the data buffer to send. + * \param size Size of the data buffer (in bytes). + */ +uint8_t USART_WriteBuffer( + Usart *usart, + void *buffer, + uint32_t size) +{ + /* Check if the first PDC bank is free*/ + if ((usart->US_TCR == 0) && (usart->US_TNCR == 0)) { + + usart->US_TPR = (uint32_t) buffer; + usart->US_TCR = size; + usart->US_PTCR = US_PTCR_TXTEN; + + return 1; + } + /* Check if the second PDC bank is free*/ + else if (usart->US_TNCR == 0) { + + usart->US_TNPR = (uint32_t) buffer; + usart->US_TNCR = size; + + return 1; + } + else { + + return 0; + } +} + + +/** + * \brief Reads and return a packet of data on the specified USART peripheral. This + * function operates asynchronously, so it waits until some data has been + * received. + * + * \param usart Pointer to an USART peripheral. + * \param timeOut Time out value (0 -> no timeout). + */ +uint16_t USART_Read( + Usart *usart, + volatile uint32_t timeOut) +{ + if (timeOut == 0) { + + while ((usart->US_CSR & US_CSR_RXRDY) == 0); + } + else { + + while ((usart->US_CSR & US_CSR_RXRDY) == 0) { + + if (timeOut == 0) { + + TRACE_ERROR( "USART_Read: Timed out.\n\r" ) ; + return 0; + } + timeOut--; + } + } + + return usart->US_RHR; +} + +/** + * \brief Reads data from an USART peripheral, filling the provided buffer until it + * becomes full. This function returns immediately with 1 if the buffer has + * been queued for transmission; otherwise 0. + * + * \param usart Pointer to an USART peripheral. + * \param buffer Pointer to the buffer where the received data will be stored. + * \param size Size of the data buffer (in bytes). + */ +uint8_t USART_ReadBuffer(Usart *usart, + void *buffer, + uint32_t size) +{ + /* Check if the first PDC bank is free*/ + if ((usart->US_RCR == 0) && (usart->US_RNCR == 0)) { + + usart->US_RPR = (uint32_t) buffer; + usart->US_RCR = size; + usart->US_PTCR = US_PTCR_RXTEN; + + return 1; + } + /* Check if the second PDC bank is free*/ + else if (usart->US_RNCR == 0) { + + usart->US_RNPR = (uint32_t) buffer; + usart->US_RNCR = size; + + return 1; + } + else { + + return 0; + } +} + +/** + * \brief Returns 1 if some data has been received and can be read from an USART; + * otherwise returns 0. + * + * \param usart Pointer to an Usart instance. + */ +uint8_t USART_IsDataAvailable(Usart *usart) +{ + if ((usart->US_CSR & US_CSR_RXRDY) != 0) { + + return 1; + } + else { + + return 0; + } +} + +/** + * \brief Sets the filter value for the IRDA demodulator. + * + * \param pUsart Pointer to an Usart instance. + * \param filter Filter value. + */ +void USART_SetIrdaFilter(Usart *pUsart, uint8_t filter) +{ + assert( pUsart != NULL ) ; + + pUsart->US_IF = filter; +} + +/** + * \brief Sends one packet of data through the specified USART peripheral. This + * function operates synchronously, so it only returns when the data has been + * actually sent. + * + * \param usart Pointer to an USART peripheral. + * \param c Character to send + */ +void USART_PutChar( + Usart *usart, + uint8_t c) +{ + /* Wait for the transmitter to be ready*/ + while ((usart->US_CSR & US_CSR_TXEMPTY) == 0); + + /* Send character*/ + usart->US_THR = c; + + /* Wait for the transfer to complete*/ + while ((usart->US_CSR & US_CSR_TXEMPTY) == 0); +} + +/** + * \brief Return 1 if a character can be read in USART + */ +uint32_t USART_IsRxReady(Usart *usart) +{ + return (usart->US_CSR & US_CSR_RXRDY); +} +/** + * \brief Get present status + */ +uint32_t USART_GetStatus(Usart *usart) +{ + return usart->US_CSR; +} +/** + * \brief Enable interrupt + */ +void USART_EnableIt(Usart *usart,uint32_t mode) +{ + usart->US_IER = mode; +} +/** + * \brief Disable interrupt + */ +void USART_DisableIt(Usart *usart,uint32_t mode) +{ + usart->US_IDR = mode; +} +/** + * \brief Reads and returns a character from the USART. + * + * \note This function is synchronous (i.e. uses polling). + * \param usart Pointer to an USART peripheral. + * \return Character received. + */ +uint8_t USART_GetChar(Usart *usart) +{ + while ((usart->US_CSR & US_CSR_RXRDY) == 0); + return usart->US_RHR; +} diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/wdt.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/wdt.c index f8a493b5..f4ad2eb1 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/wdt.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/wdt.c @@ -1,132 +1,132 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** - * \file - * - * Implementation of Watchdog Timer (WDT) controller. - * - */ - -/** \addtogroup wdt_module Working with WDT - * The WDT driver provides the interface to configure and use the WDT - * peripheral. - * - * The WDT can be used to prevent system lock-up if the software becomes - * trapped in a deadlock. It can generate a general reset or a processor - * reset only. It is clocked by slow clock divided by 128. - * - * The WDT is running at reset with 16 seconds watchdog period (slow clock at 32.768 kHz) - * and external reset generation enabled. The user must either disable it or - * reprogram it to meet the application requires. - * - * To use the WDT, the user could follow these few steps: - *
    - *
  • Enable watchdog with given mode using \ref WDT_Enable(). - *
  • Restart the watchdog using \ref WDT_Restart() within the watchdog period. - *
- * - * For more accurate information, please look at the WDT section of the - * Datasheet. - * - * \note - * The Watchdog Mode Register (WDT_MR) can be written only once.\n - * - * Related files :\n - * \ref wdt.c\n - * \ref wdt.h.\n - */ -/*@{*/ -/*@}*/ - -/*--------------------------------------------------------------------------- - * Headers - *---------------------------------------------------------------------------*/ - -#include "chip.h" - -#include - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Enable watchdog with given mode. - * - * \note The Watchdog Mode Register (WDT_MR) can be written only once. - * Only a processor reset resets it. - * - * \param dwMode WDT mode to be set - */ -extern void WDT_Enable( Wdt* pWDT, uint32_t dwMode ) -{ - pWDT->WDT_MR = dwMode ; -} - -/** - * \brief Disable watchdog. - * - * \note The Watchdog Mode Register (WDT_MR) can be written only once. - * Only a processor reset resets it. - */ -extern void WDT_Disable( Wdt* pWDT ) -{ - pWDT->WDT_MR = WDT_MR_WDDIS; -} - -/** - * \brief Watchdog restart. - */ -extern void WDT_Restart( Wdt* pWDT ) -{ - pWDT->WDT_CR = 0xA5000001; -} - -/** - * \brief Watchdog get status. - */ -extern uint32_t WDT_GetStatus( Wdt* pWDT ) -{ - return (pWDT->WDT_SR & 0x3) ; -} - -/** - * \brief Watchdog get period. - * - * \param dwMs desired watchdog period in millisecond. - */ -extern uint32_t WDT_GetPeriod( uint32_t dwMs ) -{ - if ( (dwMs < 4) || (dwMs > 16000) ) - { - return 0 ; - } - return ((dwMs << 8) / 1000) ; -} +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** + * \file + * + * Implementation of Watchdog Timer (WDT) controller. + * + */ + +/** \addtogroup wdt_module Working with WDT + * The WDT driver provides the interface to configure and use the WDT + * peripheral. + * + * The WDT can be used to prevent system lock-up if the software becomes + * trapped in a deadlock. It can generate a general reset or a processor + * reset only. It is clocked by slow clock divided by 128. + * + * The WDT is running at reset with 16 seconds watchdog period (slow clock at 32.768 kHz) + * and external reset generation enabled. The user must either disable it or + * reprogram it to meet the application requires. + * + * To use the WDT, the user could follow these few steps: + *
    + *
  • Enable watchdog with given mode using \ref WDT_Enable(). + *
  • Restart the watchdog using \ref WDT_Restart() within the watchdog period. + *
+ * + * For more accurate information, please look at the WDT section of the + * Datasheet. + * + * \note + * The Watchdog Mode Register (WDT_MR) can be written only once.\n + * + * Related files :\n + * \ref wdt.c\n + * \ref wdt.h.\n + */ +/*@{*/ +/*@}*/ + +/*--------------------------------------------------------------------------- + * Headers + *---------------------------------------------------------------------------*/ + +#include "chip.h" + +#include + +/*---------------------------------------------------------------------------- + * Exported functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Enable watchdog with given mode. + * + * \note The Watchdog Mode Register (WDT_MR) can be written only once. + * Only a processor reset resets it. + * + * \param dwMode WDT mode to be set + */ +extern void WDT_Enable( Wdt* pWDT, uint32_t dwMode ) +{ + pWDT->WDT_MR = dwMode ; +} + +/** + * \brief Disable watchdog. + * + * \note The Watchdog Mode Register (WDT_MR) can be written only once. + * Only a processor reset resets it. + */ +extern void WDT_Disable( Wdt* pWDT ) +{ + pWDT->WDT_MR = WDT_MR_WDDIS; +} + +/** + * \brief Watchdog restart. + */ +extern void WDT_Restart( Wdt* pWDT ) +{ + pWDT->WDT_CR = 0xA5000001; +} + +/** + * \brief Watchdog get status. + */ +extern uint32_t WDT_GetStatus( Wdt* pWDT ) +{ + return (pWDT->WDT_SR & 0x3) ; +} + +/** + * \brief Watchdog get period. + * + * \param dwMs desired watchdog period in millisecond. + */ +extern uint32_t WDT_GetPeriod( uint32_t dwMs ) +{ + if ( (dwMs < 4) || (dwMs > 16000) ) + { + return 0 ; + } + return ((dwMs << 8) / 1000) ; +} diff --git a/firmware/libboard/common/source/board_cstartup_gnu.c b/firmware/libboard/common/source/board_cstartup_gnu.c index c46d42ff..0e8bb875 100644 --- a/firmware/libboard/common/source/board_cstartup_gnu.c +++ b/firmware/libboard/common/source/board_cstartup_gnu.c @@ -1,208 +1,208 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2010, Atmel Corporation - * Copyright (c) 2017, Harald Welte - * Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ - -#include "board.h" -#include "board_lowlevel.h" - -/*---------------------------------------------------------------------------- - * Exported variables - *----------------------------------------------------------------------------*/ - -/* Stack Configuration */ -#define STACK_SIZE 0x900 /** Stack size (in DWords) */ -__attribute__ ((aligned(8),section(".stack"))) -uint32_t pdwStack[STACK_SIZE] ; - -/* Initialize segments */ -extern uint32_t _sfixed; -extern uint32_t _efixed; -extern uint32_t _etext; -extern uint32_t _srelocate; -extern uint32_t _erelocate; -extern uint32_t _szero; -extern uint32_t _ezero; - - -/*---------------------------------------------------------------------------- - * ProtoTypes - *----------------------------------------------------------------------------*/ - -/** \cond DOXYGEN_SHOULD_SKIP_THIS */ -extern int main( void ) ; -/** \endcond */ -void ResetException( void ) ; - -/*------------------------------------------------------------------------------ - * Exception Table - *------------------------------------------------------------------------------*/ - -__attribute__((section(".vectors"))) -IntFunc exception_table[] = { - - /* Configure Initial Stack Pointer, using linker-generated symbols */ - (IntFunc)(&pdwStack[STACK_SIZE-1]), - ResetException, - - NMI_Handler, - HardFault_Handler, - MemManage_Handler, - BusFault_Handler, - UsageFault_Handler, - 0, 0, 0, 0, /* Reserved */ - SVC_Handler, - DebugMon_Handler, - 0, /* Reserved */ - PendSV_Handler, - SysTick_Handler, - - /* Configurable interrupts */ - SUPC_IrqHandler, /* 0 Supply Controller */ - RSTC_IrqHandler, /* 1 Reset Controller */ - RTC_IrqHandler, /* 2 Real Time Clock */ - RTT_IrqHandler, /* 3 Real Time Timer */ - WDT_IrqHandler, /* 4 Watchdog Timer */ - PMC_IrqHandler, /* 5 PMC */ - EEFC_IrqHandler, /* 6 EEFC */ - IrqHandlerNotUsed, /* 7 Reserved */ - UART0_IrqHandler, /* 8 UART0 */ - UART1_IrqHandler, /* 9 UART1 */ - SMC_IrqHandler, /* 10 SMC */ - PIOA_IrqHandler, /* 11 Parallel IO Controller A */ - PIOB_IrqHandler, /* 12 Parallel IO Controller B */ - PIOC_IrqHandler, /* 13 Parallel IO Controller C */ - USART0_IrqHandler, /* 14 USART 0 */ - USART1_IrqHandler, /* 15 USART 1 */ - IrqHandlerNotUsed, /* 16 Reserved */ - IrqHandlerNotUsed, /* 17 Reserved */ - MCI_IrqHandler, /* 18 MCI */ - TWI0_IrqHandler, /* 19 TWI 0 */ - TWI1_IrqHandler, /* 20 TWI 1 */ - SPI_IrqHandler, /* 21 SPI */ - SSC_IrqHandler, /* 22 SSC */ - TC0_IrqHandler, /* 23 Timer Counter 0 */ - TC1_IrqHandler, /* 24 Timer Counter 1 */ - TC2_IrqHandler, /* 25 Timer Counter 2 */ - TC3_IrqHandler, /* 26 Timer Counter 3 */ - TC4_IrqHandler, /* 27 Timer Counter 4 */ - TC5_IrqHandler, /* 28 Timer Counter 5 */ - ADC_IrqHandler, /* 29 ADC controller */ - DAC_IrqHandler, /* 30 DAC controller */ - PWM_IrqHandler, /* 31 PWM */ - CRCCU_IrqHandler, /* 32 CRC Calculation Unit */ - ACC_IrqHandler, /* 33 Analog Comparator */ - USBD_IrqHandler, /* 34 USB Device Port */ - IrqHandlerNotUsed /* 35 not used */ -}; - -#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) -#include "usb/device/dfu/dfu.h" -static void BootIntoApp(void) -{ - unsigned int *pSrc; - void (*appReset)(void); - - pSrc = (unsigned int *) ((unsigned char *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE); - /* set vector table to application vector table (store at the beginning of the application) */ - SCB->VTOR = (unsigned int)(pSrc); - /* set stack pointer to address provided in the beginning of the application (loaded into a register first) */ - __asm__ volatile ("MSR msp,%0" : :"r"(*pSrc)); - /* start application (by jumping to the reset function which address is stored as second entry of the vector table) */ - appReset = (void(*)(void))pSrc[1]; - - g_dfu->state = DFU_STATE_appIDLE; - - appReset(); -} -#endif - -/** - * \brief This is the code that gets called on processor reset. - * To initialize the device, and call the main() routine. - */ -void ResetException( void ) -{ - uint32_t *pSrc, *pDest ; - - /* Low level Initialize */ - LowLevelInit() ; - - -#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) - if (!USBDFU_OverrideEnterDFU()) { - UART_Exit(); - __disable_irq(); - BootIntoApp(); - /* Infinite loop */ - while ( 1 ) ; - } -#endif - - /* Initialize the relocate segment */ - pSrc = &_etext ; - pDest = &_srelocate ; - - if ( pSrc != pDest ) - { - for ( ; pDest < &_erelocate ; ) - { - *pDest++ = *pSrc++ ; - } - } - - /* Clear the zero segment */ - for ( pDest = &_szero ; pDest < &_ezero ; ) - { - *pDest++ = 0; - } - - /* Set the vector table base address */ - pSrc = (uint32_t *)&_sfixed; - SCB->VTOR = ( (uint32_t)pSrc & SCB_VTOR_TBLOFF_Msk ) ; - - if ( ((uint32_t)pSrc >= IRAM_ADDR) && ((uint32_t)pSrc < IRAM_ADDR+IRAM_SIZE) ) - { - SCB->VTOR |= 1 << SCB_VTOR_TBLBASE_Pos ; - } - - /* App should have disabled interrupts during the transition */ - __enable_irq(); - - /* Branch to main function */ - main() ; - - /* Infinite loop */ - while ( 1 ) ; -} - +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2010, Atmel Corporation + * Copyright (c) 2017, Harald Welte + * Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "board.h" +#include "board_lowlevel.h" + +/*---------------------------------------------------------------------------- + * Exported variables + *----------------------------------------------------------------------------*/ + +/* Stack Configuration */ +#define STACK_SIZE 0x900 /** Stack size (in DWords) */ +__attribute__ ((aligned(8),section(".stack"))) +uint32_t pdwStack[STACK_SIZE] ; + +/* Initialize segments */ +extern uint32_t _sfixed; +extern uint32_t _efixed; +extern uint32_t _etext; +extern uint32_t _srelocate; +extern uint32_t _erelocate; +extern uint32_t _szero; +extern uint32_t _ezero; + + +/*---------------------------------------------------------------------------- + * ProtoTypes + *----------------------------------------------------------------------------*/ + +/** \cond DOXYGEN_SHOULD_SKIP_THIS */ +extern int main( void ) ; +/** \endcond */ +void ResetException( void ) ; + +/*------------------------------------------------------------------------------ + * Exception Table + *------------------------------------------------------------------------------*/ + +__attribute__((section(".vectors"))) +IntFunc exception_table[] = { + + /* Configure Initial Stack Pointer, using linker-generated symbols */ + (IntFunc)(&pdwStack[STACK_SIZE-1]), + ResetException, + + NMI_Handler, + HardFault_Handler, + MemManage_Handler, + BusFault_Handler, + UsageFault_Handler, + 0, 0, 0, 0, /* Reserved */ + SVC_Handler, + DebugMon_Handler, + 0, /* Reserved */ + PendSV_Handler, + SysTick_Handler, + + /* Configurable interrupts */ + SUPC_IrqHandler, /* 0 Supply Controller */ + RSTC_IrqHandler, /* 1 Reset Controller */ + RTC_IrqHandler, /* 2 Real Time Clock */ + RTT_IrqHandler, /* 3 Real Time Timer */ + WDT_IrqHandler, /* 4 Watchdog Timer */ + PMC_IrqHandler, /* 5 PMC */ + EEFC_IrqHandler, /* 6 EEFC */ + IrqHandlerNotUsed, /* 7 Reserved */ + UART0_IrqHandler, /* 8 UART0 */ + UART1_IrqHandler, /* 9 UART1 */ + SMC_IrqHandler, /* 10 SMC */ + PIOA_IrqHandler, /* 11 Parallel IO Controller A */ + PIOB_IrqHandler, /* 12 Parallel IO Controller B */ + PIOC_IrqHandler, /* 13 Parallel IO Controller C */ + USART0_IrqHandler, /* 14 USART 0 */ + USART1_IrqHandler, /* 15 USART 1 */ + IrqHandlerNotUsed, /* 16 Reserved */ + IrqHandlerNotUsed, /* 17 Reserved */ + MCI_IrqHandler, /* 18 MCI */ + TWI0_IrqHandler, /* 19 TWI 0 */ + TWI1_IrqHandler, /* 20 TWI 1 */ + SPI_IrqHandler, /* 21 SPI */ + SSC_IrqHandler, /* 22 SSC */ + TC0_IrqHandler, /* 23 Timer Counter 0 */ + TC1_IrqHandler, /* 24 Timer Counter 1 */ + TC2_IrqHandler, /* 25 Timer Counter 2 */ + TC3_IrqHandler, /* 26 Timer Counter 3 */ + TC4_IrqHandler, /* 27 Timer Counter 4 */ + TC5_IrqHandler, /* 28 Timer Counter 5 */ + ADC_IrqHandler, /* 29 ADC controller */ + DAC_IrqHandler, /* 30 DAC controller */ + PWM_IrqHandler, /* 31 PWM */ + CRCCU_IrqHandler, /* 32 CRC Calculation Unit */ + ACC_IrqHandler, /* 33 Analog Comparator */ + USBD_IrqHandler, /* 34 USB Device Port */ + IrqHandlerNotUsed /* 35 not used */ +}; + +#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) +#include "usb/device/dfu/dfu.h" +static void BootIntoApp(void) +{ + unsigned int *pSrc; + void (*appReset)(void); + + pSrc = (unsigned int *) ((unsigned char *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE); + /* set vector table to application vector table (store at the beginning of the application) */ + SCB->VTOR = (unsigned int)(pSrc); + /* set stack pointer to address provided in the beginning of the application (loaded into a register first) */ + __asm__ volatile ("MSR msp,%0" : :"r"(*pSrc)); + /* start application (by jumping to the reset function which address is stored as second entry of the vector table) */ + appReset = (void(*)(void))pSrc[1]; + + g_dfu->state = DFU_STATE_appIDLE; + + appReset(); +} +#endif + +/** + * \brief This is the code that gets called on processor reset. + * To initialize the device, and call the main() routine. + */ +void ResetException( void ) +{ + uint32_t *pSrc, *pDest ; + + /* Low level Initialize */ + LowLevelInit() ; + + +#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) + if (!USBDFU_OverrideEnterDFU()) { + UART_Exit(); + __disable_irq(); + BootIntoApp(); + /* Infinite loop */ + while ( 1 ) ; + } +#endif + + /* Initialize the relocate segment */ + pSrc = &_etext ; + pDest = &_srelocate ; + + if ( pSrc != pDest ) + { + for ( ; pDest < &_erelocate ; ) + { + *pDest++ = *pSrc++ ; + } + } + + /* Clear the zero segment */ + for ( pDest = &_szero ; pDest < &_ezero ; ) + { + *pDest++ = 0; + } + + /* Set the vector table base address */ + pSrc = (uint32_t *)&_sfixed; + SCB->VTOR = ( (uint32_t)pSrc & SCB_VTOR_TBLOFF_Msk ) ; + + if ( ((uint32_t)pSrc >= IRAM_ADDR) && ((uint32_t)pSrc < IRAM_ADDR+IRAM_SIZE) ) + { + SCB->VTOR |= 1 << SCB_VTOR_TBLBASE_Pos ; + } + + /* App should have disabled interrupts during the transition */ + __enable_irq(); + + /* Branch to main function */ + main() ; + + /* Infinite loop */ + while ( 1 ) ; +} + diff --git a/firmware/libboard/common/source/board_lowlevel.c b/firmware/libboard/common/source/board_lowlevel.c index 98eb74d8..b37719c0 100644 --- a/firmware/libboard/common/source/board_lowlevel.c +++ b/firmware/libboard/common/source/board_lowlevel.c @@ -1,216 +1,216 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** - * \file - * - * Provides the low-level initialization function that called on chip startup. - */ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ - -#include "board.h" - -/*---------------------------------------------------------------------------- - * Local definitions - *----------------------------------------------------------------------------*/ - -#define BOARD_OSCOUNT (CKGR_MOR_MOSCXTST(0x8)) -#define BOARD_MCKR (PMC_MCKR_PRES_CLK | PMC_MCKR_CSS_PLLA_CLK) - -#if (BOARD_MCK == 48000000) -#if (BOARD_MAINOSC == 18432000) -/* Clock settings at 48MHz for 18 MHz crystal */ -#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ - | CKGR_PLLAR_MULA(13-1) \ - | CKGR_PLLAR_PLLACOUNT(0x1) \ - | CKGR_PLLAR_DIVA(5)) -#elif (BOARD_MAINOSC == 12000000) -/* QMod has 12 MHz clock, so multply by 8 (96 MHz) and divide by 2 */ -#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ - | CKGR_PLLAR_MULA(8-1) \ - | CKGR_PLLAR_PLLACOUNT(0x1) \ - | CKGR_PLLAR_DIVA(2)) -#else -#error "Please define PLLA config for your MAINOSC frequency" -#endif /* MAINOSC */ -#elif (BOARD_MCK == 64000000) -#if (BOARD_MAINOSC == 18432000) -/* Clock settings at 64MHz for 18 MHz crystal: 64.512 MHz */ -#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ - | CKGR_PLLAR_MULA(7-1) \ - | CKGR_PLLAR_PLLACOUNT(0x1) \ - | CKGR_PLLAR_DIVA(2)) -#elif (BOARD_MAINOSC == 12000000) -/* QMod has 12 MHz clock, so multply by 10 / div by 2: 60 MHz */ -#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ - | CKGR_PLLAR_MULA(10-1) \ - | CKGR_PLLAR_PLLACOUNT(0x1) \ - | CKGR_PLLAR_DIVA(2)) -#error "Please define PLLA config for your MAINOSC frequency" -#endif /* MAINOSC */ -#else - #error "No PLL settings for current BOARD_MCK." -#endif - -#if (BOARD_MAINOSC == 12000000) -#define PLLB_CFG (CKGR_PLLBR_DIVB(2)|CKGR_PLLBR_MULB(8-1)|CKGR_PLLBR_PLLBCOUNT_Msk) -#elif (BOARD_MAINOSC == 18432000) -#define PLLB_CFG (CKGR_PLLBR_DIVB(5)|CKGR_PLLBR_MULB(13-1)|CKGR_PLLBR_PLLBCOUNT_Msk) -#else -#error "Please configure PLLB for your MAINOSC freq" -#endif - -/* Define clock timeout */ -#define CLOCK_TIMEOUT 0xFFFFFFFF - -/** - * \brief Configure 48MHz Clock for USB - */ -static void _ConfigureUsbClock(void) -{ - /* Enable PLLB for USB */ - PMC->CKGR_PLLBR = PLLB_CFG; - while ((PMC->PMC_SR & PMC_SR_LOCKB) == 0) ; - - /* USB Clock uses PLLB */ - PMC->PMC_USB = PMC_USB_USBDIV(0) /* /1 (no divider) */ - | PMC_USB_USBS; /* PLLB */ -} - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Performs the low-level initialization of the chip. - * This includes EFC and master clock configuration. - * It also enable a low level on the pin NRST triggers a user reset. - */ -extern WEAK void LowLevelInit( void ) -{ - uint32_t timeout = 0; - - /* Configure the Supply Monitor to reset the CPU in case VDDIO is - * lower than 3.0V. As we run the board on 3.3V, any lower voltage - * might be some kind of leakage that creeps in some way, but is not - * the "official" power supply */ - SUPC->SUPC_SMMR = SUPC_SMMR_SMTH_3_0V | SUPC_SMMR_SMSMPL_CSM | - SUPC_SMMR_SMRSTEN_ENABLE; - - /* enable both LED and green LED */ - PIOA->PIO_PER |= PIO_LED_RED | PIO_LED_GREEN; - PIOA->PIO_OER |= PIO_LED_RED | PIO_LED_GREEN; - PIOA->PIO_CODR |= PIO_LED_RED | PIO_LED_GREEN; - - /* Set 3 FWS for Embedded Flash Access */ - EFC->EEFC_FMR = EEFC_FMR_FWS(3); - - /* Select external slow clock */ -/* if ((SUPC->SUPC_SR & SUPC_SR_OSCSEL) != SUPC_SR_OSCSEL_CRYST) - { - SUPC->SUPC_CR = (uint32_t)(SUPC_CR_XTALSEL_CRYSTAL_SEL | SUPC_CR_KEY(0xA5)); - timeout = 0; - while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL_CRYST) ); - } -*/ - -#ifndef qmod - /* Initialize main oscillator */ - if ( !(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) ) - { - PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN; - timeout = 0; - while (!(PMC->PMC_SR & PMC_SR_MOSCXTS) && (timeout++ < CLOCK_TIMEOUT)); - } - - /* Switch to 3-20MHz Xtal oscillator */ - PIOB->PIO_PDR = (1 << 8) | (1 << 9); - PIOB->PIO_PUDR = (1 << 8) | (1 << 9); - PIOB->PIO_PPDDR = (1 << 8) | (1 << 9); - PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL; - /* wait for Main XTAL oscillator stabilization */ - timeout = 0; - while (!(PMC->PMC_SR & PMC_SR_MOSCSELS) && (timeout++ < CLOCK_TIMEOUT)); -#else - /* QMOD has external 12MHz clock source */ - PIOB->PIO_PDR = (1 << 9); - PIOB->PIO_PUDR = (1 << 9); - PIOB->PIO_PPDDR = (1 << 9); - PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTBY| CKGR_MOR_MOSCSEL; -#endif - - /* disable the red LED after main clock initialization */ - PIOA->PIO_SODR = PIO_LED_RED; - - /* "switch" to main clock as master clock source (should already be the case */ - PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; - /* wait for master clock to be ready */ - for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; ); - - /* Initialize PLLA */ - PMC->CKGR_PLLAR = BOARD_PLLAR; - /* Wait for PLLA to lock */ - timeout = 0; - while (!(PMC->PMC_SR & PMC_SR_LOCKA) && (timeout++ < CLOCK_TIMEOUT)); - - /* Switch to main clock (again ?!?) */ - PMC->PMC_MCKR = (BOARD_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; - /* wait for master clock to be ready */ - for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; ); - - /* switch to PLLA as master clock source */ - PMC->PMC_MCKR = BOARD_MCKR ; - /* wait for master clock to be ready */ - for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; ); - - /* Configure SysTick for 1ms */ - SysTick_Config(BOARD_MCK/1000); - - _ConfigureUsbClock(); -} - -/* SysTick based delay function */ - -volatile uint32_t jiffies; - -/* Interrupt handler for SysTick interrupt */ -void SysTick_Handler(void) -{ - jiffies++; -} - -void mdelay(unsigned int msecs) -{ - uint32_t jiffies_start = jiffies; - do { - } while ((jiffies - jiffies_start) < msecs); -} +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** + * \file + * + * Provides the low-level initialization function that called on chip startup. + */ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "board.h" + +/*---------------------------------------------------------------------------- + * Local definitions + *----------------------------------------------------------------------------*/ + +#define BOARD_OSCOUNT (CKGR_MOR_MOSCXTST(0x8)) +#define BOARD_MCKR (PMC_MCKR_PRES_CLK | PMC_MCKR_CSS_PLLA_CLK) + +#if (BOARD_MCK == 48000000) +#if (BOARD_MAINOSC == 18432000) +/* Clock settings at 48MHz for 18 MHz crystal */ +#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ + | CKGR_PLLAR_MULA(13-1) \ + | CKGR_PLLAR_PLLACOUNT(0x1) \ + | CKGR_PLLAR_DIVA(5)) +#elif (BOARD_MAINOSC == 12000000) +/* QMod has 12 MHz clock, so multply by 8 (96 MHz) and divide by 2 */ +#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ + | CKGR_PLLAR_MULA(8-1) \ + | CKGR_PLLAR_PLLACOUNT(0x1) \ + | CKGR_PLLAR_DIVA(2)) +#else +#error "Please define PLLA config for your MAINOSC frequency" +#endif /* MAINOSC */ +#elif (BOARD_MCK == 64000000) +#if (BOARD_MAINOSC == 18432000) +/* Clock settings at 64MHz for 18 MHz crystal: 64.512 MHz */ +#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ + | CKGR_PLLAR_MULA(7-1) \ + | CKGR_PLLAR_PLLACOUNT(0x1) \ + | CKGR_PLLAR_DIVA(2)) +#elif (BOARD_MAINOSC == 12000000) +/* QMod has 12 MHz clock, so multply by 10 / div by 2: 60 MHz */ +#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ + | CKGR_PLLAR_MULA(10-1) \ + | CKGR_PLLAR_PLLACOUNT(0x1) \ + | CKGR_PLLAR_DIVA(2)) +#error "Please define PLLA config for your MAINOSC frequency" +#endif /* MAINOSC */ +#else + #error "No PLL settings for current BOARD_MCK." +#endif + +#if (BOARD_MAINOSC == 12000000) +#define PLLB_CFG (CKGR_PLLBR_DIVB(2)|CKGR_PLLBR_MULB(8-1)|CKGR_PLLBR_PLLBCOUNT_Msk) +#elif (BOARD_MAINOSC == 18432000) +#define PLLB_CFG (CKGR_PLLBR_DIVB(5)|CKGR_PLLBR_MULB(13-1)|CKGR_PLLBR_PLLBCOUNT_Msk) +#else +#error "Please configure PLLB for your MAINOSC freq" +#endif + +/* Define clock timeout */ +#define CLOCK_TIMEOUT 0xFFFFFFFF + +/** + * \brief Configure 48MHz Clock for USB + */ +static void _ConfigureUsbClock(void) +{ + /* Enable PLLB for USB */ + PMC->CKGR_PLLBR = PLLB_CFG; + while ((PMC->PMC_SR & PMC_SR_LOCKB) == 0) ; + + /* USB Clock uses PLLB */ + PMC->PMC_USB = PMC_USB_USBDIV(0) /* /1 (no divider) */ + | PMC_USB_USBS; /* PLLB */ +} + +/*---------------------------------------------------------------------------- + * Exported functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Performs the low-level initialization of the chip. + * This includes EFC and master clock configuration. + * It also enable a low level on the pin NRST triggers a user reset. + */ +extern WEAK void LowLevelInit( void ) +{ + uint32_t timeout = 0; + + /* Configure the Supply Monitor to reset the CPU in case VDDIO is + * lower than 3.0V. As we run the board on 3.3V, any lower voltage + * might be some kind of leakage that creeps in some way, but is not + * the "official" power supply */ + SUPC->SUPC_SMMR = SUPC_SMMR_SMTH_3_0V | SUPC_SMMR_SMSMPL_CSM | + SUPC_SMMR_SMRSTEN_ENABLE; + + /* enable both LED and green LED */ + PIOA->PIO_PER |= PIO_LED_RED | PIO_LED_GREEN; + PIOA->PIO_OER |= PIO_LED_RED | PIO_LED_GREEN; + PIOA->PIO_CODR |= PIO_LED_RED | PIO_LED_GREEN; + + /* Set 3 FWS for Embedded Flash Access */ + EFC->EEFC_FMR = EEFC_FMR_FWS(3); + + /* Select external slow clock */ +/* if ((SUPC->SUPC_SR & SUPC_SR_OSCSEL) != SUPC_SR_OSCSEL_CRYST) + { + SUPC->SUPC_CR = (uint32_t)(SUPC_CR_XTALSEL_CRYSTAL_SEL | SUPC_CR_KEY(0xA5)); + timeout = 0; + while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL_CRYST) ); + } +*/ + +#ifndef qmod + /* Initialize main oscillator */ + if ( !(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) ) + { + PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN; + timeout = 0; + while (!(PMC->PMC_SR & PMC_SR_MOSCXTS) && (timeout++ < CLOCK_TIMEOUT)); + } + + /* Switch to 3-20MHz Xtal oscillator */ + PIOB->PIO_PDR = (1 << 8) | (1 << 9); + PIOB->PIO_PUDR = (1 << 8) | (1 << 9); + PIOB->PIO_PPDDR = (1 << 8) | (1 << 9); + PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL; + /* wait for Main XTAL oscillator stabilization */ + timeout = 0; + while (!(PMC->PMC_SR & PMC_SR_MOSCSELS) && (timeout++ < CLOCK_TIMEOUT)); +#else + /* QMOD has external 12MHz clock source */ + PIOB->PIO_PDR = (1 << 9); + PIOB->PIO_PUDR = (1 << 9); + PIOB->PIO_PPDDR = (1 << 9); + PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTBY| CKGR_MOR_MOSCSEL; +#endif + + /* disable the red LED after main clock initialization */ + PIOA->PIO_SODR = PIO_LED_RED; + + /* "switch" to main clock as master clock source (should already be the case */ + PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; + /* wait for master clock to be ready */ + for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; ); + + /* Initialize PLLA */ + PMC->CKGR_PLLAR = BOARD_PLLAR; + /* Wait for PLLA to lock */ + timeout = 0; + while (!(PMC->PMC_SR & PMC_SR_LOCKA) && (timeout++ < CLOCK_TIMEOUT)); + + /* Switch to main clock (again ?!?) */ + PMC->PMC_MCKR = (BOARD_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; + /* wait for master clock to be ready */ + for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; ); + + /* switch to PLLA as master clock source */ + PMC->PMC_MCKR = BOARD_MCKR ; + /* wait for master clock to be ready */ + for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; ); + + /* Configure SysTick for 1ms */ + SysTick_Config(BOARD_MCK/1000); + + _ConfigureUsbClock(); +} + +/* SysTick based delay function */ + +volatile uint32_t jiffies; + +/* Interrupt handler for SysTick interrupt */ +void SysTick_Handler(void) +{ + jiffies++; +} + +void mdelay(unsigned int msecs) +{ + uint32_t jiffies_start = jiffies; + do { + } while ((jiffies - jiffies_start) < msecs); +} diff --git a/firmware/libboard/common/source/uart_console.c b/firmware/libboard/common/source/uart_console.c index 07f41ed6..88c91661 100644 --- a/firmware/libboard/common/source/uart_console.c +++ b/firmware/libboard/common/source/uart_console.c @@ -1,426 +1,426 @@ -/* ---------------------------------------------------------------------------- - * ATMEL Microcontroller Software Support - * ---------------------------------------------------------------------------- - * Copyright (c) 2009, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the disclaimer below. - * - * Atmel's name may not be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. - * ---------------------------------------------------------------------------- - */ - -/** - * \file - * - * Implements UART console. - * - */ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ - -#include "board.h" - -#include -#include - -#include "ringbuffer.h" - -/*---------------------------------------------------------------------------- - * Definitions - *----------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------------- - * Variables - *----------------------------------------------------------------------------*/ - -/** Is Console Initialized. */ -static uint8_t _ucIsConsoleInitialized=0; -/** Ring buffer to queue data to be sent */ -static ringbuf uart_tx_buffer; - -/** - * \brief Configures an USART peripheral with the specified parameters. - * - * \param baudrate Baudrate at which the USART should operate (in Hz). - * \param masterClock Frequency of the system master clock (in Hz). - */ -extern void UART_Configure( uint32_t baudrate, uint32_t masterClock) -{ - const Pin pPins[] = CONSOLE_PINS; - Uart *pUart = CONSOLE_UART; - - /* Configure PIO */ - PIO_Configure(pPins, PIO_LISTSIZE(pPins)); - - /* Configure PMC */ - PMC->PMC_PCER0 = 1 << CONSOLE_ID; - - /* Reset and disable receiver & transmitter */ - pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX - | UART_CR_RXDIS | UART_CR_TXDIS; - - /* Configure mode */ - pUart->UART_MR = UART_MR_PAR_NO; - - /* Configure baudrate */ - /* Asynchronous, no oversampling */ - pUart->UART_BRGR = (masterClock / baudrate) / 16; - - /* Disable PDC channel */ - pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS; - - /* Reset transmit ring buffer */ - rbuf_reset(&uart_tx_buffer); - - /* Enable TX interrupts */ - pUart->UART_IER = UART_IER_TXRDY; - NVIC_EnableIRQ(CONSOLE_IRQ); - - /* Enable receiver and transmitter */ - pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN; - - /* Remember the configuration is complete */ - _ucIsConsoleInitialized=1 ; -} - -/** - * \brief Disables the USART peripheral and related IRQ - */ -void UART_Exit(void) -{ - if (!_ucIsConsoleInitialized) { - return; - } - - Uart *pUart = CONSOLE_UART; - pUart->UART_IDR = UART_IDR_TXRDY; - pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA; - PMC->PMC_PCDR0 = 1 << CONSOLE_ID; - NVIC_DisableIRQ(CONSOLE_IRQ); -} - -/** Interrupt Service routine to transmit queued data */ -void CONSOLE_ISR(void) -{ - Uart *uart = CONSOLE_UART; - if (uart->UART_SR & UART_SR_TXRDY) { - if (!rbuf_is_empty(&uart_tx_buffer)) { - uart->UART_THR = rbuf_read(&uart_tx_buffer); - } else { - uart->UART_IDR = UART_IER_TXRDY; - } - } -} - -/** - * \brief Outputs a character on the UART line. - * - * \note This function is synchronous (i.e. uses polling). - * \param c Character to send. - */ -extern void UART_PutChar( uint8_t c ) -{ - Uart *pUart = CONSOLE_UART ; - - /* Initialize console is not already done */ - if ( !_ucIsConsoleInitialized ) - { - UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK); - } - - /* Only store input if buffer is not full, else drop it */ - if (!rbuf_is_full(&uart_tx_buffer)) { - rbuf_write(&uart_tx_buffer, c); - if (!(pUart->UART_IMR & UART_IMR_TXRDY)) { - pUart->UART_IER = UART_IER_TXRDY; - CONSOLE_ISR(); - } - } -} - -/** - * \brief Input a character from the UART line. - * - * \note This function is synchronous - * \return character received. - */ -extern uint32_t UART_GetChar( void ) -{ - Uart *pUart = CONSOLE_UART ; - - if ( !_ucIsConsoleInitialized ) - { - UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK); - } - - while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 ) - WDT_Restart(WDT); - - return pUart->UART_RHR ; -} - -/** - * \brief Check if there is Input from UART line. - * - * \return true if there is Input. - */ -extern uint32_t UART_IsRxReady( void ) -{ - Uart *pUart = CONSOLE_UART; - - if ( !_ucIsConsoleInitialized ) - { - UART_Configure( CONSOLE_BAUDRATE, BOARD_MCK ) ; - } - - return (pUart->UART_SR & UART_SR_RXRDY) > 0 ; -} - -/** - * Displays the content of the given frame on the UART0. - * - * \param pucFrame Pointer to the frame to dump. - * \param dwSize Buffer size in bytes. - */ -extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize ) -{ - uint32_t dw ; - - for ( dw=0 ; dw < dwSize ; dw++ ) - { - printf( "%02X ", pucFrame[dw] ) ; - } - - printf( "\n\r" ) ; -} - -/** - * Displays the content of the given buffer on the UART0. - * - * \param pucBuffer Pointer to the buffer to dump. - * \param dwSize Buffer size in bytes. - * \param dwAddress Start address to display - */ -extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress ) -{ - uint32_t i ; - uint32_t j ; - uint32_t dwLastLineStart ; - uint8_t* pucTmp ; - - for ( i=0 ; i < (dwSize / 16) ; i++ ) - { - printf( "0x%08X: ", (unsigned int)(dwAddress + (i*16)) ) ; - pucTmp = (uint8_t*)&pucBuffer[i*16] ; - - for ( j=0 ; j < 4 ; j++ ) - { - printf( "%02X%02X%02X%02X ", pucTmp[0], pucTmp[1], pucTmp[2], pucTmp[3] ) ; - pucTmp += 4 ; - } - - pucTmp=(uint8_t*)&pucBuffer[i*16] ; - - for ( j=0 ; j < 16 ; j++ ) - { - UART_PutChar( *pucTmp++ ) ; - } - - printf( "\n\r" ) ; - } - - if ( (dwSize%16) != 0 ) - { - dwLastLineStart=dwSize - (dwSize%16) ; - - printf( "0x%08X: ", (unsigned int)(dwAddress + dwLastLineStart) ) ; - for ( j=dwLastLineStart ; j < dwLastLineStart+16 ; j++ ) - { - if ( (j!=dwLastLineStart) && (j%4 == 0) ) - { - printf( " " ) ; - } - - if ( j < dwSize ) - { - printf( "%02X", pucBuffer[j] ) ; - } - else - { - printf(" ") ; - } - } - - printf( " " ) ; - for ( j=dwLastLineStart ; j < dwSize ; j++ ) - { - UART_PutChar( pucBuffer[j] ) ; - } - - printf( "\n\r" ) ; - } -} - -/** - * Reads an integer - * - * \param pdwValue Pointer to the uint32_t variable to contain the input value. - */ -extern uint32_t UART_GetInteger( uint32_t* pdwValue ) -{ - uint8_t ucKey ; - uint8_t ucNbNb=0 ; - uint32_t dwValue=0 ; - - while ( 1 ) - { - ucKey=UART_GetChar() ; - UART_PutChar( ucKey ) ; - - if ( ucKey >= '0' && ucKey <= '9' ) - { - dwValue = (dwValue * 10) + (ucKey - '0'); - ucNbNb++ ; - } - else - { - if ( ucKey == 0x0D || ucKey == ' ' ) - { - if ( ucNbNb == 0 ) - { - printf( "\n\rWrite a number and press ENTER or SPACE!\n\r" ) ; - return 0 ; - } - else - { - printf( "\n\r" ) ; - *pdwValue=dwValue ; - - return 1 ; - } - } - else - { - printf( "\n\r'%c' not a number!\n\r", ucKey ) ; - - return 0 ; - } - } - WDT_Restart(WDT); - } -} - -/** - * Reads an integer and check the value - * - * \param pdwValue Pointer to the uint32_t variable to contain the input value. - * \param dwMin Minimum value - * \param dwMax Maximum value - */ -extern uint32_t UART_GetIntegerMinMax( uint32_t* pdwValue, uint32_t dwMin, uint32_t dwMax ) -{ - uint32_t dwValue=0 ; - - if ( UART_GetInteger( &dwValue ) == 0 ) - { - return 0 ; - } - - if ( dwValue < dwMin || dwValue > dwMax ) - { - printf( "\n\rThe number have to be between %d and %d\n\r", (int)dwMin, (int)dwMax ) ; - - return 0 ; - } - - printf( "\n\r" ) ; - - *pdwValue = dwValue ; - - return 1 ; -} - -/** - * Reads an hexadecimal number - * - * \param pdwValue Pointer to the uint32_t variable to contain the input value. - */ -extern uint32_t UART_GetHexa32( uint32_t* pdwValue ) -{ - uint8_t ucKey ; - uint32_t dw = 0 ; - uint32_t dwValue = 0 ; - - for ( dw=0 ; dw < 8 ; dw++ ) - { - ucKey = UART_GetChar() ; - UART_PutChar( ucKey ) ; - - if ( ucKey >= '0' && ucKey <= '9' ) - { - dwValue = (dwValue * 16) + (ucKey - '0') ; - } - else - { - if ( ucKey >= 'A' && ucKey <= 'F' ) - { - dwValue = (dwValue * 16) + (ucKey - 'A' + 10) ; - } - else - { - if ( ucKey >= 'a' && ucKey <= 'f' ) - { - dwValue = (dwValue * 16) + (ucKey - 'a' + 10) ; - } - else - { - printf( "\n\rIt is not a hexa character!\n\r" ) ; - - return 0 ; - } - } - } - } - - printf("\n\r" ) ; - *pdwValue = dwValue ; - - return 1 ; -} - -#if defined __ICCARM__ /* IAR Ewarm 5.41+ */ -/** - * \brief Outputs a character on the UART. - * - * \param c Character to output. - * - * \return The character that was output. - */ -extern WEAK signed int putchar( signed int c ) -{ - UART_PutChar( c ) ; - - return c ; -} -#endif // defined __ICCARM__ - +/* ---------------------------------------------------------------------------- + * ATMEL Microcontroller Software Support + * ---------------------------------------------------------------------------- + * Copyright (c) 2009, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * ---------------------------------------------------------------------------- + */ + +/** + * \file + * + * Implements UART console. + * + */ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "board.h" + +#include +#include + +#include "ringbuffer.h" + +/*---------------------------------------------------------------------------- + * Definitions + *----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Variables + *----------------------------------------------------------------------------*/ + +/** Is Console Initialized. */ +static uint8_t _ucIsConsoleInitialized=0; +/** Ring buffer to queue data to be sent */ +static ringbuf uart_tx_buffer; + +/** + * \brief Configures an USART peripheral with the specified parameters. + * + * \param baudrate Baudrate at which the USART should operate (in Hz). + * \param masterClock Frequency of the system master clock (in Hz). + */ +extern void UART_Configure( uint32_t baudrate, uint32_t masterClock) +{ + const Pin pPins[] = CONSOLE_PINS; + Uart *pUart = CONSOLE_UART; + + /* Configure PIO */ + PIO_Configure(pPins, PIO_LISTSIZE(pPins)); + + /* Configure PMC */ + PMC->PMC_PCER0 = 1 << CONSOLE_ID; + + /* Reset and disable receiver & transmitter */ + pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX + | UART_CR_RXDIS | UART_CR_TXDIS; + + /* Configure mode */ + pUart->UART_MR = UART_MR_PAR_NO; + + /* Configure baudrate */ + /* Asynchronous, no oversampling */ + pUart->UART_BRGR = (masterClock / baudrate) / 16; + + /* Disable PDC channel */ + pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS; + + /* Reset transmit ring buffer */ + rbuf_reset(&uart_tx_buffer); + + /* Enable TX interrupts */ + pUart->UART_IER = UART_IER_TXRDY; + NVIC_EnableIRQ(CONSOLE_IRQ); + + /* Enable receiver and transmitter */ + pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN; + + /* Remember the configuration is complete */ + _ucIsConsoleInitialized=1 ; +} + +/** + * \brief Disables the USART peripheral and related IRQ + */ +void UART_Exit(void) +{ + if (!_ucIsConsoleInitialized) { + return; + } + + Uart *pUart = CONSOLE_UART; + pUart->UART_IDR = UART_IDR_TXRDY; + pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA; + PMC->PMC_PCDR0 = 1 << CONSOLE_ID; + NVIC_DisableIRQ(CONSOLE_IRQ); +} + +/** Interrupt Service routine to transmit queued data */ +void CONSOLE_ISR(void) +{ + Uart *uart = CONSOLE_UART; + if (uart->UART_SR & UART_SR_TXRDY) { + if (!rbuf_is_empty(&uart_tx_buffer)) { + uart->UART_THR = rbuf_read(&uart_tx_buffer); + } else { + uart->UART_IDR = UART_IER_TXRDY; + } + } +} + +/** + * \brief Outputs a character on the UART line. + * + * \note This function is synchronous (i.e. uses polling). + * \param c Character to send. + */ +extern void UART_PutChar( uint8_t c ) +{ + Uart *pUart = CONSOLE_UART ; + + /* Initialize console is not already done */ + if ( !_ucIsConsoleInitialized ) + { + UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK); + } + + /* Only store input if buffer is not full, else drop it */ + if (!rbuf_is_full(&uart_tx_buffer)) { + rbuf_write(&uart_tx_buffer, c); + if (!(pUart->UART_IMR & UART_IMR_TXRDY)) { + pUart->UART_IER = UART_IER_TXRDY; + CONSOLE_ISR(); + } + } +} + +/** + * \brief Input a character from the UART line. + * + * \note This function is synchronous + * \return character received. + */ +extern uint32_t UART_GetChar( void ) +{ + Uart *pUart = CONSOLE_UART ; + + if ( !_ucIsConsoleInitialized ) + { + UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK); + } + + while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 ) + WDT_Restart(WDT); + + return pUart->UART_RHR ; +} + +/** + * \brief Check if there is Input from UART line. + * + * \return true if there is Input. + */ +extern uint32_t UART_IsRxReady( void ) +{ + Uart *pUart = CONSOLE_UART; + + if ( !_ucIsConsoleInitialized ) + { + UART_Configure( CONSOLE_BAUDRATE, BOARD_MCK ) ; + } + + return (pUart->UART_SR & UART_SR_RXRDY) > 0 ; +} + +/** + * Displays the content of the given frame on the UART0. + * + * \param pucFrame Pointer to the frame to dump. + * \param dwSize Buffer size in bytes. + */ +extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize ) +{ + uint32_t dw ; + + for ( dw=0 ; dw < dwSize ; dw++ ) + { + printf( "%02X ", pucFrame[dw] ) ; + } + + printf( "\n\r" ) ; +} + +/** + * Displays the content of the given buffer on the UART0. + * + * \param pucBuffer Pointer to the buffer to dump. + * \param dwSize Buffer size in bytes. + * \param dwAddress Start address to display + */ +extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress ) +{ + uint32_t i ; + uint32_t j ; + uint32_t dwLastLineStart ; + uint8_t* pucTmp ; + + for ( i=0 ; i < (dwSize / 16) ; i++ ) + { + printf( "0x%08X: ", (unsigned int)(dwAddress + (i*16)) ) ; + pucTmp = (uint8_t*)&pucBuffer[i*16] ; + + for ( j=0 ; j < 4 ; j++ ) + { + printf( "%02X%02X%02X%02X ", pucTmp[0], pucTmp[1], pucTmp[2], pucTmp[3] ) ; + pucTmp += 4 ; + } + + pucTmp=(uint8_t*)&pucBuffer[i*16] ; + + for ( j=0 ; j < 16 ; j++ ) + { + UART_PutChar( *pucTmp++ ) ; + } + + printf( "\n\r" ) ; + } + + if ( (dwSize%16) != 0 ) + { + dwLastLineStart=dwSize - (dwSize%16) ; + + printf( "0x%08X: ", (unsigned int)(dwAddress + dwLastLineStart) ) ; + for ( j=dwLastLineStart ; j < dwLastLineStart+16 ; j++ ) + { + if ( (j!=dwLastLineStart) && (j%4 == 0) ) + { + printf( " " ) ; + } + + if ( j < dwSize ) + { + printf( "%02X", pucBuffer[j] ) ; + } + else + { + printf(" ") ; + } + } + + printf( " " ) ; + for ( j=dwLastLineStart ; j < dwSize ; j++ ) + { + UART_PutChar( pucBuffer[j] ) ; + } + + printf( "\n\r" ) ; + } +} + +/** + * Reads an integer + * + * \param pdwValue Pointer to the uint32_t variable to contain the input value. + */ +extern uint32_t UART_GetInteger( uint32_t* pdwValue ) +{ + uint8_t ucKey ; + uint8_t ucNbNb=0 ; + uint32_t dwValue=0 ; + + while ( 1 ) + { + ucKey=UART_GetChar() ; + UART_PutChar( ucKey ) ; + + if ( ucKey >= '0' && ucKey <= '9' ) + { + dwValue = (dwValue * 10) + (ucKey - '0'); + ucNbNb++ ; + } + else + { + if ( ucKey == 0x0D || ucKey == ' ' ) + { + if ( ucNbNb == 0 ) + { + printf( "\n\rWrite a number and press ENTER or SPACE!\n\r" ) ; + return 0 ; + } + else + { + printf( "\n\r" ) ; + *pdwValue=dwValue ; + + return 1 ; + } + } + else + { + printf( "\n\r'%c' not a number!\n\r", ucKey ) ; + + return 0 ; + } + } + WDT_Restart(WDT); + } +} + +/** + * Reads an integer and check the value + * + * \param pdwValue Pointer to the uint32_t variable to contain the input value. + * \param dwMin Minimum value + * \param dwMax Maximum value + */ +extern uint32_t UART_GetIntegerMinMax( uint32_t* pdwValue, uint32_t dwMin, uint32_t dwMax ) +{ + uint32_t dwValue=0 ; + + if ( UART_GetInteger( &dwValue ) == 0 ) + { + return 0 ; + } + + if ( dwValue < dwMin || dwValue > dwMax ) + { + printf( "\n\rThe number have to be between %d and %d\n\r", (int)dwMin, (int)dwMax ) ; + + return 0 ; + } + + printf( "\n\r" ) ; + + *pdwValue = dwValue ; + + return 1 ; +} + +/** + * Reads an hexadecimal number + * + * \param pdwValue Pointer to the uint32_t variable to contain the input value. + */ +extern uint32_t UART_GetHexa32( uint32_t* pdwValue ) +{ + uint8_t ucKey ; + uint32_t dw = 0 ; + uint32_t dwValue = 0 ; + + for ( dw=0 ; dw < 8 ; dw++ ) + { + ucKey = UART_GetChar() ; + UART_PutChar( ucKey ) ; + + if ( ucKey >= '0' && ucKey <= '9' ) + { + dwValue = (dwValue * 16) + (ucKey - '0') ; + } + else + { + if ( ucKey >= 'A' && ucKey <= 'F' ) + { + dwValue = (dwValue * 16) + (ucKey - 'A' + 10) ; + } + else + { + if ( ucKey >= 'a' && ucKey <= 'f' ) + { + dwValue = (dwValue * 16) + (ucKey - 'a' + 10) ; + } + else + { + printf( "\n\rIt is not a hexa character!\n\r" ) ; + + return 0 ; + } + } + } + } + + printf("\n\r" ) ; + *pdwValue = dwValue ; + + return 1 ; +} + +#if defined __ICCARM__ /* IAR Ewarm 5.41+ */ +/** + * \brief Outputs a character on the UART. + * + * \param c Character to output. + * + * \return The character that was output. + */ +extern WEAK signed int putchar( signed int c ) +{ + UART_PutChar( c ) ; + + return c ; +} +#endif // defined __ICCARM__ +