diff options
Diffstat (limited to 'peripherals')
117 files changed, 23111 insertions, 0 deletions
diff --git a/peripherals/ac97c/ac97c.c b/peripherals/ac97c/ac97c.c new file mode 100644 index 0000000..bfc3883 --- /dev/null +++ b/peripherals/ac97c/ac97c.c @@ -0,0 +1,692 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "ac97c.h"
+#include <board.h>
+#include <irq/irq.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+#include <utility/math.h>
+
+//------------------------------------------------------------------------------
+// Local constants
+//------------------------------------------------------------------------------
+
+/// Maximum size of one PDC buffer (in bytes).
+#define MAX_PDC_COUNTER 65535
+
+//------------------------------------------------------------------------------
+// Local types
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// AC97 transfer descriptor. Tracks the status and parameters of a transfer
+/// on the AC97 bus.
+//------------------------------------------------------------------------------
+typedef struct _Ac97Transfer {
+
+ /// Buffer containing the slots to send.
+ unsigned char *pBuffer;
+ /// Total number of samples to send.
+ volatile unsigned int numSamples;
+ /// Optional callback function.
+ Ac97Callback callback;
+ /// Optional argument to the callback function.
+ void *pArg;
+
+} Ac97Transfer;
+
+//------------------------------------------------------------------------------
+/// AC97 controller driver structure. Monitors the status of transfers on all
+/// AC97 channels.
+//------------------------------------------------------------------------------
+typedef struct _Ac97c {
+
+ /// List of transfers occuring on each channel.
+ Ac97Transfer transfers[5];
+} Ac97c;
+
+//------------------------------------------------------------------------------
+// Local variables
+//------------------------------------------------------------------------------
+
+/// Global AC97 controller instance.
+static Ac97c ac97c;
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Returns the size of one sample (in bytes) on the given channel.
+/// \param channel Channel number.
+//------------------------------------------------------------------------------
+static unsigned char GetSampleSize(unsigned char channel)
+{
+ unsigned int size = 0;
+
+ SANITY_CHECK((channel == AC97C_CHANNEL_A)
+ || (channel == AC97C_CHANNEL_B)
+ || (channel == AC97C_CHANNEL_CODEC));
+
+ // Check selected channel
+ switch (channel) {
+ case AC97C_CHANNEL_CODEC: return 2;
+
+ case AC97C_CHANNEL_A:
+ size = (AT91C_BASE_AC97C->AC97C_CAMR & AT91C_AC97C_SIZE) >> 16;
+ break;
+
+ case AC97C_CHANNEL_B:
+ size = (AT91C_BASE_AC97C->AC97C_CBMR & AT91C_AC97C_SIZE) >> 16;
+ break;
+ }
+
+ // Compute size in bytes given SIZE field
+ if ((size & 2) != 0) {
+
+ return 2;
+ }
+ else {
+
+ return 4;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Interrupt service routine for Codec, is invoked by AC97C_Handler.
+//------------------------------------------------------------------------------
+static void CodecHandler(void)
+{
+ unsigned int status;
+ unsigned int data;
+ Ac97Transfer *pTransfer = &(ac97c.transfers[AC97C_CODEC_TRANSFER]);
+
+ // Read CODEC status register
+ status = AT91C_BASE_AC97C->AC97C_COSR;
+ status &= AT91C_BASE_AC97C->AC97C_COMR;
+
+ // A sample has been transmitted
+ if (status & AT91C_AC97C_TXRDY) {
+
+ pTransfer->numSamples--;
+
+ // If there are remaining samples, transmit one
+ if (pTransfer->numSamples > 0) {
+
+ data = *((unsigned int *) pTransfer->pBuffer);
+ AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_TXRDY);
+ AT91C_BASE_AC97C->AC97C_COTHR = data;
+
+ // Check if transfer is read or write
+ if ((data & AT91C_AC97C_READ) != 0) {
+
+ AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;
+ }
+ else {
+
+ pTransfer->pBuffer += sizeof(unsigned int);
+ AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;
+ }
+ }
+ // Transfer finished
+ else {
+
+ AT91C_BASE_AC97C->AC97C_IDR = AT91C_AC97C_COEVT;
+ AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_TXRDY);
+ if (pTransfer->callback) {
+
+ pTransfer->callback(pTransfer->pArg, 0, 0);
+ }
+ }
+ }
+
+ // A sample has been received
+ if (status & AT91C_AC97C_RXRDY) {
+
+ // Store sample
+ data = AT91C_BASE_AC97C->AC97C_CORHR;
+ *((unsigned int *) pTransfer->pBuffer) = data;
+
+ pTransfer->pBuffer += sizeof(unsigned int);
+ pTransfer->numSamples--;
+
+ // Transfer finished
+ if (pTransfer->numSamples > 0) {
+
+ data = *((unsigned int *) pTransfer->pBuffer);
+ AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_RXRDY);
+ AT91C_BASE_AC97C->AC97C_COTHR = data;
+
+ // Check if transfer is read or write
+ if ((data & AT91C_AC97C_READ) != 0) {
+
+ AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;
+ }
+ else {
+
+ pTransfer->pBuffer += sizeof(unsigned int);
+ AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;
+ }
+ }
+ else {
+
+ AT91C_BASE_AC97C->AC97C_IDR = AT91C_AC97C_COEVT;
+ AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_RXRDY);
+ if (pTransfer->callback) {
+
+ pTransfer->callback(pTransfer->pArg, 0, 0);
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Interrupt service routine for channel A, is invoked by AC97C_Handler.
+//------------------------------------------------------------------------------
+static void ChannelAHandler(void)
+{
+ unsigned int status;
+ Ac97Transfer *pTransmit = &(ac97c.transfers[AC97C_CHANNEL_A_TRANSMIT]);
+ Ac97Transfer *pReceive = &(ac97c.transfers[AC97C_CHANNEL_A_RECEIVE]);
+
+ // Read channel A status register
+ status = AT91C_BASE_AC97C->AC97C_CASR;
+
+ // A buffer has been transmitted
+ if ((status & AT91C_AC97C_ENDTX) != 0) {
+
+ // Update transfer information
+ if (pTransmit->numSamples > MAX_PDC_COUNTER) {
+
+ pTransmit->numSamples -= MAX_PDC_COUNTER;
+ }
+ else {
+
+ pTransmit->numSamples = 0;
+ }
+
+ // Transmit new buffers if necessary
+ if (pTransmit->numSamples > MAX_PDC_COUNTER) {
+
+ // Fill next PDC
+ AT91C_BASE_AC97C->AC97C_TNPR = (unsigned int) pTransmit->pBuffer;
+ if (pTransmit->numSamples > 2 * MAX_PDC_COUNTER) {
+
+ AT91C_BASE_AC97C->AC97C_TNCR = MAX_PDC_COUNTER;
+ pTransmit->pBuffer += MAX_PDC_COUNTER
+ * GetSampleSize(AC97C_CHANNEL_A);
+ }
+ else {
+
+ AT91C_BASE_AC97C->AC97C_TNCR = pTransmit->numSamples
+ - MAX_PDC_COUNTER;
+ }
+ }
+ // Only one buffer remaining
+ else {
+
+ AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_ENDTX;
+ AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_TXBUFE;
+ }
+ }
+
+ // Transmit completed
+ if ((status & AT91C_AC97C_TXBUFE) != 0) {
+
+ pTransmit->numSamples = 0;
+ AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;
+ AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_TXBUFE;
+ if (pTransmit->callback) {
+
+ pTransmit->callback(pTransmit->pArg, 0, 0);
+ }
+ }
+
+ // A buffer has been received
+ if (status & AT91C_AC97C_ENDRX) {
+
+ if (pReceive->numSamples > MAX_PDC_COUNTER) {
+
+ pReceive->numSamples -= MAX_PDC_COUNTER;
+ }
+ else {
+
+ pReceive->numSamples = 0;
+ }
+
+ // Transfer remaining samples
+ if (pReceive->numSamples > MAX_PDC_COUNTER) {
+
+ AT91C_BASE_AC97C->AC97C_RNPR = (unsigned int) pReceive->pBuffer;
+ if (pReceive->numSamples > 2 * MAX_PDC_COUNTER) {
+
+ AT91C_BASE_AC97C->AC97C_RNCR = MAX_PDC_COUNTER;
+ pReceive->pBuffer += MAX_PDC_COUNTER
+ * GetSampleSize(AC97C_CHANNEL_A);
+ }
+ else {
+
+ AT91C_BASE_AC97C->AC97C_RNCR = pReceive->numSamples
+ - MAX_PDC_COUNTER;
+ }
+ }
+ // Only one buffer remaining
+ else {
+
+ AT91C_BASE_AC97C->AC97C_CAMR &= ~(AT91C_AC97C_ENDRX);
+ AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_RXBUFF;
+ }
+ }
+
+ // Receive complete
+ if ((status & AT91C_AC97C_RXBUFF) != 0) {
+
+ pReceive->numSamples = 0;
+ AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;
+ AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_RXBUFF;
+ if (pReceive->callback) {
+
+ pReceive->callback(pReceive->pArg, 0, 0);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// This handler function must be called by the AC97C interrupt service routine.
+/// Identifies which event was activated and calls the associated function.
+//------------------------------------------------------------------------------
+void AC97C_Handler(void)
+{
+ unsigned int status;
+
+ // Get the real interrupt source
+ status = AT91C_BASE_AC97C->AC97C_SR;
+ status &= AT91C_BASE_AC97C->AC97C_IMR;
+
+ // Check if an event on the codec channel is active
+ if ((status & AT91C_AC97C_COEVT) != 0) {
+
+ CodecHandler();
+ }
+ // Check if an event on channel A is active
+ if ((status & AT91C_AC97C_CAEVT) != 0) {
+
+ ChannelAHandler();
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Starts a read or write transfer on the given channel
+/// \param channel particular channel (AC97C_CODEC_TRANSFER,
+/// AC97C_CHANNEL_A_RECEIVE, AC97C_CHANNEL_A_TRANSMIT,
+/// AC97C_CHANNEL_B_RECEIVE or AC97C_CHANNEL_B_TRANSMIT).
+/// \param pBuffer buffer containing the slots to send.
+/// \param numSamples total number of samples to send.
+/// \param callback optional callback function.
+/// \param pArg optional argument to the callback function.
+//------------------------------------------------------------------------------
+unsigned char AC97C_Transfer(
+ unsigned char channel,
+ unsigned char *pBuffer,
+ unsigned int numSamples,
+ Ac97Callback callback,
+ void *pArg)
+{
+ unsigned int size;
+ unsigned int data;
+ Ac97Transfer *pTransfer;
+
+ SANITY_CHECK(channel <= 5);
+ SANITY_CHECK(pBuffer);
+ SANITY_CHECK(numSamples > 0);
+
+ // Check that no transfer is pending on the channel
+ pTransfer = &(ac97c.transfers[channel]);
+ if (pTransfer->numSamples > 0) {
+
+ TRACE_WARNING(
+ "AC97C_Transfer: Channel %d is busy\n\r", channel);
+ return AC97C_ERROR_BUSY;
+ }
+
+ // Fill transfer information
+ pTransfer->pBuffer = pBuffer;
+ pTransfer->numSamples = numSamples;
+ pTransfer->callback = callback;
+ pTransfer->pArg = pArg;
+
+ // Transmit or receive over codec channel
+ if (channel == AC97C_CODEC_TRANSFER) {
+
+ // Send command
+ data = *((unsigned int *) pTransfer->pBuffer);
+ AT91C_BASE_AC97C->AC97C_COTHR = data;
+
+ // Check if transfer is read or write
+ if ((data & AT91C_AC97C_READ) != 0) {
+
+ AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;
+ }
+ else {
+
+ pTransfer->pBuffer += sizeof(unsigned int);
+ AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;
+ }
+
+ // Enable interrupts
+ AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_COEVT;
+ }
+ // Transmit over channel A
+ else if (channel == AC97C_CHANNEL_A_TRANSMIT) {
+
+ // Disable PDC
+ AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;
+
+ // Fill PDC buffers
+ size = min(pTransfer->numSamples, MAX_PDC_COUNTER);
+ AT91C_BASE_AC97C->AC97C_TPR = (unsigned int) pTransfer->pBuffer;
+ AT91C_BASE_AC97C->AC97C_TCR = size;
+ pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
+
+ size = min(pTransfer->numSamples - size, MAX_PDC_COUNTER);
+ if (size > 0) {
+
+ AT91C_BASE_AC97C->AC97C_TNPR = (unsigned int) pTransfer->pBuffer;
+ AT91C_BASE_AC97C->AC97C_TNCR = size;
+ pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
+ }
+
+ // Enable interrupts
+ AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_PDCEN | AT91C_AC97C_ENDTX;
+ AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_CAEVT;
+
+ // Start transfer
+ AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTEN;
+ }
+ // Receive over channel A
+ else if (channel == AC97C_CHANNEL_A_RECEIVE) {
+
+ // Disable PDC
+ AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;
+
+ // Fill PDC buffers
+ size = min(pTransfer->numSamples, MAX_PDC_COUNTER);
+ AT91C_BASE_AC97C->AC97C_RPR = (unsigned int) pTransfer->pBuffer;
+ AT91C_BASE_AC97C->AC97C_RCR = size;
+ pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
+
+ size = min(pTransfer->numSamples - size, MAX_PDC_COUNTER);
+ if (size > 0) {
+
+ AT91C_BASE_AC97C->AC97C_RNPR = (unsigned int) pTransfer->pBuffer;
+ AT91C_BASE_AC97C->AC97C_RNCR = size;
+ pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
+ }
+
+ // Enable interrupts
+ AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_PDCEN | AT91C_AC97C_ENDRX;
+ AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_CAEVT;
+
+ // Start transfer
+ AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTEN;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Stop read or write transfer on the given channel.
+/// \param channel Channel number.
+//------------------------------------------------------------------------------
+void AC97C_CancelTransfer(unsigned char channel)
+{
+ unsigned int size = 0;
+ Ac97Transfer *pTransfer;
+
+ SANITY_CHECK(channel <= AC97C_CHANNEL_B_TRANSMIT);
+
+ // Save remaining size
+ pTransfer = &(ac97c.transfers[channel]);
+ size = pTransfer->numSamples;
+ pTransfer->numSamples = 0;
+
+ // Stop PDC
+ if (channel == AC97C_CHANNEL_A_TRANSMIT) {
+
+ AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;
+ size -= min(size, MAX_PDC_COUNTER) - AT91C_BASE_AC97C->AC97C_TCR;
+ }
+ if (channel == AC97C_CHANNEL_A_RECEIVE) {
+
+ AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;
+ size -= min(size, MAX_PDC_COUNTER) - AT91C_BASE_AC97C->AC97C_RCR;
+ }
+
+ // Invoke callback if provided
+ if (pTransfer->callback) {
+
+ pTransfer->callback(pTransfer->pArg, AC97C_ERROR_STOPPED, size);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Initializes the AC97 controller.
+//------------------------------------------------------------------------------
+void AC97C_Configure(void)
+{
+ unsigned char channel;
+
+ // Enable the AC97 controller peripheral clock
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_AC97C);
+
+ // Enable the peripheral and variable rate adjustment
+ AT91C_BASE_AC97C->AC97C_MR = AT91C_AC97C_ENA | AT91C_AC97C_VRA;
+
+ // Unassigns all input & output slots
+ AC97C_AssignInputSlots(0, 0xFFFF);
+ AC97C_AssignOutputSlots(0, 0xFFFF);
+
+ // Install the AC97C interrupt handler
+ AT91C_BASE_AC97C->AC97C_IDR = 0xFFFFFFFF;
+ IRQ_ConfigureIT(AT91C_ID_AC97C, 0, AC97C_Handler);
+ IRQ_EnableIT(AT91C_ID_AC97C);
+
+ // Disable PDC transfers
+ AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS;
+
+ // Clear channel transfers
+ for (channel = 0; channel < AC97C_CHANNEL_B_TRANSMIT; channel++) {
+
+ ac97c.transfers[channel].numSamples = 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Configures the desired channel with the given value.
+/// \param channel Channel number.
+/// \param cfg Configuration value.
+//------------------------------------------------------------------------------
+void AC97C_ConfigureChannel(unsigned char channel, unsigned int cfg)
+{
+ SANITY_CHECK((channel == AC97C_CHANNEL_A) || (channel == AC97C_CHANNEL_B));
+
+ if (channel == AC97C_CHANNEL_A) {
+
+ AT91C_BASE_AC97C->AC97C_CAMR = cfg;
+ }
+ else {
+
+ AT91C_BASE_AC97C->AC97C_CBMR = cfg;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Assigns the desired input slots to a particular channel.
+/// \param channel Channel number (or 0 to unassign slots).
+/// \param slots Bitfield value of slots to assign.
+//------------------------------------------------------------------------------
+void AC97C_AssignInputSlots(unsigned char channel, unsigned int slots)
+{
+ unsigned int value;
+ unsigned int i;
+
+ SANITY_CHECK(channel <= AC97C_CHANNEL_B);
+
+ // Assign all slots
+ slots >>= 3;
+ for (i = 3; i < 15; i++) {
+
+ // Check if slots is selected
+ if (slots & 1) {
+
+ value = AT91C_BASE_AC97C->AC97C_ICA;
+ value &= ~(0x07 << ((i - 3) * 3));
+ value |= channel << ((i - 3) * 3);
+ AT91C_BASE_AC97C->AC97C_ICA = value;
+ }
+ slots >>= 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Assigns the desired output slots to a particular channel.
+/// \param channel Channel number (or 0 to unassign slots).
+/// \param slots Bitfield value of slots to assign.
+//------------------------------------------------------------------------------
+void AC97C_AssignOutputSlots(unsigned char channel, unsigned int slots)
+{
+ unsigned int value;
+ unsigned int i;
+
+ SANITY_CHECK(channel <= AC97C_CHANNEL_B);
+
+ // Assign all slots
+ slots >>= 3;
+ for (i = 3; i < 15; i++) {
+
+ // Check if slots is selected
+ if (slots & 1) {
+
+ value = AT91C_BASE_AC97C->AC97C_OCA;
+ value &= ~(0x07 << ((i - 3) * 3));
+ value |= channel << ((i - 3) * 3);
+ AT91C_BASE_AC97C->AC97C_OCA = value;
+ }
+ slots >>= 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if no transfer is currently pending on the given channel;
+/// otherwise, returns 0.
+/// \param channel Channel number.
+//------------------------------------------------------------------------------
+unsigned char AC97C_IsFinished(unsigned char channel)
+{
+ SANITY_CHECK(channel <= AC97C_CHANNEL_B_TRANSMIT);
+
+ if (ac97c.transfers[channel].numSamples > 0) {
+
+ return 0;
+ }
+ else {
+
+ return 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Convenience function for synchronously sending commands to the codec.
+/// \param address Register address.
+/// \param data Command data.
+//------------------------------------------------------------------------------
+void AC97C_WriteCodec(unsigned char address, unsigned short data)
+{
+ unsigned int sample;
+
+ sample = (address << 16) | data;
+ AC97C_Transfer(AC97C_CODEC_TRANSFER, (unsigned char *) &sample, 1, 0, 0);
+ while (!AC97C_IsFinished(AC97C_CODEC_TRANSFER));
+}
+
+//------------------------------------------------------------------------------
+/// Convenience function for receiving data from the AC97 codec.
+/// \param address Register address.
+//------------------------------------------------------------------------------
+unsigned short AC97C_ReadCodec(unsigned char address)
+{
+ unsigned int sample;
+
+ sample = AT91C_AC97C_READ | (address << 16);
+ AC97C_Transfer(AC97C_CODEC_TRANSFER, (unsigned char *) &sample, 1, 0, 0);
+ while (!AC97C_IsFinished(AC97C_CODEC_TRANSFER));
+
+ return sample;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the size in bits of one sample on the given channel.
+/// \param channel Channel number.
+/// \param size Size of one sample in bits (10, 16, 18 or 24).
+//------------------------------------------------------------------------------
+void AC97C_SetChannelSize(unsigned char channel, unsigned char size)
+{
+ unsigned int bits = 0;
+
+ SANITY_CHECK((size == 10) || (size == 16) || (size == 18) || (size == 24));
+ SANITY_CHECK((channel == AC97C_CHANNEL_A) || (channel == AC97C_CHANNEL_B));
+
+ switch (size) {
+
+ case 10 : bits = AT91C_AC97C_SIZE_10_BITS; break;
+ case 16 : bits = AT91C_AC97C_SIZE_16_BITS; break;
+ case 18 : bits = AT91C_AC97C_SIZE_18_BITS; break;
+ case 20 : bits = AT91C_AC97C_SIZE_20_BITS; break;
+ }
+
+ if (channel == AC97C_CHANNEL_A) {
+
+ AT91C_BASE_AC97C->AC97C_CAMR &= ~(AT91C_AC97C_SIZE);
+ AT91C_BASE_AC97C->AC97C_CAMR |= bits;
+ }
+ else {
+
+ AT91C_BASE_AC97C->AC97C_CBMR &= ~(AT91C_AC97C_SIZE);
+ AT91C_BASE_AC97C->AC97C_CBMR |= bits;
+ }
+}
+
diff --git a/peripherals/ac97c/ac97c.dir b/peripherals/ac97c/ac97c.dir new file mode 100644 index 0000000..ac7e2de --- /dev/null +++ b/peripherals/ac97c/ac97c.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// This directory contains an API for configuring the Peripheral AC'97
+/// controller (AC97C).
+//------------------------------------------------------------------------------
\ No newline at end of file diff --git a/peripherals/ac97c/ac97c.h b/peripherals/ac97c/ac97c.h new file mode 100644 index 0000000..1dbb1a8 --- /dev/null +++ b/peripherals/ac97c/ac97c.h @@ -0,0 +1,168 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !!!Purpose
+///
+/// This module provides definitions and functions for using the AC'97
+/// controller (AC97C).
+///
+/// !!!Usage
+///
+/// -# Enable the AC'97 interface pins (see pio & board.h).
+/// -# Configure the AC'97 controller using AC97C_Configure
+/// -# Assign the input and output slots to channels, and the data size used to
+/// transfer AC97 data stream.
+/// - Three functions can be used:
+/// - AC97C_AssignInputSlots: set slots for AC'97 data in, recording.
+/// - AC97C_AssignOutputSlots: set slots for AC'97 data out, playing.
+/// - AC97C_SetChannelSize: set data sizes in bits for AC'97 data stream.
+/// - Three different channels can be configured:
+/// - AC97C_CHANNEL_CODEC: AC'97 register access channel, its size is
+/// fixed and #must not# change by AC97C_SetChannelSize
+/// - AC97C_CHANNEL_A: AC'97 stream channel, with PDC support.
+/// - AC97C_CHANNEL_B: AC'97 data channel, without PDC support.
+/// -# Configure the used AC97 channel with AC97C_ConfigureChannel, to enable
+/// the channel.
+/// -# Then you can operate the connected AC'97 codec:
+/// - AC97C_ReadCodec / AC97C_WriteCodec: Read / Write codec register.
+/// - AC97C_Transfer: Transfer through AC97C channels to setup codec register
+/// or transfer %audio data stream.
+/// - AC97C_CODEC_TRANSFER: access the codec register.
+/// - AC97C_CHANNEL_A_RECEIVE, AC97C_CHANNEL_B_RECEIVE: start reading.
+/// - AC97C_CHANNEL_A_TRANSMIT, AC97C_CHANNEL_B_TRANSMIT: start writing.
+/// Normally you can initialize a set of AC'97 codec registers to initialize
+/// the codec for %audio playing and recording.
+/// -# Example code for playing & recording:
+/// - General process:
+/// -# Configure the codec registers for the %audio settings and formats;
+/// -# Setup the channel size if necessery;
+/// -# Start %audio stream transfer.
+/// - Audio playing sample:
+/// \code
+/// // Configure sample rate of codec
+/// AC97C_WriteCodec(AD1981B_PMC_DAC, expectedSampleRate);
+/// // Set channel size
+/// AC97C_SetChannelSize(AC97C_CHANNEL_A, bitsPerSample);
+/// // Start channel A transfer
+/// AC97C_Transfer(AC97C_CHANNEL_A_TRANSMIT,
+/// (unsigned char *) (pointerToAudioDataBuffer),
+/// numberOfSamplesToSend,
+/// (Ac97Callback) PlayingFinished,
+/// 0);
+/// \endcode
+/// - Audio recording sample:
+/// \code
+/// // Enable recording
+/// AC97C_WriteCodec(AD1981B_REC_SEL, 0);
+/// // Set sample rate
+/// AC97C_WriteCodec(AD1981B_PMC_ADC, 7000);
+/// // Always use 16-bits recording
+/// AC97C_SetChannelSize(AC97C_CHANNEL_A, 16);
+/// // Start recording
+/// AC97C_Transfer(AC97C_CHANNEL_A_RECEIVE,
+/// (unsigned char *) RECORD_ADDRESS,
+/// MAX_RECORD_SIZE,
+/// (Ac97Callback) RecordFinished,
+/// 0);
+/// \endcode
+//------------------------------------------------------------------------------
+
+#ifndef AC97C_H
+#define AC97C_H
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+/// The channel is already busy with a transfer.
+#define AC97C_ERROR_BUSY 1
+/// The transfer has been stopped by the user.
+#define AC97C_ERROR_STOPPED 2
+
+/// Codec channel index.
+#define AC97C_CHANNEL_CODEC 0
+/// Channel A index.
+#define AC97C_CHANNEL_A 1
+/// Channel B index.
+#define AC97C_CHANNEL_B 2
+
+/// Codec transmit/receive transfer index.
+#define AC97C_CODEC_TRANSFER 0
+/// Channel A receive transfer index.
+#define AC97C_CHANNEL_A_RECEIVE 1
+/// Channel A transmit transfer index.
+#define AC97C_CHANNEL_A_TRANSMIT 2
+/// Channel B receive transfer index.
+#define AC97C_CHANNEL_B_RECEIVE 3
+/// Channel B transmit transfer index.
+#define AC97C_CHANNEL_B_TRANSMIT 4
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// AC97C transfer callback function.
+typedef void (*Ac97Callback)(void *pArg,
+ unsigned char status,
+ unsigned int remaining);
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void AC97C_Configure();
+
+extern void AC97C_ConfigureChannel(unsigned char channel, unsigned int cfg);
+
+extern void AC97C_AssignInputSlots(unsigned char channel, unsigned int slots);
+
+extern void AC97C_AssignOutputSlots(unsigned char channel, unsigned int slots);
+
+extern unsigned char AC97C_Transfer(
+ unsigned char channel,
+ unsigned char *pBuffer,
+ unsigned int numSamples,
+ Ac97Callback callback,
+ void *pArg);
+
+extern unsigned char AC97C_IsFinished(unsigned char channel);
+
+extern void AC97C_WriteCodec(unsigned char address, unsigned short data);
+
+extern unsigned short AC97C_ReadCodec(unsigned char address);
+
+extern void AC97C_SetChannelSize(unsigned char channel, unsigned char size);
+
+extern void AC97C_CancelTransfer(unsigned char channel);
+
+#endif //#ifndef AC97C_H
+
diff --git a/peripherals/adc/adc.c b/peripherals/adc/adc.c new file mode 100644 index 0000000..6e0cfac --- /dev/null +++ b/peripherals/adc/adc.c @@ -0,0 +1,346 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include <adc/adc.h>
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+//-----------------------------------------------------------------------------
+/// Configure the Mode Register of the ADC controller
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param mode value to write in mode register
+//-----------------------------------------------------------------------------
+
+//replaced with macro definition in adc.h
+
+//void ADC_CfgModeReg(AT91S_ADC *pAdc, unsigned int mode, unsigned int extmode)
+//{
+// ASSERT((mode&0xF00000C0)== 0, "ADC Bad configuration ADC MR");
+//
+// // Write to the MR register
+// pAdc->ADC_MR = mode;
+//}
+
+//------------------------------------------------------------------------------
+// Global Functions
+//------------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+/// Initialize the ADC controller
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param trgEn trigger mode, software or Hardware
+/// \param trgSel hardware trigger selection
+/// \param sleepMode sleep mode selection
+/// \param resolution resolution selection 8 bits or 10 bits
+/// \param mckClock value of MCK in Hz
+/// \param adcClock value of the ADC clock in Hz
+/// \param startupTime value of the start up time (in us) (see datasheet)
+/// \param sampleAndHoldTime (in ns)
+//-----------------------------------------------------------------------------
+void ADC_Initialize (AT91S_ADC *pAdc,
+ unsigned char idAdc,
+ unsigned char trgEn,
+ unsigned char trgSel,
+ unsigned char sleepMode,
+ unsigned char resolution,
+ unsigned int mckClock,
+ unsigned int adcClock,
+ unsigned int startupTime,
+ unsigned int sampleAndHoldTime)
+{
+ unsigned int prescal;
+ unsigned int startup;
+ unsigned int shtim;
+
+ ASSERT(startupTime<=ADC_STARTUP_TIME_MAX, "ADC Bad startupTime\n\r");
+ ASSERT(sampleAndHoldTime>=ADC_TRACK_HOLD_TIME_MIN, "ADC Bad sampleAndHoldTime\n\r");
+
+ // Example:
+ // 5 MHz operation, 20us startup time, 600ns track and hold time
+ // PRESCAL: Prescaler Rate Selection ADCClock = MCK / ( (PRESCAL+1) * 2 )
+ // PRESCAL = [MCK / (ADCClock * 2)] -1 = [48/(5*2)]-1 = 3,8
+ // PRESCAL = 4 -> 48/((4+1)*2) = 48/10 = 4.8MHz
+ // 48/((3+1)*2) = 48/8 = 6MHz
+ // Startup Time = (STARTUP+1) * 8 / ADCClock
+ // STARTUP = [(Startup Time * ADCClock)/8]-1 = [(20 10e-6 * 5000000)/8]-1 = 11,5
+ // STARTUP = 11 -> (11+1)*8/48000000 = 96/4800000 = 20us
+ //
+ // Sample & Hold Time = (SHTIM) / ADCClock
+ // SHTIM = (HoldTime * ADCClock) = (600 10e-9 * 5000000) = 3
+ // SHTIM = 3 -> (3)/4800000 = 1/1600000 = 625ns
+ prescal = (mckClock / (2*adcClock)) - 1;
+ startup = ((adcClock/1000000) * startupTime / 8) - 1;
+ shtim = (((adcClock/1000000) * sampleAndHoldTime)/1000);
+
+ ASSERT( (prescal<0x3F), "ADC Bad PRESCAL\n\r");
+ ASSERT(startup<0x7F, "ADC Bad STARTUP\n\r");
+ ASSERT(shtim<0xF, "ADC Bad SampleAndHoldTime\n\r");
+
+ TRACE_DEBUG("adcClock:%d MasterClock:%d\n\r", (mckClock/((prescal+1)*2)), mckClock);
+ TRACE_DEBUG("prescal:0x%X startup:0x%X shtim:0x%X\n\r", prescal, startup, shtim);
+
+ if( adcClock != (mckClock/((prescal+1)*2)) ) {
+ TRACE_WARNING("User and calculated adcClocks are different : user=%d calc=%d\n\r",
+ adcClock, (mckClock/((prescal+1)*2)));
+ }
+
+ // Enable peripheral clock
+ AT91C_BASE_PMC->PMC_PCER = 1 << idAdc;
+
+ // Reset the controller
+ ADC_SoftReset(pAdc);
+
+ // Write to the MR register
+ ADC_CfgModeReg( pAdc,
+ ( trgEn & AT91C_ADC_TRGEN)
+ | ( trgSel & AT91C_ADC_TRGSEL)
+ | ( resolution & AT91C_ADC_LOWRES)
+ | ( sleepMode & AT91C_ADC_SLEEP)
+ | ( (prescal<<8) & AT91C_ADC_PRESCAL)
+ | ( (startup<<16) & AT91C_ADC_STARTUP)
+ | ( (shtim<<24) & AT91C_ADC_SHTIM) );
+}
+
+//-----------------------------------------------------------------------------
+/// Return the Mode Register of the ADC controller value
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \return ADC Mode register
+//-----------------------------------------------------------------------------
+
+//replaced with macro definition in adc.h
+
+//unsigned int ADC_GetModeReg(AT91S_ADC *pAdc)
+//{
+// return pAdc->ADC_MR;
+//}
+
+//-----------------------------------------------------------------------------
+/// Enable Channel
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param channel channel to enable
+//-----------------------------------------------------------------------------
+//void ADC_EnableChannel(AT91S_ADC *pAdc, unsigned int channel)
+//{
+// ASSERT(channel < 8, "ADC Channel not exist");
+//
+// // Write to the CHER register
+// pAdc->ADC_CHER = (1 << channel);
+//}
+
+//-----------------------------------------------------------------------------
+/// Disable Channel
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param channel channel to disable
+//-----------------------------------------------------------------------------
+//void ADC_DisableChannel (AT91S_ADC *pAdc, unsigned int channel)
+//{
+// ASSERT(channel < 8, "ADC Channel not exist");
+//
+// // Write to the CHDR register
+// pAdc->ADC_CHDR = (1 << channel);
+//}
+
+//-----------------------------------------------------------------------------
+/// Return chanel status
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \return ADC Channel Status Register
+//-----------------------------------------------------------------------------
+//unsigned int ADC_GetChannelStatus(AT91S_ADC *pAdc)
+//{
+// return pAdc->ADC_CHSR;
+//}
+
+//-----------------------------------------------------------------------------
+/// Software request for a analog to digital conversion
+/// \param pAdc Pointer to an AT91S_ADC instance.
+//-----------------------------------------------------------------------------
+//void ADC_StartConversion(AT91S_ADC *pAdc)
+//{
+// pAdc->ADC_CR = AT91C_ADC_START;
+//}
+
+//-----------------------------------------------------------------------------
+/// Software reset
+/// \param pAdc Pointer to an AT91S_ADC instance.
+//-----------------------------------------------------------------------------
+//void ADC_SoftReset(AT91S_ADC *pAdc)
+//{
+// pAdc->ADC_CR = AT91C_ADC_SWRST;
+//}
+
+//-----------------------------------------------------------------------------
+/// Return the Last Converted Data
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \return Last Converted Data
+//-----------------------------------------------------------------------------
+//unsigned int ADC_GetLastConvertedData(AT91S_ADC *pAdc)
+//{
+// return pAdc->ADC_LCDR;
+//}
+
+//-----------------------------------------------------------------------------
+/// Return the Channel Converted Data
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param channel channel to get converted value
+/// \return Channel converted data of the specified channel
+//-----------------------------------------------------------------------------
+unsigned int ADC_GetConvertedData(AT91S_ADC *pAdc, unsigned int channel)
+{
+ unsigned int data=0;
+
+ ASSERT(channel < 8, "ADC channel not exist");
+
+ switch(channel) {
+ case 0: data = pAdc->ADC_CDR0; break;
+ case 1: data = pAdc->ADC_CDR1; break;
+ case 2: data = pAdc->ADC_CDR2; break;
+ case 3: data = pAdc->ADC_CDR3; break;
+ #ifdef AT91C_ADC_CDR4
+ case 4: data = pAdc->ADC_CDR4; break;
+ #endif
+ #ifdef AT91C_ADC_CDR5
+ case 5: data = pAdc->ADC_CDR5; break;
+ #endif
+ #ifdef AT91C_ADC_CDR6
+ case 6: data = pAdc->ADC_CDR6; break;
+ #endif
+ #ifdef AT91C_ADC_CDR7
+ case 7: data = pAdc->ADC_CDR7; break;
+ #endif
+ }
+ return data;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable ADC interrupt
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param flag IT to be enabled
+//-----------------------------------------------------------------------------
+//void ADC_EnableIt(AT91S_ADC *pAdc, unsigned int flag)
+//{
+// ASSERT((flag&0xFFF00000)== 0, "ADC bad interrupt IER");
+//
+// // Write to the IER register
+// pAdc->ADC_IER = flag;
+//}
+
+//-----------------------------------------------------------------------------
+/// Enable ADC Data Ready interrupt
+/// \param pAdc Pointer to an AT91S_ADC instance.
+//-----------------------------------------------------------------------------
+
+//void ADC_EnableDataReadyIt(AT91S_ADC *pAdc)
+//{
+// pAdc->ADC_IER = AT91C_ADC_DRDY;
+//}
+
+//-----------------------------------------------------------------------------
+/// Disable ADC interrupt
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param flag IT to be disabled
+//-----------------------------------------------------------------------------
+//void ADC_DisableIt(AT91S_ADC *pAdc, unsigned int flag)
+//{
+// ASSERT((flag&0xFFF00000)== 0, "ADC bad interrupt IDR");
+//
+// // Write to the IDR register
+// pAdc->ADC_IDR = flag;
+//}
+
+//-----------------------------------------------------------------------------
+/// Return ADC Interrupt Status
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \return ADC Stats register
+//-----------------------------------------------------------------------------
+//unsigned int ADC_GetStatus(AT91S_ADC *pAdc)
+//{
+// return pAdc->ADC_SR;
+//}
+
+//-----------------------------------------------------------------------------
+/// Return ADC Interrupt Mask Status
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \return ADC Interrupt Mask Register
+//-----------------------------------------------------------------------------
+//unsigned int ADC_GetInterruptMaskStatus(AT91S_ADC *pAdc)
+//{
+// return pAdc->ADC_IMR;
+//}
+
+//-----------------------------------------------------------------------------
+/// Test if ADC Interrupt is Masked
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param flag flag to be tested
+/// \return 1 if interrupt is masked, otherwise 0
+//-----------------------------------------------------------------------------
+unsigned int ADC_IsInterruptMasked(AT91S_ADC *pAdc, unsigned int flag)
+{
+ return (ADC_GetInterruptMaskStatus(pAdc) & flag);
+}
+
+//-----------------------------------------------------------------------------
+/// Test if ADC Status is Set
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param flag flag to be tested
+/// \return 1 if the staus is set; 0 otherwise
+//-----------------------------------------------------------------------------
+unsigned int ADC_IsStatusSet(AT91S_ADC *pAdc, unsigned int flag)
+{
+ return (ADC_GetStatus(pAdc) & flag);
+}
+
+
+//-----------------------------------------------------------------------------
+/// Test if ADC channel interrupt Status is Set
+/// \param adc_sr Value of SR register
+/// \param channel Channel to be tested
+/// \return 1 if interrupt status is set, otherwise 0
+//-----------------------------------------------------------------------------
+unsigned char ADC_IsChannelInterruptStatusSet(unsigned int adc_sr,
+ unsigned int channel)
+{
+ unsigned char status;
+
+ if((adc_sr & (1<<channel)) == (1<<channel)) {
+ status = 1;
+ }
+ else {
+ status = 0;
+ }
+ return status;
+}
+
+
+
+
diff --git a/peripherals/adc/adc.dir b/peripherals/adc/adc.dir new file mode 100644 index 0000000..69da9df --- /dev/null +++ b/peripherals/adc/adc.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the peripheral API for the Analog-to-Digital Converter (ADC).
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/adc/adc.h b/peripherals/adc/adc.h new file mode 100644 index 0000000..331ceae --- /dev/null +++ b/peripherals/adc/adc.h @@ -0,0 +1,145 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the Analog-to-Digital Converter (ADC) peripheral.
+///
+/// !Usage
+///
+/// -# Configurate the pins for ADC
+/// -# Initialize the ADC with ADC_Initialize().
+/// -# Select the active channel using ADC_EnableChannel()
+/// -# Start the conversion with ADC_StartConversion()
+// -# Wait the end of the conversion by polling status with ADC_GetStatus()
+// -# Finally, get the converted data using ADC_GetConvertedData()
+///
+//------------------------------------------------------------------------------
+#ifndef ADC_H
+#define ADC_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+#define ADC_CHANNEL_0 0
+#define ADC_CHANNEL_1 1
+#define ADC_CHANNEL_2 2
+#define ADC_CHANNEL_3 3
+#define ADC_CHANNEL_4 4
+#define ADC_CHANNEL_5 5
+#define ADC_CHANNEL_6 6
+#define ADC_CHANNEL_7 7
+
+//------------------------------------------------------------------------------
+// Macros function of register access
+//------------------------------------------------------------------------------
+#define ADC_CfgModeReg(pAdc, mode) { \
+ ASSERT(((mode)&0xF00000C0)== 0, "ADC Bad configuration ADC MR");\
+ (pAdc)->ADC_MR = (mode);\
+ }
+
+#define ADC_GetModeReg(pAdc) ((pAdc)->ADC_MR)
+
+#define ADC_StartConversion(pAdc) ((pAdc)->ADC_CR = AT91C_ADC_START)
+
+#define ADC_SoftReset(pAdc) ((pAdc)->ADC_CR = AT91C_ADC_SWRST)
+
+#define ADC_EnableChannel(pAdc, channel) {\
+ ASSERT(channel < 8, "ADC Channel not exist");\
+ (pAdc)->ADC_CHER = (1 << (channel));\
+ }
+
+#define ADC_DisableChannel (pAdc, channel) {\
+ ASSERT((channel) < 8, "ADC Channel not exist");\
+ (pAdc)->ADC_CHDR = (1 << (channel));\
+ }
+
+
+#define ADC_EnableIt(pAdc, mode) {\
+ ASSERT(((mode)&0xFFF00000)== 0, "ADC bad interrupt IER");\
+ (pAdc)->ADC_IER = (mode);\
+ }
+
+#define ADC_DisableIt(pAdc, mode) {\
+ ASSERT(((mode)&0xFFF00000)== 0, "ADC bad interrupt IDR");\
+ (pAdc)->ADC_IDR = (mode);\
+ }
+
+#define ADC_EnableDataReadyIt(pAdc) ((pAdc)->ADC_IER = AT91C_ADC_DRDY)
+
+#define ADC_GetStatus(pAdc) ((pAdc)->ADC_SR)
+
+#define ADC_GetChannelStatus(pAdc) ((pAdc)->ADC_CHSR)
+
+#define ADC_GetInterruptMaskStatus(pAdc) ((pAdc)->ADC_IMR)
+
+#define ADC_GetLastConvertedData(pAdc) ((pAdc)->ADC_LCDR)
+
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+extern void ADC_Initialize (AT91S_ADC *pAdc,
+ unsigned char idAdc,
+ unsigned char trgEn,
+ unsigned char trgSel,
+ unsigned char sleepMode,
+ unsigned char resolution,
+ unsigned int mckClock,
+ unsigned int adcClock,
+ unsigned int startupTime,
+ unsigned int sampleAndHoldTime);
+//extern void ADC_CfgModeReg(AT91S_ADC *pAdc, unsigned int mode);
+//extern unsigned int ADC_GetModeReg(AT91S_ADC *pAdc);
+//extern void ADC_EnableChannel(AT91S_ADC *pAdc, unsigned int channel);
+//extern void ADC_DisableChannel (AT91S_ADC *pAdc, unsigned int channel);
+//extern unsigned int ADC_GetChannelStatus(AT91S_ADC *pAdc);
+//extern void ADC_StartConversion(AT91S_ADC *pAdc);
+//extern void ADC_SoftReset(AT91S_ADC *pAdc);
+//extern unsigned int ADC_GetLastConvertedData(AT91S_ADC *pAdc);
+extern unsigned int ADC_GetConvertedData(AT91S_ADC *pAdc, unsigned int channel);
+//extern void ADC_EnableIt(AT91S_ADC *pAdc, unsigned int flag);
+//extern void ADC_EnableDataReadyIt(AT91S_ADC *pAdc);
+//extern void ADC_DisableIt(AT91S_ADC *pAdc, unsigned int flag);
+//extern unsigned int ADC_GetStatus(AT91S_ADC *pAdc);
+//extern unsigned int ADC_GetInterruptMaskStatus(AT91S_ADC *pAdc);
+extern unsigned int ADC_IsInterruptMasked(AT91S_ADC *pAdc, unsigned int flag);
+extern unsigned int ADC_IsStatusSet(AT91S_ADC *pAdc, unsigned int flag);
+extern unsigned char ADC_IsChannelInterruptStatusSet(unsigned int adc_sr,
+ unsigned int channel);
+
+#endif //#ifndef ADC_H
diff --git a/peripherals/adc/adc12.c b/peripherals/adc/adc12.c new file mode 100644 index 0000000..79024dc --- /dev/null +++ b/peripherals/adc/adc12.c @@ -0,0 +1,196 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include <adc/adc12.h>
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+
+
+//------------------------------------------------------------------------------
+// Global Functions
+//------------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+/// Initialize the ADC controller
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param trgEn trigger mode, software or Hardware
+/// \param trgSel hardware trigger selection
+/// \param sleepMode sleep mode selection
+/// \param resolution resolution selection 8 bits or 10 bits
+/// \param mckClock value of MCK in Hz
+/// \param adcClock value of the ADC clock in Hz
+/// \param startupTime value of the start up time (in us) (see datasheet)
+/// \param sampleAndHoldTime (in ns)
+//-----------------------------------------------------------------------------
+void ADC12_Initialize (AT91S_ADC12B *pAdc,
+ unsigned char idAdc,
+ unsigned char trgEn,
+ unsigned char trgSel,
+ unsigned char sleepMode,
+ unsigned char resolution,
+ unsigned int mckClock,
+ unsigned int adcClock,
+ unsigned int startupTime,
+ unsigned int sampleAndHoldTime)
+{
+ unsigned int prescal;
+ unsigned int startup;
+ unsigned int shtim;
+
+ ASSERT(startupTime<=ADC_STARTUP_TIME_MAX, "ADC Bad startupTime\n\r");
+ ASSERT(sampleAndHoldTime>=ADC_TRACK_HOLD_TIME_MIN, "ADC Bad sampleAndHoldTime\n\r");
+
+ // Example:
+ // 5 MHz operation, 20µs startup time, 600ns track and hold time
+ // PRESCAL: Prescaler Rate Selection ADCClock = MCK / ( (PRESCAL+1) * 2 )
+ // PRESCAL = [MCK / (ADCClock * 2)] -1 = [48/(5*2)]-1 = 3,8
+ // PRESCAL = 4 -> 48/((4+1)*2) = 48/10 = 4.8MHz
+ // 48/((3+1)*2) = 48/8 = 6MHz
+ // Startup Time = (STARTUP+1) * 8 / ADCClock
+ // STARTUP = [(Startup Time * ADCClock)/8]-1 = [(20 10e-6 * 5000000)/8]-1 = 11,5
+ // STARTUP = 11 -> (11+1)*8/48000000 = 96/4800000 = 20us
+ //
+ // Sample & Hold Time = (SHTIM) / ADCClock
+ // SHTIM = (HoldTime * ADCClock)-1 = (600 10e-9 * 5000000) = 3
+ // SHTIM = 3 -> (3)/4800000 = 1/1600000 = 625ns
+ prescal = (mckClock / (2*adcClock)) - 1;
+ startup = ((adcClock/1000000) * startupTime / 8) - 1;
+ shtim = (((adcClock/1000000) * sampleAndHoldTime)/1000);
+
+ ASSERT( (prescal<0x3F), "ADC12 Bad PRESCAL\n\r");
+ ASSERT(startup<0x7F, "ADC12 Bad STARTUP\n\r");
+ ASSERT(shtim<0xF, "ADC12 Bad SampleAndHoldTime\n\r");
+
+ TRACE_DEBUG("adcClock:%d MasterClock:%d\n\r", (mckClock/((prescal+1)*2)), mckClock);
+ TRACE_DEBUG("prescal:0x%X startup:0x%X shtim:0x%X\n\r", prescal, startup, shtim);
+
+ if( adcClock != (mckClock/((prescal+1)*2)) ) {
+ TRACE_WARNING("User and calculated adcClocks are different : user=%d calc=%d\n\r",
+ adcClock, (mckClock/((prescal+1)*2)));
+ }
+
+ // Enable peripheral clock
+ AT91C_BASE_PMC->PMC_PCER = 1 << idAdc;
+
+ // Reset the controller
+ ADC12_SoftReset(pAdc);
+
+ // Write to the MR register
+ ADC12_CfgModeReg( pAdc,
+ ( trgEn & AT91C_ADC12B_MR_TRGEN)
+ | ( trgSel & AT91C_ADC12B_MR_TRGSEL)
+ | ( resolution & AT91C_ADC12B_MR_LOWRES)
+ | ( sleepMode & AT91C_ADC12B_MR_SLEEP)
+ | ( (prescal<<8) & AT91C_ADC12B_MR_PRESCAL)
+ | ( (startup<<16) & AT91C_ADC12B_MR_STARTUP)
+ | ( (shtim<<24) & AT91C_ADC12B_MR_SHTIM) );
+}
+
+
+//-----------------------------------------------------------------------------
+/// Return the Channel Converted Data
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param channel channel to get converted value
+/// \return Channel converted data of the specified channel
+//-----------------------------------------------------------------------------
+unsigned int ADC12_GetConvertedData(AT91S_ADC12B *pAdc, unsigned int channel)
+{
+ unsigned int data=0;
+
+ ASSERT(channel < 8, "ADC channel %u not exist", channel);
+
+ switch(channel) {
+ case 0: data = pAdc->ADC12B_CDR[0]; break;
+ case 1: data = pAdc->ADC12B_CDR[1]; break;
+ case 2: data = pAdc->ADC12B_CDR[2]; break;
+ case 3: data = pAdc->ADC12B_CDR[3]; break;
+ case 4: data = pAdc->ADC12B_CDR[4]; break;
+ case 5: data = pAdc->ADC12B_CDR[5]; break;
+ case 6: data = pAdc->ADC12B_CDR[6]; break;
+ case 7: data = pAdc->ADC12B_CDR[7]; break;
+ default: printf("\n\r Channel is not available!\n\r");
+
+ }
+ return data;
+}
+
+
+//-----------------------------------------------------------------------------
+/// Test if ADC Interrupt is Masked
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param flag flag to be tested
+/// \return 1 if interrupt is masked, otherwise 0
+//-----------------------------------------------------------------------------
+unsigned int ADC12_IsInterruptMasked(AT91S_ADC12B *pAdc, unsigned int flag)
+{
+ return (ADC12_GetInterruptMaskStatus(pAdc) & flag);
+}
+
+//-----------------------------------------------------------------------------
+/// Test if ADC Status is Set
+/// \param pAdc Pointer to an AT91S_ADC instance.
+/// \param flag flag to be tested
+/// \return 1 if the staus is set; 0 otherwise
+//-----------------------------------------------------------------------------
+unsigned int ADC12_IsStatusSet(AT91S_ADC12B *pAdc, unsigned int flag)
+{
+ return (ADC12_GetStatus(pAdc) & flag);
+}
+
+
+//-----------------------------------------------------------------------------
+/// Test if ADC channel interrupt Status is Set
+/// \param adc_sr Value of SR register
+/// \param channel Channel to be tested
+/// \return 1 if interrupt status is set, otherwise 0
+//-----------------------------------------------------------------------------
+unsigned char ADC12_IsChannelInterruptStatusSet(unsigned int adc_sr,
+ unsigned int channel)
+{
+ unsigned char status;
+
+ if((adc_sr & (1<<channel)) == (1<<channel)) {
+ status = 1;
+ }
+ else {
+ status = 0;
+ }
+ return status;
+}
+
+
+
+
+
diff --git a/peripherals/adc/adc12.h b/peripherals/adc/adc12.h new file mode 100644 index 0000000..5a854aa --- /dev/null +++ b/peripherals/adc/adc12.h @@ -0,0 +1,142 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the Analog-to-Digital Converter (ADC) peripheral.
+///
+/// !Usage
+///
+/// -# Configurate the pins for ADC
+/// -# Initialize the ADC with ADC_Initialize().
+/// -# Select the active channel using ADC_EnableChannel()
+/// -# Start the conversion with ADC_StartConversion()
+// -# Wait the end of the conversion by polling status with ADC_GetStatus()
+// -# Finally, get the converted data using ADC_GetConvertedData()
+///
+//------------------------------------------------------------------------------
+#ifndef ADC12_H
+#define ADC12_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+#define ADC12_CHANNEL_0 0
+#define ADC12_CHANNEL_1 1
+#define ADC12_CHANNEL_2 2
+#define ADC12_CHANNEL_3 3
+#define ADC12_CHANNEL_4 4
+#define ADC12_CHANNEL_5 5
+#define ADC12_CHANNEL_6 6
+#define ADC12_CHANNEL_7 7
+
+//------------------------------------------------------------------------------
+// Macros function of register access
+//------------------------------------------------------------------------------
+#define ADC12_CfgModeReg(pAdc, mode) { \
+ ASSERT(((mode)&0xF00000C0)== 0, "ADC Bad configuration ADC MR");\
+ (pAdc)->ADC12B_MR = (mode);\
+ }
+
+#define ADC12_GetModeReg(pAdc) ((pAdc)->ADC12B_MR)
+
+#define ADC12_StartConversion(pAdc) ((pAdc)->ADC12B_CR = AT91C_ADC_START)
+
+#define ADC12_SoftReset(pAdc) ((pAdc)->ADC12B_CR = AT91C_ADC_SWRST)
+
+#define ADC12_EnableChannel(pAdc, channel) {\
+ ASSERT(channel < 8, "ADC Channel not exist");\
+ (pAdc)->ADC12B_CHER = (1 << (channel));\
+ }
+
+#define ADC12_DisableChannel (pAdc, channel) {\
+ ASSERT((channel) < 8, "ADC Channel not exist");\
+ (pAdc)->ADC12B_CHDR = (1 << (channel));\
+ }
+
+#define ADC12_EnableIt(pAdc, mode) {\
+ ASSERT(((mode)&0xFFF00000)== 0, "ADC bad interrupt IER");\
+ (pAdc)->ADC12B_IER = (mode);\
+ }
+
+#define ADC12_DisableIt(pAdc, mode) {\
+ ASSERT(((mode)&0xFFF00000)== 0, "ADC bad interrupt IDR");\
+ (pAdc)->ADC12B_IDR = (mode);\
+ }
+
+#define ADC12_EnableDataReadyIt(pAdc) ((pAdc)->ADC12B_IER = AT91C_ADC_DRDY)
+
+#define ADC12_GetStatus(pAdc) ((pAdc)->ADC12B_SR)
+
+#define ADC12_GetChannelStatus(pAdc) ((pAdc)->ADC12B_CHSR)
+
+#define ADC12_GetInterruptMaskStatus(pAdc) ((pAdc)->ADC12B_IMR)
+
+#define ADC12_GetLastConvertedData(pAdc) ((pAdc)->ADC12B_LCDR)
+
+#define ADC12_CfgAnalogCtrlReg(pAdc,mode) {\
+ ASSERT(((mode) & 0xFFFCFF3C)==0, "ADC bad analog control config");\
+ (pAdc)->ADC12B_ACR = (mode);\
+ }
+
+#define ADC12_CfgExtModeReg(pAdc, extmode) {\
+ ASSERT(((extmode) & 0xFF00FFFE)==0, "ADC bad extended mode config");\
+ (pAdc)->ADC12B_EMR = (extmode);\
+ }
+
+#define ADC12_GetAnalogCtrlReg(pAdc) ((pAdc)->ADC12B_ACR)
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+extern void ADC12_Initialize (AT91S_ADC12B *pAdc,
+ unsigned char idAdc,
+ unsigned char trgEn,
+ unsigned char trgSel,
+ unsigned char sleepMode,
+ unsigned char resolution,
+ unsigned int mckClock,
+ unsigned int adcClock,
+ unsigned int startupTime,
+ unsigned int sampleAndHoldTime);
+extern unsigned int ADC12_GetConvertedData(AT91S_ADC12B *pAdc, unsigned int channel);
+extern unsigned int ADC12_IsInterruptMasked(AT91S_ADC12B *pAdc, unsigned int flag);
+extern unsigned int ADC12_IsStatusSet(AT91S_ADC12B *pAdc, unsigned int flag);
+extern unsigned char ADC12_IsChannelInterruptStatusSet(unsigned int adc_sr,
+ unsigned int channel);
+
+#endif //#ifndef ADC12_H
diff --git a/peripherals/aes/aes_p.c b/peripherals/aes/aes_p.c new file mode 100644 index 0000000..8614643 --- /dev/null +++ b/peripherals/aes/aes_p.c @@ -0,0 +1,231 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "aes_p.h"
+#include <board.h>
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configures the AES peripheral to encrypt/decrypt, start mode (manual, auto,
+/// PDC) and operating mode (ECB, CBC, OFB, CFB, CTR).
+/// \param cipher Indicates if the peripheral should encrypt or decrypt data.
+/// \param smode Start mode.
+/// \param opmode Operating mode.
+//------------------------------------------------------------------------------
+void AES_Configure(
+ unsigned char cipher,
+ unsigned int smode,
+ unsigned int opmode)
+{
+ TRACE_DEBUG("AES_Configure()\n\r");
+ SANITY_CHECK((cipher & 0xFFFFFFFE) == 0);
+ SANITY_CHECK((smode & 0xFFFFFCFF) == 0);
+ SANITY_CHECK((opmode & 0xFFFF8FFF) == 0);
+
+ // Reset the peripheral first
+ AT91C_BASE_AES->AES_CR = AT91C_AES_SWRST;
+
+ // Configure mode register
+ AT91C_BASE_AES->AES_MR = cipher | smode | opmode;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the key used by the AES algorithm to cipher the plain text or
+/// decipher the encrypted text.
+/// \param pKey Pointer to a 16/24/32 bytes cipher key.
+//------------------------------------------------------------------------------
+void AES_SetKey(const unsigned int *pKey, unsigned char keyLength)
+{
+ TRACE_DEBUG("AES_SetKey()\n\r");
+ SANITY_CHECK(pKey);
+
+ AT91C_BASE_AES->AES_KEYWxR[0] = pKey[0];
+ AT91C_BASE_AES->AES_KEYWxR[1] = pKey[1];
+ AT91C_BASE_AES->AES_KEYWxR[2] = pKey[2];
+ AT91C_BASE_AES->AES_KEYWxR[3] = pKey[3];
+
+ if( keyLength >= 24 ) {
+ AT91C_BASE_AES->AES_KEYWxR[4] = pKey[4];
+ AT91C_BASE_AES->AES_KEYWxR[5] = pKey[5];
+ }
+ if( keyLength == 32 ) {
+ AT91C_BASE_AES->AES_KEYWxR[6] = pKey[6];
+ AT91C_BASE_AES->AES_KEYWxR[7] = pKey[7];
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the initialization vector that is used to encrypt the plain text or
+/// decrypt the cipher text in chained block modes (CBC, CFB, OFB & CTR).
+/// \param pVector Pointer to a 16-bytes initialization vector.
+//------------------------------------------------------------------------------
+void AES_SetVector(const unsigned int *pVector)
+{
+ TRACE_DEBUG("AES_SetVector()\n\r");
+ SANITY_CHECK(pVector);
+
+ AT91C_BASE_AES->AES_IVxR[0] = pVector[0];
+ AT91C_BASE_AES->AES_IVxR[1] = pVector[1];
+ AT91C_BASE_AES->AES_IVxR[2] = pVector[2];
+ AT91C_BASE_AES->AES_IVxR[3] = pVector[3];
+}
+
+//------------------------------------------------------------------------------
+/// Sets the input data of the AES algorithm (i.e. plain text in cipher mode,
+/// ciphered text in decipher mode). If auto mode is active, the encryption is
+/// started automatically after writing the last word.
+/// \param pData Pointer to the 16-bytes data to cipher/decipher.
+//------------------------------------------------------------------------------
+void AES_SetInputData(const unsigned int *pData)
+{
+ TRACE_DEBUG("AES_SetInputData()\n\r");
+ SANITY_CHECK(pData);
+
+ AT91C_BASE_AES->AES_IDATAxR[0] = pData[0];
+ AT91C_BASE_AES->AES_IDATAxR[1] = pData[1];
+ AT91C_BASE_AES->AES_IDATAxR[2] = pData[2];
+ AT91C_BASE_AES->AES_IDATAxR[3] = pData[3];
+}
+
+//------------------------------------------------------------------------------
+/// Stores the result of the last AES operation (encrypt/decrypt) in the
+/// provided buffer.
+/// \param pData Pointer to a 16-bytes buffer.
+//------------------------------------------------------------------------------
+void AES_GetOutputData(unsigned int *pData)
+{
+ TRACE_DEBUG("AES_GetOutputData()\n\r");
+ SANITY_CHECK(pData);
+
+ pData[0] = AT91C_BASE_AES->AES_ODATAxR[0];
+ pData[1] = AT91C_BASE_AES->AES_ODATAxR[1];
+ pData[2] = AT91C_BASE_AES->AES_ODATAxR[2];
+ pData[3] = AT91C_BASE_AES->AES_ODATAxR[3];
+}
+
+//------------------------------------------------------------------------------
+/// Sets the input buffer to use when in PDC mode.
+/// \param pInput Pointer to the input buffer.
+//------------------------------------------------------------------------------
+void AES_SetInputBuffer(const unsigned int *pInput, unsigned char length)
+{
+ TRACE_DEBUG("AES_SetInputBuffer()\n\r");
+ SANITY_CHECK(pInput);
+
+#ifdef AT91C_BASE_PDC_AES
+ // Transmit Pointer Register
+ AT91C_BASE_AES->AES_TPR = (unsigned int) pInput;
+ // Transmit Counter Registers
+ AT91C_BASE_AES->AES_TCR = length;
+#else
+ //Start address
+ AT91C_BASE_HDMA->HDMA_CH[0].HDMA_SADDR = (unsigned int)pInput;
+ //Width and size
+ AT91C_BASE_HDMA->HDMA_CH[0].HDMA_CTRLA = ( length
+ | AT91C_HDMA_SCSIZE_1
+ | AT91C_HDMA_DCSIZE_4
+ | AT91C_HDMA_SRC_WIDTH_WORD
+ | AT91C_HDMA_DST_WIDTH_WORD );
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Sets the output buffer to use when in PDC mode.
+/// \param pOutput Pointer to the output buffer.
+//------------------------------------------------------------------------------
+void AES_SetOutputBuffer(unsigned int *pOutput, unsigned char length)
+{
+ TRACE_DEBUG("AES_SetOutputBuffer()\n\r");
+ SANITY_CHECK(pOutput);
+
+#ifdef AT91C_BASE_PDC_AES
+ // Receive Pointer Register
+ AT91C_BASE_AES->AES_RPR = (unsigned int) pOutput;
+ // Receive Counter Registers
+ AT91C_BASE_AES->AES_RCR = length;
+#else
+ //Destination address
+ AT91C_BASE_HDMA->HDMA_CH[1].HDMA_DADDR = (unsigned int)pOutput;
+
+ //Width and size
+ AT91C_BASE_HDMA->HDMA_CH[1].HDMA_CTRLA = ( length
+ | AT91C_HDMA_SCSIZE_4
+ | AT91C_HDMA_DCSIZE_1
+ | AT91C_HDMA_SRC_WIDTH_WORD
+ | AT91C_HDMA_DST_WIDTH_WORD );
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Starts the encryption/decryption process when in manual or PDC mode. In
+/// manual mode, the key and input data must have been entered using
+/// AES_SetKey() and AES_SetInputData(). In PDC mode, the key, input & output
+/// buffer must have been set using AES_SetKey(), AES_SetInputBuffer() and
+/// AES_SetOutputBuffer().
+//------------------------------------------------------------------------------
+void AES_Start(void)
+{
+ TRACE_DEBUG("AES_Start()\n\r");
+ SANITY_CHECK(((AT91C_BASE_AES->AES_MR & AT91C_AES_SMOD) == AT91C_AES_SMOD_MANUAL)
+ || ((AT91C_BASE_AES->AES_MR & AT91C_AES_SMOD) == AT91C_AES_SMOD_PDC));
+
+ // Manual mode
+ if ((AT91C_BASE_AES->AES_MR & AT91C_AES_SMOD) == AT91C_AES_SMOD_MANUAL) {
+
+ AT91C_BASE_AES->AES_CR = AT91C_AES_START;
+ }
+ // PDC
+ else {
+
+#ifdef AT91C_BASE_PDC_AES
+ AT91C_BASE_AES->AES_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
+#else
+ //Enable DMA chanels
+ AT91C_BASE_HDMA->HDMA_CHER = (1<<0) | (1<<1);
+#endif
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns the current value of the AES interrupt status register.
+//------------------------------------------------------------------------------
+unsigned int AES_GetStatus(void)
+{
+ return AT91C_BASE_AES->AES_ISR;
+}
+
diff --git a/peripherals/aes/aes_p.h b/peripherals/aes/aes_p.h new file mode 100644 index 0000000..0e49983 --- /dev/null +++ b/peripherals/aes/aes_p.h @@ -0,0 +1,76 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef AES_H
+#define AES_H
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Methods to manage the Advanced Encryption Standard (AES)
+///
+/// !Usage
+///
+/// -# Configure AES
+/// -# Sets the key used by the AES algorithm
+/// -# Sets the input data of the AES algorithm
+/// -# Starts the encryption/decryption process
+/// -# Stores the result of the last AES operation
+///
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void AES_Configure(
+ unsigned char cipher,
+ unsigned int smode,
+ unsigned int opmode);
+
+extern void AES_SetKey(const unsigned int *pKey, unsigned char keyLength);
+
+extern void AES_SetVector(const unsigned int *pVector);
+
+extern void AES_SetInputData(const unsigned int *pData);
+
+extern void AES_GetOutputData(unsigned int *pData);
+
+extern void AES_SetInputBuffer(const unsigned int *pInput, unsigned char length);
+
+extern void AES_SetOutputBuffer(unsigned int *pOutput, unsigned char length);
+
+extern void AES_Start(void);
+
+extern unsigned int AES_GetStatus(void);
+
+#endif //#ifndef AES_H
+
diff --git a/peripherals/can/can.c b/peripherals/can/can.c new file mode 100644 index 0000000..5486fcf --- /dev/null +++ b/peripherals/can/can.c @@ -0,0 +1,1066 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include <pio/pio.h>
+#include <utility/trace.h>
+#include <irq/irq.h>
+#include "can.h"
+
+//------------------------------------------------------------------------------
+// Local definitions
+//------------------------------------------------------------------------------
+// CAN state
+#define CAN_DISABLED 0
+#define CAN_HALTED 1
+#define CAN_IDLE 2
+#define CAN_SENDING 3
+#define CAN_RECEIVING 4
+
+// MOT: Mailbox Object Type
+#define CAN_MOT_DISABLE 0 // Mailbox is disabled
+#define CAN_MOT_RECEPT 1 // Reception Mailbox
+#define CAN_MOT_RECEPT_OW 2 // Reception mailbox with overwrite
+#define CAN_MOT_TRANSMIT 3 // Transmit mailbox
+#define CAN_MOT_CONSUMER 4 // Consumer mailbox
+#define CAN_MOT_PRODUCER 5 // Producer mailbox
+
+//------------------------------------------------------------------------------
+// Local variables
+//------------------------------------------------------------------------------
+#if defined (PINS_CAN_TRANSCEIVER_TXD)
+static const Pin pins_can_transceiver_txd[] = {PINS_CAN_TRANSCEIVER_TXD};
+#endif
+#if defined (PINS_CAN_TRANSCEIVER_RXD)
+static const Pin pins_can_transceiver_rxd[] = {PINS_CAN_TRANSCEIVER_RXD};
+#endif
+static const Pin pin_can_transceiver_rs = PIN_CAN_TRANSCEIVER_RS;
+#if defined (PIN_CAN_TRANSCEIVER_RXEN)
+static const Pin pin_can_transceiver_rxen = PIN_CAN_TRANSCEIVER_RXEN;
+#endif
+
+static CanTransfer *pCAN0Transfer=NULL;
+#ifdef AT91C_BASE_CAN1
+static CanTransfer *pCAN1Transfer=NULL;
+#endif
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// CAN Error Detection
+/// \param status error type
+/// \param can_number can nulber
+//------------------------------------------------------------------------------
+static void CAN_ErrorHandling( unsigned int status, unsigned char can_number)
+{
+ if( (status&AT91C_CAN_ERRA) == AT91C_CAN_ERRA) {
+ TRACE_ERROR("(CAN) CAN is in active Error Active mode\n\r");
+ }
+ else if( (status&AT91C_CAN_ERRP) == AT91C_CAN_ERRP) {
+ TRACE_ERROR("(CAN) CAN is in Error Passive mode\n\r");
+ }
+ else if( (status&AT91C_CAN_BOFF) == AT91C_CAN_BOFF) {
+ TRACE_ERROR("(CAN) CAN is in Buff Off mode\n\r");
+ // CAN reset
+ TRACE_ERROR("(CAN) CAN%d reset\n\r", can_number);
+ // CAN Controller Disable
+ if (can_number == 0) {
+ AT91C_BASE_CAN0->CAN_MR &= ~AT91C_CAN_CANEN;
+ // CAN Controller Enable
+ AT91C_BASE_CAN0->CAN_MR |= AT91C_CAN_CANEN;
+ }
+#ifdef AT91C_BASE_CAN1
+ else if (can_number == 1) {
+ AT91C_BASE_CAN1->CAN_MR &= ~AT91C_CAN_CANEN;
+ // CAN Controller Enable
+ AT91C_BASE_CAN1->CAN_MR |= AT91C_CAN_CANEN;
+ }
+#endif
+ }
+
+ // Error for Frame dataframe
+ // CRC error
+ if( (status&AT91C_CAN_CERR) == AT91C_CAN_CERR) {
+ TRACE_ERROR("(CAN) CRC Error\n\r");
+ }
+ // Bit-stuffing error
+ else if( (status&AT91C_CAN_SERR) == AT91C_CAN_SERR) {
+ TRACE_ERROR("(CAN) Stuffing Error\n\r");
+ }
+ // Bit error
+ else if( (status&AT91C_CAN_BERR) == AT91C_CAN_BERR) {
+ TRACE_ERROR("(CAN) Bit Error\n\r");
+ }
+ // Form error
+ else if( (status&AT91C_CAN_FERR) == AT91C_CAN_FERR) {
+ TRACE_ERROR("(CAN) Form Error\n\r");
+ }
+ // Acknowledgment error
+ else if( (status&AT91C_CAN_AERR) == AT91C_CAN_AERR) {
+ TRACE_ERROR("(CAN) Acknowledgment Error\n\r");
+ }
+
+ // Error interrupt handler
+ // Represent the current status of the CAN bus and are not latched.
+ // See CAN, par. Error Interrupt Handler
+ // AT91C_CAN_WARN
+ // AT91C_CAN_ERRA
+}
+
+//------------------------------------------------------------------------------
+// Generic CAN Interrupt handler
+/// \param can_number can nulber
+//------------------------------------------------------------------------------
+static void CAN_Handler( unsigned char can_number )
+{
+ AT91PS_CAN base_can;
+ AT91PS_CAN_MB CAN_Mailbox;
+
+ unsigned int status;
+ unsigned int can_msr;
+ unsigned int* pCan_mcr;
+ unsigned int message_mode;
+ unsigned char numMailbox;
+ unsigned char state0=CAN_DISABLED;
+ unsigned char state1=CAN_DISABLED;
+
+ if( can_number == 0 ) {
+ base_can = AT91C_BASE_CAN0;
+ CAN_Mailbox = AT91C_BASE_CAN0_MB0;
+ state0 = pCAN0Transfer->state;
+ }
+#ifdef AT91C_BASE_CAN1
+ else {
+ base_can = AT91C_BASE_CAN1;
+ CAN_Mailbox = AT91C_BASE_CAN1_MB0;
+ state1 = pCAN1Transfer->state;
+ }
+#endif
+ status = (base_can->CAN_SR) & (base_can->CAN_IMR);
+ base_can->CAN_IDR = status;
+
+ TRACE_DEBUG("CAN0 status=0x%X\n\r", status);
+ if(status & AT91C_CAN_WAKEUP) {
+ if( can_number == 0 ) {
+ pCAN0Transfer->test_can = AT91C_TEST_OK;
+ pCAN0Transfer->state = CAN_IDLE;
+ }
+#ifdef AT91C_BASE_CAN1
+ else {
+ pCAN1Transfer->test_can = AT91C_TEST_OK;
+ pCAN1Transfer->state = CAN_IDLE;
+ }
+#endif
+ }
+ // Mailbox event ?
+ else if ((status&0x0000FFFF) != 0) {
+ TRACE_DEBUG("Mailbox event\n\r");
+
+ // Handle Mailbox interrupts
+ for (numMailbox = 0; numMailbox < NUM_MAILBOX_MAX; numMailbox++) {
+
+ can_msr = *(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x10+(0x20*numMailbox)));
+ if ((AT91C_CAN_MRDY & can_msr) == AT91C_CAN_MRDY) {
+ // Mailbox object type
+ message_mode = ((*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x00+(0x20*numMailbox))))>>24)&0x7;
+ TRACE_DEBUG("message_mode 0x%X\n\r", message_mode);
+ TRACE_DEBUG("numMailbox 0x%X\n\r", numMailbox);
+
+ if( message_mode == 0 ) {
+ TRACE_ERROR("Error in MOT\n\r");
+ }
+ else if( ( message_mode == CAN_MOT_RECEPT )
+ || ( message_mode == CAN_MOT_RECEPT_OW )
+ || ( message_mode == CAN_MOT_PRODUCER ) ) {
+ TRACE_DEBUG("Mailbox is in RECEPTION\n\r");
+ TRACE_DEBUG("Length 0x%X\n\r", (can_msr>>16)&0xF);
+ TRACE_DEBUG("CAN_MB_MID 0x%X\n\r", ((*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x08+(0x20*numMailbox)))&AT91C_CAN_MIDvA)>>18));
+
+ TRACE_DEBUG("can_number %d\n\r", can_number);
+ if( can_number == 0 ) {
+ //CAN_MB_MDLx
+ pCAN0Transfer->data_low_reg =
+ (*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x14+(0x20*numMailbox))));
+ //CAN_MB_MDHx
+ pCAN0Transfer->data_high_reg =
+ (*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x18+(0x20*numMailbox))));
+ pCAN0Transfer->size = (can_msr>>16)&0xF;
+ pCAN0Transfer->mailbox_number = numMailbox;
+ state0 = CAN_IDLE;
+ }
+#ifdef AT91C_BASE_CAN1
+ else {
+ //CAN_MB_MDLx
+ pCAN1Transfer->data_low_reg =
+ (*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x14+(0x20*numMailbox))));
+ //CAN_MB_MDHx
+ pCAN1Transfer->data_high_reg =
+ (*(unsigned int*)((unsigned int)CAN_Mailbox+(unsigned int)(0x18+(0x20*numMailbox))));
+ pCAN1Transfer->size = (can_msr>>16)&0xF;
+ pCAN1Transfer->mailbox_number = numMailbox;
+ state1 = CAN_IDLE;
+ }
+#endif
+ // Message Data has been received
+ pCan_mcr = (unsigned int*)((unsigned int)CAN_Mailbox+0x1C+(0x20*numMailbox));
+ *pCan_mcr = AT91C_CAN_MTCR;
+
+ }
+ else {
+ TRACE_DEBUG("Mailbox is in TRANSMIT\n\r");
+ TRACE_DEBUG("Length 0x%X\n\r", (can_msr>>16)&0xF);
+ TRACE_DEBUG("can_number %d\n\r", can_number);
+ if( can_number == 0 ) {
+ state0 = CAN_IDLE;
+ }
+ else {
+ state1 = CAN_IDLE;
+ }
+ }
+ }
+ }
+ if( can_number == 0 ) {
+ pCAN0Transfer->state = state0;
+ }
+#ifdef AT91C_BASE_CAN1
+ else {
+ pCAN1Transfer->state = state1;
+ }
+#endif
+ }
+ if ((status&0xFFCF0000) != 0) {
+ CAN_ErrorHandling(status, 0);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// CAN 0 Interrupt handler
+//------------------------------------------------------------------------------
+static void CAN0_Handler(void)
+{
+ CAN_Handler( 0 );
+}
+
+//------------------------------------------------------------------------------
+/// CAN 1 Interrupt handler
+//------------------------------------------------------------------------------
+#if defined AT91C_BASE_CAN1
+static void CAN1_Handler(void)
+{
+ CAN_Handler( 1 );
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configure the corresponding mailbox
+/// \param pTransfer can transfer structure
+//------------------------------------------------------------------------------
+void CAN_InitMailboxRegisters( CanTransfer *pTransfer )
+{
+ AT91PS_CAN base_can;
+ AT91PS_CAN_MB CAN_Mailbox;
+
+ if( pTransfer->can_number == 0 ) {
+ base_can = AT91C_BASE_CAN0;
+ CAN_Mailbox = AT91C_BASE_CAN0_MB0;
+ }
+#ifdef AT91C_BASE_CAN1
+ else {
+ base_can = AT91C_BASE_CAN1;
+ CAN_Mailbox = AT91C_BASE_CAN1_MB0;
+ }
+#endif
+ CAN_Mailbox = (AT91PS_CAN_MB)((unsigned int)CAN_Mailbox+(unsigned int)(0x20*pTransfer->mailbox_number));
+
+ pTransfer->mailbox_in_use |= 1<<(pTransfer->mailbox_number);
+ // MailBox Control Register
+ CAN_Mailbox->CAN_MB_MCR = 0x0;
+ // MailBox Mode Register
+ CAN_Mailbox->CAN_MB_MMR = 0x00;
+ // CAN Message Acceptance Mask Register
+ CAN_Mailbox->CAN_MB_MAM = pTransfer->acceptance_mask_reg;
+ // MailBox ID Register
+ // Disable the mailbox before writing to CAN_MIDx registers
+ if( (pTransfer->identifier & AT91C_CAN_MIDE) == AT91C_CAN_MIDE ) {
+ // Extended
+ CAN_Mailbox->CAN_MB_MAM |= AT91C_CAN_MIDE;
+ }
+ else {
+ CAN_Mailbox->CAN_MB_MAM &= ~AT91C_CAN_MIDE;
+ }
+ CAN_Mailbox->CAN_MB_MID = pTransfer->identifier;
+
+ // MailBox Mode Register
+ CAN_Mailbox->CAN_MB_MMR = pTransfer->mode_reg;
+ // MailBox Data Low Register
+ CAN_Mailbox->CAN_MB_MDL = pTransfer->data_low_reg;
+ // MailBox Data High Register
+ CAN_Mailbox->CAN_MB_MDH = pTransfer->data_high_reg;
+ // MailBox Control Register
+ CAN_Mailbox->CAN_MB_MCR = pTransfer->control_reg;
+}
+
+//------------------------------------------------------------------------------
+/// Reset the MBx
+//------------------------------------------------------------------------------
+void CAN_ResetAllMailbox( void )
+{
+ unsigned char i;
+
+#if defined (AT91C_BASE_CAN0_MB0)
+ CAN_ResetTransfer( pCAN0Transfer );
+ for( i=0; i<8; i++ ) {
+ pCAN0Transfer->can_number = 0;
+ pCAN0Transfer->mailbox_number = i;
+ pCAN0Transfer->mode_reg = AT91C_CAN_MOT_DIS;
+ pCAN0Transfer->acceptance_mask_reg = 0;
+ pCAN0Transfer->identifier = 0;
+ pCAN0Transfer->data_low_reg = 0x00000000;
+ pCAN0Transfer->data_high_reg = 0x00000000;
+ pCAN0Transfer->control_reg = 0x00000000;
+ CAN_InitMailboxRegisters( pCAN0Transfer );
+ }
+#endif
+#if defined (AT91C_BASE_CAN0_MB8)
+ for( i=0; i<8; i++ ) {
+ pCAN0Transfer->can_number = 0;
+ pCAN0Transfer->mailbox_number = i+8;
+ pCAN0Transfer->mode_reg = AT91C_CAN_MOT_DIS;
+ pCAN0Transfer->acceptance_mask_reg = 0;
+ pCAN0Transfer->identifier = 0;
+ pCAN0Transfer->data_low_reg = 0x00000000;
+ pCAN0Transfer->data_high_reg = 0x00000000;
+ pCAN0Transfer->control_reg = 0x00000000;
+ CAN_InitMailboxRegisters( pCAN0Transfer );
+ }
+#endif
+
+#if defined (AT91C_BASE_CAN1_MB0)
+ if( pCAN1Transfer != NULL ) {
+ CAN_ResetTransfer( pCAN1Transfer );
+ for( i=0; i<8; i++ ) {
+ pCAN1Transfer->can_number = 1;
+ pCAN1Transfer->mailbox_number = i;
+ pCAN1Transfer->mode_reg = AT91C_CAN_MOT_DIS;
+ pCAN1Transfer->acceptance_mask_reg = 0;
+ pCAN1Transfer->identifier = 0;
+ pCAN1Transfer->data_low_reg = 0x00000000;
+ pCAN1Transfer->data_high_reg = 0x00000000;
+ pCAN1Transfer->control_reg = 0x00000000;
+ CAN_InitMailboxRegisters( pCAN1Transfer );
+ }
+ }
+#endif
+#if defined (AT91C_BASE_CAN1_MB8)
+ if( pCAN1Transfer != NULL ) {
+ for( i=0; i<8; i++ ) {
+ pCAN1Transfer->can_number = 1;
+ pCAN1Transfer->mailbox_number = i+8;
+ pCAN1Transfer->mode_reg = AT91C_CAN_MOT_DIS;
+ pCAN1Transfer->acceptance_mask_reg = 0;
+ pCAN1Transfer->identifier = 0;
+ pCAN1Transfer->data_low_reg = 0x00000000;
+ pCAN1Transfer->data_high_reg = 0x00000000;
+ pCAN1Transfer->control_reg = 0x00000000;
+ CAN_InitMailboxRegisters( pCAN1Transfer );
+ }
+ }
+#endif
+
+}
+
+//------------------------------------------------------------------------------
+/// CAN reset Transfer descriptor
+/// \param pTransfer can transfer structure
+//------------------------------------------------------------------------------
+void CAN_ResetTransfer( CanTransfer *pTransfer )
+{
+ pTransfer->state = CAN_IDLE;
+ pTransfer->can_number = 0;
+ pTransfer->mailbox_number = 0;
+ pTransfer->test_can = 0;
+ pTransfer->mode_reg = 0;
+ pTransfer->acceptance_mask_reg = 0;
+ pTransfer->identifier = 0;
+ pTransfer->data_low_reg = 0;
+ pTransfer->data_high_reg = 0;
+ pTransfer->control_reg = 0;
+ pTransfer->mailbox_in_use = 0;
+ pTransfer->size = 0;
+}
+
+//------------------------------------------------------------------------------
+/// Wait for CAN synchronisation
+/// \return return 1 for good initialisation, otherwise return 0
+//------------------------------------------------------------------------------
+static unsigned char CAN_Synchronisation( void )
+{
+ unsigned int tick=0;
+
+ TRACE_INFO("CAN_Synchronisation\n\r");
+
+ pCAN0Transfer->test_can = AT91C_TEST_NOK;
+#ifdef AT91C_BASE_CAN1
+ if( pCAN1Transfer != NULL ) {
+ pCAN1Transfer->test_can = AT91C_TEST_NOK;
+ }
+#endif
+ // Enable CAN and Wait for WakeUp Interrupt
+ AT91C_BASE_CAN0->CAN_IER = AT91C_CAN_WAKEUP;
+ // CAN Controller Enable
+ AT91C_BASE_CAN0->CAN_MR = AT91C_CAN_CANEN;
+ // Enable Autobaud/Listen mode
+ // dangerous, CAN not answer in this mode
+
+ while( (pCAN0Transfer->test_can != AT91C_TEST_OK)
+ && (tick < AT91C_CAN_TIMEOUT) ) {
+ tick++;
+ }
+ if (tick == AT91C_CAN_TIMEOUT) {
+ TRACE_ERROR("CAN0 Initialisations FAILED\n\r");
+ return 0;
+ } else {
+ TRACE_INFO("CAN0 Initialisations Completed\n\r");
+ }
+
+#if defined AT91C_BASE_CAN1
+ if( pCAN1Transfer != NULL ) {
+ AT91C_BASE_CAN1->CAN_IER = AT91C_CAN_WAKEUP;
+ // CAN Controller Enable
+ AT91C_BASE_CAN1->CAN_MR = AT91C_CAN_CANEN;
+
+ tick = 0;
+ // Wait for WAKEUP flag raising <=> 11-recessive-bit were scanned by the transceiver
+ while( ((pCAN1Transfer->test_can != AT91C_TEST_OK))
+ && (tick < AT91C_CAN_TIMEOUT) ) {
+ tick++;
+ }
+
+ if (tick == AT91C_CAN_TIMEOUT) {
+ TRACE_ERROR("CAN1 Initialisations FAILED\n\r");
+ return 0;
+ } else {
+ TRACE_INFO("CAN1 Initialisations Completed\n\r");
+ }
+ }
+#endif
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+/// Write a CAN transfer
+/// \param pTransfer can transfer structure
+/// \return return CAN_STATUS_SUCCESS if command passed, otherwise
+/// return CAN_STATUS_LOCKED
+//------------------------------------------------------------------------------
+unsigned char CAN_Write( CanTransfer *pTransfer )
+{
+ AT91PS_CAN base_can;
+
+ if (pTransfer->state == CAN_RECEIVING) {
+ pTransfer->state = CAN_IDLE;
+ }
+
+ if (pTransfer->state != CAN_IDLE) {
+ return CAN_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG("CAN_Write\n\r");
+ pTransfer->state = CAN_SENDING;
+ if( pTransfer->can_number == 0 ) {
+ base_can = AT91C_BASE_CAN0;
+ }
+#ifdef AT91C_BASE_CAN1
+ else {
+ base_can = AT91C_BASE_CAN1;
+ }
+#endif
+ base_can->CAN_TCR = pTransfer->mailbox_in_use;
+ base_can->CAN_IER = pTransfer->mailbox_in_use;
+
+ return CAN_STATUS_SUCCESS;
+
+}
+
+
+//------------------------------------------------------------------------------
+/// Read a CAN transfer
+/// \param pTransfer can transfer structure
+/// \return return CAN_STATUS_SUCCESS if command passed, otherwise
+/// return CAN_STATUS_LOCKED
+//------------------------------------------------------------------------------
+unsigned char CAN_Read( CanTransfer *pTransfer )
+{
+ AT91PS_CAN base_can;
+
+ if (pTransfer->state != CAN_IDLE) {
+ return CAN_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG("CAN_Read\n\r");
+ pTransfer->state = CAN_RECEIVING;
+
+
+ if( pTransfer->can_number == 0 ) {
+ base_can = AT91C_BASE_CAN0;
+ }
+#ifdef AT91C_BASE_CAN1
+ else {
+ base_can = AT91C_BASE_CAN1;
+ }
+#endif
+ // enable interrupt
+ base_can->CAN_IER = pTransfer->mailbox_in_use;
+
+ return CAN_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Test if CAN is in IDLE state
+/// \param pTransfer can transfer structure
+/// \return return 0 if CAN is in IDLE, otherwise return 1
+//------------------------------------------------------------------------------
+unsigned char CAN_IsInIdle( CanTransfer *pTransfer )
+{
+ return( pTransfer->state != CAN_IDLE );
+}
+
+//------------------------------------------------------------------------------
+/// Basic CAN test without Interrupt
+//------------------------------------------------------------------------------
+void CAN_BasicTestSuiteWithoutInterrupt(void)
+{
+#if defined AT91C_BASE_CAN1
+ unsigned int status;
+ unsigned int tick=0;
+
+ TRACE_INFO("Without Interrupt ");
+ TRACE_INFO("CAN0 Mailbox 0 transmitting to CAN1 Mailbox 0\n\r");
+ // Init CAN0 Mailbox 0, transmit
+ CAN_ResetTransfer( pCAN0Transfer );
+ pCAN0Transfer->can_number = 0;
+ pCAN0Transfer->mailbox_number = 0;
+ pCAN0Transfer->mode_reg = AT91C_CAN_MOT_TX | AT91C_CAN_PRIOR;
+ pCAN0Transfer->acceptance_mask_reg = 0x00000000;
+ pCAN0Transfer->identifier = AT91C_CAN_MIDvA & (0x07<<18);
+ pCAN0Transfer->data_low_reg = 0x11223344;
+ pCAN0Transfer->data_high_reg = 0x01234567;
+ pCAN0Transfer->control_reg = (AT91C_CAN_MDLC & (0x8<<16));
+ CAN_InitMailboxRegisters( pCAN0Transfer );
+
+ // Init CAN1 Mailbox 0, receive,
+ CAN_ResetTransfer( pCAN1Transfer );
+ pCAN1Transfer->can_number = 1;
+ pCAN1Transfer->mailbox_number = 0;
+ pCAN1Transfer->mode_reg = AT91C_CAN_MOT_RX;
+ pCAN1Transfer->acceptance_mask_reg = AT91C_CAN_MIDvA | AT91C_CAN_MIDvB;
+ pCAN1Transfer->identifier = AT91C_CAN_MIDvA & (0x07<<18);
+ pCAN1Transfer->data_low_reg = 0x00000000;
+ pCAN1Transfer->data_high_reg = 0x00000000;
+ pCAN1Transfer->control_reg = 0x00000000;
+ CAN_InitMailboxRegisters( pCAN1Transfer );
+
+ // Transfer Request for Mailbox 0
+ AT91C_BASE_CAN0->CAN_TCR = AT91C_CAN_MB0;
+
+ tick = 0;
+ do {
+ // CAN Message Status Register
+ status = AT91C_BASE_CAN0_MB0->CAN_MB_MSR;
+ }
+ while( !(status & AT91C_CAN_MRDY) && (++tick < AT91C_CAN_TIMEOUT) );
+
+ if (tick == AT91C_CAN_TIMEOUT) {
+ TRACE_ERROR("Test FAILED\n\r");
+ }
+ else {
+ TRACE_DEBUG("Transfer completed: CAN1 Mailbox 0 MRDY flag has raised\n\r");
+ if( AT91C_BASE_CAN0_MB0->CAN_MB_MDL != AT91C_BASE_CAN1_MB0->CAN_MB_MDL ) {
+ TRACE_ERROR("Data Corrupted\n\r");
+ }
+ else if( AT91C_BASE_CAN0_MB0->CAN_MB_MDH != AT91C_BASE_CAN1_MB0->CAN_MB_MDH ) {
+ TRACE_ERROR("Data Corrupted\n\r");
+ }
+ else {
+ TRACE_INFO("Test passed\n\r");
+ }
+ }
+
+ CAN_ResetAllMailbox();
+
+ TRACE_INFO("Without Interrupt ");
+ TRACE_INFO("CAN0 Mailboxes 1 & 2 transmitting to CAN1 Mailbox 15\n\r");
+ // Init CAN0 Mailbox 1, transmit
+ CAN_ResetTransfer( pCAN0Transfer );
+ pCAN0Transfer->can_number = 0;
+ pCAN0Transfer->mailbox_number = 1;
+ pCAN0Transfer->mode_reg = AT91C_CAN_MOT_TX | AT91C_CAN_PRIOR;
+ pCAN0Transfer->acceptance_mask_reg = 0x00000000;
+ pCAN0Transfer->identifier = AT91C_CAN_MIDvA & (0x09<<18); // ID 9
+ pCAN0Transfer->data_low_reg = 0xAABBCCDD;
+ pCAN0Transfer->data_high_reg = 0xCAFEDECA;
+ pCAN0Transfer->control_reg = (AT91C_CAN_MDLC & (0x8<<16)); // Mailbox Data Length Code
+ CAN_InitMailboxRegisters( pCAN0Transfer );
+
+ // Init CAN0 Mailbox 2, transmit
+ pCAN0Transfer->can_number = 0;
+ pCAN0Transfer->mailbox_number = 2;
+ pCAN0Transfer->mode_reg = AT91C_CAN_MOT_TX | (AT91C_CAN_PRIOR-(1<<16));
+ pCAN0Transfer->acceptance_mask_reg = 0x00000000;
+ pCAN0Transfer->identifier = AT91C_CAN_MIDvA & (0x0A<<18); // ID 10
+ pCAN0Transfer->data_low_reg = 0x55667788;
+ pCAN0Transfer->data_high_reg = 0x99AABBCC;
+ pCAN0Transfer->control_reg = (AT91C_CAN_MDLC & (0x8<<16)); // Mailbox Data Length Code
+ CAN_InitMailboxRegisters( pCAN0Transfer );
+
+ // Init CAN1 Mailbox 15, reception with overwrite
+ CAN_ResetTransfer( pCAN1Transfer );
+ pCAN1Transfer->can_number = 1;
+ pCAN1Transfer->mailbox_number = 15;
+ pCAN1Transfer->mode_reg = AT91C_CAN_MOT_RXOVERWRITE;
+ pCAN1Transfer->acceptance_mask_reg = 0;
+ pCAN1Transfer->identifier = 0x0;
+ pCAN1Transfer->data_low_reg = 0x00000000;
+ pCAN1Transfer->data_high_reg = 0x00000000;
+ pCAN1Transfer->control_reg = 0x00000000;
+ CAN_InitMailboxRegisters( pCAN1Transfer );
+
+ // Ask Transmissions on Mailbox 1 & 2 --> AT91C_CAN_MRDY & AT91C_CAN_MMI raises for Mailbox 15 CAN_MB_SR
+ AT91C_BASE_CAN0->CAN_TCR = AT91C_CAN_MB1 | AT91C_CAN_MB2;
+
+ // Wait for Last Transmit Mailbox
+ tick = 0;
+ do {
+ status = AT91C_BASE_CAN1_MB15->CAN_MB_MSR;
+ }
+ while( !(status & AT91C_CAN_MMI) && (++tick < AT91C_CAN_TIMEOUT) );
+
+ if (tick == AT91C_CAN_TIMEOUT) {
+ }
+ else {
+ TRACE_DEBUG("Transfer completed: CAN1 Mailbox 15 MRDY and MMI flags have raised\n\r");
+ if( AT91C_BASE_CAN0_MB1->CAN_MB_MDL != AT91C_BASE_CAN1_MB15->CAN_MB_MDL ) {
+ TRACE_ERROR("Data Corrupted\n\r");
+ }
+ else if( AT91C_BASE_CAN0_MB1->CAN_MB_MDH != AT91C_BASE_CAN1_MB15->CAN_MB_MDH ) {
+ TRACE_ERROR("Data Corrupted\n\r");
+ }
+ else {
+ TRACE_INFO("Test passed\n\r");
+ }
+ }
+
+ CAN_ResetAllMailbox();
+ TRACE_INFO("Without Interrupt ");
+ TRACE_INFO("CAN0 Mailboxes 1 & 2 transmitting to CAN1 Mailbox 15\n\r");
+ // Init CAN0 Mailbox 1, transmit
+ CAN_ResetTransfer( pCAN0Transfer );
+ pCAN0Transfer->can_number = 0;
+ pCAN0Transfer->mailbox_number = 1;
+ pCAN0Transfer->mode_reg = AT91C_CAN_MOT_TX | AT91C_CAN_PRIOR;
+ pCAN0Transfer->acceptance_mask_reg = 0x00000000;
+ pCAN0Transfer->identifier = AT91C_CAN_MIDvA & (0x09<<18); // ID 9
+ pCAN0Transfer->data_low_reg = 0xAABBCCDD;
+ pCAN0Transfer->data_high_reg = 0xCAFEDECA;
+ pCAN0Transfer->control_reg = (AT91C_CAN_MDLC & (0x8<<16)); // Mailbox Data Length Code
+ CAN_InitMailboxRegisters( pCAN0Transfer );
+
+ // Init CAN0 Mailbox 2, transmit
+ pCAN0Transfer->can_number = 0;
+ pCAN0Transfer->mailbox_number = 2;
+ pCAN0Transfer->mode_reg = AT91C_CAN_MOT_TX | (AT91C_CAN_PRIOR-(1<<16));
+ pCAN0Transfer->acceptance_mask_reg = 0x00000000;
+ pCAN0Transfer->identifier = AT91C_CAN_MIDvA & (0x0A<<18); // ID 10
+ pCAN0Transfer->data_low_reg = 0x55667788;
+ pCAN0Transfer->data_high_reg = 0x99AABBCC;
+ pCAN0Transfer->control_reg = (AT91C_CAN_MDLC & (0x8<<16)); // Mailbox Data Length Code
+ CAN_InitMailboxRegisters( pCAN0Transfer );
+
+ // Init CAN1 Mailbox 15, reception with overwrite
+ CAN_ResetTransfer( pCAN1Transfer );
+ pCAN1Transfer->can_number = 1;
+ pCAN1Transfer->mailbox_number = 15;
+ pCAN1Transfer->mode_reg = AT91C_CAN_MOT_RX;
+ pCAN1Transfer->acceptance_mask_reg = 0;
+ pCAN1Transfer->identifier = 0x0;
+ pCAN1Transfer->data_low_reg = 0x00000000;
+ pCAN1Transfer->data_high_reg = 0x00000000;
+ pCAN1Transfer->control_reg = 0x00000000;
+ CAN_InitMailboxRegisters( pCAN1Transfer );
+
+ // Ask Transmissions on Mailbox 1 & 2 --> AT91C_CAN_MRDY & AT91C_CAN_MMI raises for Mailbox 15 CAN_MB_SR
+ AT91C_BASE_CAN0->CAN_TCR = AT91C_CAN_MB1 | AT91C_CAN_MB2;
+
+ // Wait for Last Transmit Mailbox
+ tick = 0;
+ do {
+ status = AT91C_BASE_CAN1_MB15->CAN_MB_MSR;
+ }
+ while( !(status & AT91C_CAN_MMI) && (++tick < AT91C_CAN_TIMEOUT) );
+
+ if (tick == AT91C_CAN_TIMEOUT) {
+ TRACE_ERROR("Test FAILED\n\r");
+ }
+ else {
+ TRACE_DEBUG("Transfer completed: CAN1 Mailbox 15 MRDY and MMI flags have raised\n\r");
+ TRACE_DEBUG("MB_MDL: 0x%X\n\r", AT91C_BASE_CAN1_MB15->CAN_MB_MDL);
+ TRACE_DEBUG("MB_MDLH: 0x%X\n\r", AT91C_BASE_CAN1_MB15->CAN_MB_MDH);
+ if( AT91C_BASE_CAN0_MB2->CAN_MB_MDL != AT91C_BASE_CAN1_MB15->CAN_MB_MDL ) {
+ TRACE_ERROR("Data Corrupted\n\r");
+ }
+ else if( AT91C_BASE_CAN0_MB2->CAN_MB_MDH != AT91C_BASE_CAN1_MB15->CAN_MB_MDH ) {
+ TRACE_ERROR("Data Corrupted\n\r");
+ }
+ else {
+ TRACE_INFO("Test passed\n\r");
+ }
+ }
+
+ CAN_ResetAllMailbox();
+ TRACE_INFO("Without Interrupt ");
+ TRACE_INFO("CAN0 Mailbox 3 asking for CAN1 Mailbox 3 transmission\n\r");
+ // Init CAN0 Mailbox 3, consumer mailbox
+ // Sends a remote frame and waits for an answer
+ CAN_ResetTransfer( pCAN0Transfer );
+ pCAN0Transfer->can_number = 0;
+ pCAN0Transfer->mailbox_number = 3;
+ pCAN0Transfer->mode_reg = AT91C_CAN_MOT_CONSUMER | AT91C_CAN_PRIOR;
+ pCAN0Transfer->acceptance_mask_reg = AT91C_CAN_MIDvA | AT91C_CAN_MIDvB;
+ pCAN0Transfer->identifier = AT91C_CAN_MIDvA & (0x0B<<18); // ID 11
+ pCAN0Transfer->data_low_reg = 0x00000000;
+ pCAN0Transfer->data_high_reg = 0x00000000;
+ pCAN0Transfer->control_reg = 0x00000000;
+ CAN_InitMailboxRegisters( pCAN0Transfer );
+
+ // Init CAN1 Mailbox 3, porducer mailbox
+ // Waits to receive a Remote Frame before sending its contents
+ CAN_ResetTransfer( pCAN1Transfer );
+ pCAN1Transfer->can_number = 1;
+ pCAN1Transfer->mailbox_number = 3;
+ pCAN1Transfer->mode_reg = AT91C_CAN_MOT_PRODUCER | AT91C_CAN_PRIOR;
+ pCAN1Transfer->acceptance_mask_reg = 0;
+ pCAN1Transfer->identifier = AT91C_CAN_MIDvA & (0x0B<<18); // ID 11
+ pCAN1Transfer->data_low_reg = 0xEEDDFF00;
+ pCAN1Transfer->data_high_reg = 0x34560022;
+ pCAN1Transfer->control_reg = (AT91C_CAN_MDLC & (0x8<<16));
+ CAN_InitMailboxRegisters( pCAN1Transfer );
+
+ // Ask Transmissions on Mailbox 3 --> AT91C_CAN_MRDY raises for Mailbox 3 CAN_MB_SR
+ AT91C_BASE_CAN1->CAN_TCR = AT91C_CAN_MB3;
+ AT91C_BASE_CAN0->CAN_TCR = AT91C_CAN_MB3;
+
+ // Wait for Last Transmit Mailbox
+ tick = 0;
+ do {
+ status = AT91C_BASE_CAN0_MB3->CAN_MB_MSR;
+ }
+ while( !(status & AT91C_CAN_MRDY) && (++tick < AT91C_CAN_TIMEOUT) );
+
+ if (tick == AT91C_CAN_TIMEOUT) {
+ TRACE_ERROR("Test FAILED\n\r");
+ }
+ else {
+ TRACE_DEBUG("Transfer Completed: CAN0 & CAN1 Mailboxes 3 MRDY flags have raised\n\r");
+ if( AT91C_BASE_CAN0_MB3->CAN_MB_MDL != AT91C_BASE_CAN1_MB3->CAN_MB_MDL ) {
+ TRACE_ERROR("Data Corrupted\n\r");
+ }
+ else if( AT91C_BASE_CAN0_MB3->CAN_MB_MDH != AT91C_BASE_CAN1_MB3->CAN_MB_MDH ) {
+ TRACE_ERROR("Data Corrupted\n\r");
+ }
+ else {
+ TRACE_INFO("Test passed\n\r");
+ }
+ }
+#endif // AT91C_BASE_CAN1
+
+ return;
+}
+
+
+//------------------------------------------------------------------------------
+/// Disable CAN and enter in low power
+//------------------------------------------------------------------------------
+void CAN_disable( void )
+{
+ // Disable the interrupt on the interrupt controller
+ IRQ_DisableIT(AT91C_ID_CAN0);
+ // disable all IT
+ AT91C_BASE_CAN0->CAN_IDR = 0x1FFFFFFF;
+#if defined AT91C_BASE_CAN1
+ IRQ_DisableIT(AT91C_ID_CAN1);
+ // disable all IT
+ AT91C_BASE_CAN1->CAN_IDR = 0x1FFFFFFF;
+#endif
+
+ // Enable Low Power mode
+ AT91C_BASE_CAN0->CAN_MR |= AT91C_CAN_LPM;
+
+ // Disable CANs Transceivers
+ // Enter standby mode
+ PIO_Set(&pin_can_transceiver_rs);
+#if defined (PIN_CAN_TRANSCEIVER_RXEN)
+ // Enable ultra Low Power mode
+ PIO_Clear(&pin_can_transceiver_rxen);
+#endif
+
+ // Disable clock for CAN PIO
+#if defined(AT91C_ID_PIOA)
+ AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_PIOA);
+#elif defined(AT91C_ID_PIOABCD)
+ AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_PIOABCD);
+#elif defined(AT91C_ID_PIOABCDE)
+ AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_PIOABCDE);
+#endif
+
+ // Disable the CAN0 controller peripheral clock
+ AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_CAN0);
+
+}
+
+//------------------------------------------------------------------------------
+/// baudrate calcul
+/// \param base_CAN CAN base address
+/// \param baudrate Baudrate value (kB/s)
+/// allowed values: 1000, 800, 500, 250, 125, 50, 25, 10
+/// \return return 1 in success, otherwise return 0
+//------------------------------------------------------------------------------
+unsigned char CAN_BaudRateCalculate( AT91PS_CAN base_CAN,
+ unsigned int baudrate )
+{
+ unsigned int BRP;
+ unsigned int PROPAG;
+ unsigned int PHASE1;
+ unsigned int PHASE2;
+ unsigned int SJW;
+ unsigned int t1t2;
+ unsigned char TimeQuanta;
+
+ base_CAN->CAN_BR = 0;
+
+ if( baudrate == 1000) {
+ TimeQuanta = 8;
+ }
+ else {
+ TimeQuanta = 16;
+ }
+
+ BRP = (BOARD_MCK / (baudrate*1000*TimeQuanta))-1;
+ //TRACE_DEBUG("BRP = 0x%X\n\r", BRP);
+ // timing Delay:
+ // Delay Bus Driver: 50 ns
+ // Delay Receiver: 30 ns
+ // Delay Bus Line (20m): 110 ns
+ if( (TimeQuanta*baudrate*2*(50+30+110)/1000000) >= 1) {
+ PROPAG = (TimeQuanta*baudrate*2*(50+30+110)/1000000)-1;
+ }
+ else {
+ PROPAG = 0;
+ }
+ //TRACE_DEBUG("PROPAG = 0x%X\n\r", PROPAG);
+
+ t1t2 = TimeQuanta-1-(PROPAG+1);
+ //TRACE_DEBUG("t1t2 = 0x%X\n\r", t1t2);
+
+ if( (t1t2 & 0x01) == 0x01 ) {
+ // ODD
+ //TRACE_DEBUG("ODD\n\r");
+ PHASE1 = ((t1t2-1)/2)-1;
+ PHASE2 = PHASE1+1;
+ }
+ else {
+ // EVEN
+ //TRACE_DEBUG("EVEN\n\r");
+ PHASE1 = (t1t2/2)-1;
+ PHASE2 = PHASE1;
+ }
+ //TRACE_DEBUG("PHASE1 = 0x%X\n\r", PHASE1);
+ //TRACE_DEBUG("PHASE2 = 0x%X\n\r", PHASE2);
+
+ if( 1 > (4/(PHASE1+1)) ) {
+ //TRACE_DEBUG("4*Tcsc\n\r");
+ SJW = 3;
+ }
+ else {
+ //TRACE_DEBUG("Tphs1\n\r");
+ SJW = PHASE1;
+ }
+ //TRACE_DEBUG("SJW = 0x%X\n\r", SJW);
+ // Verif
+ if( BRP == 0 ) {
+ TRACE_DEBUG("BRP = 0 is not authorized\n\r");
+ return 0;
+ }
+
+ if( (PROPAG + PHASE1 + PHASE2) != (TimeQuanta-4) ) {
+ TRACE_DEBUG("Pb (PROPAG + PHASE1 + PHASE2) = %d\n\r", PROPAG + PHASE1 + PHASE2);
+ TRACE_DEBUG("with TimeQuanta-4 = %d\n\r", TimeQuanta-4);
+ return 0;
+ }
+ base_CAN->CAN_BR = (AT91C_CAN_PHASE2 & (PHASE2 << 0))
+ + (AT91C_CAN_PHASE1 & (PHASE1 << 4))
+ + (AT91C_CAN_PROPAG & (PROPAG << 8))
+ + (AT91C_CAN_SYNC & (SJW << 12))
+ + (AT91C_CAN_BRP & (BRP << 16))
+ + (AT91C_CAN_SMP & (0 << 24));
+ return 1;
+
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// Init of the CAN peripheral
+/// \param baudrate Baudrate value (kB/s)
+/// allowed values: 1000, 800, 500, 250, 125, 50, 25, 10
+/// \param canTransfer0 CAN0 structure transfer
+/// \param canTransfer1 CAN1 structure transfer
+/// \return return 1 if CAN has good baudrate and CAN is synchronized,
+/// otherwise return 0
+//------------------------------------------------------------------------------
+unsigned char CAN_Init( unsigned int baudrate,
+ CanTransfer *canTransfer0,
+ CanTransfer *canTransfer1 )
+{
+ unsigned char ret;
+
+ // CAN Transmit Serial Data
+#if defined (PINS_CAN_TRANSCEIVER_TXD)
+ PIO_Configure(pins_can_transceiver_txd, PIO_LISTSIZE(pins_can_transceiver_txd));
+#endif
+#if defined (PINS_CAN_TRANSCEIVER_RXD)
+ // CAN Receive Serial Data
+ PIO_Configure(pins_can_transceiver_rxd, PIO_LISTSIZE(pins_can_transceiver_rxd));
+#endif
+ // CAN RS
+ PIO_Configure(&pin_can_transceiver_rs, PIO_LISTSIZE(pin_can_transceiver_rs));
+#if defined (PIN_CAN_TRANSCEIVER_RXEN)
+ // CAN RXEN
+ PIO_Configure(&pin_can_transceiver_rxen, PIO_LISTSIZE(pin_can_transceiver_rxen));
+#endif
+
+ // Enable clock for CAN PIO
+#if defined(AT91C_ID_PIOA)
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PIOA);
+#elif defined(AT91C_ID_PIOABCD)
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PIOABCD);
+#elif defined(AT91C_ID_PIOABCDE)
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PIOABCDE);
+#endif
+
+ // Enable the CAN0 controller peripheral clock
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_CAN0);
+
+ // disable all IT
+ AT91C_BASE_CAN0->CAN_IDR = 0x1FFFFFFF;
+
+ // Enable CANs Transceivers
+#if defined (PIN_CAN_TRANSCEIVER_RXEN)
+ // Disable ultra Low Power mode
+ PIO_Set(&pin_can_transceiver_rxen);
+#endif
+ // Normal Mode (versus Standby mode)
+ PIO_Clear(&pin_can_transceiver_rs);
+
+ // Configure the AIC for CAN interrupts
+ IRQ_ConfigureIT(AT91C_ID_CAN0, 0x7, CAN0_Handler);
+
+ // Enable the interrupt on the interrupt controller
+ IRQ_EnableIT(AT91C_ID_CAN0);
+
+ if( CAN_BaudRateCalculate(AT91C_BASE_CAN0, baudrate) == 0 ) {
+ // Baudrate problem
+ TRACE_DEBUG("Baudrate CAN0 problem\n\r");
+ return 0;
+ }
+
+ pCAN0Transfer = canTransfer0;
+
+#if defined AT91C_BASE_CAN1
+ if( canTransfer1 != NULL ) {
+ pCAN1Transfer = canTransfer1;
+ // Enable CAN1 Clocks
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_CAN1);
+
+ // disable all IT
+ AT91C_BASE_CAN1->CAN_IDR = 0x1FFFFFFF;
+
+ // Configure the AIC for CAN interrupts
+ IRQ_ConfigureIT(AT91C_ID_CAN1, 0x7, CAN1_Handler);
+
+ // Enable the interrupt on the interrupt controller
+ IRQ_EnableIT(AT91C_ID_CAN1);
+
+ if( CAN_BaudRateCalculate(AT91C_BASE_CAN1, baudrate) == 0 ) {
+ // Baudrate problem
+ TRACE_DEBUG("Baudrate CAN1 problem\n\r");
+ return 0;
+ }
+ }
+#endif
+ // Reset all mailbox
+ CAN_ResetAllMailbox();
+
+ // Enable the interrupt with all error cases
+ AT91C_BASE_CAN0->CAN_IER = AT91C_CAN_CERR // (CAN) CRC Error
+ | AT91C_CAN_SERR // (CAN) Stuffing Error
+ | AT91C_CAN_BERR // (CAN) Bit Error
+ | AT91C_CAN_FERR // (CAN) Form Error
+ | AT91C_CAN_AERR; // (CAN) Acknowledgment Error
+
+#if defined AT91C_BASE_CAN1
+ if( canTransfer1 != NULL ) {
+ AT91C_BASE_CAN1->CAN_IER = AT91C_CAN_CERR // (CAN) CRC Error
+ | AT91C_CAN_SERR // (CAN) Stuffing Error
+ | AT91C_CAN_BERR // (CAN) Bit Error
+ | AT91C_CAN_FERR // (CAN) Form Error
+ | AT91C_CAN_AERR; // (CAN) Acknowledgment Error
+ }
+#endif
+
+ // Wait for CAN synchronisation
+ if( CAN_Synchronisation( ) == 1 ) {
+ ret = 1;
+ }
+ else {
+ ret = 0;
+ }
+
+ return ret;
+}
+
diff --git a/peripherals/can/can.h b/peripherals/can/can.h new file mode 100644 index 0000000..63a83b3 --- /dev/null +++ b/peripherals/can/can.h @@ -0,0 +1,113 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef _CAN_H
+#define _CAN_H
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+#define AT91C_CAN_TIMEOUT 100000
+
+#define AT91C_TEST_NOK 0
+#define AT91C_TEST_OK 1
+
+#define CAN_STATUS_SUCCESS 0
+#define CAN_STATUS_LOCKED 1
+#define CAN_STATUS_ABORTED 2
+#define CAN_STATUS_RESET 3
+
+#if defined (AT91C_BASE_CAN)
+ #define AT91C_BASE_CAN0 AT91C_BASE_CAN
+#endif
+#if defined (AT91C_ID_CAN)
+ #define AT91C_ID_CAN0 AT91C_ID_CAN
+#endif
+#if defined (AT91C_BASE_CAN_MB0)
+ #define AT91C_BASE_CAN0_MB0 AT91C_BASE_CAN_MB0
+ #define AT91C_BASE_CAN0_MB1 AT91C_BASE_CAN_MB1
+ #define AT91C_BASE_CAN0_MB2 AT91C_BASE_CAN_MB2
+ #define AT91C_BASE_CAN0_MB3 AT91C_BASE_CAN_MB3
+ #define AT91C_BASE_CAN0_MB4 AT91C_BASE_CAN_MB4
+ #define AT91C_BASE_CAN0_MB5 AT91C_BASE_CAN_MB5
+ #define AT91C_BASE_CAN0_MB6 AT91C_BASE_CAN_MB6
+ #define AT91C_BASE_CAN0_MB7 AT91C_BASE_CAN_MB7
+#endif
+#if defined (AT91C_BASE_CAN_MB8)
+ #define AT91C_BASE_CAN0_MB8 AT91C_BASE_CAN_MB8
+ #define AT91C_BASE_CAN0_MB9 AT91C_BASE_CAN_MB9
+ #define AT91C_BASE_CAN0_MB10 AT91C_BASE_CAN_MB10
+ #define AT91C_BASE_CAN0_MB11 AT91C_BASE_CAN_MB11
+ #define AT91C_BASE_CAN0_MB12 AT91C_BASE_CAN_MB12
+ #define AT91C_BASE_CAN0_MB13 AT91C_BASE_CAN_MB13
+ #define AT91C_BASE_CAN0_MB14 AT91C_BASE_CAN_MB14
+ #define AT91C_BASE_CAN0_MB15 AT91C_BASE_CAN_MB15
+#endif
+
+#define NUM_MAILBOX_MAX 16
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+typedef struct
+{
+ volatile unsigned char state;
+ volatile unsigned char can_number;
+ volatile unsigned char mailbox_number;
+ volatile unsigned char test_can;
+ volatile unsigned int mode_reg;
+ volatile unsigned int acceptance_mask_reg;
+ volatile unsigned int identifier;
+ volatile unsigned int data_low_reg;
+ volatile unsigned int data_high_reg;
+ volatile unsigned int control_reg;
+ volatile unsigned int mailbox_in_use;
+ volatile int size;
+} CanTransfer;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+extern unsigned char CAN_Init( unsigned int baudrate,
+ CanTransfer *canTransferRead,
+ CanTransfer *canTransferWrite );
+extern void CAN_BasicTestSuite(void);
+extern void CAN_disable( void );
+extern void CAN_ResetAllMailbox( void );
+extern void CAN_ResetTransfer( CanTransfer *pTransfer );
+extern void CAN_InitMailboxRegisters( CanTransfer *pTransfer );
+extern unsigned char CAN_IsInIdle( CanTransfer *pTransfer );
+
+extern unsigned char CAN_Write( CanTransfer *pTransfer );
+extern unsigned char CAN_Read( CanTransfer *pTransfer );
+
+extern void CAN_BasicTestSuiteWithoutInterrupt( void );
+extern unsigned char CAN_IsInIdle( CanTransfer *pTransfer );
+#endif // _CAN_H
+
diff --git a/peripherals/chipid/chipid.c b/peripherals/chipid/chipid.c new file mode 100644 index 0000000..8a52eac --- /dev/null +++ b/peripherals/chipid/chipid.c @@ -0,0 +1,301 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <chipid/chipid.h>
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// ChipID register, version field
+#define AT91C_CHIPID_CIDR_VERSION (0x1fUL << 0)
+#define AT91C_CHIPID_CIDR_VERSION_BITFLD 0
+#define AT91C_CHIPID_CIDR_VERSION_BITS 5
+/// ChipID register, embedded processor field
+#define AT91C_CHIPID_CIDR_EPROC (0x7UL << 5)
+#define AT91C_CHIPID_CIDR_EPROC_BITFLD 5
+#define AT91C_CHIPID_CIDR_EPROC_BITS 3
+/// ChipID register, nonvolatile program memory size field
+#define AT91C_CHIPID_CIDR_NVPSIZ (0xfUL << 8)
+#define AT91C_CHIPID_CIDR_NVPSIZ_BITFLD 8
+#define AT91C_CHIPID_CIDR_NVPSIZ_BITS 4
+/// ChipID register, second nonvolatile program memory size field
+#define AT91C_CHIPID_CIDR_NVPSIZ2 (0xfUL << 12)
+#define AT91C_CHIPID_CIDR_NVPSIZ2_BITFLD 12
+#define AT91C_CHIPID_CIDR_NVPSIZ2_BITS 4
+/// ChipID register, Internal SRAM siize field
+#define AT91C_CHIPID_CIDR_SRAMSIZ (0xfUL << 16)
+#define AT91C_CHIPID_CIDR_SRAMSIZ_BITFLD 16
+#define AT91C_CHIPID_CIDR_SRAMSIZ_BITS 4
+/// ChipID register, Architecture identifier field
+#define AT91C_CHIPID_CIDR_ARCH (0xffUL << 20)
+#define AT91C_CHIPID_CIDR_ARCH_BITFLD 20
+#define AT91C_CHIPID_CIDR_ARCH_BITS 8
+/// ChipID register, nonvolatile program memory type field
+#define AT91C_CHIPID_CIDR_NVPTYP (0x7UL << 28)
+#define AT91C_CHIPID_CIDR_NVPTYP_BITFLD 28
+#define AT91C_CHIPID_CIDR_NVPTYP_BITS 3
+/// ChipID register, extersion flag field
+#define AT91C_CHIPID_CIDR_EXT (0x1UL << 31)
+#define AT91C_CHIPID_CIDR_EXT_BITFLD 31
+#define AT91C_CHIPID_CIDR_EXT_BITS 1
+
+#define CHIPID_ID(chipid, bitfield, bits) ((chipid >> bitfield) & ((1 << (bits)) - 1))
+
+//------------------------------------------------------------------------------
+// Internal variables
+//------------------------------------------------------------------------------
+#define AT91C_CHIPID_EPROC_SIZE 5
+const struct ChipIDType CHIPID_eProc[AT91C_CHIPID_EPROC_SIZE] = {
+
+ // identifier description
+ {0x1, "ARM946ES"},
+ {0x2, "ARM7TDMI"},
+ {0x3, "Cortex-M3"},
+ {0x4, "ARM920T"},
+ {0x5, "ARM926EJS"},
+};
+
+#define AT91C_CHIPID_NVPSIZE_SIZE 16
+const struct ChipIDType CHIPID_nvpSiz[AT91C_CHIPID_NVPSIZE_SIZE] = {
+
+ // identifier description
+ {0x0, "None"},
+ {0x1, "8K bytes"},
+ {0x2, "16K bytes"},
+ {0x3, "32K bytes"},
+ {0x4, "Reserved"},
+ {0x5, "64K bytes"},
+ {0x6, "Reserved"},
+ {0x7, "128K bytes"},
+ {0x8, "Reserved"},
+ {0x9, "256K bytes"},
+ {0xA, "512K bytes"},
+ {0xB, "Reserved"},
+ {0xC, "1024K bytes"},
+ {0xD, "Reserved"},
+ {0xE, "2048K bytes"},
+ {0xF, "Reserved"}
+};
+
+#define AT91C_CHIPID_NVPSIZE2_SIZE 16
+const struct ChipIDType CHIPID_nvpSiz2[AT91C_CHIPID_NVPSIZE2_SIZE] = {
+
+ // identifier description
+ {0x0, "None"},
+ {0x1, "8K bytes"},
+ {0x2, "16K bytes"},
+ {0x3, "32K bytes"},
+ {0x4, "Reserved"},
+ {0x5, "64K bytes"},
+ {0x6, "Reserved"},
+ {0x7, "128K bytes"},
+ {0x8, "Reserved"},
+ {0x9, "256K bytes"},
+ {0xA, "512K bytes"},
+ {0xB, "Reserved"},
+ {0xC, "1024K bytes"},
+ {0xD, "Reserved"},
+ {0xE, "2048K bytes"},
+ {0xF, "Reserved"}
+};
+
+#define AT91C_CHIPID_SRAMSIZE_SIZE 16
+const struct ChipIDType CHIPID_sramSiz[AT91C_CHIPID_SRAMSIZE_SIZE] = {
+
+ // identifier description
+ {0x0, "48K bytes"},
+ {0x1, "1K bytes"},
+ {0x2, "2K bytes"},
+ {0x3, "6K bytes"},
+ {0x4, "112K bytes"},
+ {0x5, "4K bytes"},
+ {0x6, "80K bytes"},
+ {0x7, "160K bytes"},
+ {0x8, "8K bytes"},
+ {0x9, "16K bytes"},
+ {0xA, "32K bytes"},
+ {0xB, "64K bytes"},
+ {0xC, "128K bytes"},
+ {0xD, "256K bytes"},
+ {0xE, "96K bytes"},
+ {0xF, "512K bytes"}
+};
+
+#define AT91C_CHIPID_ARCH_SIZE 22
+const struct ChipIDType CHIPID_archSiz[AT91C_CHIPID_ARCH_SIZE] = {
+
+ // identifier description
+ {0x19, "AT91SAM9xx Series"},
+ {0x29, "AT91SAM9XExx Series"},
+ {0x34, "AT91x34 series"},
+ {0x37, "CAP7 Series"},
+ {0x39, "CAP9 Series"},
+ {0x3B, "CAP11 Series"},
+ {0x40, "AT91x40 Series"},
+ {0x42, "AT91x42 Series"},
+ {0x55, "AT91x55 Series"},
+ {0x60, "AT91SAM7Axx Series"},
+ {0x61, "AT91SAM7AQxx Series"},
+ {0x63, "AT91x63 Series"},
+ {0x70, "AT91SAM7Sxx Series"},
+ {0x71, "AT91SAM7XCxx Series"},
+ {0x72, "AT91SAM7SExx Series"},
+ {0x73, "AT91SAM7Lxx Series"},
+ {0x75, "AT91SAM7Xxx Series"},
+ {0x76, "AT91SAM7SLxx Series"},
+ {0x80, "AT91SAM3Uxx Series"},
+ {0x81, "AT91SAM3UExx Series"},
+ {0x92, "AT91x92 Series"},
+ {0xF0, "AT75Cxx Series"}
+};
+
+#define AT91C_CHIPID_NVPTYPE_SIZE 5
+const struct ChipIDType CHIPID_nvpTyp[AT91C_CHIPID_NVPTYPE_SIZE] = {
+
+ // identifier description
+ {0x0, "ROM"},
+ {0x1, "ROMless or on-chip Flash"},
+ {0x4, "SRAM emulating ROM"},
+ {0x2, "Embedded Flash Memory"},
+ {0x3, "ROM and Embedded Flash Memory, NVPSIZ is ROM size, NVPSIZ2 is Flash size"}
+};
+
+//------------------------------------------------------------------------------
+/// Internal functions
+//------------------------------------------------------------------------------
+unsigned char CHIPID_Find(const struct ChipIDType* pChipIDTypeList,
+ unsigned int size,
+ unsigned int id,
+ struct ChipIDType* pChipIDType)
+{
+ unsigned int i;
+
+ for(i=0; i<size; i++)
+ {
+ if(pChipIDTypeList[i].num == id)
+ {
+ memcpy(pChipIDType, &pChipIDTypeList[i], sizeof(struct ChipIDType));
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+/// Exported functions
+//------------------------------------------------------------------------------
+unsigned char CHIPID_Get(ChipId* pChipId)
+{
+ unsigned int chipId, chipIdExt;
+
+ chipId = AT91C_BASE_DBGU->DBGU_CIDR;
+ chipIdExt = AT91C_BASE_DBGU->DBGU_EXID;
+
+ pChipId->version = CHIPID_ID(chipId, AT91C_CHIPID_CIDR_VERSION_BITFLD, AT91C_CHIPID_CIDR_VERSION_BITS);
+ pChipId->eProc = CHIPID_ID(chipId, AT91C_CHIPID_CIDR_EPROC_BITFLD, AT91C_CHIPID_CIDR_EPROC_BITS);
+ pChipId->nvpSiz = CHIPID_ID(chipId, AT91C_CHIPID_CIDR_NVPSIZ_BITFLD, AT91C_CHIPID_CIDR_NVPSIZ_BITS);
+ pChipId->nvpSiz2 = CHIPID_ID(chipId, AT91C_CHIPID_CIDR_NVPSIZ2_BITFLD, AT91C_CHIPID_CIDR_NVPSIZ2_BITS);
+ pChipId->sramSiz = CHIPID_ID(chipId, AT91C_CHIPID_CIDR_SRAMSIZ_BITFLD, AT91C_CHIPID_CIDR_SRAMSIZ_BITS);
+ pChipId->arch = CHIPID_ID(chipId, AT91C_CHIPID_CIDR_ARCH_BITFLD, AT91C_CHIPID_CIDR_ARCH_BITS);
+ pChipId->nvpTyp = CHIPID_ID(chipId, AT91C_CHIPID_CIDR_NVPTYP_BITFLD, AT91C_CHIPID_CIDR_NVPTYP_BITS);
+ pChipId->extFlag= CHIPID_ID(chipId, AT91C_CHIPID_CIDR_EXT_BITFLD, AT91C_CHIPID_CIDR_EXT_BITS);
+ pChipId->extID = chipIdExt;
+
+ return 0;
+}
+
+void CHIPID_Print(ChipId* pChipId)
+{
+ unsigned char status;
+ struct ChipIDType chipIdType;
+
+ // Version
+ printf("Version 0x%x.\r\n", pChipId->version);
+
+ // Find Embedded Processor
+ status = CHIPID_Find(CHIPID_eProc, AT91C_CHIPID_EPROC_SIZE, pChipId->eProc, &chipIdType);
+ if(!status)
+ {
+ printf("Embedded Processor %s.\r\n", chipIdType.pStr);
+ }
+
+ // Find nonvolatile program memory size
+ status = CHIPID_Find(CHIPID_nvpSiz, AT91C_CHIPID_NVPSIZE_SIZE, pChipId->nvpSiz, &chipIdType);
+ if(!status)
+ {
+ printf("Nonvolatile program memory size %s.\r\n", chipIdType.pStr);
+ }
+
+ // Find Second nonvolatile program memory size
+ status = CHIPID_Find(CHIPID_nvpSiz2, AT91C_CHIPID_NVPSIZE2_SIZE, pChipId->nvpSiz2, &chipIdType);
+ if(!status)
+ {
+ printf("Second nonvolatile program memory size %s.\r\n", chipIdType.pStr);
+ }
+
+ // Find Internal SRAM size
+ status = CHIPID_Find(CHIPID_sramSiz, AT91C_CHIPID_SRAMSIZE_SIZE, pChipId->sramSiz, &chipIdType);
+ if(!status)
+ {
+ printf("Internal SRAM size %s.\r\n", chipIdType.pStr);
+ }
+
+ // Find Architecture identifier
+ status = CHIPID_Find(CHIPID_archSiz, AT91C_CHIPID_ARCH_SIZE, pChipId->arch, &chipIdType);
+ if(!status)
+ {
+ printf("Architecture identifier %s.\r\n", chipIdType.pStr);
+ }
+
+ // Find nonvolatile program memory type
+ status = CHIPID_Find(CHIPID_nvpTyp, AT91C_CHIPID_NVPTYPE_SIZE, pChipId->nvpTyp, &chipIdType);
+ if(!status)
+ {
+ printf("Nonvolatile program memory type %s.\r\n", chipIdType.pStr);
+ }
+
+ // Find extension flag
+ if(pChipId->extFlag)
+ {
+ printf("Extended chip ID is 0x%x. \r\n", pChipId->extID);
+ }
+ else
+ {
+ printf("Extended chip ID is not existed. \r\n");
+ }
+
+}
diff --git a/peripherals/chipid/chipid.dir b/peripherals/chipid/chipid.dir new file mode 100644 index 0000000..641a730 --- /dev/null +++ b/peripherals/chipid/chipid.dir @@ -0,0 +1,36 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// This directory contains an API for access the ChipID perpheral of AT91 microcontrollers.
+//------------------------------------------------------------------------------
\ No newline at end of file diff --git a/peripherals/chipid/chipid.h b/peripherals/chipid/chipid.h new file mode 100644 index 0000000..f450673 --- /dev/null +++ b/peripherals/chipid/chipid.h @@ -0,0 +1,109 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Methods and definitions for access Chip ID peripheral in AT91 microcontrollers.
+///
+/// !Usage
+///
+/// -#
+///
+//------------------------------------------------------------------------------
+
+#ifndef CHIPID_H
+#define CHIPID_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Definition for chip id register
+//------------------------------------------------------------------------------
+typedef struct _ChipId {
+
+ /// Version of the device
+ unsigned int version;
+ /// Embedded processor
+ unsigned int eProc;
+ /// Nonvolatile program memory size
+ unsigned int nvpSiz;
+ /// Second nonvolatile program memory size
+ unsigned int nvpSiz2;
+ /// Internal SRAM size
+ unsigned int sramSiz;
+ /// Architecture identifier
+ unsigned int arch;
+ /// Nonvolatile program memory type
+ unsigned int nvpTyp;
+ /// Extension flag
+ unsigned int extFlag;
+ /// Chip ID extersion extension
+ unsigned int extID;
+}ChipId;
+
+#if 1
+struct ChipIDType {
+
+ /// Identifier
+ unsigned int num;
+ /// Type
+ unsigned char pStr[80];
+};
+#else
+typedef struct _ChipIDType {
+
+ /// Identifier
+ unsigned int num;
+ /// Type
+ unsigned char pStr[80];
+}ChipIDType;
+#endif
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+/// Get chip ID
+extern unsigned char CHIPID_Get(ChipId* pChipId);
+
+/// Print chip ID
+extern void CHIPID_Print(ChipId* pChipId);
+
+#endif //#ifndef CHIPID_H
\ No newline at end of file diff --git a/peripherals/cp15/core.h b/peripherals/cp15/core.h new file mode 100644 index 0000000..3de96ea --- /dev/null +++ b/peripherals/cp15/core.h @@ -0,0 +1,88 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+// core list
+//-------------------
+// arm7tdmi
+// arm926ej_s
+// arm1176jzf_s
+// cortexm3
+
+#include "board.h"
+
+#ifndef _CORE_H
+#define _CORE_H
+
+#if defined(at91sam7a3) \
+ || defined(at91sam7l) \
+ || defined(at91sam7s32) \
+ || defined(at91sam7s321) \
+ || defined(at91sam7s64) \
+ || defined(at91sam7s128) \
+ || defined(at91sam7s256) \
+ || defined(at91sam7s512) \
+ || defined(at91sam7se32) \
+ || defined(at91sam7se256) \
+ || defined(at91sam7se512) \
+ || defined(at91sam7x128) \
+ || defined(at91sam7x256) \
+ || defined(at91sam7x512) \
+ || defined(at91sam7xc128) \
+ || defined(at91sam7xc256) \
+ || defined(at91sam7xc512)
+
+#define arm7tdmi
+
+#elif defined(at91cap9) \
+ || defined(at91sam9260) \
+ || defined(at91sam9261) \
+ || defined(at91sam9263) \
+ || defined(at91sam9g20) \
+ || defined(at91sam9m10) \
+ || defined(at91sam9m11) \
+ || defined(at91sam9rl) \
+ || defined(at91sam9xe)
+
+#define arm926ej_s
+
+#elif defined(at91cap11)
+
+#define arm1176jzf_s
+
+#elif defined(at91sam3u)
+
+#define cortexm3
+
+#else
+
+#error ARM core not defined!
+
+#endif
+
+#endif // #ifndef _CORE_H
\ No newline at end of file diff --git a/peripherals/cp15/cp15.c b/peripherals/cp15/cp15.c new file mode 100644 index 0000000..6a89187 --- /dev/null +++ b/peripherals/cp15/cp15.c @@ -0,0 +1,319 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//-----------------------------------------------------------------------------
+// Reg Reads Writes
+//----------------------------------------------------------------------------
+// 0 ID code Unpredictable
+// 0 cache type Unpredictable
+// 0 TCM status Unpredictable
+// 1 Control Control
+// 2 Translation table base Translation table base
+// 3 Domain access control Domain access control
+// 4 (Reserved)
+// 5 Data fault status Data fault status
+// 5 Instruction fault status Instruction fault status
+// 6 Fault address Fault address
+// 7 cache operations cache operations
+// 8 Unpredictable TLB operations
+// 9 cache lockdown cache lockdown
+// 9 TCM region TCM region
+// 10 TLB lockdown TLB lockdown
+// 11 (Reserved)
+// 12 (Reserved)
+// 13 FCSE PID FCSE PID
+// 13 Context ID Context ID
+// 14 (Reserved)
+// 15 Test configuration Test configuration
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Headers
+//-----------------------------------------------------------------------------
+
+#include <board.h>
+
+#ifdef CP15_PRESENT
+
+#include <utility/trace.h>
+#include "cp15.h"
+
+#if defined(__ICCARM__)
+#include <intrinsics.h>
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Macros
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Defines
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Global functions
+//-----------------------------------------------------------------------------
+
+
+///////////////////////////////////////////////////////////////////////////////
+/// CP15 c1
+/// * I cache
+/// * D cache
+///////////////////////////////////////////////////////////////////////////////
+
+//------------------------------------------------------------------------------
+/// Check Instruction cache
+/// \return 0 if I_cache disable, 1 if I_cache enable
+//------------------------------------------------------------------------------
+unsigned int CP15_IsIcacheEnabled(void)
+{
+ unsigned int control;
+
+ control = CP15_ReadControl();
+ return ((control & (1 << CP15_I_BIT)) != 0);
+}
+
+//------------------------------------------------------------------------------
+/// Enable Instruction cache
+//------------------------------------------------------------------------------
+void CP15_EnableIcache(void)
+{
+ unsigned int control;
+
+ control = CP15_ReadControl();
+
+ // Check if cache is disabled
+ if ((control & (1 << CP15_I_BIT)) == 0) {
+
+ control |= (1 << CP15_I_BIT);
+ CP15_WriteControl(control);
+ TRACE_INFO("I cache enabled.\n\r");
+ }
+#if !defined(OP_BOOTSTRAP_on)
+ else {
+
+ TRACE_INFO("I cache is already enabled.\n\r");
+ }
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Disable Instruction cache
+//------------------------------------------------------------------------------
+void CP15_DisableIcache(void)
+{
+ unsigned int control;
+
+ control = CP15_ReadControl();
+
+ // Check if cache is enabled
+ if ((control & (1 << CP15_I_BIT)) != 0) {
+
+ control &= ~(1 << CP15_I_BIT);
+ CP15_WriteControl(control);
+ TRACE_INFO("I cache disabled.\n\r");
+ }
+ else {
+
+ TRACE_INFO("I cache is already disabled.\n\r");
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Check MMU
+/// \return 0 if MMU disable, 1 if MMU enable
+//------------------------------------------------------------------------------
+unsigned int CP15_IsMMUEnabled(void)
+{
+ unsigned int control;
+
+ control = CP15_ReadControl();
+ return ((control & (1 << CP15_M_BIT)) != 0);
+}
+
+//------------------------------------------------------------------------------
+/// Enable MMU
+//------------------------------------------------------------------------------
+void CP15_EnableMMU(void)
+{
+ unsigned int control;
+
+ control = CP15_ReadControl();
+
+ // Check if MMU is disabled
+ if ((control & (1 << CP15_M_BIT)) == 0) {
+
+ control |= (1 << CP15_M_BIT);
+ CP15_WriteControl(control);
+ TRACE_INFO("MMU enabled.\n\r");
+ }
+ else {
+
+ TRACE_INFO("MMU is already enabled.\n\r");
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Disable MMU
+//------------------------------------------------------------------------------
+void CP15_DisableMMU(void)
+{
+ unsigned int control;
+
+ control = CP15_ReadControl();
+
+ // Check if MMU is enabled
+ if ((control & (1 << CP15_M_BIT)) != 0) {
+
+ control &= ~(1 << CP15_M_BIT);
+ control &= ~(1 << CP15_C_BIT);
+ CP15_WriteControl(control);
+ TRACE_INFO("MMU disabled.\n\r");
+ }
+ else {
+
+ TRACE_INFO("MMU is already disabled.\n\r");
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Check D_cache
+/// \return 0 if D_cache disable, 1 if D_cache enable (with MMU of course)
+//------------------------------------------------------------------------------
+unsigned int CP15_IsDcacheEnabled(void)
+{
+ unsigned int control;
+
+ control = CP15_ReadControl();
+ return ((control & ((1 << CP15_C_BIT)||(1 << CP15_M_BIT))) != 0);
+}
+
+//------------------------------------------------------------------------------
+/// Enable Data cache
+//------------------------------------------------------------------------------
+void CP15_EnableDcache(void)
+{
+ unsigned int control;
+
+ control = CP15_ReadControl();
+
+ if( !CP15_IsMMUEnabled() ) {
+ TRACE_ERROR("Do nothing: MMU not enabled\n\r");
+ }
+ else {
+ // Check if cache is disabled
+ if ((control & (1 << CP15_C_BIT)) == 0) {
+
+ control |= (1 << CP15_C_BIT);
+ CP15_WriteControl(control);
+ TRACE_INFO("D cache enabled.\n\r");
+ }
+ else {
+
+ TRACE_INFO("D cache is already enabled.\n\r");
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Disable Data cache
+//------------------------------------------------------------------------------
+void CP15_DisableDcache(void)
+{
+ unsigned int control;
+
+ control = CP15_ReadControl();
+
+ // Check if cache is enabled
+ if ((control & (1 << CP15_C_BIT)) != 0) {
+
+ control &= ~(1 << CP15_C_BIT);
+ CP15_WriteControl(control);
+ TRACE_INFO("D cache disabled.\n\r");
+ }
+ else {
+
+ TRACE_INFO("D cache is already disabled.\n\r");
+ }
+}
+
+//----------------------------------------------------------------------------
+/// Lock I cache
+/// \param I cache index
+//----------------------------------------------------------------------------
+void CP15_LockIcache(unsigned int index)
+{
+ unsigned int victim = 0;
+
+ // invalidate all the cache (4 ways)
+ CP15_InvalidateIcache();
+
+ // lockdown all the ways except this in parameter
+ victim = CP15_ReadIcacheLockdown();
+ victim = 0;
+ victim |= ~index;
+ victim &= 0xffff;
+ CP15_WriteIcacheLockdown(victim);
+}
+
+//----------------------------------------------------------------------------
+/// Lock D cache
+/// \param D cache way
+//----------------------------------------------------------------------------
+void CP15_LockDcache(unsigned int index)
+{
+ unsigned int victim = 0;
+
+ // invalidate all the cache (4 ways)
+ CP15_InvalidateDcache();
+
+ // lockdown all the ways except this in parameter
+ victim = CP15_ReadDcacheLockdown();
+ victim = 0;
+ victim |= ~index;
+ victim &= 0xffff;
+ CP15_WriteDcacheLockdown(victim);
+}
+
+//----------------------------------------------------------------------------
+/// Lock D cache
+/// \param D cache way
+//----------------------------------------------------------------------------
+void CP15_ShutdownDcache(void)
+{
+ CP15_TestCleanInvalidateDcache();
+ CP15_DrainWriteBuffer();
+ CP15_DisableDcache();
+ CP15_InvalidateTLB();
+}
+
+#endif // CP15_PRESENT
+
diff --git a/peripherals/cp15/cp15.dir b/peripherals/cp15/cp15.dir new file mode 100644 index 0000000..171ea0b --- /dev/null +++ b/peripherals/cp15/cp15.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the API for coprocessor 15.
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/cp15/cp15.h b/peripherals/cp15/cp15.h new file mode 100644 index 0000000..462ae9c --- /dev/null +++ b/peripherals/cp15/cp15.h @@ -0,0 +1,195 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Methods to manage the Coprocessor 15. Coprocessor 15, or System Control
+/// Coprocessor CP15, is used to configure and control all the items in the
+/// list below:
+/// • ARM core
+/// • caches (Icache, Dcache and write buffer)
+/// • TCM
+/// • MMU
+/// • Other system options
+///
+/// !Usage
+///
+/// -# Enable or disable D cache with Enable_D_cache and Disable_D_cache
+/// -# Enable or disable I cache with Enable_I_cache and Disable_I_cache
+///
+//------------------------------------------------------------------------------
+
+#ifndef _CP15_H
+#define _CP15_H
+
+#ifdef CP15_PRESENT
+
+//-----------------------------------------------------------------------------
+// Defines
+//-----------------------------------------------------------------------------
+
+#define CP15_L4_BIT 15 // Determines if the T bit is set when load instructions
+ // change the PC:
+ // 0 = loads to PC set the T bit
+ // 1 = loads to PC do not set T bit
+
+#define CP15_RR_BIT 14 // RR bit Replacement strategy for Icache and Dcache:
+ // 0 = Random replacement
+ // 1 = Round-robin replacement.
+
+#define CP15_V_BIT 13 // V bit Location of exception vectors:
+ // 0 = Normal exception vectors selected address range = 0x0000 0000 to 0x0000 001C
+ // 1 = High exception vect selected, address range = 0xFFFF 0000 to 0xFFFF 001C
+
+#define CP15_I_BIT 12 // I bit Icache enable/disable:
+ // 0 = Icache disabled
+ // 1 = Icache enabled
+
+#define CP15_R_BIT 9 // R bit ROM protection
+
+#define CP15_S_BIT 8 // S bit System protection
+
+#define CP15_B_BIT 7 // B bit Endianness:
+ // 0 = Little-endian operation
+ // 1 = Big-endian operation.
+
+#define CP15_C_BIT 2 // C bit Dcache enable/disable:
+ // 0 = cache disabled
+ // 1 = cache enabled
+
+#define CP15_A_BIT 1 // A bit Alignment fault enable/disable:
+ // 0 = Data address alignment fault checking disabled
+ // 1 = Data address alignment fault checking enabled
+
+#define CP15_M_BIT 0 // M bit MMU enable/disable: 0 = disabled 1 = enabled.
+ // 0 = disabled
+ // 1 = enabled
+
+// No access Any access generates a domain fault.
+#define CP15_DOMAIN_NO_ACCESS 0x00
+// Client Accesses are checked against the access permission bits in the section or page descriptor.
+#define CP15_DOMAIN_CLIENT_ACCESS 0x01
+// Manager Accesses are not checked against the access permission bits so a permission fault cannot be generated.
+#define CP15_DOMAIN_MANAGER_ACCESS 0x03
+
+//-----------------------------------------------------------------------------
+// External functions defined in cp15_asm.S
+//-----------------------------------------------------------------------------
+
+// c0
+extern unsigned int CP15_ReadID(void);
+extern unsigned int CP15_ReadCacheType(void);
+extern unsigned int CP15_ReadTCMStatus(void);
+
+// c1
+extern unsigned int CP15_ReadControl(void);
+extern void CP15_WriteControl(unsigned int value);
+
+// c2
+extern unsigned int CP15_ReadTTB(void);
+extern void CP15_WriteTTB(unsigned int value);
+
+// c3
+extern unsigned int CP15_ReadDomainAccessControl(void);
+extern void CP15_WriteDomainAccessControl(unsigned int value);
+
+// c5
+// CP15_ReadDFSR
+// CP15_writeDFSR
+// CP15_ReadIFSR
+// CP15_WriteIFSR
+
+// c6
+// CP15_ReadFAR
+// CP15_writeFAR
+
+// c7
+extern void CP15_InvalidateIDcache(void);
+extern void CP15_InvalidateDcache(void);
+extern void CP15_InvalidateIcache(void);
+extern void CP15_PrefetchIcacheLine(unsigned int value);
+extern void CP15_TestCleanInvalidateDcache(void);
+extern void CP15_DrainWriteBuffer(void);
+extern void CP15_WaitForInterrupt(void);
+
+// c8
+extern void CP15_InvalidateTLB(void);
+extern void CP15_InvalidateTLBMVA(unsigned int mva);
+extern void CP15_InvalidateITLB(void);
+extern void CP15_InvalidateITLBMVA(unsigned int mva);
+extern void CP15_InvalidateDTLB(void);
+extern void CP15_InvalidateDTLBMVA(unsigned int mva);
+
+// c9
+extern unsigned int CP15_ReadDcacheLockdown(void);
+extern void CP15_WriteDcacheLockdown(unsigned int value);
+extern unsigned int CP15_ReadIcacheLockdown(void);
+extern void CP15_WriteIcacheLockdown(unsigned int value);
+
+// c10
+// CP15_ReadTLBLockdown:
+// CP15_WriteTLBLockdown:
+
+// c13
+// CP15_ReadFCSE_PID
+// CP15_WriteFCSE_PID
+
+//-----------------------------------------------------------------------------
+// Exported functions from CP15.c
+//-----------------------------------------------------------------------------
+
+// MMU (Status/Enable/Disable)
+extern unsigned int CP15_IsMMUEnabled(void);
+extern void CP15_EnableMMU(void);
+extern void CP15_DisableMMU(void);
+
+// I cache (Status/Enable/Disable)
+extern unsigned int CP15_IsIcacheEnabled(void);
+extern void CP15_EnableIcache(void);
+extern void CP15_DisableIcache(void);
+
+// D cache (Status/Enable/Disable)
+extern unsigned int CP15_IsDcacheEnabled(void);
+extern void CP15_EnableDcache(void);
+extern void CP15_DisableDcache(void);
+
+// complex functions
+extern void CP15_LockIcache(unsigned int way);
+extern void CP15_LockDcache(unsigned int way);
+
+extern void CP15_ShutdownDcache(void);
+
+
+#endif // CP15_PRESENT
+
+#endif // #ifndef _CP15_H
+
diff --git a/peripherals/cp15/cp15_asm_gcc.S b/peripherals/cp15/cp15_asm_gcc.S new file mode 100644 index 0000000..6407909 --- /dev/null +++ b/peripherals/cp15/cp15_asm_gcc.S @@ -0,0 +1,607 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "board.h"
+
+#ifdef CP15_PRESENT
+
+//------------------------------------------------------------------------------
+/// Functions to access CP15 coprocessor register
+//------------------------------------------------------------------------------
+ // c0
+ .global CP15_ReadCacheType
+ .global CP15_ReadTCMStatus
+ // c1
+ .global CP15_ReadControl
+ .global CP15_WriteControl
+ // c2
+ // c3
+ .global CP15_ReadDomainAccessControl
+ .global CP15_WriteDomainAccessControl
+ // c7
+ .global CP15_InvalidateIDcache
+ .global CP15_InvalidateDcache
+ .global CP15_InvalidateIcache
+ .global CP15_PrefetchIcacheLine
+ .global CP15_TestCleanInvalidateDcache
+ .global CP15_DrainWriteBuffer
+ .global CP15_WaitForInterrupt
+ // c8
+ .global CP15_InvalidateTLB
+ .global CP15_InvalidateTLBMVA
+ .global CP15_InvalidateITLB
+ .global CP15_InvalidateITLBMVA
+ .global CP15_InvalidateDTLB
+ .global CP15_InvalidateDTLBMVA
+ // c9
+ .global CP15_ReadDcacheLockdown
+ .global CP15_WriteDcacheLockdown
+ .global CP15_ReadIcacheLockdown
+ .global CP15_WriteIcacheLockdown
+ .global CP15_ReadTLBLockdown
+ .global CP15_WriteTLBLockdown
+ // c13
+ .global CP15_ReadTLBLockdown
+ .global CP15_WriteTLBLockdown
+ // c13
+ .global CP15_ReadFCSE_PID
+ .global CP15_WriteFCSE_PID
+
+//------------------------------------------------------------------------------
+/// c0
+/// Register c0 accesses the ID Register, Cache Type Register, and TCM Status Registers.
+/// Reading from this register returns the device ID, the cache type, or the TCM status
+/// depending on the value of Opcode_2 used:
+/// Opcode_2 = 0 ID value.
+/// Opcode_2 = 1 instruction and data cache type.
+/// Opcode_2 = 2 TCM status.
+//------------------------------------------------------------------------------
+
+ .section .CP15_ReadID
+ .global CP15_ReadID
+// C0 read ID
+CP15_ReadID:
+ mov r0, #0
+ mrc p15, 0, r0, c0, c0, 0
+ bx lr
+
+ .section .CP15_ReaDcacheType
+ .global CP15_ReaDcacheType
+// C0 read Cache Type
+CP15_ReaDcacheType:
+ mov r0, #0
+ mrc p15, 0, r0, c0, c0, 1
+ bx lr
+
+// C0 read TCM status
+ .section .CP15_ReadTCMStatus
+ .global CP15_ReadTCMStatus
+CP15_ReadTCMStatus:
+ mov r0, #0
+ mrc p15, 0, r0, c0, c0, 2
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Control Register c1
+/// Register c1 is the Control Register for the ARM926EJ-S processor.
+/// This register specifies the configuration used to enable and disable the
+/// caches and MMU. It is recommended that you access this register using a
+/// read-modify-write sequence.
+//------------------------------------------------------------------------------
+ .section .CP15_ReadControl
+ .global CP15_ReadControl
+// CP15 Read Control Register
+CP15_ReadControl:
+ mov r0, #0
+ mrc p15, 0, r0, c1, c0, 0
+ bx lr
+
+// CP15 Write Control Register
+ .section .CP15_WriteControl
+ .global CP15_WriteControl
+CP15_WriteControl:
+ mcr p15, 0, r0, c1, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// CP15 Translation Table Base Register c2
+/// Register c2 is the Translation Table Base Register (TTBR), for the base
+/// address of the first-level translation table.
+/// Reading from c2 returns the pointer to the currently active first-level
+/// translation table in bits [31:14] and an Unpredictable value in bits [13:0].
+/// Writing to register c2 updates the pointer to the first-level translation
+/// table from the value in bits [31:14] of the written value. Bits [13:0]
+/// Should Be Zero.
+/// You can use the following instructions to access the TTBR:
+/// Read TTBR : MRC p15, 0, <Rd>, c2, c0, 0
+/// Write TTBR : MCR p15, 0, <Rd>, c2, c0, 0
+//------------------------------------------------------------------------------
+ .section .CP15_ReadTTB
+ .global CP15_ReadTTB
+CP15_ReadTTB:
+ mov r0, #0
+ mrc p15, 0, r0, c2, c0, 0
+ bx lr
+
+ .section .CP15_WriteTTB
+ .global CP15_WriteTTB
+CP15_WriteTTB:
+ mcr p15, 0, r0, c2, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Domain Access Control Register c3
+/// Read domain access permissions : MRC p15, 0, <Rd>, c3, c0, 0
+/// Write domain access permissions : MCR p15, 0, <Rd>, c3, c0, 0
+//------------------------------------------------------------------------------
+ .section .CP15_ReadDomainAccessControl
+ .global CP15_ReadDomainAccessControl
+CP15_ReadDomainAccessControl:
+ mov r0, #0
+ mrc p15, 0, r0, c3, c0, 0
+ bx lr
+
+ .section .CP15_WriteDomainAccessControl
+ .global CP15_WriteDomainAccessControl
+CP15_WriteDomainAccessControl:
+ mcr p15, 0, r0, c3, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Fault Status Registers Register c5
+/// Register c5 accesses the Fault Status Registers (FSRs). The FSRs contain the source of
+/// the last instruction or data fault. The instruction-side FSR is intended for debug
+/// purposes only. The FSR is updated for alignment faults, and external aborts that occur
+/// while the MMU is disabled.
+/// The FSR accessed is determined by the value of the Opcode_2 field:
+/// Opcode_2 = 0 Data Fault Status Register (DFSR).
+/// Opcode_2 = 1 Instruction Fault Status Register (IFSR).
+/// The fault type encoding is listed in Table 3-9 on page 3-22.
+/// You can access the FSRs using the following instructions:
+/// MRC p15, 0, <Rd>, c5, c0, 0 ;read DFSR
+/// MCR p15, 0, <Rd>, c5, c0, 0 ;write DFSR
+/// MRC p15, 0, <Rd>, c5, c0, 1 ;read IFSR
+/// MCR p15, 0, <Rd>, c5, c0, 1 ;write IFSR
+//------------------------------------------------------------------------------
+
+ .section .CP15_ReadDFSR
+ .global CP15_ReadDFSR
+CP15_ReadDFSR:
+ mov r0, #0
+ mrc p15, 0, r0, c5, c0, 0
+ bx lr
+
+ .section .CP15_writeDFSR
+ .global CP15_writeDFSR
+CP15_writeDFSR:
+ mcr p15, 0, r0, c5, c0, 0
+ bx lr
+
+ .section .CP15_ReadIFSR
+ .global CP15_ReadIFSR
+CP15_ReadIFSR:
+ mov r0, #0
+ mrc p15, 0, r0, c5, c0, 1
+ bx lr
+
+ .section .CP15_WriteIFSR
+ .global CP15_WriteIFSR
+CP15_WriteIFSR:
+ mcr p15, 0, r0, c5, c0, 1
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Fault Address Register c6
+/// Register c6 accesses the Fault Address Register (FAR). The FAR contains the Modified
+/// Virtual Address of the access being attempted when a Data Abort occurred. The FAR is
+/// only updated for Data Aborts, not for Prefetch Aborts. The FAR is updated for
+/// alignment faults, and external aborts that occur while the MMU is disabled.
+/// You can use the following instructions to access the FAR:
+/// MRC p15, 0, <Rd>, c6, c0, 0 ; read FAR
+/// MCR p15, 0, <Rd>, c6, c0, 0 ; write FAR
+//------------------------------------------------------------------------------
+ .section .CP15_ReadFAR
+ .global CP15_ReadFAR
+CP15_ReadFAR:
+ mov r0, #0
+ mrc p15, 0, r0, c6, c0, 0
+ bx lr
+
+ .section .CP15_writeFAR
+ .global CP15_writeFAR
+CP15_writeFAR:
+ mcr p15, 0, r0, c6, c0, 0
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Control functions caches and the write buffer c7
+/// Register c7 controls the caches and the write buffer. The function of each cache
+/// operation is selected by the Opcode_2 and CRm fields in the MCR instruction used to
+/// write to CP15 c7. Writing other Opcode_2 or CRm values is Unpredictable.
+/// Reading from CP15 c7 is Unpredictable, with the exception of the two test and clean
+/// operations (see Table 2-18 on page 2-21 and Test and clean operations on page 2-23).
+/// You can use the following instruction to write to c7:
+/// MCR p15, <Opcode_1>, <Rd>, <CRn>, <CRm>, <Opcode_2>
+//------------------------------------------------------------------------------
+/// Invalidate Icache and Dcache MCR p15, 0, <Rd>, c7, c7, 0
+/// Invalidate Icache MCR p15, 0, <Rd>, c7, c5, 0
+/// Invalidate Icache single entry (MVA) MVA MCR p15, 0, <Rd>, c7, c5, 1
+/// Invalidate Icache single entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c5, 2
+/// Prefetch Icache line (MVA) MVA MCR p15, 0, <Rd>, c7, c13, 1
+/// Invalidate Dcache MCR p15, 0, <Rd>, c7, c6, 0
+/// Invalidate Dcache single entry (MVA) MVA MCR p15, 0, <Rd>, c7, c6, 1
+/// Invalidate Dcache single entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c6, 2
+/// Clean Dcache single entry (MVA) MVA MCR p15, 0, <Rd>, c7, c10, 1
+/// Clean Dcache single entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c10, 2
+/// Test and clean Dcache - MRC p15, 0, <Rd>, c7, c10, 3
+/// Clean and invalidate Dcache entry (MVA) MVA MCR p15, 0, <Rd>, c7, c14, 1
+/// Clean and invalidate Dcache entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c14, 2
+/// Test, clean, and invalidate Dcache - MRC p15, 0, <Rd>, c7, c14, 3
+/// Drain write buffer SBZ MCR p15, 0, <Rd>, c7, c10, 4
+/// Wait for interrupt SBZ MCR p15, 0, <Rd>, c7, c0, 4
+//------------------------------------------------------------------------------
+
+// Invalidate Icache and Dcache
+ .section .CP15_InvalidateIDcache
+ .global CP15_InvalidateIDcache
+CP15_InvalidateIDcache:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c7, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+// Invalidate Icache
+ .section .CP15_InvalidateIcache
+ .global CP15_InvalidateIcache
+CP15_InvalidateIcache:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+// Invalidate Dcache
+ .section .CP15_InvalidateDcache
+ .global CP15_InvalidateDcache
+CP15_InvalidateDcache:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c6, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// CP15 Prefetch Icache line c7
+/// Performs an Icache lookup of the specified modified virtual address.
+/// If the cache misses, and the region is cacheable, a linefill is performed.
+/// Prefetch Icache line (MVA): MCR p15, 0, <Rd>, c7, c13, 1
+//------------------------------------------------------------------------------
+ .section .CP15_PrefetchIcacheLine
+ .global CP15_PrefetchIcacheLine
+CP15_PrefetchIcacheLine:
+ mcr p15, 0, r0, c7, c13, 1
+ bx lr
+
+//------------------------------------------------------------------------------
+/// CP15 Test, clean, and invalidate Dcache c7
+/// As for test and clean, except that when the entire cache has
+/// been tested and cleaned, it is invalidated.
+//------------------------------------------------------------------------------
+ .section .CP15_TestCleanInvalidateDcache
+ .global CP15_TestCleanInvalidateDcache
+CP15_TestCleanInvalidateDcache:
+ mrc p15, 0, r0, c7, c14, 3
+ bne CP15_TestCleanInvalidateDcache
+ bx lr
+
+//------------------------------------------------------------------------------
+/// CP15 Drain write buffer c7
+/// This instruction acts as an explicit memory barrier. It drains
+/// the contents of the write buffers of all memory stores
+/// occurring in program order before this instruction is
+/// completed. No instructions occurring in program order
+/// after this instruction are executed until it completes. This
+/// can be used when timing of specific stores to the level two
+/// memory system has to be controlled (for example, when a
+/// store to an interrupt acknowledge location has to complete
+/// before interrupts are enabled).
+//------------------------------------------------------------------------------
+ .section .CP15_DrainWriteBuffer
+ .global CP15_DrainWriteBuffer
+CP15_DrainWriteBuffer:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4
+ bx lr
+
+//------------------------------------------------------------------------------
+/// CP15 Wait For Interrupt operation c7
+/// The purpose of the Wait For Interrupt operation is to put the processor in
+/// to a low power state.
+/// This puts the processor into a low-power state and stops it executing more
+/// instructions until an interrupt, or debug request occurs, regardless of
+/// whether the interrupts are disabled by the masks in the CPSR.
+/// When an interrupt does occur, the mcr instruction completes and the IRQ or
+/// FIQ handler is entered as normal. The return link in r14_irq or r14_fiq
+/// contains the address of the mcr instruction plus 8, so that the normal
+/// instruction used for interrupt return (SUBS PC,R14,#4) returns to the
+/// instruction following the mcr.
+/// Wait For Interrupt : MCR p15, 0, <Rd>, c7, c0, 4
+//------------------------------------------------------------------------------
+ .section .CP15_WaitForInterrupt
+ .global CP15_WaitForInterrupt
+CP15_WaitForInterrupt:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c0, 4
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Translation Lookaside Buffer (TLB) : c8
+/// This is a write-only register used to control the Translation Lookaside Buffer (TLB).
+/// There is a single TLB used to hold entries for both data and instructions. The TLB is
+/// divided into two parts:
+/// • a set-associative part
+/// • a fully-associative part.
+/// The fully-associative part (also referred to as the lockdown part of the TLB) is used to
+/// store entries to be locked down. Entries held in the lockdown part of the TLB are
+/// preserved during an invalidate TLB operation. Entries can be removed from the
+/// lockdown TLB using an invalidate TLB single entry operation.
+/// Six TLB operations are defined, and the function to be performed is selected by the
+/// Opcode_2 and CRm fields in the MCR instruction used to write CP15 c8. Writing other
+/// Opcode_2 or CRm values is Unpredictable. Reading from this register is Unpredictable.
+//------------------------------------------------------------------------------
+/// Invalidate TLB MCR p15, 0, <Rd>, c8, c7, 0
+/// Invalidate TLB single entry (MVA) MCR p15, 0, <Rd>, c8, c7, 1
+/// Invalidate instruction TLB MCR p15, 0, <Rd>, c8, c5, 0
+/// Invalidate instruction TLB single entry (MVA) MCR p15, 0, <Rd>, c8, c5, 1
+/// Invalidate data TLB MCR p15, 0, <Rd>, c8, c6, 0
+/// Invalidate data TLB single entry (MVA) MCR p15, 0, <Rd>, c8, c6, 1
+//------------------------------------------------------------------------------
+
+ .section .CP15_InvalidateTLB
+ .global CP15_InvalidateTLB
+CP15_InvalidateTLB:
+ mov r0, #0
+ mcr p15, 0, r0, c8, c7, 0
+ bx lr
+
+ .section .CP15_InvalidateTLBMVA
+ .global CP15_InvalidateTLBMVA
+CP15_InvalidateTLBMVA:
+ mcr p15, 0, r0, c8, c7, 1
+ bx lr
+
+ .section .CP15_InvalidateITLB
+ .global CP15_InvalidateITLB
+CP15_InvalidateITLB:
+ mov r0, #0
+ mcr p15, 0, r0, c8, c5, 0
+ bx lr
+
+ .section .CP15_InvalidateITLBMVA
+ .global CP15_InvalidateITLBMVA
+CP15_InvalidateITLBMVA:
+ mcr p15, 0, r0, c8, c5, 1
+ bx lr
+
+ .section .CP15_InvalidateDTLB
+ .global CP15_InvalidateDTLB
+CP15_InvalidateDTLB:
+ mov r0, #0
+ mcr p15, 0, r0, c8, c6, 0
+ bx lr
+
+ .section .CP15_InvalidateDTLBMVA
+ .global CP15_InvalidateDTLBMVA
+CP15_InvalidateDTLBMVA:
+ mcr p15, 0, r0, c8, c6, 1
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Cache Lockdown Register c9
+/// The Cache Lockdown Register uses a cache-way-based locking scheme (Format C) that
+/// enables you to control each cache way independently.
+/// These registers enable you to control which cache ways of the four-way cache are used
+/// for the allocation on a linefill. When the registers are defined, subsequent linefills are
+/// only placed in the specified target cache way. This gives you some control over the
+/// cache pollution caused by particular applications, and provides a traditional lockdown
+/// operation for locking critical code into the cache.
+//------------------------------------------------------------------------------
+/// Read Dcache Lockdown Register MRC p15,0,<Rd>,c9,c0,0
+/// Write Dcache Lockdown Register MCR p15,0,<Rd>,c9,c0,0
+/// Read Icache Lockdown Register MRC p15,0,<Rd>,c9,c0,1
+/// Write Icache Lockdown Register MCR p15,0,<Rd>,c9,c0,1
+//------------------------------------------------------------------------------
+
+ .section .CP15_ReadDcacheLockdown
+ .global CP15_ReadDcacheLockdown
+CP15_ReadDcacheLockdown:
+ mov r0, #0
+ mrc p15, 0, r0, c9, c0, 0
+ bx lr
+
+ .section .CP15_WriteDcacheLockdown
+ .global CP15_WriteDcacheLockdown
+CP15_WriteDcacheLockdown:
+ mcr p15, 0, r0, c9, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+ .section .CP15_ReadIcacheLockdown
+ .global CP15_ReadIcacheLockdown
+CP15_ReadIcacheLockdown:
+ mov r0, #0
+ mrc p15, 0, r0, c9, c0, 1
+ bx lr
+
+ .section .CP15_WriteIcacheLockdown
+ .global CP15_WriteIcacheLockdown
+CP15_WriteIcacheLockdown:
+ mcr p15, 0, r0, c9, c0, 1
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// TLB Lockdown Register c10
+/// The TLB Lockdown Register controls where hardware page table walks place the
+/// TLB entry, in the set associative region or the lockdown region of the TLB,
+/// and if in the lockdown region, which entry is written. The lockdown region
+/// of the TLB contains eight entries. See TLB structure for a description of
+/// the structure of the TLB.
+//------------------------------------------------------------------------------
+/// Read data TLB lockdown victim MRC p15,0,<Rd>,c10,c0,0
+/// Write data TLB lockdown victim MCR p15,0,<Rd>,c10,c0,0
+//------------------------------------------------------------------------------
+ .section .CP15_ReadTLBLockdown
+ .global CP15_ReadTLBLockdown
+CP15_ReadTLBLockdown:
+ mov r0, #0
+ mrc p15, 0, r0, c10, c0, 0
+ bx lr
+
+ .section .CP15_WriteTLBLockdown
+ .global CP15_WriteTLBLockdown
+CP15_WriteTLBLockdown:
+ mcr p15, 0, r0, c10, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Register c13 accesses the process identifier registers. The register accessed depends on
+/// the value of the Opcode_2 field:
+/// Opcode_2 = 0 Selects the Fast Context Switch Extension (FCSE) Process Identifier (PID) Register.
+/// Opcode_2 = 1 Selects the Context ID Register.
+//------------------------------------------------------------------------------
+/// FCSE PID Register
+/// Addresses issued by the ARM9EJ-S core in the range 0 to 32MB are translated in
+/// accordance with the value contained in this register. Address A becomes A + (FCS
+/// PID x 32MB). It is this modified address that is seen by the caches, MMU, and TC
+/// interface. Addresses above 32MB are not modified. The FCSE PID is a seven-bit fie
+/// enabling 128 x 32MB processes to be mapped.
+/// If the FCSE PID is 0, there is a flat mapping between the virtual addresses output by
+/// ARM9EJ-S core and the modified virtual addresses used by the caches, MMU, and
+/// TCM interface. The FCSE PID is set to 0 at system reset.
+/// If the MMU is disabled, then no FCSE address translation occurs.
+/// FCSE translation is not applied for addresses used for entry based cache or TLB
+/// maintenance operations. For these operations VA = MVA.
+//------------------------------------------------------------------------------
+/// Read FCSE PID MRC p15,0,<Rd>,c13,c0, 0
+/// Write FCSE PID MCR p15,0,<Rd>,c13,c0, 0
+//------------------------------------------------------------------------------
+/// Context ID Register
+/// The Context ID Register provides a mechanism to allow real-time trace tools to identify
+/// the currently executing process in multi-tasking environments.
+/// The contents of this register are replicated on the ETMPROCID pins of the
+/// ARM926EJ-S processor. ETMPROCIDWR is pulsed when a write occurs to the
+/// Context ID Register.
+//------------------------------------------------------------------------------
+/// Read context ID MRC p15,0,<Rd>,c13,c0, 1
+/// Write context ID MCR p15,0,<Rd>,c13,c0, 1
+//------------------------------------------------------------------------------
+ .section .CP15_ReadFCSE_PID
+ .global CP15_ReadFCSE_PID
+CP15_ReadFCSE_PID:
+ mov r0, #0
+ mrc p15, 0, r0, c13, c0, 0
+ bx lr
+
+ .section .CP15_WriteFCSE_PID
+ .global CP15_WriteFCSE_PID
+CP15_WriteFCSE_PID:
+ mcr p15, 0, r0, c13, c0, 0
+ bx lr
+#endif
+
diff --git a/peripherals/cp15/cp15_asm_iar.s b/peripherals/cp15/cp15_asm_iar.s new file mode 100644 index 0000000..b18aff1 --- /dev/null +++ b/peripherals/cp15/cp15_asm_iar.s @@ -0,0 +1,659 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+ MODULE ?cp15
+
+ ;; Forward declaration of sections.
+ SECTION IRQ_STACK:DATA:NOROOT(2)
+ SECTION CSTACK:DATA:NOROOT(3)
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#define __ASSEMBLY__
+#include "board.h"
+
+#ifdef CP15_PRESENT
+
+//------------------------------------------------------------------------------
+/// Functions to access CP15 coprocessor register
+//------------------------------------------------------------------------------
+ // c0
+ PUBLIC CP15_ReadID
+ PUBLIC CP15_ReaDcacheType
+ PUBLIC CP15_ReadTCMStatus
+ // c1
+ PUBLIC CP15_ReadControl
+ PUBLIC CP15_WriteControl
+ // c2
+ PUBLIC CP15_ReadTTB
+ PUBLIC CP15_WriteTTB
+ // c3
+ PUBLIC CP15_ReadDomainAccessControl
+ PUBLIC CP15_WriteDomainAccessControl
+ // c7
+ PUBLIC CP15_InvalidateIDcache
+ PUBLIC CP15_InvalidateDcache
+ PUBLIC CP15_InvalidateIcache
+ PUBLIC CP15_PrefetchIcacheLine
+ PUBLIC CP15_TestCleanInvalidateDcache
+ PUBLIC CP15_DrainWriteBuffer
+ PUBLIC CP15_WaitForInterrupt
+ // c8
+ PUBLIC CP15_InvalidateTLB
+ PUBLIC CP15_InvalidateTLBMVA
+ PUBLIC CP15_InvalidateITLB
+ PUBLIC CP15_InvalidateITLBMVA
+ PUBLIC CP15_InvalidateDTLB
+ PUBLIC CP15_InvalidateDTLBMVA
+ // c9
+ PUBLIC CP15_ReadDcacheLockdown
+ PUBLIC CP15_WriteDcacheLockdown
+ PUBLIC CP15_ReadIcacheLockdown
+ PUBLIC CP15_WriteIcacheLockdown
+ PUBLIC CP15_ReadTLBLockdown
+ PUBLIC CP15_WriteTLBLockdown
+ // c13
+ PUBLIC CP15_ReadTLBLockdown
+ PUBLIC CP15_WriteTLBLockdown
+ // c13
+ PUBLIC CP15_ReadFCSE_PID
+ PUBLIC CP15_WriteFCSE_PID
+
+//------------------------------------------------------------------------------
+/// c0
+/// Register c0 accesses the ID Register, Cache Type Register, and TCM Status Registers.
+/// Reading from this register returns the device ID, the cache type, or the TCM status
+/// depending on the value of Opcode_2 used:
+/// Opcode_2 = 0 ID value.
+/// Opcode_2 = 1 instruction and data cache type.
+/// Opcode_2 = 2 TCM status.
+//------------------------------------------------------------------------------
+ SECTION .CP15_ReadID:DATA:NOROOT(2)
+ PUBLIC CP15_ReadID
+ //ARM
+// C0 read ID
+CP15_ReadID:
+ mov r0, #0
+ mrc p15, 0, r0, c0, c0, 0
+ bx lr
+
+ SECTION .CP15_ReaDcacheType:CODE:NOROOT(2)
+ PUBLIC CP15_ReaDcacheType
+ //ARM
+// C0 read Cache Type
+CP15_ReaDcacheType:
+ mov r0, #0
+ mrc p15, 0, r0, c0, c0, 1
+ bx lr
+
+ SECTION .CP15_ReadTCMStatus:CODE:NOROOT(2)
+ PUBLIC CP15_ReadTCMStatus
+ //ARM
+// C0 read TCM status
+CP15_ReadTCMStatus:
+ mov r0, #0
+ mrc p15, 0, r0, c0, c0, 2
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Control Register c1
+/// Register c1 is the Control Register for the ARM926EJ-S processor.
+/// This register specifies the configuration used to enable and disable the
+/// caches and MMU. It is recommended that you access this register using a
+/// read-modify-write sequence.
+//------------------------------------------------------------------------------
+
+ SECTION .CP15_ReadControl:CODE:NOROOT(2)
+ PUBLIC CP15_ReadControl
+ //ARM
+// CP15 Read Control Register
+CP15_ReadControl:
+ mov r0, #0
+ mrc p15, 0, r0, c1, c0, 0
+ bx lr
+
+ SECTION .CP15_WriteControl:CODE:NOROOT(2)
+ PUBLIC CP15_WriteControl
+ //ARM
+// CP15 Write Control Register
+CP15_WriteControl:
+ mcr p15, 0, r0, c1, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// CP15 Translation Table Base Register c2
+/// Register c2 is the Translation Table Base Register (TTBR), for the base
+/// address of the first-level translation table.
+/// Reading from c2 returns the pointer to the currently active first-level
+/// translation table in bits [31:14] and an Unpredictable value in bits [13:0].
+/// Writing to register c2 updates the pointer to the first-level translation
+/// table from the value in bits [31:14] of the written value. Bits [13:0]
+/// Should Be Zero.
+/// You can use the following instructions to access the TTBR:
+/// Read TTBR : MRC p15, 0, <Rd>, c2, c0, 0
+/// Write TTBR : MCR p15, 0, <Rd>, c2, c0, 0
+//------------------------------------------------------------------------------
+
+ SECTION .CP15_ReadTTB:CODE:NOROOT(2)
+ PUBLIC CP15_ReadTTB
+ //ARM
+CP15_ReadTTB:
+ mov r0, #0
+ mrc p15, 0, r0, c2, c0, 0
+ bx lr
+
+ SECTION .CP15_WriteTTB:CODE:NOROOT(2)
+ PUBLIC CP15_WriteTTB
+ //ARM
+CP15_WriteTTB:
+ mcr p15, 0, r0, c2, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Domain Access Control Register c3
+/// Read domain access permissions : MRC p15, 0, <Rd>, c3, c0, 0
+/// Write domain access permissions : MCR p15, 0, <Rd>, c3, c0, 0
+//------------------------------------------------------------------------------
+
+ SECTION .CP15_ReadDomainAccessControl:CODE:NOROOT(2)
+ PUBLIC CP15_ReadDomainAccessControl
+ //ARM
+CP15_ReadDomainAccessControl:
+ mov r0, #0
+ mrc p15, 0, r0, c3, c0, 0
+ bx lr
+
+ SECTION .CP15_WriteDomainAccessControl:CODE:NOROOT(2)
+ PUBLIC CP15_WriteDomainAccessControl
+ //ARM
+CP15_WriteDomainAccessControl:
+ mcr p15, 0, r0, c3, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Fault Status Registers Register c5
+/// Register c5 accesses the Fault Status Registers (FSRs). The FSRs contain the source of
+/// the last instruction or data fault. The instruction-side FSR is intended for debug
+/// purposes only. The FSR is updated for alignment faults, and external aborts that occur
+/// while the MMU is disabled.
+/// The FSR accessed is determined by the value of the Opcode_2 field:
+/// Opcode_2 = 0 Data Fault Status Register (DFSR).
+/// Opcode_2 = 1 Instruction Fault Status Register (IFSR).
+/// The fault type encoding is listed in Table 3-9 on page 3-22.
+/// You can access the FSRs using the following instructions:
+/// MRC p15, 0, <Rd>, c5, c0, 0 ;read DFSR
+/// MCR p15, 0, <Rd>, c5, c0, 0 ;write DFSR
+/// MRC p15, 0, <Rd>, c5, c0, 1 ;read IFSR
+/// MCR p15, 0, <Rd>, c5, c0, 1 ;write IFSR
+//------------------------------------------------------------------------------
+
+ SECTION .CP15_ReadDFSR:CODE:NOROOT(2)
+ PUBLIC CP15_ReadDFSR
+ //ARM
+CP15_ReadDFSR:
+ mov r0, #0
+ mrc p15, 0, r0, c5, c0, 0
+ bx lr
+
+ SECTION .CP15_writeDFSR:CODE:NOROOT(2)
+ PUBLIC CP15_writeDFSR
+ //ARM
+CP15_writeDFSR:
+ mcr p15, 0, r0, c5, c0, 0
+ bx lr
+
+ SECTION .CP15_ReadIFSR:CODE:NOROOT(2)
+ PUBLIC CP15_ReadIFSR
+ //ARM
+CP15_ReadIFSR:
+ mov r0, #0
+ mrc p15, 0, r0, c5, c0, 1
+ bx lr
+
+ SECTION .CP15_WriteIFSR:CODE:NOROOT(2)
+ PUBLIC CP15_WriteIFSR
+ //ARM
+CP15_WriteIFSR:
+ mcr p15, 0, r0, c5, c0, 1
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Fault Address Register c6
+/// Register c6 accesses the Fault Address Register (FAR). The FAR contains the Modified
+/// Virtual Address of the access being attempted when a Data Abort occurred. The FAR is
+/// only updated for Data Aborts, not for Prefetch Aborts. The FAR is updated for
+/// alignment faults, and external aborts that occur while the MMU is disabled.
+/// You can use the following instructions to access the FAR:
+/// MRC p15, 0, <Rd>, c6, c0, 0 ; read FAR
+/// MCR p15, 0, <Rd>, c6, c0, 0 ; write FAR
+//------------------------------------------------------------------------------
+ SECTION .CP15_ReadFAR:CODE:NOROOT(2)
+ PUBLIC CP15_ReadFAR
+ //ARM
+CP15_ReadFAR:
+ mov r0, #0
+ mrc p15, 0, r0, c6, c0, 0
+ bx lr
+
+ SECTION .CP15_writeFAR:CODE:NOROOT(2)
+ PUBLIC CP15_writeFAR
+ //ARM
+CP15_writeFAR:
+ mcr p15, 0, r0, c6, c0, 0
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Control functions caches and the write buffer c7
+/// Register c7 controls the caches and the write buffer. The function of each cache
+/// operation is selected by the Opcode_2 and CRm fields in the MCR instruction used to
+/// write to CP15 c7. Writing other Opcode_2 or CRm values is Unpredictable.
+/// Reading from CP15 c7 is Unpredictable, with the exception of the two test and clean
+/// operations (see Table 2-18 on page 2-21 and Test and clean operations on page 2-23).
+/// You can use the following instruction to write to c7:
+/// MCR p15, <Opcode_1>, <Rd>, <CRn>, <CRm>, <Opcode_2>
+//------------------------------------------------------------------------------
+/// Invalidate Icache and Dcache MCR p15, 0, <Rd>, c7, c7, 0
+/// Invalidate Icache MCR p15, 0, <Rd>, c7, c5, 0
+/// Invalidate Icache single entry (MVA) MVA MCR p15, 0, <Rd>, c7, c5, 1
+/// Invalidate Icache single entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c5, 2
+/// Prefetch Icache line (MVA) MVA MCR p15, 0, <Rd>, c7, c13, 1
+/// Invalidate Dcache MCR p15, 0, <Rd>, c7, c6, 0
+/// Invalidate Dcache single entry (MVA) MVA MCR p15, 0, <Rd>, c7, c6, 1
+/// Invalidate Dcache single entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c6, 2
+/// Clean Dcache single entry (MVA) MVA MCR p15, 0, <Rd>, c7, c10, 1
+/// Clean Dcache single entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c10, 2
+/// Test and clean Dcache - MRC p15, 0, <Rd>, c7, c10, 3
+/// Clean and invalidate Dcache entry (MVA) MVA MCR p15, 0, <Rd>, c7, c14, 1
+/// Clean and invalidate Dcache entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c14, 2
+/// Test, clean, and invalidate Dcache - MRC p15, 0, <Rd>, c7, c14, 3
+/// Drain write buffer SBZ MCR p15, 0, <Rd>, c7, c10, 4
+/// Wait for interrupt SBZ MCR p15, 0, <Rd>, c7, c0, 4
+//------------------------------------------------------------------------------
+
+ SECTION .CP15_InvalidateIDcache:CODE:NOROOT(2)
+ PUBLIC CP15_InvalidateIDcache
+ //ARM
+// Invalidate Icache and Dcache
+CP15_InvalidateIDcache:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c7, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+ SECTION .CP15_InvalidateIcache:CODE:NOROOT(2)
+ PUBLIC CP15_InvalidateIcache
+ //ARM
+// Invalidate Icache
+CP15_InvalidateIcache:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+ SECTION .CP15_InvalidateDcache:CODE:NOROOT(2)
+ PUBLIC CP15_InvalidateDcache
+ //ARM
+// Invalidate Dcache
+CP15_InvalidateDcache:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c6, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// CP15 Prefetch Icache line c7
+/// Performs an Icache lookup of the specified modified virtual address.
+/// If the cache misses, and the region is cacheable, a linefill is performed.
+/// Prefetch Icache line (MVA): MCR p15, 0, <Rd>, c7, c13, 1
+//------------------------------------------------------------------------------
+ SECTION .CP15_PrefetchIcacheLine:CODE:NOROOT(2)
+ PUBLIC CP15_PrefetchIcacheLine
+ //ARM
+CP15_PrefetchIcacheLine:
+ mcr p15, 0, r0, c7, c13, 1
+ bx lr
+
+//------------------------------------------------------------------------------
+/// CP15 Test, clean, and invalidate Dcache c7
+/// As for test and clean, except that when the entire cache has
+/// been tested and cleaned, it is invalidated.
+//------------------------------------------------------------------------------
+ SECTION .CP15_TestCleanInvalidateDcache:CODE:NOROOT(2)
+ PUBLIC CP15_TestCleanInvalidateDcache
+ //ARM
+CP15_TestCleanInvalidateDcache:
+ mrc p15, 0, r0, c7, c14, 3
+ bne CP15_TestCleanInvalidateDcache
+ bx lr
+
+//------------------------------------------------------------------------------
+/// CP15 Drain write buffer c7
+/// This instruction acts as an explicit memory barrier. It drains
+/// the contents of the write buffers of all memory stores
+/// occurring in program order before this instruction is
+/// completed. No instructions occurring in program order
+/// after this instruction are executed until it completes. This
+/// can be used when timing of specific stores to the level two
+/// memory system has to be controlled (for example, when a
+/// store to an interrupt acknowledge location has to complete
+/// before interrupts are enabled).
+//------------------------------------------------------------------------------
+ SECTION .CP15_DrainWriteBuffer:CODE:NOROOT(2)
+ PUBLIC CP15_DrainWriteBuffer
+ //ARM
+CP15_DrainWriteBuffer:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4
+ bx lr
+
+//------------------------------------------------------------------------------
+/// CP15 Wait For Interrupt operation c7
+/// The purpose of the Wait For Interrupt operation is to put the processor in
+/// to a low power state.
+/// This puts the processor into a low-power state and stops it executing more
+/// instructions until an interrupt, or debug request occurs, regardless of
+/// whether the interrupts are disabled by the masks in the CPSR.
+/// When an interrupt does occur, the mcr instruction completes and the IRQ or
+/// FIQ handler is entered as normal. The return link in r14_irq or r14_fiq
+/// contains the address of the mcr instruction plus 8, so that the normal
+/// instruction used for interrupt return (SUBS PC,R14,#4) returns to the
+/// instruction following the mcr.
+/// Wait For Interrupt : MCR p15, 0, <Rd>, c7, c0, 4
+//------------------------------------------------------------------------------
+ SECTION .CP15_WaitForInterrupt:CODE:NOROOT(2)
+ PUBLIC CP15_WaitForInterrupt
+ //ARM
+CP15_WaitForInterrupt:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c0, 4
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Translation Lookaside Buffer (TLB) : c8
+/// This is a write-only register used to control the Translation Lookaside Buffer (TLB).
+/// There is a single TLB used to hold entries for both data and instructions. The TLB is
+/// divided into two parts:
+/// • a set-associative part
+/// • a fully-associative part.
+/// The fully-associative part (also referred to as the lockdown part of the TLB) is used to
+/// store entries to be locked down. Entries held in the lockdown part of the TLB are
+/// preserved during an invalidate TLB operation. Entries can be removed from the
+/// lockdown TLB using an invalidate TLB single entry operation.
+/// Six TLB operations are defined, and the function to be performed is selected by the
+/// Opcode_2 and CRm fields in the MCR instruction used to write CP15 c8. Writing other
+/// Opcode_2 or CRm values is Unpredictable. Reading from this register is Unpredictable.
+//------------------------------------------------------------------------------
+/// Invalidate TLB MCR p15, 0, <Rd>, c8, c7, 0
+/// Invalidate TLB single entry (MVA) MCR p15, 0, <Rd>, c8, c7, 1
+/// Invalidate instruction TLB MCR p15, 0, <Rd>, c8, c5, 0
+/// Invalidate instruction TLB single entry (MVA) MCR p15, 0, <Rd>, c8, c5, 1
+/// Invalidate data TLB MCR p15, 0, <Rd>, c8, c6, 0
+/// Invalidate data TLB single entry (MVA) MCR p15, 0, <Rd>, c8, c6, 1
+//------------------------------------------------------------------------------
+
+ SECTION .CP15_InvalidateTLB:CODE:NOROOT(2)
+ PUBLIC CP15_InvalidateTLB
+ //ARM
+CP15_InvalidateTLB:
+ mov r0, #0
+ mcr p15, 0, r0, c8, c7, 0
+ bx lr
+
+ SECTION .CP15_InvalidateTLBMVA:CODE:NOROOT(2)
+ PUBLIC CP15_InvalidateTLBMVA
+ //ARM
+CP15_InvalidateTLBMVA:
+ mcr p15, 0, r0, c8, c7, 1
+ bx lr
+
+ SECTION .CP15_InvalidateITLB:CODE:NOROOT(2)
+ PUBLIC CP15_InvalidateITLB
+ //ARM
+CP15_InvalidateITLB:
+ mov r0, #0
+ mcr p15, 0, r0, c8, c5, 0
+ bx lr
+
+ SECTION .CP15_InvalidateITLBMVA:CODE:NOROOT(2)
+ PUBLIC CP15_InvalidateITLBMVA
+ //ARM
+CP15_InvalidateITLBMVA:
+ mcr p15, 0, r0, c8, c5, 1
+ bx lr
+
+ SECTION .CP15_InvalidateDTLB:CODE:NOROOT(2)
+ PUBLIC CP15_InvalidateDTLB
+ //ARM
+CP15_InvalidateDTLB:
+ mov r0, #0
+ mcr p15, 0, r0, c8, c6, 0
+ bx lr
+
+ SECTION .CP15_InvalidateDTLBMVA:CODE:NOROOT(2)
+ PUBLIC CP15_InvalidateDTLBMVA
+ //ARM
+CP15_InvalidateDTLBMVA:
+ mcr p15, 0, r0, c8, c6, 1
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Cache Lockdown Register c9
+/// The Cache Lockdown Register uses a cache-way-based locking scheme (Format C) that
+/// enables you to control each cache way independently.
+/// These registers enable you to control which cache ways of the four-way cache are used
+/// for the allocation on a linefill. When the registers are defined, subsequent linefills are
+/// only placed in the specified target cache way. This gives you some control over the
+/// cache pollution caused by particular applications, and provides a traditional lockdown
+/// operation for locking critical code into the cache.
+//------------------------------------------------------------------------------
+/// Read Dcache Lockdown Register MRC p15,0,<Rd>,c9,c0,0
+/// Write Dcache Lockdown Register MCR p15,0,<Rd>,c9,c0,0
+/// Read Icache Lockdown Register MRC p15,0,<Rd>,c9,c0,1
+/// Write Icache Lockdown Register MCR p15,0,<Rd>,c9,c0,1
+//------------------------------------------------------------------------------
+
+ SECTION .CP15_ReadDcacheLockdown:CODE:NOROOT(2)
+ PUBLIC CP15_ReadDcacheLockdown
+ //ARM
+CP15_ReadDcacheLockdown:
+ mov r0, #0
+ mrc p15, 0, r0, c9, c0, 0
+ bx lr
+
+ SECTION .CP15_WriteDcacheLockdown:CODE:NOROOT(2)
+ PUBLIC CP15_WriteDcacheLockdown
+ //ARM
+CP15_WriteDcacheLockdown:
+ mcr p15, 0, r0, c9, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+ SECTION .CP15_ReadIcacheLockdown:CODE:NOROOT(2)
+ PUBLIC CP15_ReadIcacheLockdown
+ //ARM
+CP15_ReadIcacheLockdown:
+ mov r0, #0
+ mrc p15, 0, r0, c9, c0, 1
+ bx lr
+
+ SECTION .CP15_WriteIcacheLockdown:CODE:NOROOT(2)
+ PUBLIC CP15_WriteIcacheLockdown
+ //ARM
+CP15_WriteIcacheLockdown:
+ mcr p15, 0, r0, c9, c0, 1
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// TLB Lockdown Register c10
+/// The TLB Lockdown Register controls where hardware page table walks place the
+/// TLB entry, in the set associative region or the lockdown region of the TLB,
+/// and if in the lockdown region, which entry is written. The lockdown region
+/// of the TLB contains eight entries. See TLB structure for a description of
+/// the structure of the TLB.
+//------------------------------------------------------------------------------
+/// Read data TLB lockdown victim MRC p15,0,<Rd>,c10,c0,0
+/// Write data TLB lockdown victim MCR p15,0,<Rd>,c10,c0,0
+//------------------------------------------------------------------------------
+
+ SECTION .CP15_ReadTLBLockdown:CODE:NOROOT(2)
+ PUBLIC CP15_ReadTLBLockdown
+ //ARM
+CP15_ReadTLBLockdown:
+ mov r0, #0
+ mrc p15, 0, r0, c10, c0, 0
+ bx lr
+
+ SECTION .CP15_WriteTLBLockdown:CODE:NOROOT(2)
+ PUBLIC CP15_WriteTLBLockdown
+ //ARM
+CP15_WriteTLBLockdown:
+ mcr p15, 0, r0, c10, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+//------------------------------------------------------------------------------
+/// Register c13 accesses the process identifier registers. The register accessed depends on
+/// the value of the Opcode_2 field:
+/// Opcode_2 = 0 Selects the Fast Context Switch Extension (FCSE) Process Identifier (PID) Register.
+/// Opcode_2 = 1 Selects the Context ID Register.
+//------------------------------------------------------------------------------
+/// FCSE PID Register
+/// Addresses issued by the ARM9EJ-S core in the range 0 to 32MB are translated in
+/// accordance with the value contained in this register. Address A becomes A + (FCS
+/// PID x 32MB). It is this modified address that is seen by the caches, MMU, and TC
+/// interface. Addresses above 32MB are not modified. The FCSE PID is a seven-bit fie
+/// enabling 128 x 32MB processes to be mapped.
+/// If the FCSE PID is 0, there is a flat mapping between the virtual addresses output by
+/// ARM9EJ-S core and the modified virtual addresses used by the caches, MMU, and
+/// TCM interface. The FCSE PID is set to 0 at system reset.
+/// If the MMU is disabled, then no FCSE address translation occurs.
+/// FCSE translation is not applied for addresses used for entry based cache or TLB
+/// maintenance operations. For these operations VA = MVA.
+//------------------------------------------------------------------------------
+/// Read FCSE PID MRC p15,0,<Rd>,c13,c0, 0
+/// Write FCSE PID MCR p15,0,<Rd>,c13,c0, 0
+//------------------------------------------------------------------------------
+/// Context ID Register
+/// The Context ID Register provides a mechanism to allow real-time trace tools to identify
+/// the currently executing process in multi-tasking environments.
+/// The contents of this register are replicated on the ETMPROCID pins of the
+/// ARM926EJ-S processor. ETMPROCIDWR is pulsed when a write occurs to the
+/// Context ID Register.
+//------------------------------------------------------------------------------
+/// Read context ID MRC p15,0,<Rd>,c13,c0, 1
+/// Write context ID MCR p15,0,<Rd>,c13,c0, 1
+//------------------------------------------------------------------------------
+
+ SECTION .CP15_ReadFCSE_PID:CODE:NOROOT(2)
+ PUBLIC CP15_ReadFCSE_PID
+ //ARM
+CP15_ReadFCSE_PID:
+ mov r0, #0
+ mrc p15, 0, r0, c13, c0, 0
+ bx lr
+
+ SECTION .CP15_WriteFCSE_PID:CODE:NOROOT(2)
+ PUBLIC CP15_WriteFCSE_PID
+ //ARM
+CP15_WriteFCSE_PID:
+ mcr p15, 0, r0, c13, c0, 0
+ bx lr
+
+#endif
+ END
+
diff --git a/peripherals/cp15/cp15_asm_keil.s b/peripherals/cp15/cp15_asm_keil.s new file mode 100644 index 0000000..700d96b --- /dev/null +++ b/peripherals/cp15/cp15_asm_keil.s @@ -0,0 +1,536 @@ +; ----------------------------------------------------------------------------
+; 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.
+; ----------------------------------------------------------------------------
+;
+
+ AREA cp15, CODE
+
+;------------------------------------------------------------------------------
+; Headers
+;------------------------------------------------------------------------------
+
+;------------------------------------------------------------------------------
+; Functions to access CP15 coprocessor register
+;------------------------------------------------------------------------------
+ ; c0
+ EXPORT CP15_ReadID
+ EXPORT CP15_ReaDcacheType
+ EXPORT CP15_ReadTCMStatus
+ ; c1
+ EXPORT CP15_ReadControl
+ EXPORT CP15_WriteControl
+ ; c2
+ EXPORT CP15_ReadTTB
+ EXPORT CP15_WriteTTB
+ ; c3
+ EXPORT CP15_ReadDomainAccessControl
+ EXPORT CP15_WriteDomainAccessControl
+ ; c7
+ EXPORT CP15_InvalidateIDcache
+ EXPORT CP15_InvalidateDcache
+ EXPORT CP15_InvalidateIcache
+ EXPORT CP15_PrefetchIcacheLine
+ EXPORT CP15_TestCleanInvalidateDcache
+ EXPORT CP15_DrainWriteBuffer
+ EXPORT CP15_WaitForInterrupt
+ ; c8
+ EXPORT CP15_InvalidateTLB
+ EXPORT CP15_InvalidateTLBMVA
+ EXPORT CP15_InvalidateITLB
+ EXPORT CP15_InvalidateITLBMVA
+ EXPORT CP15_InvalidateDTLB
+ EXPORT CP15_InvalidateDTLBMVA
+ ; c9
+ EXPORT CP15_ReadDcacheLockdown
+ EXPORT CP15_WriteDcacheLockdown
+ EXPORT CP15_ReadIcacheLockdown
+ EXPORT CP15_WriteIcacheLockdown
+ EXPORT CP15_ReadTLBLockdown
+ EXPORT CP15_WriteTLBLockdown
+ ; c13
+ EXPORT CP15_ReadTLBLockdown
+ EXPORT CP15_WriteTLBLockdown
+ ; c13
+ EXPORT CP15_ReadFCSE_PID
+ EXPORT CP15_WriteFCSE_PID
+
+;------------------------------------------------------------------------------
+; c0
+; Register c0 accesses the ID Register, Cache Type Register, and TCM Status Registers.
+; Reading from this register returns the device ID, the cache type, or the TCM status
+; depending on the value of Opcode_2 used:
+; Opcode_2 = 0 ID value.
+; Opcode_2 = 1 instruction and data cache type.
+; Opcode_2 = 2 TCM status.
+;------------------------------------------------------------------------------
+
+; C0 read ID
+CP15_ReadID
+ mov r0, #0
+ mrc p15, 0, r0, c0, c0, 0
+ bx lr
+
+; C0 read Cache Type
+CP15_ReaDcacheType
+ mov r0, #0
+ mrc p15, 0, r0, c0, c0, 1
+ bx lr
+
+; C0 read TCM status
+CP15_ReadTCMStatus
+ mov r0, #0
+ mrc p15, 0, r0, c0, c0, 2
+ bx lr
+
+;------------------------------------------------------------------------------
+; Control Register c1
+; Register c1 is the Control Register for the ARM926EJ-S processor.
+; This register specifies the configuration used to enable and disable the
+; caches and MMU. It is recommended that you access this register using a
+; read-modify-write sequence.
+;------------------------------------------------------------------------------
+; CP15 Read Control Register
+CP15_ReadControl
+ mov r0, #0
+ mrc p15, 0, r0, c1, c0, 0
+ bx lr
+
+; CP15 Write Control Register
+CP15_WriteControl
+ mcr p15, 0, r0, c1, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+;------------------------------------------------------------------------------
+; CP15 Translation Table Base Register c2
+; Register c2 is the Translation Table Base Register (TTBR), for the base
+; address of the first-level translation table.
+; Reading from c2 returns the pointer to the currently active first-level
+; translation table in bits [31:14] and an Unpredictable value in bits [13:0].
+; Writing to register c2 updates the pointer to the first-level translation
+; table from the value in bits [31:14] of the written value. Bits [13:0]
+; Should Be Zero.
+; You can use the following instructions to access the TTBR:
+; Read TTBR : MRC p15, 0, <Rd>, c2, c0, 0
+; Write TTBR : MCR p15, 0, <Rd>, c2, c0, 0
+;------------------------------------------------------------------------------
+CP15_ReadTTB
+ mov r0, #0
+ mrc p15, 0, r0, c2, c0, 0
+ bx lr
+
+CP15_WriteTTB
+ mcr p15, 0, r0, c2, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+;------------------------------------------------------------------------------
+; Domain Access Control Register c3
+; Read domain access permissions : MRC p15, 0, <Rd>, c3, c0, 0
+; Write domain access permissions : MCR p15, 0, <Rd>, c3, c0, 0
+;------------------------------------------------------------------------------
+CP15_ReadDomainAccessControl
+ mov r0, #0
+ mrc p15, 0, r0, c3, c0, 0
+ bx lr
+
+CP15_WriteDomainAccessControl
+ mcr p15, 0, r0, c3, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+;------------------------------------------------------------------------------
+; Fault Status Registers Register c5
+; Register c5 accesses the Fault Status Registers (FSRs). The FSRs contain the source of
+; the last instruction or data fault. The instruction-side FSR is intended for debug
+; purposes only. The FSR is updated for alignment faults, and external aborts that occur
+; while the MMU is disabled.
+; The FSR accessed is determined by the value of the Opcode_2 field:
+; Opcode_2 = 0 Data Fault Status Register (DFSR).
+; Opcode_2 = 1 Instruction Fault Status Register (IFSR).
+; The fault type encoding is listed in Table 3-9 on page 3-22.
+; You can access the FSRs using the following instructions:
+; MRC p15, 0, <Rd>, c5, c0, 0 ;read DFSR
+; MCR p15, 0, <Rd>, c5, c0, 0 ;write DFSR
+; MRC p15, 0, <Rd>, c5, c0, 1 ;read IFSR
+; MCR p15, 0, <Rd>, c5, c0, 1 ;write IFSR
+;------------------------------------------------------------------------------
+
+CP15_ReadDFSR
+ mov r0, #0
+ mrc p15, 0, r0, c5, c0, 0
+ bx lr
+
+CP15_writeDFSR
+ mcr p15, 0, r0, c5, c0, 0
+ bx lr
+
+CP15_ReadIFSR
+ mov r0, #0
+ mrc p15, 0, r0, c5, c0, 1
+ bx lr
+
+CP15_WriteIFSR
+ mcr p15, 0, r0, c5, c0, 1
+ bx lr
+
+;------------------------------------------------------------------------------
+; Fault Address Register c6
+; Register c6 accesses the Fault Address Register (FAR). The FAR contains the Modified
+; Virtual Address of the access being attempted when a Data Abort occurred. The FAR is
+; only updated for Data Aborts, not for Prefetch Aborts. The FAR is updated for
+; alignment faults, and external aborts that occur while the MMU is disabled.
+; You can use the following instructions to access the FAR:
+; MRC p15, 0, <Rd>, c6, c0, 0 ; read FAR
+; MCR p15, 0, <Rd>, c6, c0, 0 ; write FAR
+;------------------------------------------------------------------------------
+CP15_ReadFAR
+ mov r0, #0
+ mrc p15, 0, r0, c6, c0, 0
+ bx lr
+
+CP15_writeFAR
+ mcr p15, 0, r0, c6, c0, 0
+ bx lr
+
+;------------------------------------------------------------------------------
+; Control functions caches and the write buffer c7
+; Register c7 controls the caches and the write buffer. The function of each cache
+; operation is selected by the Opcode_2 and CRm fields in the MCR instruction used to
+; write to CP15 c7. Writing other Opcode_2 or CRm values is Unpredictable.
+; Reading from CP15 c7 is Unpredictable, with the exception of the two test and clean
+; operations (see Table 2-18 on page 2-21 and Test and clean operations on page 2-23).
+; You can use the following instruction to write to c7:
+; MCR p15, <Opcode_1>, <Rd>, <CRn>, <CRm>, <Opcode_2>
+;------------------------------------------------------------------------------
+; Invalidate Icache and Dcache MCR p15, 0, <Rd>, c7, c7, 0
+; Invalidate Icache MCR p15, 0, <Rd>, c7, c5, 0
+; Invalidate Icache single entry (MVA) MVA MCR p15, 0, <Rd>, c7, c5, 1
+; Invalidate Icache single entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c5, 2
+; Prefetch Icache line (MVA) MVA MCR p15, 0, <Rd>, c7, c13, 1
+; Invalidate Dcache MCR p15, 0, <Rd>, c7, c6, 0
+; Invalidate Dcache single entry (MVA) MVA MCR p15, 0, <Rd>, c7, c6, 1
+; Invalidate Dcache single entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c6, 2
+; Clean Dcache single entry (MVA) MVA MCR p15, 0, <Rd>, c7, c10, 1
+; Clean Dcache single entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c10, 2
+; Test and clean Dcache - MRC p15, 0, <Rd>, c7, c10, 3
+; Clean and invalidate Dcache entry (MVA) MVA MCR p15, 0, <Rd>, c7, c14, 1
+; Clean and invalidate Dcache entry (Set/Way) Set/Way MCR p15, 0, <Rd>, c7, c14, 2
+; Test, clean, and invalidate Dcache - MRC p15, 0, <Rd>, c7, c14, 3
+; Drain write buffer SBZ MCR p15, 0, <Rd>, c7, c10, 4
+; Wait for interrupt SBZ MCR p15, 0, <Rd>, c7, c0, 4
+;------------------------------------------------------------------------------
+
+; Invalidate Icache and Dcache
+CP15_InvalidateIDcache
+ mov r0, #0
+ mcr p15, 0, r0, c7, c7, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+; Invalidate Icache
+CP15_InvalidateIcache
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+; Invalidate Dcache
+CP15_InvalidateDcache
+ mov r0, #0
+ mcr p15, 0, r0, c7, c6, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+;------------------------------------------------------------------------------
+; CP15 Prefetch Icache line c7
+; Performs an Icache lookup of the specified modified virtual address.
+; If the cache misses, and the region is cacheable, a linefill is performed.
+; Prefetch Icache line (MVA): MCR p15, 0, <Rd>, c7, c13, 1
+;------------------------------------------------------------------------------
+CP15_PrefetchIcacheLine
+ mcr p15, 0, r0, c7, c13, 1
+ bx lr
+
+;------------------------------------------------------------------------------
+; CP15 Test, clean, and invalidate Dcache c7
+; As for test and clean, except that when the entire cache has
+; been tested and cleaned, it is invalidated.
+;------------------------------------------------------------------------------
+CP15_TestCleanInvalidateDcache
+ mrc p15, 0, r0, c7, c14, 3
+ bne CP15_TestCleanInvalidateDcache
+ bx lr
+
+;------------------------------------------------------------------------------
+; CP15 Drain write buffer c7
+; This instruction acts as an explicit memory barrier. It drains
+; the contents of the write buffers of all memory stores
+; occurring in program order before this instruction is
+; completed. No instructions occurring in program order
+; after this instruction are executed until it completes. This
+; can be used when timing of specific stores to the level two
+; memory system has to be controlled (for example, when a
+; store to an interrupt acknowledge location has to complete
+; before interrupts are enabled).
+;------------------------------------------------------------------------------
+CP15_DrainWriteBuffer
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4
+ bx lr
+
+;------------------------------------------------------------------------------
+; CP15 Wait For Interrupt operation c7
+; The purpose of the Wait For Interrupt operation is to put the processor in
+; to a low power state.
+; This puts the processor into a low-power state and stops it executing more
+; instructions until an interrupt, or debug request occurs, regardless of
+; whether the interrupts are disabled by the masks in the CPSR.
+; When an interrupt does occur, the mcr instruction completes and the IRQ or
+; FIQ handler is entered as normal. The return link in r14_irq or r14_fiq
+; contains the address of the mcr instruction plus 8, so that the normal
+; instruction used for interrupt return (SUBS PC,R14,#4) returns to the
+; instruction following the mcr.
+; Wait For Interrupt : MCR p15, 0, <Rd>, c7, c0, 4
+;------------------------------------------------------------------------------
+CP15_WaitForInterrupt
+ mov r0, #0
+ mcr p15, 0, r0, c7, c0, 4
+ bx lr
+
+;------------------------------------------------------------------------------
+; Translation Lookaside Buffer (TLB) : c8
+; This is a write-only register used to control the Translation Lookaside Buffer (TLB).
+; There is a single TLB used to hold entries for both data and instructions. The TLB is
+; divided into two parts:
+; • a set-associative part
+; • a fully-associative part.
+; The fully-associative part (also referred to as the lockdown part of the TLB) is used to
+; store entries to be locked down. Entries held in the lockdown part of the TLB are
+; preserved during an invalidate TLB operation. Entries can be removed from the
+; lockdown TLB using an invalidate TLB single entry operation.
+; Six TLB operations are defined, and the function to be performed is selected by the
+; Opcode_2 and CRm fields in the MCR instruction used to write CP15 c8. Writing other
+; Opcode_2 or CRm values is Unpredictable. Reading from this register is Unpredictable.
+;------------------------------------------------------------------------------
+; Invalidate TLB MCR p15, 0, <Rd>, c8, c7, 0
+; Invalidate TLB single entry (MVA) MCR p15, 0, <Rd>, c8, c7, 1
+; Invalidate instruction TLB MCR p15, 0, <Rd>, c8, c5, 0
+; Invalidate instruction TLB single entry (MVA) MCR p15, 0, <Rd>, c8, c5, 1
+; Invalidate data TLB MCR p15, 0, <Rd>, c8, c6, 0
+; Invalidate data TLB single entry (MVA) MCR p15, 0, <Rd>, c8, c6, 1
+;------------------------------------------------------------------------------
+
+CP15_InvalidateTLB
+ mov r0, #0
+ mcr p15, 0, r0, c8, c7, 0
+ bx lr
+
+CP15_InvalidateTLBMVA
+ mcr p15, 0, r0, c8, c7, 1
+ bx lr
+
+CP15_InvalidateITLB
+ mov r0, #0
+ mcr p15, 0, r0, c8, c5, 0
+ bx lr
+
+CP15_InvalidateITLBMVA
+ mcr p15, 0, r0, c8, c5, 1
+ bx lr
+
+CP15_InvalidateDTLB
+ mov r0, #0
+ mcr p15, 0, r0, c8, c6, 0
+ bx lr
+
+CP15_InvalidateDTLBMVA
+ mcr p15, 0, r0, c8, c6, 1
+ bx lr
+
+;------------------------------------------------------------------------------
+; Cache Lockdown Register c9
+; The Cache Lockdown Register uses a cache-way-based locking scheme (Format C) that
+; enables you to control each cache way independently.
+; These registers enable you to control which cache ways of the four-way cache are used
+; for the allocation on a linefill. When the registers are defined, subsequent linefills are
+; only placed in the specified target cache way. This gives you some control over the
+; cache pollution caused by particular applications, and provides a traditional lockdown
+; operation for locking critical code into the cache.
+;------------------------------------------------------------------------------
+; Read Dcache Lockdown Register MRC p15,0,<Rd>,c9,c0,0
+; Write Dcache Lockdown Register MCR p15,0,<Rd>,c9,c0,0
+; Read Icache Lockdown Register MRC p15,0,<Rd>,c9,c0,1
+; Write Icache Lockdown Register MCR p15,0,<Rd>,c9,c0,1
+;------------------------------------------------------------------------------
+
+CP15_ReadDcacheLockdown
+ mov r0, #0
+ mrc p15, 0, r0, c9, c0, 0
+ bx lr
+
+CP15_WriteDcacheLockdown
+ mcr p15, 0, r0, c9, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+CP15_ReadIcacheLockdown
+ mov r0, #0
+ mrc p15, 0, r0, c9, c0, 1
+ bx lr
+
+CP15_WriteIcacheLockdown
+ mcr p15, 0, r0, c9, c0, 1
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+;------------------------------------------------------------------------------
+; TLB Lockdown Register c10
+; The TLB Lockdown Register controls where hardware page table walks place the
+; TLB entry, in the set associative region or the lockdown region of the TLB,
+; and if in the lockdown region, which entry is written. The lockdown region
+; of the TLB contains eight entries. See TLB structure for a description of
+; the structure of the TLB.
+;------------------------------------------------------------------------------
+; Read data TLB lockdown victim MRC p15,0,<Rd>,c10,c0,0
+; Write data TLB lockdown victim MCR p15,0,<Rd>,c10,c0,0
+;------------------------------------------------------------------------------
+CP15_ReadTLBLockdown
+ mov r0, #0
+ mrc p15, 0, r0, c10, c0, 0
+ bx lr
+
+CP15_WriteTLBLockdown
+ mcr p15, 0, r0, c10, c0, 0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bx lr
+
+;------------------------------------------------------------------------------
+; Register c13 accesses the process identifier registers. The register accessed depends on
+; the value of the Opcode_2 field:
+; Opcode_2 = 0 Selects the Fast Context Switch Extension (FCSE) Process Identifier (PID) Register.
+; Opcode_2 = 1 Selects the Context ID Register.
+;------------------------------------------------------------------------------
+; FCSE PID Register
+; Addresses issued by the ARM9EJ-S core in the range 0 to 32MB are translated in
+; accordance with the value contained in this register. Address A becomes A + (FCS
+; PID x 32MB). It is this modified address that is seen by the caches, MMU, and TC
+; interface. Addresses above 32MB are not modified. The FCSE PID is a seven-bit fie
+; enabling 128 x 32MB processes to be mapped.
+; If the FCSE PID is 0, there is a flat mapping between the virtual addresses output by
+; ARM9EJ-S core and the modified virtual addresses used by the caches, MMU, and
+; TCM interface. The FCSE PID is set to 0 at system reset.
+; If the MMU is disabled, then no FCSE address translation occurs.
+; FCSE translation is not applied for addresses used for entry based cache or TLB
+; maintenance operations. For these operations VA = MVA.
+;------------------------------------------------------------------------------
+; Read FCSE PID MRC p15,0,<Rd>,c13,c0, 0
+; Write FCSE PID MCR p15,0,<Rd>,c13,c0, 0
+;------------------------------------------------------------------------------
+; Context ID Register
+; The Context ID Register provides a mechanism to allow real-time trace tools to identify
+; the currently executing process in multi-tasking environments.
+; The contents of this register are replicated on the ETMPROCID pins of the
+; ARM926EJ-S processor. ETMPROCIDWR is pulsed when a write occurs to the
+; Context ID Register.
+;------------------------------------------------------------------------------
+; Read context ID MRC p15,0,<Rd>,c13,c0, 1
+; Write context ID MCR p15,0,<Rd>,c13,c0, 1
+;------------------------------------------------------------------------------
+CP15_ReadFCSE_PID
+ mov r0, #0
+ mrc p15, 0, r0, c13, c0, 0
+ bx lr
+
+CP15_WriteFCSE_PID
+ mcr p15, 0, r0, c13, c0, 0
+ bx lr
+ END
+
diff --git a/peripherals/dbgu/dbgu.c b/peripherals/dbgu/dbgu.c new file mode 100644 index 0000000..0b3b380 --- /dev/null +++ b/peripherals/dbgu/dbgu.c @@ -0,0 +1,114 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "dbgu.h"
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// Initializes the DBGU with the given parameters, and enables both the
+/// transmitter and the receiver. The mode parameter contains the value of the
+/// DBGU_MR register.
+/// Value DBGU_STANDARD can be used for mode to get the most common configuration
+/// (i.e. aysnchronous, 8bits, no parity, 1 stop bit, no flow control).
+/// \param mode Operating mode to configure.
+/// \param baudrate Desired baudrate (e.g. 115200).
+/// \param mck Frequency of the system master clock in Hz.
+//------------------------------------------------------------------------------
+void DBGU_Configure(
+ unsigned int mode,
+ unsigned int baudrate,
+ unsigned int mck)
+{
+ #if defined(cortexm3)
+ // Enable clock for UART
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_DBGU);
+ #endif
+
+ // Reset & disable receiver and transmitter, disable interrupts
+ AT91C_BASE_DBGU->DBGU_CR = AT91C_US_RSTRX | AT91C_US_RSTTX;
+ AT91C_BASE_DBGU->DBGU_IDR = 0xFFFFFFFF;
+
+ // Configure baud rate
+ AT91C_BASE_DBGU->DBGU_BRGR = mck / (baudrate * 16);
+
+ // Configure mode register
+ AT91C_BASE_DBGU->DBGU_MR = mode;
+
+ // Disable DMA channel
+ AT91C_BASE_DBGU->DBGU_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
+
+ // Enable receiver and transmitter
+ AT91C_BASE_DBGU->DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN;
+}
+
+//------------------------------------------------------------------------------
+/// Outputs a character on the DBGU line.
+/// \note This function is synchronous (i.e. uses polling).
+/// \param c Character to send.
+//------------------------------------------------------------------------------
+void DBGU_PutChar(unsigned char c)
+{
+ // Wait for the transmitter to be ready
+ while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXEMPTY) == 0);
+
+ // Send character
+ AT91C_BASE_DBGU->DBGU_THR = c;
+
+ // Wait for the transfer to complete
+ while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXEMPTY) == 0);
+}
+
+//------------------------------------------------------------------------------
+/// Return 1 if a character can be read in DBGU
+//------------------------------------------------------------------------------
+unsigned int DBGU_IsRxReady()
+{
+ return (AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_RXRDY);
+}
+
+//------------------------------------------------------------------------------
+/// Reads and returns a character from the DBGU.
+/// \note This function is synchronous (i.e. uses polling).
+/// \return Character received.
+//------------------------------------------------------------------------------
+unsigned char DBGU_GetChar(void)
+{
+ while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_RXRDY) == 0);
+ return AT91C_BASE_DBGU->DBGU_RHR;
+}
+
+
+
diff --git a/peripherals/dbgu/dbgu.dir b/peripherals/dbgu/dbgu.dir new file mode 100644 index 0000000..ec31900 --- /dev/null +++ b/peripherals/dbgu/dbgu.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the peripheral API for the Debug Unit (DBGU).
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/dbgu/dbgu.h b/peripherals/dbgu/dbgu.h new file mode 100644 index 0000000..816f11d --- /dev/null +++ b/peripherals/dbgu/dbgu.h @@ -0,0 +1,79 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// This module provides definitions and functions for using the Debug Unit
+/// (DBGU).
+///
+/// It also overloads the fputc(), fputs() & putchar() functions so the printf()
+/// method outputs its data on the DBGU. This behavior can be suppressed by
+/// defining NOFPUT during compilation.
+///
+/// !Usage
+///
+/// -# Enable the DBGU pins (see pio & board.h).
+/// -# Configure the DBGU using DBGU_Configure with the desired operating mode.
+/// -# Send characters using DBGU_PutChar() or the printf() method.
+/// -# Receive characters using DBGU_GetChar().
+///
+/// \note Unless specified, all the functions defined here operate synchronously;
+/// i.e. they all wait the data is sent/received before returning.
+//------------------------------------------------------------------------------
+
+#ifndef DBGU_H
+#define DBGU_H
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// Standard operating mode (asynchronous, 8bit, no parity, 1 stop bit)
+#define DBGU_STANDARD AT91C_US_PAR_NONE
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void DBGU_Configure(
+ unsigned int mode,
+ unsigned int baudrate,
+ unsigned int mck);
+
+extern unsigned char DBGU_GetChar(void);
+
+extern void DBGU_PutChar(unsigned char c);
+
+extern unsigned int DBGU_IsRxReady(void);
+
+#endif //#ifndef DBGU_H
+
diff --git a/peripherals/dma/dma.c b/peripherals/dma/dma.c new file mode 100644 index 0000000..cfae3dc --- /dev/null +++ b/peripherals/dma/dma.c @@ -0,0 +1,393 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "dma.h"
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configure a DMAC peripheral
+//------------------------------------------------------------------------------
+void DMA_Config(unsigned int flag)
+{
+ AT91C_BASE_HDMA->HDMA_GCFG = flag;
+}
+
+//------------------------------------------------------------------------------
+/// Enables a DMAC peripheral
+//------------------------------------------------------------------------------
+void DMA_Enable(void)
+{
+ AT91C_BASE_HDMA->HDMA_EN = AT91C_HDMA_ENABLE;
+}
+
+//------------------------------------------------------------------------------
+/// Disables DMAC peripheral
+//------------------------------------------------------------------------------
+void DMA_Disable(void)
+{
+ AT91C_BASE_HDMA->HDMA_EN = ~(unsigned int)AT91C_HDMA_ENABLE;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable DMA interrupt
+/// \param flag IT to be enabled
+//-----------------------------------------------------------------------------
+void DMA_EnableIt (unsigned int flag)
+{
+ AT91C_BASE_HDMA->HDMA_EBCIER = flag;
+}
+
+//-----------------------------------------------------------------------------
+/// Disable DMA interrupt
+/// \param flag IT to be enabled
+//-----------------------------------------------------------------------------
+void DMA_DisableIt (unsigned int flag)
+{
+ AT91C_BASE_HDMA->HDMA_EBCIDR = flag;
+}
+
+//-----------------------------------------------------------------------------
+/// Return DMA Interrupt Status
+//-----------------------------------------------------------------------------
+unsigned int DMA_GetStatus(void)
+{
+ return (AT91C_BASE_HDMA->HDMA_EBCISR);
+}
+
+//-----------------------------------------------------------------------------
+/// Return DMA Interrupt Mask Status
+//-----------------------------------------------------------------------------
+unsigned int DMA_GetInterruptMask(void)
+{
+ return (AT91C_BASE_HDMA->HDMA_EBCIMR);
+}
+
+//-----------------------------------------------------------------------------
+/// Returns the current status register of the given DMA peripheral, but
+/// masking interrupt sources which are not currently enabled.
+//-----------------------------------------------------------------------------
+unsigned int DMA_GetMaskedStatus(void)
+{
+ unsigned int status;
+ status = AT91C_BASE_HDMA->HDMA_EBCISR;
+ status &= AT91C_BASE_HDMA->HDMA_EBCIMR;
+ return status;
+}
+
+//------------------------------------------------------------------------------
+/// Enables DMAC channel
+/// \param channel Particular channel number.
+//------------------------------------------------------------------------------
+void DMA_EnableChannel(unsigned int channel)
+{
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ AT91C_BASE_HDMA->HDMA_CHER |= DMA_ENA << channel;
+}
+void DMA_EnableChannels(unsigned int bmChannels)
+{
+ AT91C_BASE_HDMA->HDMA_CHER = bmChannels;
+}
+
+//------------------------------------------------------------------------------
+/// Disables a DMAC channel
+/// \param channel Particular channel number.
+//------------------------------------------------------------------------------
+void DMA_DisableChannel(unsigned int channel)
+{
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ AT91C_BASE_HDMA->HDMA_CHDR |= DMA_DIS << channel;
+}
+void DMA_DisableChannels(unsigned int bmChannels)
+{
+ AT91C_BASE_HDMA->HDMA_CHDR = bmChannels;
+}
+
+//------------------------------------------------------------------------------
+/// Resume DMAC channel from an stall state.
+/// \param channel Particular channel number.
+//------------------------------------------------------------------------------
+void DMA_KeeponChannel(unsigned int channel)
+{
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ AT91C_BASE_HDMA->HDMA_CHER |= DMA_KEEPON << channel;
+}
+
+//------------------------------------------------------------------------------
+/// Clear automatic mode for multi-buffer transfer.
+/// \param channel Particular channel number.
+//------------------------------------------------------------------------------
+void DMA_ClearAutoMode(unsigned int channel)
+{
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB &= 0x7FFFFFFF;
+}
+
+//------------------------------------------------------------------------------
+/// Return DMAC channel status
+//------------------------------------------------------------------------------
+unsigned int DMA_GetChannelStatus(void)
+{
+ return( AT91C_BASE_HDMA->HDMA_CHSR);
+}
+
+//-----------------------------------------------------------------------------
+/// Set DMA source address used by a HDMA channel.
+/// \param channel Particular channel number.
+/// \param sources sources address.
+//-----------------------------------------------------------------------------
+void DMA_SetSourceAddr(unsigned char channel, unsigned int address)
+{
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_SADDR = address;
+}
+
+//-----------------------------------------------------------------------------
+/// Set DMA destination address used by a HDMA channel.
+/// \param channel Particular channel number.
+/// \param sources destination address.
+//-----------------------------------------------------------------------------
+void DMA_SetDestinationAddr(unsigned char channel, unsigned int address)
+{
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_DADDR = address;
+}
+
+//-----------------------------------------------------------------------------
+/// Set DMA descriptor address used by a HDMA channel.
+/// \param channel Particular channel number.
+/// \param sources destination address.
+//-----------------------------------------------------------------------------
+void DMA_SetDescriptorAddr(unsigned char channel, unsigned int address)
+{
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_DSCR = address ;
+}
+
+
+//-----------------------------------------------------------------------------
+/// Set DMA control A register used by a HDMA channel.
+/// \param channel Particular channel number.
+/// \param size Dma transfer size in byte.
+/// \param sourceWidth Single transfer width for source.
+/// \param destWidth Single transfer width for destination.
+/// \param done Transfer done field.
+//-----------------------------------------------------------------------------
+void DMA_SetSourceBufferSize(unsigned char channel,
+ unsigned int size,
+ unsigned char sourceWidth,
+ unsigned char destWidth,
+ unsigned char done)
+{
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ ASSERT(sourceWidth < 4, "width does not support");
+ ASSERT(destWidth < 4, "width does not support");
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLA = (size |
+ sourceWidth << 24 |
+ destWidth << 28 |
+ done << 31);
+}
+
+//-----------------------------------------------------------------------------
+/// Set DMA transfer mode for source used by a HDMA channel.
+/// \param channel Particular channel number.
+/// \param transferMode Transfer buffer mode (single, LLI, reload or contiguous)
+/// \param addressingType Type of addrassing mode
+/// 0 : incrementing, 1: decrementing, 2: fixed.
+//-----------------------------------------------------------------------------
+void DMA_SetSourceBufferMode(unsigned char channel,
+ unsigned char transferMode,
+ unsigned char addressingType)
+{
+ unsigned int value;
+
+ ASSERT(channel < DMA_CHANNEL_NUM, "channel %d does not exist", channel);
+
+ value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB;
+ value &= ~ (AT91C_SRC_DSCR | AT91C_SRC_INCR | 1<<31);
+ switch(transferMode){
+ case DMA_TRANSFER_SINGLE:
+ value |= AT91C_SRC_DSCR | addressingType << 24;
+ break;
+ case DMA_TRANSFER_LLI:
+ value |= addressingType << 24;
+ break;
+ case DMA_TRANSFER_RELOAD:
+ case DMA_TRANSFER_CONTIGUOUS:
+ value |= AT91C_SRC_DSCR | addressingType << 24 | 1<<31;
+ break;
+ }
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB = value;
+
+ if(transferMode == DMA_TRANSFER_RELOAD || transferMode == DMA_TRANSFER_CONTIGUOUS){
+ value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG;
+ #if defined(AT91C_SRC_REP)
+ value &= ~(unsigned int)AT91C_SRC_REP;
+ // When automatic mode is activated, the source address and the control register are reloaded from previous transfer.
+ if(transferMode == DMA_TRANSFER_RELOAD) {
+ value |= AT91C_SRC_REP;
+ }
+ #endif
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG = value;
+ }
+ else {
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+/// Set DMA transfer mode for destination used by a HDMA channel.
+/// \param channel Particular channel number.
+/// \param transferMode Transfer buffer mode (single, LLI, reload or contiguous)
+/// \param addressingType Type of addrassing mode
+/// 0 : incrementing, 1: decrementing, 2: fixed.
+//-----------------------------------------------------------------------------
+void DMA_SetDestBufferMode(unsigned char channel,
+ unsigned char transferMode,
+ unsigned char addressingType)
+{
+ unsigned int value;
+
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+
+ value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB;
+ value &= ~(unsigned int)(AT91C_DST_DSCR | AT91C_DST_INCR);
+
+ switch(transferMode){
+ case DMA_TRANSFER_SINGLE:
+ case DMA_TRANSFER_RELOAD:
+ case DMA_TRANSFER_CONTIGUOUS:
+ value |= AT91C_DST_DSCR | addressingType << 28;
+ break;
+ case DMA_TRANSFER_LLI:
+ value |= addressingType << 28;
+ break;
+ }
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB = value;
+ if(transferMode == DMA_TRANSFER_RELOAD || transferMode == DMA_TRANSFER_CONTIGUOUS){
+ value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG;
+ #if defined(AT91C_DST_REP)
+ value &= ~(unsigned int)AT91C_DST_REP;
+ // When automatic mode is activated, the source address and the control register are reloaded from previous transfer.
+ if(transferMode == DMA_TRANSFER_RELOAD) {
+ value |= AT91C_DST_REP;
+ }
+ #endif
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG = value;
+ }
+ else {
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG = 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Set DMA configuration registe used by a HDMA channel.
+/// \param channel Particular channel number.
+/// \param value configuration value.
+//------------------------------------------------------------------------------
+void DMA_SetConfiguration(unsigned char channel, unsigned int value)
+{
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CFG = value;
+}
+
+#if defined(AT91C_SRC_PIP)
+//------------------------------------------------------------------------------
+/// Set DMA source PIP configuration used by a HDMA channel.
+/// \param channel Particular channel number.
+/// \param pipHole stop on done mode.
+/// \param pipBoundary lock mode.
+//------------------------------------------------------------------------------
+void DMA_SPIPconfiguration(unsigned char channel,
+ unsigned int pipHole,
+ unsigned int pipBoundary)
+
+{
+ unsigned int value;
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB;
+ value &= ~(unsigned int)AT91C_SRC_PIP;
+ value |= AT91C_SRC_PIP;
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB = value;
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_SPIP = (pipHole + 1) | pipBoundary <<16;
+}
+#endif
+
+#if defined(AT91C_DST_PIP)
+//------------------------------------------------------------------------------
+/// Set DMA destination PIP configuration used by a HDMA channel.
+/// \param channel Particular channel number.
+/// \param pipHole stop on done mode.
+/// \param pipBoundary lock mode.
+//------------------------------------------------------------------------------
+void DMA_DPIPconfiguration(unsigned char channel,
+ unsigned int pipHole,
+ unsigned int pipBoundary)
+
+{
+ unsigned int value;
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB;
+ value &= ~(unsigned int)AT91C_DST_PIP;
+ value |= AT91C_DST_PIP;
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB = value;
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_DPIP = (pipHole + 1) | pipBoundary <<16;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+/// Set DMA control B register Flow control bit field.
+/// \param channel Particular channel number.
+/// \param size Dma transfer size in byte.
+/// \param sourceWidth Single transfer width for source.
+/// \param destWidth Single transfer width for destination.
+/// \param done Transfer done field.
+//-----------------------------------------------------------------------------
+void DMA_SetFlowControl(unsigned char channel,
+ unsigned int flow)
+{
+ unsigned int value;
+
+ ASSERT(channel < DMA_CHANNEL_NUM, "this channel does not exist");
+ ASSERT(flow < 4, "flow control does not support");
+
+ value = AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB;
+ value &= ~(unsigned int)AT91C_FC;
+ value |= flow << 21;
+ AT91C_BASE_HDMA->HDMA_CH[channel].HDMA_CTRLB = value;
+}
+
diff --git a/peripherals/dma/dma.dir b/peripherals/dma/dma.dir new file mode 100644 index 0000000..af77f27 --- /dev/null +++ b/peripherals/dma/dma.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the peripheral API for the DMA controller (DMAC).
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/dma/dma.h b/peripherals/dma/dma.h new file mode 100644 index 0000000..dbf50b9 --- /dev/null +++ b/peripherals/dma/dma.h @@ -0,0 +1,190 @@ +/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support - ROUSSET -
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2006, 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 disclaiimer below.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the disclaimer below in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !Purpose
+///
+/// Interface for configuration the %DMA controller(DMAC).
+///
+/// !Usage
+///
+/// -# Enable or disable the a DMAC controller with
+/// DMA_Enable() and or DMA_Disable().
+/// -# Enable or disable %Dma interrupt using DMA_EnableIt()
+/// or DMA_DisableIt().
+/// -# Get %Dma interrupt status by DMA_GetStatus().
+/// -# Enable or disable specified %Dma channel with
+/// DMA_EnableChannel() or DMA_DisableChannel().
+/// -# Get %Dma channel status by DMA_GetChannelStatus().
+/// -# Configure source and/or destination start address with
+/// DMA_SetSourceAddr() and/or DMA_SetDestAddr().
+/// -# Set %Dma descriptor address using DMA_SetDescriptorAddr().
+/// -# Set source transfer buffer size with DMA_SetSourceBufferSize().
+/// -# Configure source and/or destination transfer mode with
+/// DMA_SetSourceBufferMode() and/or DMA_SetDestBufferMode().
+/// -# Configure source and/or destination Picture-In-Picutre
+/// mode with DMA_SPIPconfiguration() and/or DMA_DPIPconfiguration().
+//------------------------------------------------------------------------------
+
+#ifndef DMA_H
+#define DMA_H
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+#define DMA_CHANNEL_0 0
+#define DMA_CHANNEL_1 1
+#define DMA_CHANNEL_2 2
+#define DMA_CHANNEL_3 3
+#define DMA_CHANNEL_4 4
+#define DMA_CHANNEL_5 5
+#define DMA_CHANNEL_6 6
+#define DMA_CHANNEL_7 7
+
+#if defined(CHIP_DMA_CHANNEL_NUM)
+#define DMA_CHANNEL_NUM CHIP_DMA_CHANNEL_NUM
+#endif
+
+#define DMA_TRANSFER_SINGLE 0
+#define DMA_TRANSFER_LLI 1
+#define DMA_TRANSFER_RELOAD 2
+#define DMA_TRANSFER_CONTIGUOUS 3
+
+
+#define DMA_ENA (1 << 0)
+#define DMA_DIS (1 << 0)
+#define DMA_SUSP (1 << 8)
+#define DMA_KEEPON (1 << 24)
+
+#define DMA_BTC (1 << 0)
+#define DMA_CBTC (1 << 8)
+#define DMA_ERR (1 << 16)
+
+#ifdef AT91C_HDMA_SRC_DSCR
+ #define AT91C_SRC_DSCR AT91C_HDMA_SRC_DSCR
+ #define AT91C_DST_DSCR AT91C_HDMA_DST_DSCR
+ #define AT91C_SRC_INCR AT91C_HDMA_SRC_ADDRESS_MODE
+ #define AT91C_DST_INCR AT91C_HDMA_DST_ADDRESS_MODE
+ #define AT91C_SRC_PER AT91C_HDMA_SRC_PER
+ #define AT91C_DST_PER AT91C_HDMA_DST_PER
+#if defined(AT91C_HDMA_SRC_REP)
+ #define AT91C_SRC_REP AT91C_HDMA_SRC_REP
+#endif
+#if defined(AT91C_HDMA_DST_REP)
+ #define AT91C_DST_REP AT91C_HDMA_DST_REP
+#endif
+#if defined(AT91C_HDMA_SRC_PIP)
+ #define AT91C_SRC_PIP AT91C_HDMA_SRC_PIP
+#endif
+#if defined(AT91C_HDMA_DST_PIP)
+ #define AT91C_DST_PIP AT91C_HDMA_DST_PIP
+#endif
+ #define AT91C_FC AT91C_HDMA_FC
+
+ #define AT91C_BTC (0xFF << 0)
+ #define AT91C_CBTC (0xFF << 8)
+ #define AT91C_ERR (0xFF << 16)
+#endif
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void DMA_Config(unsigned int flag);
+
+extern void DMA_Enable(void);
+
+extern void DMA_Disable(void);
+
+extern void DMA_EnableChannel(unsigned int channel);
+extern void DMA_EnableChannels(unsigned int bmChannels);
+
+extern void DMA_DisableChannel(unsigned int channel);
+extern void DMA_DisableChannels(unsigned int bmChannels);
+
+extern void DMA_KeeponChannel(unsigned int channel);
+
+extern void DMA_ClearAutoMode(unsigned int channel);
+
+extern unsigned int DMA_GetChannelStatus(void);
+
+extern unsigned int DMA_GetStatus(void);
+
+extern unsigned int DMA_GetInterruptMask(void);
+
+extern unsigned int DMA_GetMaskedStatus(void);
+
+extern void DMA_EnableIt (unsigned int flag);
+
+extern void DMA_DisableIt (unsigned int flag);
+
+extern void DMA_SetSourceAddr(unsigned char channel, unsigned int address);
+
+extern void DMA_SetDestinationAddr(unsigned char channel, unsigned int address);
+
+extern void DMA_SetDescriptorAddr(unsigned char channel, unsigned int address);
+
+extern void DMA_SetSourceBufferSize(unsigned char channel,
+ unsigned int size,
+ unsigned char sourceWidth,
+ unsigned char desDMAdth,
+ unsigned char done);
+
+extern void DMA_SetSourceBufferMode(unsigned char channel,
+ unsigned char transferMode,
+ unsigned char addressingType);
+
+extern void DMA_SetDestBufferMode(unsigned char channel,
+ unsigned char transferMode,
+ unsigned char addressingType);
+
+extern void DMA_SetConfiguration(unsigned char channel, unsigned int value);
+
+#if defined(AT91C_SRC_PIP)
+extern void DMA_SPIPconfiguration(unsigned char channel,
+ unsigned int pipHole, unsigned int pipBoundary);
+#endif
+
+#if defined(AT91C_DST_PIP)
+extern void DMA_DPIPconfiguration(unsigned char channel,
+ unsigned int pipHole, unsigned int pipBoundary);
+#endif
+
+extern void DMA_SetFlowControl(unsigned char channel,
+ unsigned int flow);
+
+
+#endif //#ifndef DMA_H
diff --git a/peripherals/eefc/eefc.c b/peripherals/eefc/eefc.c new file mode 100644 index 0000000..506e016 --- /dev/null +++ b/peripherals/eefc/eefc.c @@ -0,0 +1,296 @@ +/* ----------------------------------------------------------------------------
+ * 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 <board.h>
+#include "eefc.h"
+
+#if !defined (CHIP_FLASH_EEFC)
+#error eefc not supported
+#endif
+
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Enables the flash ready interrupt source on the EEFC peripheral.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+//------------------------------------------------------------------------------
+void EFC_EnableFrdyIt(AT91S_EFC *pEfc)
+{
+ pEfc->EFC_FMR |= AT91C_EFC_FRDY;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the flash ready interrupt source on the EEFC peripheral.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+//------------------------------------------------------------------------------
+void EFC_DisableFrdyIt(AT91S_EFC *pEfc)
+{
+ pEfc->EFC_FMR &= ~AT91C_EFC_FRDY;
+}
+
+//------------------------------------------------------------------------------
+/// Translates the given address page and offset values. The resulting
+/// values are stored in the provided variables if they are not null.
+/// \param ppEfc Pointer to target EFC peripheral.
+/// \param address Address to translate.
+/// \param pPage First page accessed.
+/// \param pOffset Byte offset in first page.
+//------------------------------------------------------------------------------
+void EFC_TranslateAddress(
+ AT91S_EFC **ppEfc,
+ unsigned int address,
+ unsigned short *pPage,
+ unsigned short *pOffset)
+{
+ AT91S_EFC *pEfc;
+ unsigned short page;
+ unsigned short offset;
+
+#if defined(AT91C_BASE_EFC1)
+ // Convert wrapped address to physical address.
+ address &= 0x19FFFF;
+ SANITY_CHECK(address >= AT91C_IFLASH);
+ if (address >= AT91C_IFLASH1) {
+ SANITY_CHECK(address <= (AT91C_IFLASH1 + AT91C_IFLASH1_SIZE));
+ }
+ else {
+ SANITY_CHECK(address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE));
+ }
+#else
+ SANITY_CHECK(address >= AT91C_IFLASH);
+ SANITY_CHECK(address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE));
+#endif
+
+ pEfc = AT91C_BASE_EFC;
+ page = (address - AT91C_IFLASH) / AT91C_IFLASH_PAGE_SIZE;
+ offset = (address - AT91C_IFLASH) % AT91C_IFLASH_PAGE_SIZE;
+
+#if defined(AT91C_BASE_EFC1)
+ if (address >= AT91C_IFLASH1) {
+ pEfc = AT91C_BASE_EFC1;
+ page = (address - AT91C_IFLASH1) / AT91C_IFLASH1_PAGE_SIZE;
+ offset = (address - AT91C_IFLASH1) % AT91C_IFLASH1_PAGE_SIZE;
+ }
+#endif
+
+ TRACE_DEBUG("Translated 0x%08X to page=%d and offset=%d\n\r",
+ address, page, offset);
+
+ // Store values
+ if (ppEfc) {
+ *ppEfc = pEfc;
+ }
+ if (pPage) {
+
+ *pPage = page;
+ }
+ if (pOffset) {
+
+ *pOffset = offset;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Computes the address of a flash access given the page and offset.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+/// \param page Page number.
+/// \param offset Byte offset inside page.
+/// \param pAddress Computed address (optional).
+//------------------------------------------------------------------------------
+void EFC_ComputeAddress(
+ AT91S_EFC *pEfc,
+ unsigned short page,
+ unsigned short offset,
+ unsigned int *pAddress)
+{
+ unsigned int address;
+ SANITY_CHECK(pEfc);
+ SANITY_CHECK(page <= AT91C_IFLASH_NB_OF_PAGES);
+ SANITY_CHECK(offset < AT91C_IFLASH_PAGE_SIZE);
+
+ // Compute address
+ address = AT91C_IFLASH + page * AT91C_IFLASH_PAGE_SIZE + offset;
+#if defined(AT91C_BASE_EFC1)
+ if (pEfc == AT91C_BASE_EFC1) {
+ address = AT91C_IFLASH1 + page * AT91C_IFLASH1_PAGE_SIZE + offset;
+ }
+#endif
+
+ // Store result
+ if (pAddress) {
+
+ *pAddress = address;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Starts the executing the given command on the EEFC. This function returns
+/// as soon as the command is started. It does NOT set the FMCN field automatically.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+/// \param command Command to execute.
+/// \param argument Command argument (should be 0 if not used).
+//------------------------------------------------------------------------------
+#if defined(flash) || defined (USE_FLASH)
+ #ifdef __ICCARM__
+__ramfunc
+ #else
+__attribute__ ((section (".ramfunc")))
+ #endif
+#endif
+void EFC_StartCommand(AT91S_EFC *pEfc, unsigned char command, unsigned short argument)
+{
+ // Check command & argument
+ switch (command) {
+
+ case AT91C_EFC_FCMD_WP:
+ case AT91C_EFC_FCMD_WPL:
+ case AT91C_EFC_FCMD_EWP:
+ case AT91C_EFC_FCMD_EWPL:
+ case AT91C_EFC_FCMD_EPL:
+ case AT91C_EFC_FCMD_EPA:
+ case AT91C_EFC_FCMD_SLB:
+ case AT91C_EFC_FCMD_CLB:
+ ASSERT(argument < AT91C_IFLASH_NB_OF_PAGES,
+ "-F- Embedded flash has only %d pages\n\r",
+ AT91C_IFLASH_NB_OF_PAGES);
+ break;
+
+ case AT91C_EFC_FCMD_SFB:
+ case AT91C_EFC_FCMD_CFB:
+ ASSERT(argument < CHIP_EFC_NUM_GPNVMS, "-F- Embedded flash has only %d GPNVMs\n\r", CHIP_EFC_NUM_GPNVMS);
+ break;
+
+ case AT91C_EFC_FCMD_GETD:
+ case AT91C_EFC_FCMD_EA:
+ case AT91C_EFC_FCMD_GLB:
+ case AT91C_EFC_FCMD_GFB:
+#ifdef AT91C_EFC_FCMD_STUI
+ case AT91C_EFC_FCMD_STUI:
+#endif
+ ASSERT(argument == 0, "-F- Argument is meaningless for the given command.\n\r");
+ break;
+
+ default: ASSERT(0, "-F- Unknown command %d\n\r", command);
+ }
+
+ // Start commandEmbedded flash
+ ASSERT((pEfc->EFC_FSR & AT91C_EFC_FRDY) == AT91C_EFC_FRDY, "-F- EEFC is not ready\n\r");
+ pEfc->EFC_FCR = (0x5A << 24) | (argument << 8) | command;
+}
+
+//------------------------------------------------------------------------------
+/// Performs the given command and wait until its completion (or an error).
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+/// \param command Command to perform.
+/// \param argument Optional command argument.
+//------------------------------------------------------------------------------
+#if defined(flash) || defined (USE_FLASH)
+ #ifdef __ICCARM__
+__ramfunc
+ #else
+__attribute__ ((section (".ramfunc")))
+ #endif
+#endif
+unsigned char EFC_PerformCommand(AT91S_EFC *pEfc, unsigned char command, unsigned short argument)
+{
+ unsigned int status;
+
+#ifdef CHIP_FLASH_IAP_ADDRESS
+
+#ifdef AT91C_BASE_EFC1
+
+// Pointer on IAP function in ROM
+ static unsigned int (*IAP_PerformCommand)(unsigned int, unsigned int);
+ unsigned int index = 0;
+ if (pEfc == AT91C_BASE_EFC1) {
+
+ index = 1;
+ }
+ IAP_PerformCommand = (unsigned int (*)(unsigned int, unsigned int)) *((unsigned int *) CHIP_FLASH_IAP_ADDRESS);
+ EFCIndex = pEfc == AT91C_BASE_EFC0? 0: 1;
+ // Check if IAP function is implemented (opcode in SWI != 'b' or 'ldr') */
+ if ((((((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xEA) &&
+ (((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xE5)) {
+
+ IAP_PerformCommand(index, (0x5A << 24) | (argument << 8) | command);
+ return (pEfc->EFC_FSR & (AT91C_EFC_LOCKE | AT91C_EFC_FCMDE));
+ }
+#else //only have one EEFC (AT91SAM9XE for example)
+ // Pointer on IAP function in ROM
+ static void (*IAP_PerformCommand)(unsigned int);
+ IAP_PerformCommand = (void (*)(unsigned int)) *((unsigned int *) CHIP_FLASH_IAP_ADDRESS);
+
+ // Check if IAP function is implemented (opcode in SWI != 'b' or 'ldr') */
+ if ((((((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xEA) &&
+ (((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xE5)) {
+
+ IAP_PerformCommand((0x5A << 24) | (argument << 8) | command);
+ return (pEfc->EFC_FSR & (AT91C_EFC_LOCKE | AT91C_EFC_FCMDE));
+ }
+#endif
+#endif
+ pEfc->EFC_FCR = (0x5A << 24) | (argument << 8) | command;
+ do {
+
+ status = pEfc->EFC_FSR;
+ }
+ while ((status & AT91C_EFC_FRDY) != AT91C_EFC_FRDY);
+
+ return (status & (AT91C_EFC_LOCKE | AT91C_EFC_FCMDE));
+}
+
+//------------------------------------------------------------------------------
+/// Returns the current status of the EEFC. Keep in mind that this function clears
+/// the value of some status bits (LOCKE, PROGE).
+/// \param pEfc Pointer to an AT91S_EFC structure.
+//------------------------------------------------------------------------------
+unsigned int EFC_GetStatus(AT91S_EFC *pEfc)
+{
+ return pEfc->EFC_FSR;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the result of the last executed command.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+//------------------------------------------------------------------------------
+unsigned int EFC_GetResult(AT91S_EFC *pEfc) {
+
+ return pEfc->EFC_FRR;
+}
+
diff --git a/peripherals/eefc/eefc.dir b/peripherals/eefc/eefc.dir new file mode 100644 index 0000000..8b969db --- /dev/null +++ b/peripherals/eefc/eefc.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the peripheral API for the Enhance Embedded Flash Controller (EEFC).
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/eefc/eefc.h b/peripherals/eefc/eefc.h new file mode 100644 index 0000000..a5ebd09 --- /dev/null +++ b/peripherals/eefc/eefc.h @@ -0,0 +1,147 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the Enhanced Embedded Flash Controller (EEFC)
+/// peripheral.
+///
+/// !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_H
+#define EEFC_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+#if !defined (CHIP_FLASH_EEFC)
+#error eefc not supported
+#endif
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+// Needed when EEFC is integrated in MC.
+#if !defined(AT91C_BASE_EFC) && defined(AT91C_BASE_MC)
+typedef struct _AT91S_EFC {
+ AT91_REG EFC_FMR; // EFC Flash Mode Register
+ AT91_REG EFC_FCR; // EFC Flash Command Register
+ AT91_REG EFC_FSR; // EFC Flash Status Register
+ AT91_REG EFC_FRR; // EFC Flash Result Register
+ AT91_REG EFC_FVR; // EFC Flash Version Register
+} AT91S_EFC, *AT91PS_EFC;
+
+#define AT91C_EFC_FRDY AT91C_MC_FRDY
+#define AT91C_EFC_FWS AT91C_MC_FWS
+#define AT91C_EFC_FWS_0WS AT91C_MC_FWS_0WS
+#define AT91C_EFC_FWS_1WS AT91C_MC_FWS_1WS
+#define AT91C_EFC_FWS_2WS AT91C_MC_FWS_2WS
+#define AT91C_EFC_FWS_3WS AT91C_MC_FWS_3WS
+#define AT91C_EFC_FCMD AT91C_MC_FCMD
+#define AT91C_EFC_FCMD_GETD AT91C_MC_FCMD_GETD
+#define AT91C_EFC_FCMD_WP AT91C_MC_FCMD_WP
+#define AT91C_EFC_FCMD_WPL AT91C_MC_FCMD_WPL
+#define AT91C_EFC_FCMD_EWP AT91C_MC_FCMD_EWP
+#define AT91C_EFC_FCMD_EWPL AT91C_MC_FCMD_EWPL
+#define AT91C_EFC_FCMD_EA AT91C_MC_FCMD_EA
+#define AT91C_EFC_FCMD_EPL AT91C_MC_FCMD_EPL
+#define AT91C_EFC_FCMD_EPA AT91C_MC_FCMD_EPA
+#define AT91C_EFC_FCMD_SLB AT91C_MC_FCMD_SLB
+#define AT91C_EFC_FCMD_CLB AT91C_MC_FCMD_CLB
+#define AT91C_EFC_FCMD_GLB AT91C_MC_FCMD_GLB
+#define AT91C_EFC_FCMD_SFB AT91C_MC_FCMD_SFB
+#define AT91C_EFC_FCMD_CFB AT91C_MC_FCMD_CFB
+#define AT91C_EFC_FCMD_GFB AT91C_MC_FCMD_GFB
+#define AT91C_EFC_FARG AT91C_MC_FARG
+#define AT91C_EFC_FKEY AT91C_MC_FKEY
+#define AT91C_EFC_FRDY_S AT91C_MC_FRDY_S
+#define AT91C_EFC_FCMDE AT91C_MC_FCMDE
+#define AT91C_EFC_LOCKE AT91C_MC_LOCKE
+#define AT91C_EFC_FVALUE AT91C_MC_FVALUE
+
+#define AT91C_BASE_EFC (AT91_CAST(AT91PS_EFC) 0xFFFFFF60)
+
+#endif //#if !defined(AT91C_BASE_EFC) && defined(AT91C_BASE_MC)
+
+//------------------------------------------------------------------------------
+// Functions
+//------------------------------------------------------------------------------
+
+extern void EFC_EnableFrdyIt(AT91S_EFC *pEfc);
+
+extern void EFC_DisableFrdyIt(AT91S_EFC *pEfc);
+
+extern void EFC_TranslateAddress(
+ AT91S_EFC **ppEfc,
+ unsigned int address,
+ unsigned short *pPage,
+ unsigned short *pOffset);
+
+extern void EFC_ComputeAddress(
+ AT91S_EFC *pEfc,
+ unsigned short page,
+ unsigned short offset,
+ unsigned int *pAddress);
+
+extern void EFC_StartCommand(
+ AT91S_EFC *pEfc,
+ unsigned char command,
+ unsigned short argument);
+
+extern unsigned char EFC_PerformCommand(
+ AT91S_EFC *pEfc,
+ unsigned char command,
+ unsigned short argument);
+
+extern unsigned int EFC_GetStatus(AT91S_EFC *pEfc);
+
+extern unsigned int EFC_GetResult(AT91S_EFC *pEfc);
+
+#endif //#ifndef EEFC_H
+
diff --git a/peripherals/efc/efc.c b/peripherals/efc/efc.c new file mode 100644 index 0000000..567034f --- /dev/null +++ b/peripherals/efc/efc.c @@ -0,0 +1,396 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include "efc.h"
+
+#if !defined (CHIP_FLASH_EFC)
+#error efc not supported
+#endif
+
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Local definitions
+//------------------------------------------------------------------------------
+
+// Round a number to the nearest integral value (number must have been
+// multiplied by 10, e.g. to round 10.3 enter 103).
+#define ROUND(n) ((((n) % 10) >= 5) ? (((n) / 10) + 1) : ((n) / 10))
+
+// Returns the FMCN field value when manipulating lock bits, given MCK.
+#if defined(at91sam7a3)
+ #define FMCN_BITS(mck) (ROUND((mck) / 1000000) << 16)
+#else
+ #define FMCN_BITS(mck) (ROUND((mck) / 100000) << 16)
+#endif
+
+// Returns the FMCN field value when manipulating the rest of the flash.
+#define FMCN_FLASH(mck) ((((mck) / 2000000) * 3) << 16)
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+/// Master clock frequency, used to infer the value of the FMCN field.
+#ifdef MCK_VARIABLE
+static unsigned int lMck = 0;
+#else
+static const unsigned int lMck = BOARD_MCK;
+#endif
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Sets the system master clock so the FMCN field of the EFC(s) can be
+/// programmed properly.
+/// \param mck Master clock frequency in Hz.
+//------------------------------------------------------------------------------
+void EFC_SetMasterClock(unsigned int mck)
+{
+#ifdef MCK_VARIABLE
+ lMck = mck;
+#else
+ ASSERT(mck == BOARD_MCK, "-F- EFC has not been configured to work at a freq. different from %dMHz", BOARD_MCK);
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Enables the given interrupt sources on an EFC peripheral.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+/// \param sources Interrupt sources to enable.
+//------------------------------------------------------------------------------
+void EFC_EnableIt(AT91S_EFC *pEfc, unsigned int sources)
+{
+ SANITY_CHECK(pEfc);
+ SANITY_CHECK((sources & ~0x0000000D) == 0);
+
+ pEfc->EFC_FMR |= sources;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the given interrupt sources on an EFC peripheral.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+/// \param sources Interrupt sources to disable.
+//------------------------------------------------------------------------------
+void EFC_DisableIt(AT91S_EFC *pEfc, unsigned int sources)
+{
+ SANITY_CHECK(pEfc);
+ SANITY_CHECK((sources & ~(AT91C_MC_FRDY | AT91C_MC_LOCKE | AT91C_MC_PROGE)) == 0);
+
+ pEfc->EFC_FMR &= ~sources;
+}
+
+//------------------------------------------------------------------------------
+/// Enables or disable the "Erase before programming" feature of an EFC.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+/// \param enable If 1, the feature is enabled; otherwise it is disabled.
+//------------------------------------------------------------------------------
+void EFC_SetEraseBeforeProgramming(AT91S_EFC *pEfc, unsigned char enable)
+{
+ SANITY_CHECK(pEfc);
+
+ if (enable) {
+
+ pEfc->EFC_FMR &= ~AT91C_MC_NEBP;
+ }
+ else {
+
+ pEfc->EFC_FMR |= AT91C_MC_NEBP;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Translates the given address into EFC, page and offset values. The resulting
+/// values are stored in the provided variables if they are not null.
+/// \param address Address to translate.
+/// \param ppEfc Pointer to target EFC peripheral.
+/// \param pPage First page accessed.
+/// \param pOffset Byte offset in first page.
+//------------------------------------------------------------------------------
+void EFC_TranslateAddress(
+ AT91S_EFC **ppEfc,
+ unsigned int address,
+ unsigned short *pPage,
+ unsigned short *pOffset)
+{
+ AT91S_EFC *pEfc;
+ unsigned short page;
+ unsigned short offset;
+
+ TRACE_DEBUG("address=0x%X\n\r", address);
+ SANITY_CHECK(address >= AT91C_IFLASH);
+ SANITY_CHECK(address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE));
+
+#if defined(AT91C_BASE_EFC0)
+ if (address >= (AT91C_IFLASH + AT91C_IFLASH_SIZE / 2)) {
+
+ pEfc = AT91C_BASE_EFC1;
+ page = (address - AT91C_IFLASH - AT91C_IFLASH_SIZE / 2) / AT91C_IFLASH_PAGE_SIZE;
+ offset = (address - AT91C_IFLASH - AT91C_IFLASH_SIZE / 2) % AT91C_IFLASH_PAGE_SIZE;
+ }
+ else {
+
+ pEfc = AT91C_BASE_EFC0;
+ page = (address - AT91C_IFLASH) / AT91C_IFLASH_PAGE_SIZE;
+ offset = (address - AT91C_IFLASH) % AT91C_IFLASH_PAGE_SIZE;
+ }
+#else
+ pEfc = AT91C_BASE_EFC;
+ page = (address - AT91C_IFLASH) / AT91C_IFLASH_PAGE_SIZE;
+ offset = (address - AT91C_IFLASH) % AT91C_IFLASH_PAGE_SIZE;
+#endif
+ TRACE_DEBUG("Translated 0x%08X to EFC=0x%08X, page=%d and offset=%d\n\r",
+ address, (unsigned int) pEfc, page, offset);
+
+ // Store values
+ if (ppEfc) {
+
+ *ppEfc = pEfc;
+ }
+ if (pPage) {
+
+ *pPage = page;
+ }
+ if (pOffset) {
+
+ *pOffset = offset;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Computes the address of a flash access given the EFC, page and offset.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+/// \param page Page number.
+/// \param offset Byte offset inside page.
+/// \param pAddress Computed address (optional).
+//------------------------------------------------------------------------------
+void EFC_ComputeAddress(
+ AT91S_EFC *pEfc,
+ unsigned short page,
+ unsigned short offset,
+ unsigned int *pAddress)
+{
+ unsigned int address;
+
+ SANITY_CHECK(pEfc);
+#if defined(AT91C_BASE_EFC1)
+ SANITY_CHECK(page <= (AT91C_IFLASH_NB_OF_PAGES / 2));
+#else
+ SANITY_CHECK(page <= AT91C_IFLASH_NB_OF_PAGES);
+#endif
+ SANITY_CHECK(offset < AT91C_IFLASH_PAGE_SIZE);
+
+ // Compute address
+ address = AT91C_IFLASH + page * AT91C_IFLASH_PAGE_SIZE + offset;
+#if defined(AT91C_BASE_EFC1)
+ if (pEfc == AT91C_BASE_EFC1) {
+
+ address += AT91C_IFLASH_SIZE / 2;
+ }
+#endif
+
+ // Store result
+ if (pAddress) {
+
+ *pAddress = address;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Starts the executing the given command on an EFC. This function returns
+/// as soon as the command is started. It does NOT set the FMCN field automatically.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+/// \param command Command to execute.
+/// \param argument Command argument (should be 0 if not used).
+//------------------------------------------------------------------------------
+#if defined(flash) || defined (USE_FLASH)
+ #ifdef __ICCARM__
+__ramfunc
+ #else
+__attribute__ ((section (".ramfunc")))
+ #endif
+#endif
+void EFC_StartCommand(
+ AT91S_EFC *pEfc,
+ unsigned char command,
+ unsigned short argument)
+{
+ SANITY_CHECK(pEfc);
+ ASSERT(lMck != 0, "-F- Master clock not set.\n\r");
+
+ // Check command & argument
+ switch (command) {
+
+ case AT91C_MC_FCMD_PROG_AND_LOCK:
+ ASSERT(0, "-F- Write and lock command cannot be carried out.\n\r");
+ break;
+
+ case AT91C_MC_FCMD_START_PROG:
+ case AT91C_MC_FCMD_LOCK:
+ case AT91C_MC_FCMD_UNLOCK:
+ ASSERT(argument < AT91C_IFLASH_NB_OF_PAGES,
+ "-F- Maximum number of pages is %d (argument was %d)\n\r",
+ AT91C_IFLASH_NB_OF_PAGES,
+ argument);
+ break;
+
+#if (CHIP_EFC_NUM_GPNVMS > 0)
+ case AT91C_MC_FCMD_SET_GP_NVM:
+ case AT91C_MC_FCMD_CLR_GP_NVM:
+ ASSERT(argument < CHIP_EFC_NUM_GPNVMS, "-F- A maximum of %d GPNVMs are available on the chip.\n\r", CHIP_EFC_NUM_GPNVMS);
+ break;
+#endif
+
+ case AT91C_MC_FCMD_ERASE_ALL:
+
+#if !defined(EFC_NO_SECURITY_BIT)
+ case AT91C_MC_FCMD_SET_SECURITY:
+#endif
+ ASSERT(argument == 0, "-F- Argument is meaningless for the given command\n\r");
+ break;
+
+ default: ASSERT(0, "-F- Unknown command %d\n\r", command);
+ }
+
+ // Set FMCN
+ switch (command) {
+
+ case AT91C_MC_FCMD_LOCK:
+ case AT91C_MC_FCMD_UNLOCK:
+#if (CHIP_EFC_NUM_GPNVMS > 0)
+ case AT91C_MC_FCMD_SET_GP_NVM:
+ case AT91C_MC_FCMD_CLR_GP_NVM:
+#endif
+#if !defined(EFC_NO_SECURITY_BIT)
+ case AT91C_MC_FCMD_SET_SECURITY:
+#endif
+ pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | FMCN_BITS(lMck);
+ break;
+
+ case AT91C_MC_FCMD_START_PROG:
+ case AT91C_MC_FCMD_ERASE_ALL:
+ pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | FMCN_FLASH(lMck);
+ break;
+ }
+
+ // Start command
+ ASSERT((pEfc->EFC_FSR & AT91C_MC_FRDY) != 0, "-F- Efc is not ready\n\r");
+ pEfc->EFC_FCR = (0x5A << 24) | (argument << 8) | command;
+}
+
+//------------------------------------------------------------------------------
+/// Performs the given command and wait until its completion (or an error).
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param pEfc Pointer to an AT91S_EFC structure.
+/// \param command Command to perform.
+/// \param argument Optional command argument.
+//------------------------------------------------------------------------------
+#if defined(flash) || defined (USE_FLASH)
+ #ifdef __ICCARM__
+__ramfunc
+ #else
+__attribute__ ((section (".ramfunc")))
+ #endif
+#endif
+unsigned char EFC_PerformCommand(
+ AT91S_EFC *pEfc,
+ unsigned char command,
+ unsigned short argument)
+{
+ unsigned int status;
+
+ // Set FMCN
+ switch (command) {
+
+ case AT91C_MC_FCMD_LOCK:
+ case AT91C_MC_FCMD_UNLOCK:
+#if (CHIP_EFC_NUM_GPNVMS > 0)
+ case AT91C_MC_FCMD_SET_GP_NVM:
+ case AT91C_MC_FCMD_CLR_GP_NVM:
+#endif
+#if !defined(EFC_NO_SECURITY_BIT)
+ case AT91C_MC_FCMD_SET_SECURITY:
+#endif
+ pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | FMCN_BITS(lMck);
+ break;
+
+ case AT91C_MC_FCMD_START_PROG:
+ case AT91C_MC_FCMD_ERASE_ALL:
+ pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | FMCN_FLASH(lMck);
+ break;
+ }
+
+#ifdef CHIP_FLASH_IAP_ADDRESS
+ // Pointer on IAP function in ROM
+ static void (*IAP_PerformCommand)(unsigned int, unsigned int);
+ unsigned int index = 0;
+#ifdef AT91C_BASE_EFC1
+ if (pEfc == AT91C_BASE_EFC1) {
+
+ index = 1;
+ }
+#endif
+ IAP_PerformCommand = (void (*)(unsigned int, unsigned int)) *((unsigned int *) CHIP_FLASH_IAP_ADDRESS);
+
+ // Check if IAP function is implemented (opcode in SWI != 'b' or 'ldr') */
+ if ((((((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xEA) &&
+ (((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xE5)) {
+
+ IAP_PerformCommand(index, (0x5A << 24) | (argument << 8) | command);
+ return (pEfc->EFC_FSR & (AT91C_MC_LOCKE | AT91C_MC_PROGE));
+ }
+#endif
+
+ pEfc->EFC_FCR = (0x5A << 24) | (argument << 8) | command;
+ do {
+
+ status = pEfc->EFC_FSR;
+ }
+ while ((status & AT91C_MC_FRDY) == 0);
+
+ return (status & (AT91C_MC_PROGE | AT91C_MC_LOCKE));
+}
+
+//------------------------------------------------------------------------------
+/// Returns the current status of an EFC. Keep in mind that this function clears
+/// the value of some status bits (LOCKE, PROGE).
+/// \param pEfc Pointer to an AT91S_EFC structure.
+//------------------------------------------------------------------------------
+unsigned int EFC_GetStatus(AT91S_EFC *pEfc)
+{
+ return pEfc->EFC_FSR;
+}
diff --git a/peripherals/efc/efc.dir b/peripherals/efc/efc.dir new file mode 100644 index 0000000..57b7cc7 --- /dev/null +++ b/peripherals/efc/efc.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the peripheral API for the Embedded Flash Controller (EFC).
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/efc/efc.h b/peripherals/efc/efc.h new file mode 100644 index 0000000..4367ed5 --- /dev/null +++ b/peripherals/efc/efc.h @@ -0,0 +1,131 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the Embedded Flash Controller (EFC) peripheral.
+///
+/// !Usage
+///
+/// -# Initialize system master clock of the EFC with EFC_SetMasterClock().
+/// -# Enable/disable interrupt sources using EFC_EnableIt() and EFC_DisableIt().
+/// -# Enables or disable the "Erase before programming" feature using
+/// EFC_SetEraseBeforeProgramming().
+/// -# Translates the given address into which EFC, 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().
+///
+//------------------------------------------------------------------------------
+#ifndef EFC_H
+#define EFC_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+#if !defined (CHIP_FLASH_EFC)
+#error efc not supported
+#endif
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+
+// Missing FRDY bit for SAM7A3
+#if defined(at91sam7a3)
+ #define AT91C_MC_FRDY (AT91C_MC_EOP | AT91C_MC_EOL)
+#endif
+
+// No security bit on SAM7A3
+#if defined(at91sam7a3)
+ #define EFC_NO_SECURITY_BIT
+#endif
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+// For chips which do not define AT91S_EFC
+#if !defined(AT91C_BASE_EFC) && !defined(AT91C_BASE_EFC0)
+typedef struct _AT91S_EFC {
+
+ AT91_REG EFC_FMR;
+ AT91_REG EFC_FCR;
+ AT91_REG EFC_FSR;
+
+} AT91S_EFC, *AT91PS_EFC;
+ #define AT91C_BASE_EFC (AT91_CAST(AT91PS_EFC) 0xFFFFFF60)
+#endif
+
+//------------------------------------------------------------------------------
+// Functions
+//------------------------------------------------------------------------------
+
+extern void EFC_SetMasterClock(unsigned int mck);
+
+extern void EFC_EnableIt(AT91S_EFC *pEfc, unsigned int sources);
+
+extern void EFC_DisableIt(AT91S_EFC *pEfc, unsigned int sources);
+
+extern void EFC_SetEraseBeforeProgramming(AT91S_EFC *pEfc, unsigned char enable);
+
+extern void EFC_TranslateAddress(
+ AT91S_EFC **ppEfc,
+ unsigned int address,
+ unsigned short *pPage,
+ unsigned short *pOffset);
+
+extern void EFC_ComputeAddress(
+ AT91S_EFC *pEfc,
+ unsigned short page,
+ unsigned short offset,
+ unsigned int *pAddress);
+
+extern void EFC_StartCommand(
+ AT91S_EFC *pEfc,
+ unsigned char command,
+ unsigned short argument);
+
+extern unsigned char EFC_PerformCommand(
+ AT91S_EFC *pEfc,
+ unsigned char command,
+ unsigned short argument);
+
+extern unsigned int EFC_GetStatus(AT91S_EFC *pEfc);
+
+#endif //#ifndef EFC_H
+
diff --git a/peripherals/emac/emac.c b/peripherals/emac/emac.c new file mode 100644 index 0000000..09380f8 --- /dev/null +++ b/peripherals/emac/emac.c @@ -0,0 +1,914 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//-----------------------------------------------------------------------------
+// Headers
+//-----------------------------------------------------------------------------
+#include <board.h>
+#include "emac.h"
+#include <utility/trace.h>
+#include <utility/assert.h>
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+/// The buffer addresses written into the descriptors must be aligned so the
+/// last few bits are zero. These bits have special meaning for the EMAC
+/// peripheral and cannot be used as part of the address.
+#define EMAC_ADDRESS_MASK ((unsigned int)0xFFFFFFFC)
+#define EMAC_LENGTH_FRAME ((unsigned int)0x0FFF) /// Length of frame mask
+
+// receive buffer descriptor bits
+#define EMAC_RX_OWNERSHIP_BIT (1 << 0)
+#define EMAC_RX_WRAP_BIT (1 << 1)
+#define EMAC_RX_SOF_BIT (1 << 14)
+#define EMAC_RX_EOF_BIT (1 << 15)
+
+// Transmit buffer descriptor bits
+#define EMAC_TX_LAST_BUFFER_BIT (1 << 15)
+#define EMAC_TX_WRAP_BIT (1 << 30)
+#define EMAC_TX_USED_BIT (1 << 31)
+#define EMAC_TX_RLE_BIT (1 << 29) /// Retry Limit Exceeded
+#define EMAC_TX_UND_BIT (1 << 28) /// Tx Buffer Underrun
+#define EMAC_TX_ERR_BIT (1 << 27) /// Exhausted in mid-frame
+#define EMAC_TX_ERR_BITS \
+ (EMAC_TX_RLE_BIT | EMAC_TX_UND_BIT | EMAC_TX_ERR_BIT)
+
+//-----------------------------------------------------------------------------
+// Circular buffer management
+//-----------------------------------------------------------------------------
+// Return count in buffer
+#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))
+
+// Return space available, 0..size-1
+// We always leave one free char as a completely full buffer
+// has head == tail, which is the same as empty
+#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))
+
+// Return count up to the end of the buffer.
+// Carefully avoid accessing head and tail more than once,
+// so they can change underneath us without returning inconsistent results
+#define CIRC_CNT_TO_END(head,tail,size) \
+ ({int end = (size) - (tail); \
+ int n = ((head) + end) & ((size)-1); \
+ n < end ? n : end;})
+
+// Return space available up to the end of the buffer
+#define CIRC_SPACE_TO_END(head,tail,size) \
+ ({int end = (size) - 1 - (head); \
+ int n = (end + (tail)) & ((size)-1); \
+ n <= end ? n : end+1;})
+
+// Increment head or tail
+#define CIRC_INC(headortail,size) \
+ headortail++; \
+ if(headortail >= size) { \
+ headortail = 0; \
+ }
+
+#define CIRC_EMPTY(circ) ((circ)->head == (circ)->tail)
+#define CIRC_CLEAR(circ) ((circ)->head = (circ)->tail = 0)
+
+
+//------------------------------------------------------------------------------
+// Structures
+//------------------------------------------------------------------------------
+#ifdef __ICCARM__ // IAR
+#pragma pack(4) // IAR
+#define __attribute__(...) // IAR
+#endif // IAR
+/// Describes the type and attribute of Receive Transfer descriptor.
+typedef struct _EmacRxTDescriptor {
+ unsigned int addr;
+ unsigned int status;
+} __attribute__((packed, aligned(8))) EmacRxTDescriptor, *PEmacRxTDescriptor;
+
+/// Describes the type and attribute of Transmit Transfer descriptor.
+typedef struct _EmacTxTDescriptor {
+ unsigned int addr;
+ unsigned int status;
+} __attribute__((packed, aligned(8))) EmacTxTDescriptor, *PEmacTxTDescriptor;
+#ifdef __ICCARM__ // IAR
+#pragma pack() // IAR
+#endif // IAR
+
+#ifdef __ICCARM__ // IAR
+#pragma data_alignment=8 // IAR
+#endif // IAR
+/// Descriptors for RX (required aligned by 8)
+typedef struct {
+ volatile EmacRxTDescriptor td[RX_BUFFERS];
+ EMAC_RxCallback rxCb; /// Callback function to be invoked once a frame has been received
+ unsigned short idx;
+} RxTd;
+
+#ifdef __ICCARM__ // IAR
+#pragma data_alignment=8 // IAR
+#endif // IAR
+/// Descriptors for TX (required aligned by 8)
+typedef struct {
+ volatile EmacTxTDescriptor td[TX_BUFFERS];
+ EMAC_TxCallback txCb[TX_BUFFERS]; /// Callback function to be invoked once TD has been processed
+ EMAC_WakeupCallback wakeupCb; /// Callback function to be invoked once several TD have been released
+ unsigned short wakeupThreshold; /// Number of free TD before wakeupCb is invoked
+ unsigned short head; /// Circular buffer head pointer incremented by the upper layer (buffer to be sent)
+ unsigned short tail; /// Circular buffer head pointer incremented by the IT handler (buffer sent)
+} TxTd;
+
+//------------------------------------------------------------------------------
+// Internal variables
+//------------------------------------------------------------------------------
+// Receive Transfer Descriptor buffer
+static volatile RxTd rxTd;
+// Transmit Transfer Descriptor buffer
+static volatile TxTd txTd;
+/// Send Buffer
+// Section 3.6 of AMBA 2.0 spec states that burst should not cross 1K Boundaries.
+// Receive buffer manager writes are burst of 2 words => 3 lsb bits of the address shall be set to 0
+#ifdef __ICCARM__ // IAR
+#pragma data_alignment=8 // IAR
+#endif // IAR
+static volatile unsigned char pTxBuffer[TX_BUFFERS * EMAC_TX_UNITSIZE] __attribute__((aligned(8)));
+
+#ifdef __ICCARM__ // IAR
+#pragma data_alignment=8 // IAR
+#endif // IAR
+/// Receive Buffer
+static volatile unsigned char pRxBuffer[RX_BUFFERS * EMAC_RX_UNITSIZE] __attribute__((aligned(8)));
+/// Statistics
+static volatile EmacStats EmacStatistics;
+
+//-----------------------------------------------------------------------------
+// Internal functions
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+/// Wait PHY operation complete.
+/// Return 1 if the operation completed successfully.
+/// May be need to re-implemented to reduce CPU load.
+/// \param retry: the retry times, 0 to wait forever until complete.
+//-----------------------------------------------------------------------------
+static unsigned char EMAC_WaitPhy( unsigned int retry )
+{
+ unsigned int retry_count = 0;
+
+ while((AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE) == 0) {
+
+ // Dead LOOP!
+ if (retry == 0) {
+
+ continue;
+ }
+
+ // Timeout check
+ retry_count++;
+ if(retry_count >= retry) {
+
+ TRACE_ERROR("E: Wait PHY time out\n\r");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+/// Disable TX & reset registers and descriptor list
+//-----------------------------------------------------------------------------
+static void EMAC_ResetTx(void)
+{
+ unsigned int Index;
+ unsigned int Address;
+
+ // Disable TX
+ AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_TE;
+ // Setup the TX descriptors.
+ CIRC_CLEAR(&txTd);
+ for(Index = 0; Index < TX_BUFFERS; Index++) {
+
+ Address = (unsigned int)(&(pTxBuffer[Index * EMAC_TX_UNITSIZE]));
+ txTd.td[Index].addr = Address;
+ txTd.td[Index].status = EMAC_TX_USED_BIT;
+ }
+ txTd.td[TX_BUFFERS - 1].status = EMAC_TX_USED_BIT | EMAC_TX_WRAP_BIT;
+ // Transmit Buffer Queue Pointer Register
+ AT91C_BASE_EMAC->EMAC_TBQP = (unsigned int) (txTd.td);
+}
+
+//-----------------------------------------------------------------------------
+/// Disable RX & reset registers and descriptor list
+//-----------------------------------------------------------------------------
+static void EMAC_ResetRx(void)
+{
+ unsigned int Index;
+ unsigned int Address;
+
+ // Disable RX
+ AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_RE;
+ // Setup the RX descriptors.
+ rxTd.idx = 0;
+ for(Index = 0; Index < RX_BUFFERS; Index++) {
+
+ Address = (unsigned int)(&(pRxBuffer[Index * EMAC_RX_UNITSIZE]));
+ // Remove EMAC_RX_OWNERSHIP_BIT and EMAC_RX_WRAP_BIT
+ rxTd.td[Index].addr = Address & EMAC_ADDRESS_MASK;
+ rxTd.td[Index].status = 0;
+ }
+ rxTd.td[RX_BUFFERS - 1].addr |= EMAC_RX_WRAP_BIT;
+ // Receive Buffer Queue Pointer Register
+ AT91C_BASE_EMAC->EMAC_RBQP = (unsigned int) (rxTd.td);
+}
+
+//-----------------------------------------------------------------------------
+// Exported functions
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// PHY management functions
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+/// Set MDC clock according to current board clock. Per 802.3, MDC should be
+/// less then 2.5MHz.
+/// Return 1 if successfully, 0 if MDC clock not found.
+//-----------------------------------------------------------------------------
+unsigned char EMAC_SetMdcClock( unsigned int mck )
+{
+ int clock_dividor;
+
+ if (mck <= 20000000) {
+ clock_dividor = AT91C_EMAC_CLK_HCLK_8; /// MDC clock = MCK/8
+ }
+ else if (mck <= 40000000) {
+ clock_dividor = AT91C_EMAC_CLK_HCLK_16; /// MDC clock = MCK/16
+ }
+ else if (mck <= 80000000) {
+ clock_dividor = AT91C_EMAC_CLK_HCLK_32; /// MDC clock = MCK/32
+ }
+ else if (mck <= 160000000) {
+ clock_dividor = AT91C_EMAC_CLK_HCLK_64; /// MDC clock = MCK/64
+ }
+ else {
+ TRACE_ERROR("E: No valid MDC clock.\n\r");
+ return 0;
+ }
+ AT91C_BASE_EMAC->EMAC_NCFGR = (AT91C_BASE_EMAC->EMAC_NCFGR & (~AT91C_EMAC_CLK))
+ | clock_dividor;
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable MDI with PHY
+//-----------------------------------------------------------------------------
+void EMAC_EnableMdio( void )
+{
+ AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable MDI with PHY
+//-----------------------------------------------------------------------------
+void EMAC_DisableMdio( void )
+{
+ AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable MII mode for EMAC, called once after autonegotiate
+//-----------------------------------------------------------------------------
+void EMAC_EnableMII( void )
+{
+ AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable RMII mode for EMAC, called once after autonegotiate
+//-----------------------------------------------------------------------------
+void EMAC_EnableRMII( void )
+{
+ AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN | AT91C_EMAC_RMII;
+}
+
+//-----------------------------------------------------------------------------
+/// Read PHY register.
+/// Return 1 if successfully, 0 if timeout.
+/// \param PhyAddress PHY Address
+/// \param Address Register Address
+/// \param pValue Pointer to a 32 bit location to store read data
+/// \param retry The retry times, 0 to wait forever until complete.
+//-----------------------------------------------------------------------------
+unsigned char EMAC_ReadPhy(unsigned char PhyAddress,
+ unsigned char Address,
+ unsigned int *pValue,
+ unsigned int retry)
+{
+ AT91C_BASE_EMAC->EMAC_MAN = (AT91C_EMAC_SOF & (0x01 << 30))
+ | (AT91C_EMAC_CODE & (2 << 16))
+ | (AT91C_EMAC_RW & (2 << 28))
+ | (AT91C_EMAC_PHYA & ((PhyAddress & 0x1f) << 23))
+ | (AT91C_EMAC_REGA & (Address << 18));
+
+ if ( EMAC_WaitPhy(retry) == 0 ) {
+
+ TRACE_ERROR("TimeOut EMAC_ReadPhy\n\r");
+ return 0;
+ }
+ *pValue = ( AT91C_BASE_EMAC->EMAC_MAN & 0x0000ffff );
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+/// Write PHY register
+/// Return 1 if successfully, 0 if timeout.
+/// \param PhyAddress PHY Address
+/// \param Address Register Address
+/// \param Value Data to write ( Actually 16 bit data )
+/// \param retry The retry times, 0 to wait forever until complete.
+//-----------------------------------------------------------------------------
+unsigned char EMAC_WritePhy(unsigned char PhyAddress,
+ unsigned char Address,
+ unsigned int Value,
+ unsigned int retry)
+{
+ AT91C_BASE_EMAC->EMAC_MAN = (AT91C_EMAC_SOF & (0x01 << 30))
+ | (AT91C_EMAC_CODE & (2 << 16))
+ | (AT91C_EMAC_RW & (1 << 28))
+ | (AT91C_EMAC_PHYA & ((PhyAddress & 0x1f) << 23))
+ | (AT91C_EMAC_REGA & (Address << 18))
+ | (AT91C_EMAC_DATA & Value) ;
+ if ( EMAC_WaitPhy(retry) == 0 ) {
+
+ TRACE_ERROR("TimeOut EMAC_WritePhy\n\r");
+ return 0;
+ }
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+/// Setup the EMAC for the link : speed 100M/10M and Full/Half duplex
+/// \param speed Link speed, 0 for 10M, 1 for 100M
+/// \param fullduplex 1 for Full Duplex mode
+//-----------------------------------------------------------------------------
+void EMAC_SetLinkSpeed(unsigned char speed, unsigned char fullduplex)
+{
+ unsigned int ncfgr;
+
+ ncfgr = AT91C_BASE_EMAC->EMAC_NCFGR;
+ ncfgr &= ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
+ if (speed) {
+
+ ncfgr |= AT91C_EMAC_SPD;
+ }
+ if (fullduplex) {
+
+ ncfgr |= AT91C_EMAC_FD;
+ }
+ AT91C_BASE_EMAC->EMAC_NCFGR = ncfgr;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// EMAC functions
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+/// EMAC Interrupt handler
+//-----------------------------------------------------------------------------
+void EMAC_Handler(void)
+{
+ volatile EmacTxTDescriptor *pTxTd;
+ volatile EMAC_TxCallback *pTxCb;
+ volatile unsigned int isr;
+ volatile unsigned int rsr;
+ volatile unsigned int tsr;
+ unsigned int rxStatusFlag;
+ unsigned int txStatusFlag;
+
+ //TRACE_DEBUG("EMAC_Handler\n\r");
+ isr = AT91C_BASE_EMAC->EMAC_ISR;
+ rsr = AT91C_BASE_EMAC->EMAC_RSR;
+ tsr = AT91C_BASE_EMAC->EMAC_TSR;
+ isr &= ~(AT91C_BASE_EMAC->EMAC_IMR | 0xFFC300);
+
+ // RX packet
+ if ((isr & AT91C_EMAC_RCOMP) || (rsr & AT91C_EMAC_REC)) {
+ rxStatusFlag = AT91C_EMAC_REC;
+
+ // Frame received
+ EmacStatistics.rx_packets++;
+
+ // Check OVR
+ if (rsr & AT91C_EMAC_OVR) {
+ rxStatusFlag |= AT91C_EMAC_OVR;
+ EmacStatistics.rx_ovrs++;
+ }
+ // Check BNA
+ if (rsr & AT91C_EMAC_BNA) {
+ rxStatusFlag |= AT91C_EMAC_BNA;
+ EmacStatistics.rx_bnas++;
+ }
+ // Clear status
+ AT91C_BASE_EMAC->EMAC_RSR |= rxStatusFlag;
+
+ // Invoke callbacks
+ if (rxTd.rxCb) {
+ rxTd.rxCb(rxStatusFlag);
+ }
+ }
+
+ // TX packet
+ if ((isr & AT91C_EMAC_TCOMP) || (tsr & AT91C_EMAC_COMP)) {
+
+ txStatusFlag = AT91C_EMAC_COMP;
+ EmacStatistics.tx_comp ++;
+
+ // A frame transmitted
+ // Check RLE
+ if (tsr & AT91C_EMAC_RLES) {
+ // Status RLE & Number of discarded buffers
+ txStatusFlag = AT91C_EMAC_RLES
+ | CIRC_CNT(txTd.head, txTd.tail, TX_BUFFERS);
+ pTxCb = txTd.txCb + txTd.tail;
+ EMAC_ResetTx();
+ TRACE_INFO("Tx RLE!!\n\r");
+ AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TE;
+ EmacStatistics.tx_errors++;
+ }
+ // Check COL
+ if (tsr & AT91C_EMAC_COL) {
+ txStatusFlag |= AT91C_EMAC_COL;
+ EmacStatistics.collisions++;
+ }
+ // Check BEX
+ if (tsr & AT91C_EMAC_BEX) {
+ txStatusFlag |= AT91C_EMAC_BEX;
+ EmacStatistics.tx_exausts++;
+ }
+ // Check UND
+ if (tsr & AT91C_EMAC_UND) {
+ txStatusFlag |= AT91C_EMAC_UND;
+ EmacStatistics.tx_underruns++;
+ }
+ // Clear status
+ AT91C_BASE_EMAC->EMAC_TSR |= txStatusFlag;
+
+ if (!CIRC_EMPTY(&txTd))
+ {
+ // Check the buffers
+ do {
+ pTxTd = txTd.td + txTd.tail;
+ pTxCb = txTd.txCb + txTd.tail;
+ // Any error?
+ // Exit if buffer has not been sent yet
+ if ((pTxTd->status & EMAC_TX_USED_BIT) == 0) {
+ break;
+ }
+
+ // Notify upper layer that a packet has been sent
+ if (*pTxCb) {
+ (*pTxCb)(txStatusFlag);
+ }
+
+ CIRC_INC( txTd.tail, TX_BUFFERS );
+ } while (CIRC_CNT(txTd.head, txTd.tail, TX_BUFFERS));
+ }
+
+ if (tsr & AT91C_EMAC_RLES) {
+ // Notify upper layer RLE
+ if (*pTxCb) {
+ (*pTxCb)(txStatusFlag);
+ }
+ }
+
+ // If a wakeup has been scheduled, notify upper layer that it can
+ // send other packets, send will be successfull.
+ if( (CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) >=
+ txTd.wakeupThreshold)
+ && txTd.wakeupCb) {
+ txTd.wakeupCb();
+ }
+ }
+
+ // PAUSE Frame
+ if (isr & AT91C_EMAC_PFRE) {
+ TRACE_INFO("Pause!\n\r");
+ }
+ if (isr & AT91C_EMAC_PTZ) {
+ TRACE_INFO("Pause TO!\n\r");
+ }
+}
+
+//-----------------------------------------------------------------------------
+/// Initialize the EMAC with the emac controller address
+/// \param id HW ID for power management
+/// \param pTxWakeUpfct Thresold TX Wakeup Callback
+/// \param pRxfct RX Wakeup Callback
+/// \param pMacAddress Mac Address
+/// \param enableCAF enable AT91C_EMAC_CAF if needed by application
+/// \param enableNBC AT91C_EMAC_NBC if needed by application
+//-----------------------------------------------------------------------------
+void EMAC_Init( unsigned char id, const unsigned char *pMacAddress,
+ unsigned char enableCAF, unsigned char enableNBC )
+{
+
+ // Check parameters
+ ASSERT(RX_BUFFERS * EMAC_RX_UNITSIZE > EMAC_FRAME_LENTGH_MAX,
+ "E: RX buffers too small\n\r");
+
+ TRACE_DEBUG("EMAC_Init\n\r");
+
+ // Power ON
+ AT91C_BASE_PMC->PMC_PCER = 1 << id;
+
+ // Disable TX & RX and more
+ AT91C_BASE_EMAC->EMAC_NCR = 0;
+
+ // disable
+ AT91C_BASE_EMAC->EMAC_IDR = ~0;
+
+ EMAC_ResetRx();
+ EMAC_ResetTx();
+
+ // Set the MAC address
+ if( pMacAddress != (unsigned char *)0 ) {
+ AT91C_BASE_EMAC->EMAC_SA1L = ( ((unsigned int)pMacAddress[3] << 24)
+ | ((unsigned int)pMacAddress[2] << 16)
+ | ((unsigned int)pMacAddress[1] << 8 )
+ | pMacAddress[0] );
+
+ AT91C_BASE_EMAC->EMAC_SA1H = ( ((unsigned int)pMacAddress[5] << 8 )
+ | pMacAddress[4] );
+ }
+
+ AT91C_BASE_EMAC->EMAC_NCR = AT91C_EMAC_CLRSTAT;
+
+ // Clear all status bits in the receive status register.
+ AT91C_BASE_EMAC->EMAC_RSR = (AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);
+
+ // Clear all status bits in the transmit status register
+ AT91C_BASE_EMAC->EMAC_TSR = ( AT91C_EMAC_UBR | AT91C_EMAC_COL | AT91C_EMAC_RLES
+ | AT91C_EMAC_BEX | AT91C_EMAC_COMP
+ | AT91C_EMAC_UND );
+
+ // Clear interrupts
+ AT91C_BASE_EMAC->EMAC_ISR;
+
+ // Enable the copy of data into the buffers
+ // ignore broadcasts, and don't copy FCS.
+ AT91C_BASE_EMAC->EMAC_NCFGR |= (AT91C_EMAC_DRFCS | AT91C_EMAC_PAE);
+
+ if( enableCAF == EMAC_CAF_ENABLE ) {
+ AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_CAF;
+ }
+ if( enableNBC == EMAC_NBC_ENABLE ) {
+ AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_NBC;
+ }
+
+ // Enable Rx and Tx, plus the stats register.
+ AT91C_BASE_EMAC->EMAC_NCR |= (AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT);
+
+ // Setup the interrupts for TX (and errors)
+ AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RXUBR
+ | AT91C_EMAC_TUNDR
+ | AT91C_EMAC_RLEX
+ | AT91C_EMAC_TXERR
+ | AT91C_EMAC_TCOMP
+ | AT91C_EMAC_ROVR
+ | AT91C_EMAC_HRESP
+ | AT91C_EMAC_PFRE
+ | AT91C_EMAC_PTZ
+ ;
+
+}
+
+//-----------------------------------------------------------------------------
+/// Reset TX & RX queue & statistics
+//-----------------------------------------------------------------------------
+void EMAC_Reset(void)
+{
+ EMAC_ResetRx();
+ EMAC_ResetTx();
+ memset((void*)&EmacStatistics, 0x00, sizeof(EmacStats));
+ AT91C_BASE_EMAC->EMAC_NCR |= (AT91C_EMAC_TE
+ | AT91C_EMAC_RE
+ | AT91C_EMAC_WESTAT
+ | AT91C_EMAC_CLRSTAT);
+
+}
+
+//-----------------------------------------------------------------------------
+/// Get the statstic information & reset it
+/// \param pStats Pointer to EmacStats structure to copy the informations
+/// \param reset Reset the statistics after copy it
+//-----------------------------------------------------------------------------
+void EMAC_GetStatistics(EmacStats *pStats, unsigned char reset)
+{
+ unsigned int ncrBackup = 0;
+
+ TRACE_DEBUG("EMAC_GetStatistics\n\r");
+
+ // Sanity check
+ if (pStats == (EmacStats *) 0) {
+ return;
+ }
+
+ ncrBackup = AT91C_BASE_EMAC->EMAC_NCR & (AT91C_EMAC_TE | AT91C_EMAC_RE);
+
+
+ // Copy the informations
+ memcpy(pStats, (void*)&EmacStatistics, sizeof(EmacStats));
+
+ // Reset the statistics
+ if (reset) {
+ memset((void*)&EmacStatistics, 0x00, sizeof(EmacStats));
+ AT91C_BASE_EMAC->EMAC_NCR = ncrBackup | AT91C_EMAC_CLRSTAT;
+ }
+}
+
+//-----------------------------------------------------------------------------
+/// Send a packet with EMAC.
+/// If the packet size is larger than transfer buffer size error returned.
+/// If packet transfer status is monitored, specify callback for each packet.
+/// \param buffer The buffer to be send
+/// \param size The size of buffer to be send
+/// \param fEMAC_TxCallback Threshold Wakeup callback
+/// \param fWakeUpCb TX Wakeup
+/// \return OK, Busy or invalid packet
+//-----------------------------------------------------------------------------
+unsigned char EMAC_Send(void *pBuffer,
+ unsigned int size,
+ EMAC_TxCallback fEMAC_TxCallback)
+{
+ volatile EmacTxTDescriptor *pTxTd;
+ volatile EMAC_TxCallback *pTxCb;
+
+ //TRACE_DEBUG("EMAC_Send\n\r");
+
+ // Check parameter
+ if (size > EMAC_TX_UNITSIZE) {
+
+ TRACE_ERROR("EMAC driver does not split send packets.");
+ TRACE_ERROR("%d bytes max in one packet (%d bytes requested)\n\r",
+ EMAC_TX_UNITSIZE, size);
+ return EMAC_TX_INVALID_PACKET;
+ }
+
+ // Pointers to the current TxTd
+ pTxTd = txTd.td + txTd.head;
+
+ // If no free TxTd, buffer can't be sent, schedule the wakeup callback
+ if( CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) == 0) {
+ if ((pTxTd->status & EMAC_TX_USED_BIT) != 0) {
+ //EMAC_ResetTx();
+ //TRACE_WARNING("Circ Full but FREE TD found\n\r");
+ //AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TE;
+ }
+ //else {
+ return EMAC_TX_BUFFER_BUSY;
+ //}
+ }
+
+ // Pointers to the current TxTd
+ pTxCb = txTd.txCb + txTd.head;
+
+ // Sanity check
+
+ // Setup/Copy data to transmition buffer
+ if (pBuffer && size) {
+ // Driver manage the ring buffer
+ memcpy((void *)pTxTd->addr, pBuffer, size);
+ }
+
+ // Tx Callback
+ *pTxCb = fEMAC_TxCallback;
+
+ // Update TD status
+ // The buffer size defined is length of ethernet frame
+ // so it's always the last buffer of the frame.
+ if (txTd.head == TX_BUFFERS-1) {
+ pTxTd->status =
+ (size & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT | EMAC_TX_WRAP_BIT;
+ }
+ else {
+ pTxTd->status = (size & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT;
+ }
+
+ CIRC_INC(txTd.head, TX_BUFFERS)
+
+ // Tx packets count
+ EmacStatistics.tx_packets++;
+
+ // Now start to transmit if it is not already done
+ AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;
+
+ return EMAC_TX_OK;
+}
+
+//-----------------------------------------------------------------------------
+/// Return current load of TX.
+//-----------------------------------------------------------------------------
+unsigned int EMAC_TxLoad(void)
+{
+ unsigned short head = txTd.head;
+ unsigned short tail = txTd.tail;
+ #if 1
+ return CIRC_CNT(head, tail, TX_BUFFERS);
+ #else
+ return (TX_BUFFERS - CIRC_SPACE(head, tail, TX_BUFFERS));
+ #endif
+}
+
+//-----------------------------------------------------------------------------
+/// Receive a packet with EMAC
+/// If not enough buffer for the packet, the remaining data is lost but right
+/// frame length is returned.
+/// \param pFrame Buffer to store the frame
+/// \param frameSize Size of the frame
+/// \param pRcvSize Received size
+/// \return OK, no data, or frame too small
+//-----------------------------------------------------------------------------
+unsigned char EMAC_Poll(unsigned char *pFrame,
+ unsigned int frameSize,
+ unsigned int *pRcvSize)
+{
+ unsigned short bufferLength;
+ unsigned int tmpFrameSize=0;
+ unsigned char *pTmpFrame=0;
+ unsigned int tmpIdx = rxTd.idx;
+ volatile EmacRxTDescriptor *pRxTd = rxTd.td + rxTd.idx;
+
+ ASSERT(pFrame, "F: EMAC_Poll\n\r");
+
+ char isFrame = 0;
+ // Set the default return value
+ *pRcvSize = 0;
+
+ // Process received RxTd
+ while ((pRxTd->addr & EMAC_RX_OWNERSHIP_BIT) == EMAC_RX_OWNERSHIP_BIT) {
+
+ // A start of frame has been received, discard previous fragments
+ if ((pRxTd->status & EMAC_RX_SOF_BIT) == EMAC_RX_SOF_BIT) {
+ // Skip previous fragment
+ while (tmpIdx != rxTd.idx) {
+ pRxTd = rxTd.td + rxTd.idx;
+ pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
+ CIRC_INC(rxTd.idx, RX_BUFFERS);
+ }
+ // Reset the temporary frame pointer
+ pTmpFrame = pFrame;
+ tmpFrameSize = 0;
+ // Start to gather buffers in a frame
+ isFrame = 1;
+ }
+
+ // Increment the pointer
+ CIRC_INC(tmpIdx, RX_BUFFERS);
+
+ // Copy data in the frame buffer
+ if (isFrame) {
+ if (tmpIdx == rxTd.idx) {
+ TRACE_INFO("no EOF (Invalid of buffers too small)\n\r");
+
+ do {
+
+ pRxTd = rxTd.td + rxTd.idx;
+ pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
+ CIRC_INC(rxTd.idx, RX_BUFFERS);
+ } while(tmpIdx != rxTd.idx);
+ return EMAC_RX_NO_DATA;
+ }
+ // Copy the buffer into the application frame
+ bufferLength = EMAC_RX_UNITSIZE;
+ if ((tmpFrameSize + bufferLength) > frameSize) {
+ bufferLength = frameSize - tmpFrameSize;
+ }
+
+ memcpy(pTmpFrame, (void*)(pRxTd->addr & EMAC_ADDRESS_MASK), bufferLength);
+ pTmpFrame += bufferLength;
+ tmpFrameSize += bufferLength;
+
+ // An end of frame has been received, return the data
+ if ((pRxTd->status & EMAC_RX_EOF_BIT) == EMAC_RX_EOF_BIT) {
+ // Frame size from the EMAC
+ *pRcvSize = (pRxTd->status & EMAC_LENGTH_FRAME);
+
+ // Application frame buffer is too small all data have not been copied
+ if (tmpFrameSize < *pRcvSize) {
+ printf("size req %d size allocated %d\n\r", *pRcvSize, frameSize);
+
+ return EMAC_RX_FRAME_SIZE_TOO_SMALL;
+ }
+
+ TRACE_DEBUG("packet %d-%d (%d)\n\r", rxTd.idx, tmpIdx, *pRcvSize);
+ // All data have been copied in the application frame buffer => release TD
+ while (rxTd.idx != tmpIdx) {
+ pRxTd = rxTd.td + rxTd.idx;
+ pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
+ CIRC_INC(rxTd.idx, RX_BUFFERS);
+ }
+ EmacStatistics.rx_packets++;
+ return EMAC_RX_OK;
+ }
+ }
+
+ // SOF has not been detected, skip the fragment
+ else {
+ pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
+ rxTd.idx = tmpIdx;
+ }
+
+ // Process the next buffer
+ pRxTd = rxTd.td + tmpIdx;
+ }
+
+ //TRACE_DEBUG("E");
+ return EMAC_RX_NO_DATA;
+}
+
+//-----------------------------------------------------------------------------
+/// Registers pRxCb callback. Callback will be invoked after the next received
+/// frame.
+/// When EMAC_Poll() returns EMAC_RX_NO_DATA the application task call EMAC_Set_RxCb()
+/// to register pRxCb() callback and enters suspend state. The callback is in charge
+/// to resume the task once a new frame has been received. The next time EMAC_Poll()
+/// is called, it will be successfull.
+/// \param pRxCb Pointer to callback function
+//-----------------------------------------------------------------------------
+void EMAC_Set_RxCb(EMAC_RxCallback pRxCb)
+{
+ rxTd.rxCb = pRxCb;
+ AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP;
+}
+
+//-----------------------------------------------------------------------------
+/// Remove the RX callback function.
+/// This function is usually invoked from the RX callback itself. Once the callback
+/// has resumed the application task, there is no need to invoke the callback again.
+//-----------------------------------------------------------------------------
+void EMAC_Clear_RxCb(void)
+{
+ AT91C_BASE_EMAC->EMAC_IDR = AT91C_EMAC_RCOMP;
+ rxTd.rxCb = (EMAC_RxCallback) 0;
+}
+
+//-----------------------------------------------------------------------------
+/// Registers TX wakeup callback callback. Callback will be invoked once several
+/// transfer descriptors are available.
+/// When EMAC_Send() returns EMAC_TX_BUFFER_BUSY (all TD busy) the application
+/// task calls EMAC_Set_TxWakeUpCb() to register pTxWakeUpCb() callback and
+/// enters suspend state. The callback is in charge to resume the task once
+/// several TD have been released. The next time EMAC_Send() will be called, it
+/// shall be successfull.
+/// \param pTxWakeUpCb Pointer to callback function
+/// \param threshold Minimum number of available transfer descriptors before pTxWakeUpCb() is invoked
+/// \return 0= success, 1 = threshold exceeds nuber of transfer descriptors
+//-----------------------------------------------------------------------------
+char EMAC_Set_TxWakeUpCb(EMAC_WakeupCallback pTxWakeUpCb, unsigned short threshold)
+{
+ if (threshold <= TX_BUFFERS) {
+ txTd.wakeupCb = pTxWakeUpCb;
+ txTd.wakeupThreshold = threshold;
+ return 0;
+ }
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+/// Remove the TX wakeup callback function.
+/// This function is usually invoked from the TX wakeup callback itself. Once the callback
+/// has resumed the application task, there is no need to invoke the callback again.
+//-----------------------------------------------------------------------------
+void EMAC_Clear_TxWakeUpCb(void)
+{
+ txTd.wakeupCb = (EMAC_WakeupCallback) 0;
+}
+
+
diff --git a/peripherals/emac/emac.dir b/peripherals/emac/emac.dir new file mode 100644 index 0000000..2facd09 --- /dev/null +++ b/peripherals/emac/emac.dir @@ -0,0 +1,49 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !Purpose
+///
+/// Definition of methods and structures for using EMAC
+///
+/// !Usage
+///
+/// -# Initialize EMAC with EMAC_Init with MAC address.
+/// -# Initialize the PHY driver
+/// -# Get a packet from network
+/// -# Interrupt mode: EMAC_Set_RxCb to register a function to process the frame packet
+/// -# Polling mode: EMAC_Poll for a data packet from network
+/// -# Send a packet to network with EMAC_Send.
+///
+//-----------------------------------------------------------------------------
+///
+///
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/emac/emac.h b/peripherals/emac/emac.h new file mode 100644 index 0000000..f7484cd --- /dev/null +++ b/peripherals/emac/emac.h @@ -0,0 +1,178 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+// peripherals/emac/emac.h
+
+#ifndef EMAC_H
+#define EMAC_H
+
+//-----------------------------------------------------------------------------
+/// \dir
+/// !Purpose
+///
+/// Definition of methods and structures for using EMAC
+///
+/// !Usage
+///
+/// -# Initialize EMAC with EMAC_Init with MAC address.
+/// -# Then the caller application need to initialize the PHY driver before further calling EMAC
+/// driver.
+/// -# Get a packet from network
+/// -# Interrupt mode: EMAC_Set_RxCb to register a function to process the frame packet
+/// -# Polling mode: EMAC_Poll for a data packet from network
+/// -# Send a packet to network with EMAC_Send.
+///
+/// Please refer to the list of functions in the #Overview# tab of this unit
+/// for more detailed information.
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Headers
+//-----------------------------------------------------------------------------
+#include <board.h>
+
+//-----------------------------------------------------------------------------
+// Definitions
+//-----------------------------------------------------------------------------
+
+/// Board EMAC base address
+#if !defined(AT91C_BASE_EMAC)
+ #if defined(AT91C_BASE_MACB)
+ #define AT91C_BASE_EMAC AT91C_BASE_MACB
+ #elif defined(AT91C_BASE_EMACB)
+ #define AT91C_BASE_EMAC AT91C_BASE_EMACB
+ #else
+ #error
+ #endif
+#endif
+
+/// Number of buffer for RX, be carreful: MUST be 2^n
+#define RX_BUFFERS 16
+/// Number of buffer for TX, be carreful: MUST be 2^n
+#define TX_BUFFERS 8
+
+/// Buffer Size
+#define EMAC_RX_UNITSIZE 128 /// Fixed size for RX buffer
+#define EMAC_TX_UNITSIZE 1518 /// Size for ETH frame length
+
+// The MAC can support frame lengths up to 1536 bytes.
+#define EMAC_FRAME_LENTGH_MAX 1536
+
+
+//-----------------------------------------------------------------------------
+// Types
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+/// Describes the statistics of the EMAC.
+//-----------------------------------------------------------------------------
+typedef struct _EmacStats {
+
+ // TX errors
+ unsigned int tx_packets; /// Total Number of packets sent
+ unsigned int tx_comp; /// Packet complete
+ unsigned int tx_errors; /// TX errors ( Retry Limit Exceed )
+ unsigned int collisions; /// Collision
+ unsigned int tx_exausts; /// Buffer exhausted
+ unsigned int tx_underruns; /// Under Run, not able to read from memory
+ // RX errors
+ unsigned int rx_packets; /// Total Number of packets RX
+ unsigned int rx_eof; /// No EOF error
+ unsigned int rx_ovrs; /// Over Run, not able to store to memory
+ unsigned int rx_bnas; /// Buffer is not available
+
+} EmacStats, *PEmacStats;
+
+//-----------------------------------------------------------------------------
+// PHY Exported functions
+//-----------------------------------------------------------------------------
+extern unsigned char EMAC_SetMdcClock( unsigned int mck );
+
+extern void EMAC_EnableMdio( void );
+
+extern void EMAC_DisableMdio( void );
+
+extern void EMAC_EnableMII( void );
+
+extern void EMAC_EnableRMII( void );
+
+extern unsigned char EMAC_ReadPhy(unsigned char PhyAddress,
+ unsigned char Address,
+ unsigned int *pValue,
+ unsigned int retry);
+
+extern unsigned char EMAC_WritePhy(unsigned char PhyAddress,
+ unsigned char Address,
+ unsigned int Value,
+ unsigned int retry);
+
+extern void EMAC_SetLinkSpeed(unsigned char speed,
+ unsigned char fullduplex);
+
+//-----------------------------------------------------------------------------
+// EMAC Exported functions
+//-----------------------------------------------------------------------------
+/// Callback used by send function
+typedef void (*EMAC_TxCallback)(unsigned int status);
+typedef void (*EMAC_RxCallback)(unsigned int status);
+typedef void (*EMAC_WakeupCallback)(void);
+
+extern void EMAC_Init( unsigned char id, const unsigned char *pMacAddress,
+ unsigned char enableCAF, unsigned char enableNBC );
+#define EMAC_CAF_DISABLE 0
+#define EMAC_CAF_ENABLE 1
+#define EMAC_NBC_DISABLE 0
+#define EMAC_NBC_ENABLE 1
+
+extern void EMAC_Handler(void);
+
+extern void EMAC_Reset(void);
+
+extern unsigned char EMAC_Send(void *pBuffer,
+ unsigned int size,
+ EMAC_TxCallback fEMAC_TxCallback);
+/// Return for EMAC_Send function
+#define EMAC_TX_OK 0
+#define EMAC_TX_BUFFER_BUSY 1
+#define EMAC_TX_INVALID_PACKET 2
+
+
+extern unsigned char EMAC_Poll(unsigned char *pFrame,
+ unsigned int frameSize,
+ unsigned int *pRcvSize);
+/// Return for EMAC_Poll function
+#define EMAC_RX_OK 0
+#define EMAC_RX_NO_DATA 1
+#define EMAC_RX_FRAME_SIZE_TOO_SMALL 2
+
+extern void EMAC_GetStatistics(EmacStats *pStats, unsigned char reset);
+
+#endif // #ifndef EMAC_H
+
diff --git a/peripherals/hsmc4/hsmc.dir b/peripherals/hsmc4/hsmc.dir new file mode 100644 index 0000000..9ec8bb4 --- /dev/null +++ b/peripherals/hsmc4/hsmc.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the peripheral Static Memory Controller (HSMC4).
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/hsmc4/hsmc4.c b/peripherals/hsmc4/hsmc4.c new file mode 100644 index 0000000..350da99 --- /dev/null +++ b/peripherals/hsmc4/hsmc4.c @@ -0,0 +1,247 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "hsmc4.h"
+
+//------------------------------------------------------------------------------
+// Local variables
+//------------------------------------------------------------------------------
+/// Store value of current read only HSMC4_CTRL register.
+static unsigned int hsmc4Ctrl;
+
+//------------------------------------------------------------------------------
+// Internal functions
+//------------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+/// Returns 1 if the host main controller has terminated the command.
+/// read mode.
+/// otherwise returns 0.
+//-----------------------------------------------------------------------------
+unsigned char HSMC4_CommandDone(void)
+{
+ return ((AT91C_BASE_HSMC4->HSMC4_SR & AT91C_HSMC4_CMDDONE) == AT91C_HSMC4_CMDDONE);
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// Sets the mode of the HSMC4 to one of the following values:
+/// - AT91C_HSMC4_PAGESIZE
+/// - AT91C_HSMC4_WSPARE
+/// - AT91C_HSMC4_RSPARE
+/// - AT91C_HSMC4_EDGECTRL
+/// - AT91C_HSMC4_RBEDGE
+/// - AT91C_HSMC4_DTOCYC
+/// - AT91C_HSMC4_DTOMUL
+/// \param mode mode.
+//------------------------------------------------------------------------------
+void HSMC4_SetMode(unsigned int mode)
+{
+ AT91C_BASE_HSMC4->HSMC4_CFG = mode;
+}
+
+//-----------------------------------------------------------------------------
+/// Reset the HSMC4 Nand flash controll host.
+//-----------------------------------------------------------------------------
+void HSMC4_ResetNfc(void)
+{
+ //Disable all the HSMC4 interrupts
+ AT91C_BASE_HSMC4 -> HSMC4_IDR = 0xFFFFFFFF;
+ AT91C_BASE_HSMC4 -> HSMC4_CTRL = 0;
+ hsmc4Ctrl = 0;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable NAND flsah controller host through the APB interface.
+//-----------------------------------------------------------------------------
+void HSMC4_EnableNfc(void)
+{
+ hsmc4Ctrl |= AT91C_HSMC4_NFCEN;
+ AT91C_BASE_HSMC4->HSMC4_CTRL = hsmc4Ctrl;
+}
+
+//-----------------------------------------------------------------------------
+/// Acticated and perform a data transfer between the Host and a Nand Flash.
+//-----------------------------------------------------------------------------
+void HSMC4_EnableNfcHost(void)
+{
+ hsmc4Ctrl |= AT91C_HSMC4_HOSTEN;
+ AT91C_BASE_HSMC4->HSMC4_CTRL = hsmc4Ctrl;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable host transfer data from the internal SRAM to the memory device.
+//-----------------------------------------------------------------------------
+void HSMC4_EnableHostTransfer(void)
+{
+ hsmc4Ctrl |= AT91C_HSMC4_HOSTWR;
+ // The HOSTWR field can be modified if the host controller is not busy.
+ while((AT91C_BASE_HSMC4->HSMC4_SR & AT91C_HSMC4_HOSTBUSY) == AT91C_HSMC4_HOSTBUSY);
+ AT91C_BASE_HSMC4->HSMC4_CTRL = hsmc4Ctrl;
+ while((AT91C_BASE_HSMC4->HSMC4_SR & AT91C_HSMC4_HOSTBUSY) == AT91C_HSMC4_HOSTBUSY);
+}
+
+//-----------------------------------------------------------------------------
+/// Enables the host main controller reads both main and spare area in read mode.
+//-----------------------------------------------------------------------------
+void HSMC4_EnableSpareRead(void)
+{
+ AT91C_BASE_HSMC4->HSMC4_CFG |= AT91C_HSMC4_RSPARE;
+}
+
+//-----------------------------------------------------------------------------
+/// The host main controller skips spare area in read mode.
+//-----------------------------------------------------------------------------
+void HSMC4_DisableSpareRead(void)
+{
+ AT91C_BASE_HSMC4->HSMC4_CFG &= 0xFFFFFDFF;
+}
+
+//-----------------------------------------------------------------------------
+/// Enables the host main controller writes both main and spare area in write
+/// mode.
+//-----------------------------------------------------------------------------
+void HSMC4_EnableSpareWrite(void)
+{
+ AT91C_BASE_HSMC4->HSMC4_CFG |= AT91C_HSMC4_WSPARE;
+}
+
+//-----------------------------------------------------------------------------
+/// The host main controller skips spare area in write mode.
+//-----------------------------------------------------------------------------
+void HSMC4_DisableSpareWrite(void)
+{
+ AT91C_BASE_HSMC4->HSMC4_CFG &= 0xFFFFFEFF;
+}
+
+//-----------------------------------------------------------------------------
+/// Returns 1 if the host main controller reads both main and spare area in
+/// read mode.
+/// otherwise returns 0.
+//-----------------------------------------------------------------------------
+unsigned char HSMC4_isSpareRead(void)
+{
+ return (((AT91C_BASE_HSMC4->HSMC4_CFG) >> 9) & 0x1);
+}
+
+//-----------------------------------------------------------------------------
+/// Returns 1 if the host main controller writes both main and spare area in
+/// write mode.
+/// otherwise returns 0.
+//-----------------------------------------------------------------------------
+unsigned char HSMC4_isSpareWrite(void)
+{
+ return (((AT91C_BASE_HSMC4->HSMC4_CFG) >> 8) & 0x1);
+}
+
+
+//-----------------------------------------------------------------------------
+/// Returns 1 if the host main controller has terminated the data transmission.
+/// otherwise returns 0.
+//-----------------------------------------------------------------------------
+unsigned char HSMC4_TransferComplete(void)
+{
+ return ((AT91C_BASE_HSMC4->HSMC4_SR & AT91C_HSMC4_XFRDONE) == AT91C_HSMC4_XFRDONE);
+}
+
+//-----------------------------------------------------------------------------
+/// Returns 1 if edge has been detected on the Ready/Busy line.
+/// otherwise returns 0.
+//-----------------------------------------------------------------------------
+unsigned char HSMC4_isReadyBusy(void)
+{
+ return ((AT91C_BASE_HSMC4->HSMC4_SR & AT91C_HSMC4_RBEDGE0) == AT91C_HSMC4_RBEDGE0);
+}
+
+//-----------------------------------------------------------------------------
+/// Returns 1 if the Controller is activated and accesses the memory device.
+/// otherwise returns 0.
+//-----------------------------------------------------------------------------
+unsigned char HSMC4_isNfcBusy(void)
+{
+ return ((AT91C_BASE_HSMC4->HSMC4_SR & AT91C_HSMC4_HOSTBUSY) == AT91C_HSMC4_HOSTBUSY);
+}
+
+//-----------------------------------------------------------------------------
+/// Returns 1 if the ecc is ready
+/// otherwise returns 0.
+//-----------------------------------------------------------------------------
+unsigned char HSMC4_isEccReady(void)
+{
+ return ((AT91C_BASE_HSMC4->HSMC4_SR & AT91C_HSMC4_ECCRDY) == AT91C_HSMC4_ECCRDY);
+}
+
+//-----------------------------------------------------------------------------
+/// Returns the current status register of the HSMC4 peripheral. This
+/// resets the internal value of the status register, so further read may yield
+/// different values.
+//-----------------------------------------------------------------------------
+unsigned int HSMC4_GetStatus(void)
+{
+ return AT91C_BASE_HSMC4->HSMC4_SR;
+}
+
+//------------------------------------------------------------------------------
+// HOST command functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the host controller is busy.
+/// otherwise returns 0.
+//------------------------------------------------------------------------------
+unsigned char HSMC4_isHostBusy(void)
+{
+ return (((*((volatile unsigned int *) (CMD_BASE_ADDR + AT91C_HSMC4_HOSTCMD))) & 0x8000000) == 0x8000000);
+}
+
+//------------------------------------------------------------------------------
+/// Uses the HOST nandflash conntroller to send a command to the NFC
+/// \param cmd command to send.
+/// \param addressCycle address cycle when command access id decoded.
+/// \param cycle0 address at first cycle.
+//------------------------------------------------------------------------------
+void HSMC4_SendCommand (unsigned int cmd, unsigned int addressCycle, unsigned int cycle0)
+{
+ volatile unsigned int *pCommandAddress;
+ // Wait until host controller is not busy.
+ while(HSMC4_isHostBusy());
+ // Send the command plus the ADDR_CYCLE
+ pCommandAddress = (volatile unsigned int *) (cmd + CMD_BASE_ADDR);
+ AT91C_BASE_HSMC4->HSMC4_ADDR = cycle0;
+ *pCommandAddress = addressCycle;
+ while( !HSMC4_CommandDone());
+}
+
+
diff --git a/peripherals/hsmc4/hsmc4.h b/peripherals/hsmc4/hsmc4.h new file mode 100644 index 0000000..47e19bb --- /dev/null +++ b/peripherals/hsmc4/hsmc4.h @@ -0,0 +1,73 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef HSMC4_H
+#define HSMC4_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+#define NFC_SRAM_BASE_ADDRESS 0x20100000
+
+#ifndef BOARD_NF_COMMAND_ADDR
+ #define CMD_BASE_ADDR 0x60000000
+#else
+ #define CMD_BASE_ADDR BOARD_NF_COMMAND_ADDR
+#endif
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+extern void HSMC4_SendCommand (unsigned int cmd, unsigned int addressCycle, unsigned int cycle0);
+extern unsigned char HSMC4_isHostBusy(void);
+extern unsigned char HSMC4_TransferComplete(void);
+extern unsigned char HSMC4_isReadyBusy(void);
+extern unsigned char HSMC4_isNfcBusy(void);
+extern unsigned char HSMC4_isEccReady(void);
+extern void HSMC4_SetMode(unsigned int mode);
+extern void HSMC4_ResetNfc(void);
+extern void HSMC4_EnableNfc(void);
+extern void HSMC4_EnableNfcHost(void);
+
+extern void HSMC4_EnableSpareRead(void);
+extern void HSMC4_DisableSpareRead(void);
+extern void HSMC4_EnableSpareWrite(void);
+extern void HSMC4_DisableSpareWrite(void);
+extern unsigned char HSMC4_isSpareRead(void);
+extern unsigned char HSMC4_isSpareWrite(void);
+extern unsigned int HSMC4_GetStatus(void);
+
+#endif //#ifndef HSMC4_H
+
diff --git a/peripherals/hsmc4/hsmc4_ecc.c b/peripherals/hsmc4/hsmc4_ecc.c new file mode 100644 index 0000000..e27655f --- /dev/null +++ b/peripherals/hsmc4/hsmc4_ecc.c @@ -0,0 +1,703 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+#include "hsmc4.h"
+#include "hsmc4_ecc.h"
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Internal function
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// Counts and return the number of bits set to '1' in the given byte.
+/// \param byte Byte to count.
+//------------------------------------------------------------------------------
+static unsigned char CountBitsInByte(unsigned char byte)
+{
+ unsigned char count = 0;
+ while (byte > 0) {
+
+ if (byte & 1) {
+
+ count++;
+ }
+ byte >>= 1;
+ }
+
+ return count;
+}
+//------------------------------------------------------------------------------
+/// Counts and return the number of bits set to '1' in the given hsiao code.
+/// \param code Hsizo code.
+//------------------------------------------------------------------------------
+static unsigned char CountBitsInCode(unsigned char *code)
+{
+ return CountBitsInByte(code[0])
+ + CountBitsInByte(code[1])
+ + CountBitsInByte(code[2]);
+}
+
+//------------------------------------------------------------------------------
+/// Get all ECC parity and Nparity value.
+//------------------------------------------------------------------------------
+void HSMC4_EccGetValue(unsigned int *ecc)
+{
+ ecc[0] = AT91C_BASE_HSMC4->HSMC4_ECCPR0;
+ ecc[1] = AT91C_BASE_HSMC4->HSMC4_ECCPR1;
+ ecc[2] = AT91C_BASE_HSMC4->HSMC4_ECCPR2;
+ ecc[3] = AT91C_BASE_HSMC4->HSMC4_ECCPR3;
+ ecc[4] = AT91C_BASE_HSMC4->HSMC4_ECCPR4;
+ ecc[5] = AT91C_BASE_HSMC4->HSMC4_ECCPR5;
+ ecc[6] = AT91C_BASE_HSMC4->HSMC4_ECCPR6;
+ ecc[7] = AT91C_BASE_HSMC4->HSMC4_ECCPR7;
+ ecc[8] = AT91C_BASE_HSMC4->HSMC4_ECCPR8;
+ ecc[9] = AT91C_BASE_HSMC4->HSMC4_ECCPR9;
+ ecc[10] = AT91C_BASE_HSMC4->HSMC4_ECCPR10;
+ ecc[11] = AT91C_BASE_HSMC4->HSMC4_ECCPR11;
+ ecc[12] = AT91C_BASE_HSMC4->HSMC4_ECCPR12;
+ ecc[13] = AT91C_BASE_HSMC4->HSMC4_ECCPR13;
+ ecc[14] = AT91C_BASE_HSMC4->HSMC4_ECCPR14;
+ ecc[15] = AT91C_BASE_HSMC4->HSMC4_Eccpr15;
+#ifdef DUMP_ECC_PARITY
+ TRACE_INFO("Ecc parity(0-7) %x, %x, %x, %x, %x, %x, %x, %x \n\r",ecc[0],ecc[1],ecc[2],ecc[3],ecc[4],ecc[5],ecc[6],ecc[7]);
+ TRACE_INFO("Ecc parity(8-15) %x, %x, %x, %x, %x, %x, %x, %x \n\r",ecc[8],ecc[9],ecc[10],ecc[11],ecc[12],ecc[13],ecc[14],ecc[15]);
+#endif
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// Configures ECC mode in HSMC4 peripheral as specified.
+/// \param type Type of correction.
+/// \param pageSize Page size of NAND flash device.
+//------------------------------------------------------------------------------
+void HSMC4_EccConfigure(unsigned int type, unsigned int pageSize)
+{
+ // Software Reset ECC.
+ AT91C_BASE_HSMC4->HSMC4_ECCCR = (0x1 << 1) ;
+ AT91C_BASE_HSMC4->HSMC4_ECCCMD = type | pageSize;
+}
+
+//------------------------------------------------------------------------------
+/// Returns type of ECC correction setting.
+//------------------------------------------------------------------------------
+unsigned int HSMC4_GetEccCorrectoinType(void)
+{
+ return ((AT91C_BASE_HSMC4->HSMC4_ECCCMD)& AT91C_ECC_TYPCORRECT);
+}
+
+//------------------------------------------------------------------------------
+/// Returns ECC status by giving ecc number
+/// \param eccNumber ecc parity number from 0 to 15.
+//------------------------------------------------------------------------------
+unsigned char HSMC4_GetEccStatus(unsigned char eccNumber)
+{
+ unsigned int status;
+ if (eccNumber < 8){
+ status = AT91C_BASE_HSMC4->HSMC4_ECCSR1;
+ }
+ else {
+ status = AT91C_BASE_HSMC4->HSMC4_ECCSR2;
+ eccNumber -=8;
+ }
+ return ((status >> (eccNumber * 4)) & 0x07);
+}
+//------------------------------------------------------------------------------
+/// Verifies 4-bytes hsiao codes for a data block whose size is a page Size
+/// word. Page words block is verified between the given HSIAO code
+/// generated by hardware and original HSIAO codes store has been previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+//------------------------------------------------------------------------------
+static unsigned char HSMC4_VerifyPageOf8bitHsiao(
+ unsigned char *data,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode)
+{
+ unsigned char correctionCode[4];
+ unsigned char bitCount;
+ // Xor both codes together
+ correctionCode[0] = verifyCode[0] ^ originalCode[0];
+ correctionCode[1] = verifyCode[1] ^ originalCode[1];
+ correctionCode[2] = verifyCode[2] ^ originalCode[2];
+ correctionCode[3] = verifyCode[3] ^ originalCode[3];
+ TRACE_DEBUG("Correction code = %02X %02X %02X %02X\n\r",
+ correctionCode[0], correctionCode[1], correctionCode[2], correctionCode[3]);
+ // If all bytes are 0, there is no error
+ if ((correctionCode[0] == 0)
+ && (correctionCode[1] == 0)
+ && (correctionCode[2] == 0)
+ && (correctionCode[3] == 0)) {
+
+ return 0;
+ }
+ // If there is a single bit error, there are 15 bits set to 1
+ bitCount = CountBitsInByte(correctionCode[0]) +
+ CountBitsInByte(correctionCode[1]) +
+ CountBitsInByte(correctionCode[2]) +
+ CountBitsInByte(correctionCode[3]);
+ if (bitCount == 15) {
+ // Get byte and bit indexes
+ unsigned short byte = (correctionCode[0] & 0xf0) >> 4;
+ byte |= (correctionCode[1] & 0xff) << 4;
+ unsigned char bit = correctionCode[0] & 0x0f;
+ // Correct bit
+ TRACE_INFO("Correcting byte #%d at bit %d\n\r", byte, bit);
+ data[byte] ^= (1 << bit);
+
+ return Hsiao_ERROR_SINGLEBIT;
+ }
+
+ // Check if ECC has been corrupted
+ if (bitCount == 1) {
+ return Hsiao_ERROR_ECC;
+ }
+ // Otherwise, this is a multi-bit error
+ else {
+ return Hsiao_ERROR_MULTIPLEBITS;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Verifies 3-bytes hsiao codes for a data block whose size is multiple of
+/// 256 bytes. Each 256-bytes block is verified between the given HSIAO code
+/// generated by hardware and original HSIAO codes store has been previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param size Size of the data in words.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+//------------------------------------------------------------------------------
+static unsigned char HSMC4_Verify256x8bitHsiao(
+ unsigned char *data,
+ unsigned int size,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode)
+{
+ unsigned char correctionCode[3];
+ unsigned int position = 0;
+ unsigned char byte;
+ unsigned char bit;
+ unsigned char error = 0;
+
+ TRACE_DEBUG("HSMC4_Verify512x8bitHsiao()\n\r");
+ while (position < size) {
+ // Xor both codes together
+ correctionCode[0] = verifyCode[0] ^ originalCode[0];
+ correctionCode[1] = verifyCode[1] ^ originalCode[1];
+ correctionCode[2] = verifyCode[2] ^ originalCode[2];
+ TRACE_DEBUG("Correction code = %02X %02X %02X\n\r",
+ correctionCode[0], correctionCode[1], correctionCode[2]);
+
+ // If all bytes are 0, there is no error
+ if ( correctionCode[0] || correctionCode[1] || correctionCode[2]) {
+ // If there is a single bit error, there are 11 bits set to 1
+ if (CountBitsInCode(correctionCode) == 11) {
+ // Get byte and bit indexes
+ byte = (correctionCode[0] & 0xf8) >> 3;
+ byte |= (correctionCode[1] & 0x07) << 5;
+ bit = correctionCode[0] & 0x07;
+ // Correct bit
+ TRACE_INFO("Correcting byte #%d at bit %d\n\r", (position + byte), bit);
+ data[byte] ^= (1 << bit);
+ error = Hsiao_ERROR_SINGLEBIT;
+ }
+ // Check if ECC has been corrupted
+ else if (CountBitsInCode(correctionCode) == 1) {
+ return Hsiao_ERROR_ECC;
+ }
+ else {
+ // Otherwise, this is a multi-bit error
+ return Hsiao_ERROR_MULTIPLEBITS;
+ }
+ }
+ data += 256;
+ originalCode += 3;
+ verifyCode += 3;
+ position += 256;
+ }
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Verifies 3-bytes hsiao codes for a data block whose size is multiple of
+/// 512 bytes. Each 512-bytes block is verified between the given HSIAO code
+/// generated by hardware and original HSIAO codes store has been previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param size Size of the data in words.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+//------------------------------------------------------------------------------
+static unsigned char HSMC4_Verify512x8bitHsiao(
+ unsigned char *data,
+ unsigned int size,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode)
+{
+ unsigned char correctionCode[3];
+ unsigned int position = 0;
+ unsigned short byte;
+ unsigned char bit;
+ unsigned char error = 0;
+
+ TRACE_DEBUG("HSMC4_Verify512x8bitHsiao()\n\r");
+ while (position < size) {
+ // Xor both codes together
+ correctionCode[0] = verifyCode[0] ^ originalCode[0];
+ correctionCode[1] = verifyCode[1] ^ originalCode[1];
+ correctionCode[2] = verifyCode[2] ^ originalCode[2];
+ TRACE_DEBUG("Correction code = %02X %02X %02X\n\r",
+ correctionCode[0], correctionCode[1], correctionCode[2]);
+
+ // If all bytes are 0, there is no error
+ if ( correctionCode[0] || correctionCode[1] || correctionCode[2]) {
+ // If there is a single bit error, there are 11 bits set to 1
+ if (CountBitsInCode(correctionCode) == 12) {
+ // Get byte and bit indexes
+ byte = (correctionCode[0] & 0xf8) >> 3;
+ byte |= (correctionCode[1] & 0x0f) << 5;
+ bit = correctionCode[0] & 0x07;
+ // Correct bit
+ TRACE_INFO("Correcting byte #%d at bit %d\n\r", (position + byte), bit);
+ data[byte] ^= (1 << bit);
+ error = Hsiao_ERROR_SINGLEBIT;
+ }
+ // Check if ECC has been corrupted
+ else if (CountBitsInCode(correctionCode) == 1) {
+ return Hsiao_ERROR_ECC;
+ }
+ else {
+ // Otherwise, this is a multi-bit error
+ return Hsiao_ERROR_MULTIPLEBITS;
+ }
+ }
+ data += 512;
+ originalCode += 3;
+ verifyCode += 3;
+ position += 512;
+ }
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Verifies 4-bytes hsiao codes for a data block whose size is a page Size
+/// word. Page words block is verified between the given HSIAO code
+/// generated by hardware and original HSIAO codes store has been previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+//------------------------------------------------------------------------------
+static unsigned char HSMC4_VerifyPageOf16bitHsiao(
+ unsigned short *data,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode)
+{
+ unsigned char correctionCode[4];
+ unsigned char bitCount;
+ // Xor both codes together
+ correctionCode[0] = verifyCode[0] ^ originalCode[0];
+ correctionCode[1] = verifyCode[1] ^ originalCode[1];
+ correctionCode[2] = verifyCode[2] ^ originalCode[2];
+ correctionCode[3] = verifyCode[3] ^ originalCode[3];
+ TRACE_DEBUG("Correction code = %02X %02X %02X %02X\n\r",
+ correctionCode[0], correctionCode[1], correctionCode[2], correctionCode[3]);
+ // If all bytes are 0, there is no error
+ if ((correctionCode[0] == 0)
+ && (correctionCode[1] == 0)
+ && (correctionCode[2] == 0)
+ && (correctionCode[3] == 0)) {
+
+ return 0;
+ }
+ // If there is a single bit error, there are 11 bits set to 1
+ bitCount = CountBitsInByte(correctionCode[0]) +
+ CountBitsInByte(correctionCode[1]) +
+ CountBitsInByte(correctionCode[2]) +
+ CountBitsInByte(correctionCode[3]);
+ printf("bitCount = %d \n\r",bitCount);
+ if (bitCount == 12) {
+ // Get byte and bit indexes
+ unsigned char word = (correctionCode[0] & 0xf0) >> 4;
+ word |= (correctionCode[1] & 0xff) << 4;
+ unsigned char bit = correctionCode[0] & 0x0f;
+ // Correct bit
+ TRACE_INFO("Correcting word #%d at bit %d\n\r", word, bit);
+ data[word] ^= (1 << bit);
+
+ return Hsiao_ERROR_SINGLEBIT;
+ }
+
+ // Check if ECC has been corrupted
+ if (bitCount == 1) {
+ return Hsiao_ERROR_ECC;
+ }
+ // Otherwise, this is a multi-bit error
+ else {
+ return Hsiao_ERROR_MULTIPLEBITS;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Verifies 3-bytes hsiao codes for a data block whose size is multiple of
+/// 256 word.Each 256-words block is verified between the given HSIAO code
+/// generated by hardware and original HSIAO codes store has been previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param size Size of the data in words.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+//------------------------------------------------------------------------------
+static unsigned char HSMC4_Verify256x16bitHsiao(
+ unsigned short *data,
+ unsigned int size,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode
+ )
+{
+ unsigned char correctionCode[3];
+ unsigned int position = 0;
+ unsigned char word;
+ unsigned char bit;
+ unsigned char error = 0;
+
+ TRACE_DEBUG("HSMC4_Verify512x8bitHsiao()\n\r");
+ while (position < size) {
+ // Xor both codes together
+ correctionCode[0] = verifyCode[0] ^ originalCode[0];
+ correctionCode[1] = verifyCode[1] ^ originalCode[1];
+ correctionCode[2] = verifyCode[2] ^ originalCode[2];
+ TRACE_DEBUG("Correction code = %02X %02X %02X\n\r",
+ correctionCode[0], correctionCode[1], correctionCode[2]);
+
+ // If all bytes are 0, there is no error
+ if ( correctionCode[0] || correctionCode[1] || correctionCode[2]) {
+ // If there is a single bit error, there are 11 bits set to 1
+ if (CountBitsInCode(correctionCode) == 12) {
+ // Get word and bit indexes
+ word = (correctionCode[0] & 0xf0) >> 4;
+ word |= (correctionCode[1] & 0x0f) << 4;
+ bit = correctionCode[0] & 0x0f;
+ // Correct bit
+ TRACE_INFO("Correcting word #%d at bit %d\n\r", (position + word), bit);
+ data[word] ^= (1 << bit);
+ error = Hsiao_ERROR_SINGLEBIT;
+ }
+ // Check if ECC has been corrupted
+ else if (CountBitsInCode(correctionCode) == 1) {
+ return Hsiao_ERROR_ECC;
+ }
+ else {
+ // Otherwise, this is a multi-bit error
+ return Hsiao_ERROR_MULTIPLEBITS;
+ }
+ }
+ data += 256;
+ originalCode += 3;
+ verifyCode += 3;
+ position += 256;
+ }
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Verifies hsiao codes for a data block. The block is verified between the given
+/// HSIAO code generated by hardware and original HSIAO codes store has been
+/// previously stored.
+/// Returns 0 if the data is correct, Hsiao_ERROR_SINGLEBIT if one or more
+/// block(s) have had a single bit corrected, or either Hsiao_ERROR_ECC
+/// or Hsiao_ERROR_MULTIPLEBITS.
+/// \param data Data buffer to verify.
+/// \param size Size of the data in words.
+/// \param originalCode Original codes.
+/// \param verifyCode codes to be verified.
+/// \param dataPath 8bit/16bit data path.
+//------------------------------------------------------------------------------
+unsigned char HSMC4_VerifyHsiao(
+ unsigned char *data,
+ unsigned int size,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode,
+ unsigned char dataPath)
+{
+ unsigned char correctionType;
+ unsigned char error = 0;
+ correctionType = HSMC4_GetEccCorrectoinType();
+ // For 16-bit data path
+ if (dataPath == 16) {
+ switch (correctionType){
+ case AT91C_ECC_TYPCORRECT_ONE_PER_PAGE:
+ error = HSMC4_VerifyPageOf16bitHsiao((unsigned short*)data, originalCode, verifyCode);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES:
+ error= HSMC4_Verify256x16bitHsiao((unsigned short*)data, size / 2, originalCode, verifyCode);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_512_BYTES:
+ TRACE_WARNING("16-bit 512 per page correction not yet implement! \n\r");
+ break;
+ }
+ }
+ // For 8-bit data path
+ else {
+ switch (correctionType){
+ case AT91C_ECC_TYPCORRECT_ONE_PER_PAGE:
+ error = HSMC4_VerifyPageOf8bitHsiao(data, originalCode, verifyCode);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES:
+ error = HSMC4_Verify256x8bitHsiao(data, size, originalCode, verifyCode);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_512_BYTES:
+ error = HSMC4_Verify512x8bitHsiao(data, size, originalCode, verifyCode);
+ break;
+ }
+ }
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Get 32-bit ECC code for 16-bit data path NAND flash.
+/// 32-bit ECC is generated in order to perform one bit correction
+/// for a page in page 512/1024/2048/4096 for 16-bit words
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+//------------------------------------------------------------------------------
+void HSMC4_Get24bitPerPageEcc(unsigned int pageDataSize, unsigned char *code)
+{
+ unsigned int eccParity;
+ unsigned int eccNparity;
+ unsigned int ecc[16];
+ // Get Parity value.
+ HSMC4_EccGetValue(ecc);
+
+ // ---- P16384'P8192'P4096'P2048' P1024'P512'P256' --- 4th. Ecc Byte to store
+ /// P128' P64' P32' P16' P8' P4' P2' P1' --- 3rd. Ecc Byte to store
+ // ---- P16384 P8192 P4096 P2048 P1024 P512 P256 --- 2nd. Ecc Byte to store
+ // P128 P64 P32 P16 P8 P4 P2 P1 --- 1st. Ecc Byte to store
+
+ // Invert codes (linux compatibility)
+ eccParity = ~(ecc[0]);
+ eccNparity = ~(ecc[1]);
+ TRACE_DEBUG("ecc Parity is 0x%08x, ecc Nparity is 0x%08x \n\r", eccParity, eccNparity);
+ code[0] = eccParity & 0xff;
+ code[1] = (eccParity >> 8 )& 0xff;
+ code[2] = eccNparity & 0xff;
+ code[3] = (eccNparity >> 8 )& 0xff;
+}
+
+//------------------------------------------------------------------------------
+/// Get 24-bit ECC code for 8-bit data path NAND flash.
+/// 24-bit ECC is generated in order to perform one bit correction
+/// for 256 byte in page 512/1024/2048/4096 for 8-bit words
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+//------------------------------------------------------------------------------
+void HSMC4_Get24bitPer256Ecc(unsigned int pageDataSize, unsigned char *code)
+{
+ unsigned char i;
+ unsigned char numEcc;
+ unsigned int eccParity;
+ unsigned int ecc[16];
+ HSMC4_EccGetValue(ecc);
+ numEcc = pageDataSize / 256;
+
+ // P2048' P1024' P512' P256' P128' P64' P32' P16' --- 3rd. Ecc Byte to store
+ // P8' P4' P2' P1' P2048 P1024 P512 P256 --- 2nd. Ecc Byte to store
+ // P128 P64 P32 P16 P8 P4 P2 P1 --- 1st. Ecc Byte to store
+ for (i = 0; i < numEcc; i++) {
+ // Get Parity and NParity value.
+ eccParity = ecc[i];
+ // Invert codes (linux compatibility)
+ eccParity = ~eccParity;
+ TRACE_DEBUG("ecc Parity%d is 0x%08x \n\r", i, eccParity);
+ code[i * 3] = eccParity & 0xff;
+ code[i * 3 + 1] = (eccParity >> 8) & 0xff;
+ code[i * 3 + 2] = (eccParity >> 16) & 0xff;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Get 24-bit ECC code for 8-bit data path NAND flash.
+/// 24-bit ECC is generated in order to perform one bit correction
+/// for 512 byte in page 512/1024/2048/4096 for 8-bit words
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+//------------------------------------------------------------------------------
+void HSMC4_Get24bitPer512Ecc(unsigned int pageDataSize, unsigned char *code)
+{
+ unsigned char i;
+ unsigned char numEcc;
+ unsigned int eccParity;
+ unsigned int ecc[16];
+ HSMC4_EccGetValue(ecc);
+ numEcc = pageDataSize / 512;
+
+ // P2048' P1024' P512' P256' P128' P64' P32' P16' --- 3rd. Ecc Byte to store
+ // P8' P4' P2' P1' P2048 P1024 P512 P256 --- 2nd. Ecc Byte to store
+ // P128 P64 P32 P16 P8 P4 P2 P1 --- 1st. Ecc Byte to store
+ for (i = 0; i < numEcc; i++) {
+ // Get Parity and NParity value.
+ eccParity = ecc[i];
+ // Invert codes (linux compatibility)
+ eccParity = ~eccParity;
+ TRACE_DEBUG("ecc Parity%d is 0x%08x \n\r", i, eccParity);
+ code[i * 3] = eccParity & 0xff;
+ code[i * 3 + 1] = (eccParity >> 8) & 0xff;
+ code[i * 3 + 2] = (eccParity >> 16) & 0xff;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Get 32-bit ECC code for 16-bit data path NAND flash.
+/// 32-bit ECC is generated in order to perform one bit correction
+/// for 256 word in page 512/1024/2048/4096 for 16-bit words
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+//------------------------------------------------------------------------------
+void HSMC4_Get32bitPer256Ecc(unsigned int pageDataSize, unsigned char *code)
+{
+ unsigned char i;
+ unsigned char numEcc;
+ unsigned int eccParity;
+ unsigned int eccNparity;
+ unsigned int ecc[16];
+ HSMC4_EccGetValue(ecc);
+ numEcc = pageDataSize / 256;
+
+ // P2048' P1024' P512' P256' P128' P64' P32' P16' --- 3rd. Ecc Byte to store
+ // P8' P4' P2' P1' P2048 P1024 P512 P256 --- 2nd. Ecc Byte to store
+ // P128 P64 P32 P16 P8 P4 P2 P1 --- 1st. Ecc Byte to store
+ for (i = 0; i < numEcc; i+= 2) {
+ // Get Parity value.
+ eccParity = ecc[i];
+ // Invert codes (linux compatibility)
+ eccParity = ~eccParity;
+ // Get NParity value.
+ eccNparity = ecc[i + 1];
+ eccNparity = ~eccNparity;
+ TRACE_DEBUG("ecc Parity%d is 0x%08x, ecc Nparity%d is 0x%08x \n\r", i, eccParity, i, eccNparity);
+ code[i * 3] = eccParity & 0xff;
+ code[i * 3 + 1] = ((eccParity >> 8) & 0x0f ) | ((eccNparity & 0x0f) << 4);
+ code[i * 3 + 2] = (eccNparity >> 4) & 0xff;
+
+ code[(i + 1) * 3] = (eccParity >> 16) & 0xff;
+ code[(i + 1) * 3 + 1] = ((eccParity >> 24) & 0x0f ) | (((eccNparity >> 16)& 0x0f) << 4);
+ code[(i + 1) * 3 + 2] = (eccNparity >> 20) & 0xff;
+
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Get 32-bit ECC code for 16-bit data path NAND flash.
+/// 32-bit ECC is generated in order to perform one bit correction
+/// for a page in page 512/1024/2048/4096 for 16-bit words
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+//------------------------------------------------------------------------------
+void HSMC4_Get32bitPerPageEcc(unsigned int pageDataSize, unsigned char *code)
+{
+ unsigned int eccParity;
+ unsigned int eccNparity;
+ unsigned int ecc[16];
+ // Get Parity value.
+ HSMC4_EccGetValue(ecc);
+
+ // ---- P16384'P8192'P4096'P2048' P1024'P512'P256' --- 4th. Ecc Byte to store
+ /// P128' P64' P32' P16' P8' P4' P2' P1' --- 3rd. Ecc Byte to store
+ // ---- P16384 P8192 P4096 P2048 P1024 P512 P256 --- 2nd. Ecc Byte to store
+ // P128 P64 P32 P16 P8 P4 P2 P1 --- 1st. Ecc Byte to store
+
+ // Invert codes (linux compatibility)
+ eccParity = ~(ecc[0]);
+ eccNparity = ~(ecc[1]);
+ TRACE_DEBUG("ecc Parity%d is 0x%08x, ecc Nparity%d is 0x%08x \n\r", eccParity, eccNparity);
+ code[0] = eccParity & 0xff;
+ code[1] = (eccParity >> 8 )& 0xff;
+ code[2] = eccNparity & 0xff;
+ code[3] = (eccNparity >> 8 )& 0xff;
+}
+
+//------------------------------------------------------------------------------
+/// Get ECC code for 8bit/16-bit data path NAND flash by giving data path.
+/// 24-bit or 32-bit ECC is generated in order to perform one bit correction
+/// for a page in page 512/1024/2048/4096.
+/// \param size Data size in bytes.
+/// \param code Codes buffer.
+/// \param dataPath 8bit/16bit data path.
+//------------------------------------------------------------------------------
+void HSMC4_GetEccParity(unsigned int pageDataSize, unsigned char *code, unsigned char dataPath)
+{
+ unsigned char correctionType;
+ correctionType = HSMC4_GetEccCorrectoinType();
+ // For 16-bit data path
+ if (dataPath == 16) {
+ switch (correctionType){
+ case AT91C_ECC_TYPCORRECT_ONE_PER_PAGE:
+ HSMC4_Get32bitPerPageEcc(pageDataSize, code);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES:
+ HSMC4_Get32bitPer256Ecc(pageDataSize, code);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_512_BYTES:
+ TRACE_WARNING("16 bit 512 byte correct not yet implement! \n\r");
+ break;
+ }
+ }
+ // For 8-bit data path
+ else {
+ switch (correctionType){
+ case AT91C_ECC_TYPCORRECT_ONE_PER_PAGE:
+ HSMC4_Get24bitPerPageEcc(pageDataSize, code);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES:
+ HSMC4_Get24bitPer256Ecc(pageDataSize, code);
+ break;
+ case AT91C_ECC_TYPCORRECT_ONE_EVERY_512_BYTES:
+ HSMC4_Get24bitPer512Ecc(pageDataSize, code);
+ break;
+ }
+ }
+}
\ No newline at end of file diff --git a/peripherals/hsmc4/hsmc4_ecc.h b/peripherals/hsmc4/hsmc4_ecc.h new file mode 100644 index 0000000..8ddcc87 --- /dev/null +++ b/peripherals/hsmc4/hsmc4_ecc.h @@ -0,0 +1,85 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef HSMC4_ECC_H
+#define HSMC4_ECC_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "Hsiao Code Errors"
+/// These are the possible errors when trying to verify a block of data encoded
+/// using a Hsiao code:
+///
+/// !Errors:
+/// - Hsiao_ERROR_SINGLEBIT
+/// - Hsiao_ERROR_ECC
+/// - Hsiao_ERROR_MULTIPLEBITS
+
+/// A single bit was incorrect but has been recovered.
+#define Hsiao_ERROR_SINGLEBIT 1
+
+/// The original code has been corrupted.
+#define Hsiao_ERROR_ECC 2
+
+/// Multiple bits are incorrect in the data and they cannot be corrected.
+#define Hsiao_ERROR_MULTIPLEBITS 3
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void HSMC4_EccConfigure(unsigned int type, unsigned int pageSize);
+
+extern unsigned int HSMC4_GetEccCorrectoinType(void);
+
+extern void HSMC4_EccGetValue(unsigned int *ecc);
+
+extern void HSMC4_GetEccParity(
+ unsigned int pageDataSize,
+ unsigned char *code,
+ unsigned char dataPath);
+
+extern unsigned char HSMC4_VerifyHsiao(
+ unsigned char *data,
+ unsigned int size,
+ const unsigned char *originalCode,
+ const unsigned char *verifyCode,
+ unsigned char dataPath);
+
+#endif //#ifndef HSMC4_ECC_H
+
diff --git a/peripherals/irq/aic.c b/peripherals/irq/aic.c new file mode 100644 index 0000000..d2353f5 --- /dev/null +++ b/peripherals/irq/aic.c @@ -0,0 +1,91 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include "irq.h"
+
+#ifndef AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL
+ /// Interrupt is internal and uses a logical 1 level.
+ #define AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE
+#endif
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configures an interrupt in the AIC. The interrupt is identified by its
+/// source (AT91C_ID_xxx) and is configured to use the specified mode and
+/// interrupt handler function. Mode is the value that will be put in AIC_SMRx
+/// and the function address will be set in AIC_SVRx.
+/// The interrupt is disabled before configuration, so it is useless
+/// to do it before calling this function. When AIC_ConfigureIT returns, the
+/// interrupt will always be disabled and cleared; it must be enabled by a
+/// call to AIC_EnableIT().
+/// \param source Interrupt source to configure.
+/// \param mode Triggering mode and priority of the interrupt.
+/// \param handler Interrupt handler function.
+//------------------------------------------------------------------------------
+void IRQ_ConfigureIT(unsigned int source,
+ unsigned int mode,
+ void( *handler )( void ))
+{
+ // Disable the interrupt first
+ AT91C_BASE_AIC->AIC_IDCR = 1 << source;
+
+ // Configure mode and handler
+ AT91C_BASE_AIC->AIC_SMR[source] = mode;
+ AT91C_BASE_AIC->AIC_SVR[source] = (unsigned int) handler;
+
+ // Clear interrupt
+ AT91C_BASE_AIC->AIC_ICCR = 1 << source;
+}
+
+//------------------------------------------------------------------------------
+/// Enables interrupts coming from the given (unique) source (AT91C_ID_xxx).
+/// \param source Interrupt source to enable.
+//------------------------------------------------------------------------------
+void IRQ_EnableIT(unsigned int source)
+{
+ AT91C_BASE_AIC->AIC_IECR = 1 << source;
+}
+
+//------------------------------------------------------------------------------
+/// Disables interrupts coming from the given (unique) source (AT91C_ID_xxx).
+/// \param source Interrupt source to enable.
+//------------------------------------------------------------------------------
+void IRQ_DisableIT(unsigned int source)
+{
+ AT91C_BASE_AIC->AIC_IDCR = 1 << source;
+}
+
diff --git a/peripherals/irq/irq.dir b/peripherals/irq/irq.dir new file mode 100644 index 0000000..06e017a --- /dev/null +++ b/peripherals/irq/irq.dir @@ -0,0 +1,38 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// This directory contains an API for Configure the Interrupt controller.
+/// The interrupt controller for SAM7 and SAM9 is AIC, and the interrupt controller
+/// for SAM3 is NVIC.
+//------------------------------------------------------------------------------
\ No newline at end of file diff --git a/peripherals/irq/irq.h b/peripherals/irq/irq.h new file mode 100644 index 0000000..5f0e203 --- /dev/null +++ b/peripherals/irq/irq.h @@ -0,0 +1,84 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Methods and definitions for configuring interrupts.
+///
+/// !Usage
+///
+/// -# Configure an interrupt source using IRQ_ConfigureIT
+/// -# Enable or disable interrupt generation of a particular source with
+/// IRQ_EnableIT and IRQ_DisableIT.
+///
+/// \note Most of the time, peripheral interrupts must be also configured
+/// inside the peripheral itself.
+//------------------------------------------------------------------------------
+
+#ifndef IRQ_H
+#define IRQ_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#if defined(cortexm3)
+#include <core_cm3.h>
+#endif
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+#if 0
+#if defined(cortexm3)
+#ifdef __NVIC_PRIO_BITS
+#undef __NVIC_PRIO_BITS
+#define __NVIC_PRIO_BITS ((SCB->AIRCR & 0x700) >> 8)
+#endif
+#endif
+#endif
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void IRQ_ConfigureIT(unsigned int source,
+ unsigned int mode, // mode for AIC, priority for NVIC
+ void( *handler )( void )); // ISR
+
+extern void IRQ_EnableIT(unsigned int source);
+
+extern void IRQ_DisableIT(unsigned int source);
+
+#endif //#ifndef IRQ_H
+
diff --git a/peripherals/irq/nvic.c b/peripherals/irq/nvic.c new file mode 100644 index 0000000..b7d40b2 --- /dev/null +++ b/peripherals/irq/nvic.c @@ -0,0 +1,144 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "board.h"
+#include "irq.h"
+#include "exceptions.h"
+#include <utility/trace.h>
+
+/// The index of IRQ handler in the exception table
+#define NVIC_IRQ_HANDLER_INDEX 16
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configures an interrupt in the NVIC. The interrupt is identified by its
+/// source (AT91C_ID_xxx) and is configured to a specified priority and
+/// interrupt handler function. priority is the value that will be put in NVIC_IPRx
+/// and the function address will be set in "ExceptionTable". The parameter priority
+/// will include the preemptionPriority and the subPriority, where the subPriority
+/// defined in the B[7:0] of the parameter "priority", and the preemptionPriority defined
+/// in the B[15:8] of the parameter "priority".
+/// The interrupt is disabled before configuration, so it is useless
+/// to do it before calling this function. When NVIC_ConfigureIT returns, the
+/// interrupt will always be disabled and cleared; it must be enabled by a
+/// call to NVIC_EnableIT().
+/// \param source Interrupt source to configure.
+/// \param priority Pre-emption priority (B[15:8] )+ subPriority (B[7:0])
+/// \param handler Interrupt handler function.
+//------------------------------------------------------------------------------
+void IRQ_ConfigureIT(
+ unsigned int source,
+ //unsigned int preemptionPriority,
+ //unsigned int subPriority,
+ unsigned int priority,
+ IntFunc handler)
+{
+ unsigned int priGroup = __NVIC_PRIO_BITS;
+ unsigned int nPre = 8 - priGroup;
+ unsigned int nSub = priGroup;
+ unsigned int preemptionPriority;
+ unsigned int subPriority;
+ unsigned int IRQpriority;
+
+ preemptionPriority = (priority & 0xff00) >> 8;
+ subPriority = (priority & 0xff);
+
+ // Disable the interrupt first
+ NVIC_DisableIRQ((IRQn_Type)source);
+
+ // Clear any pending status
+ NVIC_ClearPendingIRQ((IRQn_Type)source);
+
+ // Configure interrupt handler
+ //if (handler == 0) handler = IrqHandlerNotUsed;
+ // GetExceptionTable()[NVIC_IRQ_HANDLER_INDEX + source] = handler;
+
+ if (subPriority >= (0x01 << nSub))
+ subPriority = (0x01 << nSub) - 1;
+ if (preemptionPriority >= (0x01 << nPre))
+ preemptionPriority = (0x01 << nPre) - 1;
+
+ IRQpriority = (subPriority | (preemptionPriority << nSub));
+ NVIC_SetPriority((IRQn_Type)source, IRQpriority);
+}
+
+//------------------------------------------------------------------------------
+/// Enables interrupt coming from the given (unique) source (AT91C_ID_xxx).
+/// \param source Interrupt source to enable.
+//------------------------------------------------------------------------------
+void IRQ_EnableIT(unsigned int source)
+{
+ NVIC_EnableIRQ((IRQn_Type)source);
+}
+
+//------------------------------------------------------------------------------
+/// Disables interrupt coming from the given (unique) source (AT91C_ID_xxx).
+/// \param source Interrupt source to disable.
+//------------------------------------------------------------------------------
+void IRQ_DisableIT(unsigned int source)
+{
+ NVIC_DisableIRQ((IRQn_Type)source);
+}
+
+//------------------------------------------------------------------------------
+/// Set interrupt pending bit from the given (unique) source (AT91C_ID_xxx).
+/// \param source Interrupt source to set.
+//------------------------------------------------------------------------------
+void NVIC_SetPending(unsigned int source)
+{
+ NVIC_SetPendingIRQ((IRQn_Type)source);
+}
+
+//------------------------------------------------------------------------------
+/// Clear interrupt pending bit from the given (unique) source (AT91C_ID_xxx).
+/// \param source Interrupt source to clear.
+//------------------------------------------------------------------------------
+void NVIC_ClrPending(unsigned int source)
+{
+ NVIC_ClearPendingIRQ((IRQn_Type)source);
+}
+
+#if !defined(USE_CMSIS_on)
+//------------------------------------------------------------------------------
+/// Use the Software Trigger Interrupt Register to pend an interrupt.
+/// \param source Interrupt source to trigger.
+//------------------------------------------------------------------------------
+void NVIC_Swi(unsigned int source)
+{
+ AT91C_BASE_NVIC->NVIC_STIR = source;
+}
+#endif
+
diff --git a/peripherals/irq/nvic.h b/peripherals/irq/nvic.h new file mode 100644 index 0000000..ff33ab0 --- /dev/null +++ b/peripherals/irq/nvic.h @@ -0,0 +1,55 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Methods and definitions for configuring interrupts using the Nested
+/// Vectored Interrupt Controller (NVIC).
+///
+/// !Usage
+///
+/// -# Configure interrupt source by implementing specific functions and define
+/// ...
+/// -# Configure the interrupt settings using NVIC_ConfigureIT
+/// -# Enable or disable interrupt generation of a particular source with
+/// NVIC_EnableIT and NVIC_DisableIT.
+///
+/// \note Most of the time, peripheral interrupts must be also configured
+/// inside the peripheral itself.
+//------------------------------------------------------------------------------
+
+#ifndef NVIC_H
+#define NVIC_H
+
+
+#endif //#ifndef NVIC_H
+
diff --git a/peripherals/isi/isi.c b/peripherals/isi/isi.c new file mode 100644 index 0000000..05feb4b --- /dev/null +++ b/peripherals/isi/isi.c @@ -0,0 +1,261 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Image Sensor Interface (ISI) driver
+///
+/// !Usage
+///
+/// Explanation on the usage of the code made available through the header file.
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include <utility/trace.h>
+#include <utility/video.h>
+#include "isi.h"
+
+#if !defined (BOARD_ISI_V200)
+
+//-----------------------------------------------------------------------------
+/// Enable ISI
+//-----------------------------------------------------------------------------
+void ISI_Enable(void)
+{
+ AT91C_BASE_ISI->ISI_CR1 &= ~AT91C_ISI_DIS;
+}
+
+//-----------------------------------------------------------------------------
+/// Disable ISI
+//-----------------------------------------------------------------------------
+void ISI_Disable(void)
+{
+ AT91C_BASE_ISI->ISI_CR1 |= AT91C_ISI_DIS;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable ISI interrupt
+/// \param flag of interrupt to enable
+//-----------------------------------------------------------------------------
+void ISI_EnableInterrupt(unsigned int flag)
+{
+ AT91C_BASE_ISI->ISI_IER = flag;
+}
+
+//-----------------------------------------------------------------------------
+/// Disable ISI interrupt
+/// \param flag of interrupt to disable
+//-----------------------------------------------------------------------------
+void ISI_DisableInterrupt(unsigned int flag)
+{
+ AT91C_BASE_ISI->ISI_IDR = flag;
+}
+
+//-----------------------------------------------------------------------------
+/// Return ISI status register
+/// \return Status of ISI register
+//-----------------------------------------------------------------------------
+unsigned int ISI_StatusRegister(void)
+{
+ return(AT91C_BASE_ISI->ISI_SR);
+}
+
+//-----------------------------------------------------------------------------
+/// Enable Codec path for capture next frame
+//-----------------------------------------------------------------------------
+void ISI_CodecPathFull(void)
+{
+ // The codec path is enabled and the next frame is captured.
+ // Both codec and preview datapaths are working simultaneously
+ AT91C_BASE_ISI->ISI_CR1 |= AT91C_ISI_CODEC_ON | AT91C_ISI_FULL;
+}
+
+//-----------------------------------------------------------------------------
+/// Set frame rate
+/// \param frate frame rate capture
+/// \return
+//-----------------------------------------------------------------------------
+void ISI_SetFrame(unsigned int frate)
+{
+ if( frate > 7 ) {
+ TRACE_ERROR("FRate too big\n\r");
+ frate = 7;
+ }
+ AT91C_BASE_ISI->ISI_CR1 |= ((frate<<8) & AT91C_ISI_FRATE);
+}
+
+//-----------------------------------------------------------------------------
+/// Get the number of byte per pixels
+/// \param bmpRgb BMP type can be YUV or RGB
+/// \return Number of byte for one pixel
+//-----------------------------------------------------------------------------
+unsigned char ISI_BytesForOnePixel(unsigned char bmpRgb)
+{
+ unsigned char nbByte_Pixel;
+
+ if (bmpRgb == RGB) {
+ if ((AT91C_BASE_ISI->ISI_CR2 & AT91C_ISI_RGB_MODE) == AT91C_ISI_RGB_MODE_RGB_565){
+ // RGB: 5:6:5 16bits/pixels
+ nbByte_Pixel = 2;
+ }
+ else {
+ // RGB: 8:8:8 24bits/pixels
+ nbByte_Pixel = 3;
+ }
+ }
+ else {
+ // YUV: 2 pixels for 4 bytes
+ nbByte_Pixel = 2;
+ }
+ return nbByte_Pixel;
+}
+
+//-----------------------------------------------------------------------------
+/// Reset ISI
+//-----------------------------------------------------------------------------
+void ISI_Reset(void)
+{
+ unsigned int timeout=0;
+
+ // Resets the image sensor interface.
+ // Finish capturing the current frame and then shut down the module.
+ AT91C_BASE_ISI->ISI_CR1 = AT91C_ISI_RST | AT91C_ISI_DIS;
+ // wait Software reset has completed successfully.
+ while( (!(volatile int)AT91C_BASE_ISI->ISI_SR & AT91C_ISI_SOFTRST)
+ && (timeout < 0x5000) ){
+ timeout++;
+ }
+ if( timeout == 0x5000 ) {
+ TRACE_ERROR("ISI-Reset timeout\n\r");
+ }
+}
+
+//-----------------------------------------------------------------------------
+/// ISI initialize with the pVideo parameters.
+/// By default, put ISI in RGB mode 565, YCC mode 3, different value for
+/// Color Space Conversion Matrix Coefficient
+/// \param pVideo structure of video driver
+//-----------------------------------------------------------------------------
+void ISI_Init(AT91PS_VIDEO pVideo)
+{
+ ISI_Reset();
+
+ // AT91C_ISI_HSYNC_POL Horizontal synchronisation polarity
+ // AT91C_ISI_VSYNC_POL Vertical synchronisation polarity
+ // AT91C_ISI_PIXCLK_POL Pixel Clock Polarity
+
+ // SLD pixel clock periods to wait before the beginning of a line.
+ // SFD lines are skipped at the beginning of the frame.
+ AT91C_BASE_ISI->ISI_CR1 |= ((pVideo->Hblank << 16) & AT91C_ISI_SLD)
+ + ((pVideo->Vblank << 24) & AT91C_ISI_SFD);
+ TRACE_DEBUG("ISI_CR1=0x%X\n\r", AT91C_BASE_ISI->ISI_CR1);
+
+ // IM_VSIZE: Vertical size of the Image sensor [0..2047]
+ // Vertical size = IM_VSIZE + 1
+ // IM_HSIZE: Horizontal size of the Image sensor [0..2047]
+ // Horizontal size = IM_HSIZE + 1
+ // YCC_SWAP : YCC image data
+ AT91C_BASE_ISI->ISI_CR2 = ((pVideo->codec_vsize-1) & AT91C_ISI_IM_VSIZE)
+ + (((pVideo->codec_hsize-1) << 16) & AT91C_ISI_IM_HSIZE)
+ + AT91C_ISI_YCC_SWAP_YCC_MODE2;
+
+ if (pVideo->rgb_or_yuv == RGB) {
+ AT91C_BASE_ISI->ISI_CR2 |= AT91C_ISI_COL_SPACE | AT91C_ISI_RGB_MODE_RGB_565
+ | AT91C_ISI_RGB_CFG_RGB_DEFAULT;
+ }
+ else {
+ // AT91C_BASE_HISI->ISI_CR2 &= ~AT91C_ISI_COL_SPACE;
+ }
+ TRACE_DEBUG("ISI_CR2=0x%X\n\r", AT91C_BASE_ISI->ISI_CR2);
+
+ // Vertical Preview size = PREV_VSIZE + 1 (480 max only in RGB mode).
+ // Horizontal Preview size = PREV_HSIZE + 1 (640 max only in RGB mode).
+#if defined (AT91C_ID_LCDC)
+ if( (pVideo->lcd_vsize > 480) || (pVideo->lcd_hsize > 640)) {
+ TRACE_ERROR("Size LCD bad define\n\r");
+ AT91C_BASE_ISI->ISI_PSIZE = ((BOARD_LCD_HEIGHT-1) & AT91C_ISI_PREV_VSIZE)
+ + (((BOARD_LCD_WIDTH-1) << 16) & AT91C_ISI_PREV_HSIZE);
+ }
+ else {
+
+ AT91C_BASE_ISI->ISI_PSIZE = ((pVideo->lcd_vsize -1) & AT91C_ISI_PREV_VSIZE)
+ + (((pVideo->lcd_hsize -1) << 16) & AT91C_ISI_PREV_HSIZE);
+ }
+#endif
+
+
+ // DEC_FACTOR is 8-bit width, range is from 16 to 255.
+ // Values from 0 to 16 do not perform any decimation.
+ AT91C_BASE_ISI->ISI_PDECF = (16 * pVideo->codec_hsize) / pVideo->lcd_hsize;
+
+ TRACE_DEBUG("codec_hsize: %d\n\r", pVideo->codec_hsize);
+ TRACE_DEBUG("lcd_hsize: %d\n\r", pVideo->lcd_hsize);
+ TRACE_DEBUG("ISI_PDECF: %d\n\r", AT91C_BASE_ISI->ISI_PDECF);
+ if( AT91C_BASE_ISI->ISI_PDECF <16) {
+ TRACE_ERROR("ISI_PDECF, forbidden value: %d\n\r", AT91C_BASE_ISI->ISI_PDECF);
+ AT91C_BASE_ISI->ISI_PDECF = 16;
+ }
+
+ // Written with the address of the start of the preview frame buffer queue,
+ // reads as a pointer to the current buffer being used.
+ // The frame buffer is forced to word alignment.
+ AT91C_BASE_ISI->ISI_PPFBD = pVideo->Isi_fbd_base;
+
+ // This register contains codec datapath start address of buffer location.
+ // CODEC_DMA_ADDR: Base address for codec DMA
+ AT91C_BASE_ISI->ISI_CDBA = pVideo->codec_fb_addr;
+
+ // C0: Color Space Conversion Matrix Coefficient C0
+ // C1: Color Space Conversion Matrix Coefficient C1
+ // C2: Color Space Conversion Matrix Coefficient C2
+ // C3: Color Space Conversion Matrix Coefficient C3
+ AT91C_BASE_ISI->ISI_Y2RSET0 = ( (0x95<< 0) & AT91C_ISI_Y2R_C0)
+ + ( (0xFF<< 8) & AT91C_ISI_Y2R_C1)
+ + ( (0x68<<16) & AT91C_ISI_Y2R_C2)
+ + ( (0x32<<24) & AT91C_ISI_Y2R_C3);
+
+ // C4: Color Space Conversion Matrix coefficient C4
+ // Yoff: Color Space Conversion Luminance 128 offset
+ // Croff: Color Space Conversion Red Chrominance 16 offset
+ // Cboff: Color Space Conversion Blue Chrominance 16 offset
+ AT91C_BASE_ISI->ISI_Y2RSET1 = ( (0xCC<< 0) & AT91C_ISI_Y2R_C4)
+ + ( AT91C_ISI_Y2R_YOFF_128)
+ + ( AT91C_ISI_Y2R_CROFF_16)
+ + ( AT91C_ISI_Y2R_CBOFF_16);
+}
+
+#endif // !defined (BOARD_ISI_V200)
+
diff --git a/peripherals/isi/isi.dir b/peripherals/isi/isi.dir new file mode 100644 index 0000000..c44b439 --- /dev/null +++ b/peripherals/isi/isi.dir @@ -0,0 +1,42 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// This directory contains an API for configuring the Peripheral ISI (Image
+/// Sensor Interface).
+///
+/// !!!Contents
+///
+/// Contains code for initialize, reset, enable ISI peripheral.
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/isi/isi.h b/peripherals/isi/isi.h new file mode 100644 index 0000000..0a81437 --- /dev/null +++ b/peripherals/isi/isi.h @@ -0,0 +1,99 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the Image Sensor Interface (ISI) peripheral.
+///
+/// !Usage
+///
+/// -# ISI_Init: initialize ISI with default parameters
+/// -# ISI_EnableInterrupt: enable one or more interrupts
+/// -# ISI_DisableInterrupt: disable one or more interrupts
+/// -# ISI_Enable: enable isi module
+/// -# ISI_Disable: disable isi module
+/// -# ISI_CodecPathFull: enable codec path
+/// -# ISI_SetFrame: set frame rate
+/// -# ISI_BytesForOnePixel: return number of byte for one pixel
+/// -# ISI_StatusRegister: return ISI status register
+/// -# ISI_Reset: make a software reset
+//------------------------------------------------------------------------------
+
+#ifndef ISI_H
+#define ISI_H
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// ISI descriptors
+typedef struct
+{
+ /// Current LCD index, used with AT91C_ISI_MAX_PREV_BUFFER
+ unsigned int CurrentLcdIndex;
+ /// set if Fifo Codec Empty is present
+ volatile unsigned int DisplayCodec;
+ /// upgrade for each Fifo Codec Overflow (statistics use)
+ unsigned int nb_codec_ovf;
+ /// upgrade for each Fifo Preview Overflow (statistics use)
+ unsigned int nb_prev_ovf;
+}ISI_Descriptors;
+
+/// Frame Buffer Descriptors
+typedef struct
+{
+ /// Address of the Current FrameBuffer
+ unsigned int Current;
+#if defined (BOARD_ISI_V200)
+ /// Address of the Control
+ unsigned int Control;
+#endif
+ /// Address of the Next FrameBuffer
+ unsigned int Next;
+}ISI_FrameBufferDescriptors;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+extern void ISI_Enable(void);
+extern void ISI_Disable(void);
+extern void ISI_EnableInterrupt(unsigned int flag);
+extern void ISI_DisableInterrupt(unsigned int flag);
+extern void ISI_CodecPathFull(void);
+extern void ISI_SetFrame(unsigned int frate);
+extern unsigned char ISI_BytesForOnePixel(unsigned char bmpRgb);
+extern void ISI_Reset(void);
+extern void ISI_Init(AT91PS_VIDEO pVideo);
+extern unsigned int ISI_StatusRegister(void);
+
+#endif //#ifndef ISI_H
+
diff --git a/peripherals/isi/isi2.c b/peripherals/isi/isi2.c new file mode 100644 index 0000000..9ed61f8 --- /dev/null +++ b/peripherals/isi/isi2.c @@ -0,0 +1,246 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include <utility/trace.h>
+#include <utility/video.h>
+#include "isi.h"
+
+#if defined (BOARD_ISI_V200)
+
+//-----------------------------------------------------------------------------
+/// Enable ISI
+//-----------------------------------------------------------------------------
+void ISI_Enable(void)
+{
+ AT91C_BASE_ISI->ISI_CTRL |= AT91C_ISI_EN_1;
+ while( (AT91C_BASE_ISI->ISI_SR & AT91C_ISI_EN_1)!=AT91C_ISI_EN_1);
+ AT91C_BASE_ISI->ISI_DMACHER |= AT91C_ISI_P_CH_EN_1;
+}
+
+//-----------------------------------------------------------------------------
+/// Disable ISI
+//-----------------------------------------------------------------------------
+void ISI_Disable(void)
+{
+ AT91C_BASE_ISI->ISI_CTRL |= AT91C_ISI_DIS_1;
+ AT91C_BASE_ISI->ISI_DMACHDR &= ~AT91C_ISI_P_CH_DIS_1;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable ISI interrupt
+/// \param flag of interrupt to enable
+//-----------------------------------------------------------------------------
+void ISI_EnableInterrupt(unsigned int flag)
+{
+ AT91C_BASE_ISI->ISI_IER = flag;
+}
+
+//-----------------------------------------------------------------------------
+/// Disable ISI interrupt
+/// \param flag of interrupt to disable
+//-----------------------------------------------------------------------------
+void ISI_DisableInterrupt(unsigned int flag)
+{
+ AT91C_BASE_ISI->ISI_IDR = flag;
+}
+
+//-----------------------------------------------------------------------------
+/// Return ISI status register
+/// \return Status of ISI register
+//-----------------------------------------------------------------------------
+unsigned int ISI_StatusRegister(void)
+{
+ return(AT91C_BASE_ISI->ISI_SR);
+}
+
+//-----------------------------------------------------------------------------
+/// Enable Codec path for capture next frame
+//-----------------------------------------------------------------------------
+void ISI_CodecPathFull(void)
+{
+ // The codec path is enabled and the next frame is captured.
+ // Both codec and preview datapaths are working simultaneously
+ AT91C_BASE_ISI->ISI_CTRL |= AT91C_ISI_CDC_1;
+ AT91C_BASE_ISI->ISI_CFG1 |= AT91C_ISI_FULL;
+}
+
+//-----------------------------------------------------------------------------
+/// Set frame rate
+/// \param frate frame rate capture
+/// \return
+//-----------------------------------------------------------------------------
+void ISI_SetFrame(unsigned int frate)
+{
+ if( frate > 7 ) {
+ TRACE_ERROR("FRate too big\n\r");
+ frate = 7;
+ }
+ AT91C_BASE_ISI->ISI_CFG1 |= ((frate<<8) & AT91C_ISI_FRATE);
+}
+
+//-----------------------------------------------------------------------------
+/// Get the number of byte per pixels
+/// \param bmpRgb BMP type can be YUV or RGB
+/// \return Number of byte for one pixel
+//-----------------------------------------------------------------------------
+unsigned char ISI_BytesForOnePixel(unsigned char bmpRgb)
+{
+ unsigned char nbByte_Pixel;
+
+ if (bmpRgb == RGB) {
+ if ((AT91C_BASE_ISI->ISI_CFG2 & AT91C_ISI_RGB_MODE) == AT91C_ISI_RGB_MODE_RGB_565){
+ // RGB: 5:6:5 16bits/pixels
+ nbByte_Pixel = 2;
+ }
+ else {
+ // RGB: 8:8:8 24bits/pixels
+ nbByte_Pixel = 3;
+ }
+ }
+ else {
+ // YUV: 2 pixels for 4 bytes
+ nbByte_Pixel = 2;
+ }
+ return nbByte_Pixel;
+}
+
+//-----------------------------------------------------------------------------
+/// Reset ISI
+//-----------------------------------------------------------------------------
+void ISI_Reset(void)
+{
+ unsigned int timeout=0;
+
+ // Resets the image sensor interface.
+ // Finish capturing the current frame and then shut down the module.
+ AT91C_BASE_ISI->ISI_CTRL = AT91C_ISI_SRST_1 | AT91C_ISI_DIS_1;
+ // wait Software reset has completed successfully.
+ while( (!(volatile int)AT91C_BASE_ISI->ISI_SR & AT91C_ISI_SRST)
+ && (timeout < 0x5000) ){
+ timeout++;
+ }
+ if( timeout == 0x5000 ) {
+ TRACE_ERROR("ISI-Reset timeout\n\r");
+ }
+}
+
+//-----------------------------------------------------------------------------
+/// ISI initialize
+/// \param pVideo structure of video driver
+//-----------------------------------------------------------------------------
+void ISI_Init(AT91PS_VIDEO pVideo)
+{
+ ISI_Reset();
+
+ // AT91C_ISI_HSYNC_POL Horizontal synchronisation polarity
+ // AT91C_ISI_VSYNC_POL Vertical synchronisation polarity
+ // AT91C_ISI_PIXCLK_POL Pixel Clock Polarity
+
+ // SLD pixel clock periods to wait before the beginning of a line.
+ // SFD lines are skipped at the beginning of the frame.
+ AT91C_BASE_ISI->ISI_CFG1 |= ((pVideo->Hblank << 16) & AT91C_ISI_SLD)
+ + ((pVideo->Vblank << 24) & AT91C_ISI_SFD);
+ TRACE_DEBUG("ISI_CFG1=0x%X\n\r", AT91C_BASE_ISI->ISI_CFG1);
+
+ // IM_VSIZE: Vertical size of the Image sensor [0..2047]
+ // Vertical size = IM_VSIZE + 1
+ // IM_HSIZE: Horizontal size of the Image sensor [0..2047]
+ // Horizontal size = IM_HSIZE + 1
+ // YCC_SWAP : YCC image data
+ AT91C_BASE_ISI->ISI_CFG2 = ((pVideo->codec_vsize-1) & AT91C_ISI_IM_VSIZE)
+ + (((pVideo->codec_hsize-1) << 16) & AT91C_ISI_IM_HSIZE)
+ + AT91C_ISI_YCC_SWAP_YCC_MODE2;
+
+ if (pVideo->rgb_or_yuv == RGB) {
+ AT91C_BASE_ISI->ISI_CFG2 |= AT91C_ISI_COL_SPACE | AT91C_ISI_RGB_MODE_RGB_565
+ | AT91C_ISI_RGB_CFG_RGB_DEFAULT;
+ }
+ else {
+ // AT91C_BASE_HISI->ISI_CFG2 &= ~AT91C_ISI_COL_SPACE;
+ }
+ TRACE_DEBUG("ISI_CFG2=0x%X\n\r", AT91C_BASE_ISI->ISI_CFG2);
+
+ // Vertical Preview size = PREV_VSIZE + 1 (480 max only in RGB mode).
+ // Horizontal Preview size = PREV_HSIZE + 1 (640 max only in RGB mode).
+#if defined (AT91C_ID_LCDC)
+ if( (pVideo->lcd_vsize > 480) || (pVideo->lcd_hsize > 640)) {
+ TRACE_ERROR("Size LCD bad define\n\r");
+ AT91C_BASE_ISI->ISI_PSIZE = ((BOARD_LCD_HEIGHT-1) & AT91C_ISI_PREV_VSIZE)
+ + (((BOARD_LCD_WIDTH-1) << 16) & AT91C_ISI_PREV_HSIZE);
+ }
+ else {
+
+ AT91C_BASE_ISI->ISI_PSIZE = ((pVideo->lcd_vsize -1) & AT91C_ISI_PREV_VSIZE)
+ + (((pVideo->lcd_hsize -1) << 16) & AT91C_ISI_PREV_HSIZE);
+ }
+#endif
+
+
+ // DEC_FACTOR is 8-bit width, range is from 16 to 255.
+ // Values from 0 to 16 do not perform any decimation.
+ AT91C_BASE_ISI->ISI_PDECF = (16 * pVideo->codec_hsize) / pVideo->lcd_hsize;
+
+ TRACE_DEBUG("codec_hsize: %d\n\r", pVideo->codec_hsize);
+ TRACE_DEBUG("lcd_hsize: %d\n\r", pVideo->lcd_hsize);
+ TRACE_DEBUG("ISI_PDECF: %d\n\r", AT91C_BASE_ISI->ISI_PDECF);
+ if( AT91C_BASE_ISI->ISI_PDECF <16) {
+ TRACE_ERROR("ISI_PDECF, forbidden value: %d\n\r", AT91C_BASE_ISI->ISI_PDECF);
+ AT91C_BASE_ISI->ISI_PDECF = 16;
+ }
+
+ AT91C_BASE_ISI->ISI_DMAPDSCR = pVideo->Isi_fbd_base;
+ AT91C_BASE_ISI->ISI_DMAPCTRL = AT91C_ISI_P_FETCH_ENABLE;
+ AT91C_BASE_ISI->ISI_DMAPADDR = pVideo->lcd_fb_addr;
+
+ // C0: Color Space Conversion Matrix Coefficient C0
+ // C1: Color Space Conversion Matrix Coefficient C1
+ // C2: Color Space Conversion Matrix Coefficient C2
+ // C3: Color Space Conversion Matrix Coefficient C3
+ AT91C_BASE_ISI->ISI_Y2RSET0 = ( (0x95<< 0) & AT91C_ISI_Y2R_C0)
+ + ( (0xFF<< 8) & AT91C_ISI_Y2R_C1)
+ + ( (0x68<<16) & AT91C_ISI_Y2R_C2)
+ + ( (0x32<<24) & AT91C_ISI_Y2R_C3);
+
+ // C4: Color Space Conversion Matrix coefficient C4
+ // Yoff: Color Space Conversion Luminance 128 offset
+ // Croff: Color Space Conversion Red Chrominance 16 offset
+ // Cboff: Color Space Conversion Blue Chrominance 16 offset
+ AT91C_BASE_ISI->ISI_Y2RSET1 = ( (0xCC<< 0) & AT91C_ISI_Y2R_C4)
+ + ( AT91C_ISI_Y2R_YOFF_128)
+ + ( AT91C_ISI_Y2R_CROFF_16)
+ + ( AT91C_ISI_Y2R_CBOFF_16);
+}
+
+#endif // defined (BOARD_ISI_V200)
+
diff --git a/peripherals/lcd/lcd.c b/peripherals/lcd/lcd.c new file mode 100644 index 0000000..8c2f08e --- /dev/null +++ b/peripherals/lcd/lcd.c @@ -0,0 +1,473 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#include <board.h>
+
+#if defined (AT91C_ID_LCDC)
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "lcd.h"
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Enables the LCD controller, after waiting for the specified number of
+/// frames.
+/// \param frames Number of frames before the LCD is enabled.
+//------------------------------------------------------------------------------
+void LCD_Enable(unsigned int frames)
+{
+ TRACE_DEBUG("LCD enable\n\r");
+ ASSERT((frames & 0xFFFFFF80) == 0,
+ "LCD_Enable: Wrong frames value.\n\r");
+ if( (AT91C_BASE_LCDC->LCDC_PWRCON & AT91C_LCDC_BUSY) == AT91C_LCDC_BUSY ) {
+ TRACE_DEBUG("LCD BUSY E\n\r");
+ }
+ AT91C_BASE_LCDC->LCDC_PWRCON = AT91C_LCDC_PWR | (frames << 1);
+}
+
+//------------------------------------------------------------------------------
+/// Disables the LCD controller, after waiting for the specified number of
+/// frames.
+/// \param frames Number of frames before the LCD is shut down.
+//------------------------------------------------------------------------------
+void LCD_Disable(unsigned int frames)
+{
+ TRACE_DEBUG("LCD disable\n\r");
+ ASSERT((frames & 0xFFFFFF80) == 0,
+ "LCD_Disable: Wrong frames value.\n\r");
+ // Remove AT91C_LCDC_PWR
+ AT91C_BASE_LCDC->LCDC_PWRCON = frames << 1;
+ // wait LCDC Core is in idle state
+ while( (AT91C_BASE_LCDC->LCDC_PWRCON & AT91C_LCDC_BUSY) == AT91C_LCDC_BUSY ) {
+ }
+ TRACE_DEBUG("LCD is in IDLE state\n\r");
+}
+
+//------------------------------------------------------------------------------
+/// Enables the DMA of the LCD controller.
+//------------------------------------------------------------------------------
+void LCD_EnableDma(void)
+{
+ if( (AT91C_BASE_LCDC->LCDC_DMACON & AT91C_LCDC_DMABUSY) == AT91C_LCDC_DMABUSY ) {
+ TRACE_DEBUG("LCD DMA BUSY E\n\r");
+ }
+ AT91C_BASE_LCDC->LCDC_DMACON = AT91C_LCDC_DMAEN;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the DMA of the LCD controller.
+//------------------------------------------------------------------------------
+void LCD_DisableDma(void)
+{
+ AT91C_BASE_LCDC->LCDC_DMACON = 0;
+ // wait LCDC DMA is in idle state
+ while( (AT91C_BASE_LCDC->LCDC_DMACON & AT91C_LCDC_DMABUSY) == AT91C_LCDC_DMABUSY ) {
+ }
+ TRACE_DEBUG("LCD DMA is in IDLE state\n\r");
+}
+
+//------------------------------------------------------------------------------
+/// Enables the selected LDC interrupt sources.
+/// \param sources Interrupt sources to enable.
+//------------------------------------------------------------------------------
+void LCD_EnableInterrupts(unsigned int sources)
+{
+ AT91C_BASE_LCDC->LCDC_IER = sources;
+}
+
+//------------------------------------------------------------------------------
+/// Configures the internal clock of the LCD controller given the master clock of
+/// the system and the desired pixel clock in MHz.
+/// \param masterClock Master clock frequency.
+/// \param pixelClock Pixel clock frequency.
+//------------------------------------------------------------------------------
+void LCD_SetPixelClock(unsigned int masterClock, unsigned int pixelClock)
+{
+ #if defined(LCDC_PIXELCLOCK_DOUBLE)
+ AT91C_BASE_LCDC->LCDC_LCDCON1 = ((masterClock / pixelClock) - 1) << 12;
+ #else
+ AT91C_BASE_LCDC->LCDC_LCDCON1 = ((masterClock / 2 / pixelClock) - 1) << 12;
+ #endif
+}
+
+//------------------------------------------------------------------------------
+/// DMA reset
+//------------------------------------------------------------------------------
+void LCD_DMAReset(void)
+{
+ // DMA Module should be reset only when disabled and in idle state
+ if( AT91C_LCDC_DMABUSY == (AT91C_BASE_LCDC->LCDC_DMACON & AT91C_LCDC_DMABUSY)) {
+ TRACE_ERROR("LCD BUSY so NO DMA RESET\n\r");
+ }
+ if( AT91C_LCDC_DMAEN == (AT91C_BASE_LCDC->LCDC_DMACON & AT91C_LCDC_DMAEN)) {
+ TRACE_ERROR("DMA Enabled, so NO DMA RESET\n\r");
+ }
+ AT91C_BASE_LCDC->LCDC_DMACON = AT91C_LCDC_DMARST;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the type of display used with the LCD controller.
+/// \param displayType Type of display used.
+//------------------------------------------------------------------------------
+void LCD_SetDisplayType(unsigned int displayType)
+{
+ unsigned int value;
+
+ ASSERT((displayType & ~AT91C_LCDC_DISTYPE) == 0,
+ "LCD_SetDisplayType: Wrong display type value.\n\r");
+
+ value = AT91C_BASE_LCDC->LCDC_LCDCON2;
+ value &= ~AT91C_LCDC_DISTYPE;
+ value |= displayType;
+ AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the scan mode used by the LCD (either single scan or double-scan).
+/// \param scanMode Scan mode to use.
+//------------------------------------------------------------------------------
+void LCD_SetScanMode(unsigned int scanMode)
+{
+ unsigned int value;
+
+ ASSERT((scanMode & ~AT91C_LCDC_SCANMOD) == 0,
+ "LCD_SetScanMode: Wrong scan mode value.\n\r");
+
+ value = AT91C_BASE_LCDC->LCDC_LCDCON2;
+ value &= ~AT91C_LCDC_SCANMOD;
+ value |= scanMode;
+ AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the number of bits per pixel used by the LCD display.
+/// \param bitsPerPixel Number of bits per pixel to use.
+//------------------------------------------------------------------------------
+void LCD_SetBitsPerPixel(unsigned int bitsPerPixel)
+{
+ unsigned int value;
+
+ ASSERT((bitsPerPixel & ~AT91C_LCDC_PIXELSIZE) == 0,
+ "LCD_SetScanMode: Wrong bitsPerPixel value.\n\r");
+
+ value = AT91C_BASE_LCDC->LCDC_LCDCON2;
+ value &= ~AT91C_LCDC_PIXELSIZE;
+ value |= bitsPerPixel;
+ AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the LCDD, LCDVSYNC, LCDHSYNC, LCDDOTCLK and LCDDEN signal polarities.
+/// \param lcdd LCDD signal polarity.
+/// \param lcdvsync LCDVSYNC signal polarity.
+/// \param lcdhsync LCDHSYNC signal polarity.
+/// \param lcddotclk LCDDOTCLK signal polarity.
+/// \param lcdden LCDDEN signal polarity.
+//------------------------------------------------------------------------------
+void LCD_SetPolarities(
+ unsigned int lcdd,
+ unsigned int lcdvsync,
+ unsigned int lcdhsync,
+ unsigned int lcddotclk,
+ unsigned int lcdden)
+{
+ unsigned int value;
+
+ ASSERT((lcdd & ~AT91C_LCDC_INVVD) == 0,
+ "LCD_SetPolarities: Wrong lcdd value.\n\r");
+ ASSERT((lcdvsync & ~AT91C_LCDC_INVFRAME) == 0,
+ "LCD_SetPolarities: Wrong lcdvsync value.\n\r");
+ ASSERT((lcdhsync & ~AT91C_LCDC_INVLINE) == 0,
+ "LCD_SetPolarities: Wrong lcdhsync value.\n\r");
+ ASSERT((lcddotclk & ~AT91C_LCDC_INVCLK) == 0,
+ "LCD_SetPolarities: Wrong lcddotclk value.\n\r");
+ ASSERT((lcdden & ~AT91C_LCDC_INVDVAL) == 0,
+ "LCD_SetPolarities: Wrong lcdden value.\n\r");
+
+ value = AT91C_BASE_LCDC->LCDC_LCDCON2;
+ value &= 0xFFFFE0FF;
+ value |= lcdd | lcdvsync | lcdhsync | lcddotclk | lcdden;
+ AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the LCD clock mode, i.e. always active or active only during display
+/// period.
+/// \param clockMode Clock mode to use.
+//------------------------------------------------------------------------------
+void LCD_SetClockMode(unsigned int clockMode)
+{
+ unsigned int value;
+
+ ASSERT((clockMode & ~AT91C_LCDC_CLKMOD) == 0,
+ "LCD_SetScanMode: Wrong scan mode value.\n\r");
+
+ value = AT91C_BASE_LCDC->LCDC_LCDCON2;
+ value &= ~AT91C_LCDC_CLKMOD;
+ value |= clockMode;
+ AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the format of the frame buffer memory.
+/// \param format Memory ordering format.
+//------------------------------------------------------------------------------
+void LCD_SetMemoryFormat(unsigned int format)
+{
+ unsigned int value;
+
+ ASSERT((format & ~AT91C_LCDC_MEMOR) == 0,
+ "LCD_SetMemoryFormat: Wrong memory format value.\n\r");
+
+ value = AT91C_BASE_LCDC->LCDC_LCDCON2;
+ value &= ~AT91C_LCDC_MEMOR;
+ value |= format;
+ AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the size in pixel of the LCD display.
+/// \param width Width in pixel of the LCD display.
+/// \param height Height in pixel of the LCD display.
+//------------------------------------------------------------------------------
+void LCD_SetSize(unsigned int width, unsigned int height)
+{
+ ASSERT(((width - 1) & 0xFFFFF800) == 0,
+ "LCD_SetSize: Wrong width value.\n\r");
+ ASSERT(((height - 1) & 0xFFFFF800) == 0,
+ "LCD_SetSize: Wrong height value.\n\r");
+
+ AT91C_BASE_LCDC->LCDC_LCDFRCFG = (((width - 1) << 21) &AT91C_LCDC_HOZVAL)
+ |((height - 1) & AT91C_LCDC_LINEVAL);
+}
+
+//------------------------------------------------------------------------------
+/// Sets the vertical timings of the LCD controller. Only meaningful when
+/// using a TFT display.
+/// \param vfp Number of idle lines at the end of a frame.
+/// \param vbp Number of idle lines at the beginning of a frame.
+/// \param vpw Vertical synchronization pulse width in number of lines.
+/// \param vhdly Delay between LCDVSYNC edge and LCDHSYNC rising edge, in
+/// LCDDOTCLK cycles.
+//------------------------------------------------------------------------------
+void LCD_SetVerticalTimings(
+ unsigned int vfp,
+ unsigned int vbp,
+ unsigned int vpw,
+ unsigned int vhdly)
+{
+ ASSERT((vfp & 0xFFFFFF00) == 0,
+ "LCD_SetVerticalTimings: Wrong vfp value.\n\r");
+ ASSERT((vbp & 0xFFFFFF00) == 0,
+ "LCD_SetVerticalTimings: Wrong vbp value.\n\r");
+ ASSERT(((vpw-1) & 0xFFFFFFC0) == 0,
+ "LCD_SetVerticalTimings: Wrong vpw value.\n\r");
+ ASSERT(((vhdly-1) & 0xFFFFFFF0) == 0,
+ "LCD_SetVerticalTimings: Wrong vhdly value.\n\r");
+
+ AT91C_BASE_LCDC->LCDC_TIM1 = (vfp & AT91C_LCDC_VFP)
+ | ((vbp << 8)&AT91C_LCDC_VBP)
+ | (((vpw-1) << 16)&AT91C_LCDC_VPW)
+ | (((vhdly-1) << 24)&AT91C_LCDC_VHDLY);
+}
+
+//------------------------------------------------------------------------------
+/// Sets the horizontal timings of the LCD controller. Meaningful for both
+/// STN and TFT displays.
+/// \param hbp Number of idle LCDDOTCLK cycles at the beginning of a line.
+/// \param hpw Width of the LCDHSYNC pulse, in LCDDOTCLK cycles.
+/// \param hfp Number of idel LCDDOTCLK cycles at the end of a line.
+//------------------------------------------------------------------------------
+void LCD_SetHorizontalTimings(
+ unsigned int hbp,
+ unsigned int hpw,
+ unsigned int hfp)
+{
+ ASSERT(((hbp-1) & 0xFFFFFF00) == 0,
+ "LCD_SetHorizontalTimings: Wrong hbp value.\n\r");
+ ASSERT(((hpw-1) & 0xFFFFFFC0) == 0,
+ "LCD_SetHorizontalTimings: Wrong hpw value.\n\r");
+ ASSERT(((hfp-1) & 0xFFFFFF00) == 0,
+ "LCD_SetHorizontalTimings: Wrong hfp value.\n\r");
+
+ AT91C_BASE_LCDC->LCDC_TIM2 = ((hbp-1)&AT91C_LCDC_HBP)
+ | (((hpw-1) << 8)&AT91C_LCDC_HPW)
+ | (((hfp-1) << 21)&AT91C_LCDC_HFP);
+}
+
+//------------------------------------------------------------------------------
+/// Sets the address of the frame buffer in the LCD controller DMA. When using
+/// dual-scan mode, this is the upper frame buffer.
+/// \param address Frame buffer address.
+//------------------------------------------------------------------------------
+void* LCD_SetFrameBufferAddress(void *address)
+{
+ void *pOldBuffer;
+
+ pOldBuffer = (void *) AT91C_BASE_LCDC->LCDC_BA1;
+ AT91C_BASE_LCDC->LCDC_BA1 = (unsigned int) address;
+
+ return pOldBuffer;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the size in pixels of a frame (height * width * bpp).
+/// \param frameSize Size of frame in pixels.
+//------------------------------------------------------------------------------
+void LCD_SetFrameSize(unsigned int frameSize)
+{
+ ASSERT((frameSize & 0xFF800000) == 0,
+ "LCD_SetFrameSize: Wrong frameSize value.\n\r");
+
+ AT91C_BASE_LCDC->LCDC_FRMCFG = (frameSize& AT91C_LCDC_FRSIZE)
+ | (AT91C_BASE_LCDC->LCDC_FRMCFG & AT91C_LCDC_BLENGTH);
+}
+
+//------------------------------------------------------------------------------
+/// Sets the DMA controller burst length.
+/// \param burstLength Desired burst length.
+//------------------------------------------------------------------------------
+void LCD_SetBurstLength(unsigned int burstLength)
+{
+ ASSERT(((burstLength-1) & 0xFFFFFF80) == 0,
+ "LCD_SetBurstLength: Wrong burstLength value.\n\r");
+
+ AT91C_BASE_LCDC->LCDC_FRMCFG &= ~AT91C_LCDC_BLENGTH;
+ AT91C_BASE_LCDC->LCDC_FRMCFG |= (((burstLength-1) << 24) & AT91C_LCDC_BLENGTH);
+
+ AT91C_BASE_LCDC->LCDC_FIFO = (2048 - (2 * burstLength + 3)) & AT91C_LCDC_FIFOTH;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the prescaler value of the contrast control PWM.
+/// \param prescaler Desired prescaler value.
+//------------------------------------------------------------------------------
+void LCD_SetContrastPrescaler(unsigned int prescaler)
+{
+ ASSERT((prescaler & ~AT91C_LCDC_PS) == 0,
+ "LCD_SetContrastPrescaler: Wrong prescaler value\n\r");
+
+ AT91C_BASE_LCDC->LCDC_CTRSTCON &= ~AT91C_LCDC_PS;
+ AT91C_BASE_LCDC->LCDC_CTRSTCON |= prescaler;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the polarity of the contrast PWM.
+/// \param polarity PWM polarity
+//------------------------------------------------------------------------------
+void LCD_SetContrastPolarity(unsigned int polarity)
+{
+ ASSERT((polarity & ~AT91C_LCDC_POL) == 0,
+ "LCD_SetContrastPolarity: Wrong polarity value\n\r");
+
+ AT91C_BASE_LCDC->LCDC_CTRSTCON &= ~AT91C_LCDC_POL;
+ AT91C_BASE_LCDC->LCDC_CTRSTCON |= polarity;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the threshold value of the constrast PWM.
+/// \param value PWM threshold value.
+//------------------------------------------------------------------------------
+void LCD_SetContrastValue(unsigned int value)
+{
+ ASSERT((value & ~AT91C_LCDC_CVAL) == 0,
+ "LCD_SetContrastValue: Wrong value.\n\r");
+
+ AT91C_BASE_LCDC->LCDC_CTRSTVAL = value;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the contrast PWM generator.
+//------------------------------------------------------------------------------
+void LCD_EnableContrast(void)
+{
+ AT91C_BASE_LCDC->LCDC_CTRSTCON |= AT91C_LCDC_ENA_PWMGEMENABLED;
+}
+
+//------------------------------------------------------------------------------
+/// Decode the RGB file
+/// \param file Buffer which holds the RGB file.
+/// \param bufferLCD Buffer in which to store the decoded image adapted to LCD.
+/// \param width Buffer width in pixels.
+/// \param height Buffer height in pixels.
+/// \param bpp Number of bits per pixels that the buffer stores.
+//------------------------------------------------------------------------------
+void LCD_DecodeRGB(
+ unsigned char *file,
+ unsigned char *bufferLCD,
+ unsigned int width,
+ unsigned int height,
+ unsigned char bpp)
+{
+ unsigned int offsetLine=0, offsetLCD=0;
+ unsigned int offset=1;
+
+ while( offset < (BOARD_LCD_HEIGHT)) {
+ //TRACE_DEBUG("LCD:%d LINE:%d off:%d\n\r", offsetLCD, offsetLine, offset);
+ if( width < BOARD_LCD_WIDTH ) {
+ //TRACE_DEBUG("width < BOARD_LCD_WIDTH\n\r");
+ while( offsetLine < (width*offset*(bpp/8)) ) {
+ bufferLCD[offsetLCD] = file[offsetLine];
+ offsetLine++;
+ offsetLCD++;
+ }
+ //TRACE_DEBUG("add white\n\r");
+ while( offsetLCD < (BOARD_LCD_WIDTH*offset*(bpp/8)) ) {
+ bufferLCD[offsetLCD] = 0;
+ //offsetLine++;
+ offsetLCD++;
+ }
+ }
+ else {
+ //TRACE_DEBUG(">");
+ while( offsetLCD < (BOARD_LCD_WIDTH*offset*(bpp/8)) ) {
+ bufferLCD[offsetLCD] = file[offsetLine];
+ offsetLine++;
+ offsetLCD++;
+ }
+ //TRACE_DEBUG("r ");
+ while( offsetLine < (width*offset*(bpp/8)) ) {
+ offsetLine++;
+ }
+ }
+ offset++;
+ }
+}
+
+#endif
+
diff --git a/peripherals/lcd/lcd.dir b/peripherals/lcd/lcd.dir new file mode 100644 index 0000000..b186baf --- /dev/null +++ b/peripherals/lcd/lcd.dir @@ -0,0 +1,35 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !!!Purpose
+///
+/// Contains the peripheral API for LCD Controller (LCDC) controller.
+//------------------------------------------------------------------------------
diff --git a/peripherals/lcd/lcd.h b/peripherals/lcd/lcd.h new file mode 100644 index 0000000..5974aaa --- /dev/null +++ b/peripherals/lcd/lcd.h @@ -0,0 +1,124 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the LCD Controller (LCDC) peripheral.
+///
+/// !Usage
+///
+/// -# Decode the RGB file to designated buffer using LCD_DecodeRGB().
+/// -# Sets the address of the frame buffer in the LCD controller DMA using
+/// LCD_SetFrameBufferAddress().
+/// -# LCD Configuration functions prefixed with "LCD_Set" refer to
+/// the functions in the #Overview# tab.
+///
+/// Please refer to the list of functions in the #Overview# tab of this unit
+/// for more detailed information.
+//------------------------------------------------------------------------------
+
+#ifndef LCD_H
+#define LCD_H
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void LCD_Enable(unsigned int frames);
+
+extern void LCD_Disable(unsigned int frames);
+
+extern void LCD_EnableDma(void);
+
+extern void LCD_DisableDma(void);
+
+extern void LCD_EnableInterrupts(unsigned int sources);
+
+extern void LCD_SetPixelClock(unsigned int masterClock, unsigned int pixelClock);
+
+extern void LCD_SetDisplayType(unsigned int displayType);
+
+extern void LCD_SetScanMode(unsigned int scanMode);
+
+extern void LCD_SetBitsPerPixel(unsigned int bitsPerPixel);
+
+extern void LCD_SetPolarities(
+ unsigned int lcdd,
+ unsigned int lcdvsync,
+ unsigned int lcdhsync,
+ unsigned int lcddotclk,
+ unsigned int lcdden);
+
+extern void LCD_SetClockMode(unsigned int clockMode);
+
+extern void LCD_SetMemoryFormat(unsigned int format);
+
+extern void LCD_SetSize(unsigned int width, unsigned int height);
+
+extern void LCD_SetVerticalTimings(
+ unsigned int vfp,
+ unsigned int vbp,
+ unsigned int vpw,
+ unsigned int vhdly);
+
+extern void LCD_SetHorizontalTimings(
+ unsigned int hbp,
+ unsigned int hpw,
+ unsigned int hfp);
+
+extern void* LCD_SetFrameBufferAddress(void *address);
+
+extern void LCD_SetFrameSize(unsigned int frameSize);
+
+extern void LCD_SetBurstLength(unsigned int burstLength);
+
+extern void LCD_SetContrastPrescaler(unsigned int prescaler);
+
+extern void LCD_SetContrastPolarity(unsigned int polarity);
+
+extern void LCD_SetContrastValue(unsigned int value);
+
+extern void LCD_EnableContrast(void);
+
+extern void LCD_SetPixelClock(unsigned int masterClock, unsigned int pixelClock);
+
+extern void LCD_DMAReset(void);
+
+extern void LCD_DecodeRGB(
+ unsigned char *file,
+ unsigned char *bufferLCD,
+ unsigned int width,
+ unsigned int height,
+ unsigned char bpp);
+
+#endif //#ifndef LCD_H
+
diff --git a/peripherals/mci/mci.c b/peripherals/mci/mci.c new file mode 100644 index 0000000..d829f85 --- /dev/null +++ b/peripherals/mci/mci.c @@ -0,0 +1,712 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "mci.h"
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Local constants
+//------------------------------------------------------------------------------
+
+/// Bit mask for status register errors.
+#define STATUS_ERRORS ((unsigned int)(AT91C_MCI_UNRE \
+ | AT91C_MCI_OVRE \
+ | AT91C_MCI_DTOE \
+ | AT91C_MCI_DCRCE \
+ | AT91C_MCI_RTOE \
+ | AT91C_MCI_RENDE \
+ | AT91C_MCI_RCRCE \
+ | AT91C_MCI_RDIRE \
+ | AT91C_MCI_RINDE))
+
+/// MCI data timeout configuration with 1048576 MCK cycles between 2 data transfers.
+#define DTOR_1MEGA_CYCLES (AT91C_MCI_DTOCYC | AT91C_MCI_DTOMUL)
+
+/// MCI MR: disable MCI Clock when FIFO is full
+#ifndef AT91C_MCI_WRPROOF
+ #define AT91C_MCI_WRPROOF 0
+#endif
+#ifndef AT91C_MCI_RDPROOF
+ #define AT91C_MCI_RDPROOF 0
+#endif
+
+#define SDCARD_APP_OP_COND_CMD (41 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO )
+#define MMC_SEND_OP_COND_CMD (1 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_OPDCMD)
+
+
+#define DISABLE 0 // Disable MCI interface
+#define ENABLE 1 // Enable MCI interface
+
+
+//------------------------------------------------------------------------------
+// Local macros
+//------------------------------------------------------------------------------
+
+/// Used to write in PMC registers.
+#define WRITE_PMC(pPmc, regName, value) pPmc->regName = (value)
+
+/// Used to write in MCI registers.
+#define WRITE_MCI(pMci, regName, value) pMci->regName = (value)
+
+/// Used to read from MCI registers.
+#define READ_MCI(pMci, regName) (pMci->regName)
+
+/// Enable MCI Peripheral
+#define PERIPH_ENABLE(mciId) WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << mciId))
+/// Disable MCI Peripheral
+#define PERIPH_DISABLE(mciId) WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << mciId))
+
+/// Enable MCI
+#define MCI_ENABLE(pMciHw) WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIEN)
+/// Disable MCI
+#define MCI_DISABLE(pMciHw) WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS)
+/// Reset MCI
+#define MCI_RESET(pMciHw) WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST)
+
+//------------------------------------------------------------------------------
+// Internal functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Delay some loop
+//------------------------------------------------------------------------------
+static void Delay(volatile unsigned int loop)
+{
+ for(;loop > 0; loop --);
+}
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Reset MCI interface and disable it.
+/// \param keepSettings Keep old register settings, including _MR, _SDCR, _DTOR
+//------------------------------------------------------------------------------
+void MCI_Reset(AT91PS_MCI pMciHw, unsigned int keepSettings)
+{
+ if (keepSettings) {
+
+ unsigned int mciMr, mciSdcr, mciDtor;
+
+ mciMr = READ_MCI(pMciHw, MCI_MR);
+ mciSdcr = READ_MCI(pMciHw, MCI_SDCR);
+ mciDtor = READ_MCI(pMciHw, MCI_DTOR);
+
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST);
+
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS);
+ WRITE_MCI(pMciHw, MCI_MR, mciMr);
+ WRITE_MCI(pMciHw, MCI_SDCR, mciSdcr);
+ WRITE_MCI(pMciHw, MCI_DTOR, mciDtor);
+ }
+ else {
+
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST);
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Enable/disable a MCI driver instance.
+/// \param pMci Pointer to a MCI driver instance.
+/// \param enb 0 for disable MCI and 1 for enable MCI.
+//------------------------------------------------------------------------------
+void MCI_Enable(Mci *pMci, unsigned char enb)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMci->pMciHw);
+
+ // Set the Control Register: Enable/Disable MCI interface clock
+ if(enb == DISABLE) {
+ MCI_DISABLE(pMciHw);
+ }
+ else {
+ MCI_ENABLE(pMciHw);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Initializes a MCI driver instance and the underlying peripheral.
+/// \param pMci Pointer to a MCI driver instance.
+/// \param pMciHw Pointer to a MCI peripheral.
+/// \param mciId MCI peripheral identifier.
+/// \param mode Slot and type of connected card.
+//------------------------------------------------------------------------------
+void MCI_Init(
+ Mci *pMci,
+ AT91S_MCI *pMciHw,
+ unsigned char mciId,
+ unsigned int mode,
+ unsigned int bPolling)
+{
+ unsigned short clkDiv;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMciHw);
+ SANITY_CHECK((mode == MCI_MMC_SLOTA) || (mode == MCI_SD_SLOTA)
+ || (mode == MCI_MMC_SLOTB) || (mode == MCI_SD_SLOTB));
+
+ // Initialize the MCI driver structure
+ pMci->pMciHw = pMciHw;
+ pMci->mciId = mciId;
+ pMci->mciMode = mode;
+ pMci->bPolling = bPolling;
+ pMci->semaphore = 1;
+ pMci->pCommand = 0;
+
+#if !defined(OP_BOOTSTRAP_MCI_on) || defined(at91sam9g20)
+ // Enable the MCI peripheral
+ PERIPH_ENABLE(mciId);
+
+ // Reset the MCI
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST);
+
+ // Disable the MCI
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS);
+
+ // Disable all the interrupts
+ WRITE_MCI(pMciHw, MCI_IDR, 0xFFFFFFFF);
+
+ // Set the Data Timeout Register
+ WRITE_MCI(pMciHw, MCI_DTOR, DTOR_1MEGA_CYCLES);
+
+ // Set the Mode Register: 400KHz for MCK = 48MHz (CLKDIV = 58)
+ clkDiv = (BOARD_MCK / (MCI_INITIAL_SPEED * 2)) - 1;
+ WRITE_MCI(pMciHw, MCI_MR, (clkDiv | (AT91C_MCI_PWSDIV & (0x7 << 8))));
+
+ // Set the SDCard Register
+ WRITE_MCI(pMciHw, MCI_SDCR, mode);
+
+ // Enable the MCI and the Power Saving
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIEN);
+
+ // Disable the MCI peripheral clock.
+ PERIPH_DISABLE(mciId);
+#else
+ // Assume ROM code initialize the MCI already
+ TRACE_INFO("SD bootstrap not init mci!\n\r");
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Close a MCI driver instance and the underlying peripheral.
+/// \param pMci Pointer to a MCI driver instance.
+/// \param pMciHw Pointer to a MCI peripheral.
+/// \param mciId MCI peripheral identifier.
+//------------------------------------------------------------------------------
+void MCI_Close(Mci *pMci)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+
+ SANITY_CHECK(pMci);
+
+ if (!pMciHw)
+ return;
+
+ // Disable the MCI
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS);
+
+ // Disable all the interrupts
+ WRITE_MCI(pMciHw, MCI_IDR, 0xFFFFFFFF);
+
+ // Disable the MCI peripheral clock.
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pMci->mciId));
+
+ // Initialize the MCI driver structure
+ pMci->semaphore = 1;
+ pMci->pCommand = 0;
+}
+
+//------------------------------------------------------------------------------
+/// Get the MCI CLKDIV in the MCI_MR register. The max. for MCI clock is
+/// MCK/2 and corresponds to CLKDIV = 0
+/// \param pMci Pointer to the low level MCI driver.
+/// \return The current speed used, 0 for fail.
+//------------------------------------------------------------------------------
+unsigned int MCI_GetSpeed(Mci *pMci, unsigned int *mciDiv)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ unsigned int mciMr;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMci->pMciHw);
+
+ // Get the Mode Register
+ mciMr = READ_MCI(pMciHw, MCI_MR);
+ mciMr &= AT91C_MCI_CLKDIV;
+ if (mciDiv) *mciDiv = mciMr;
+ return (BOARD_MCK / 2 / (mciMr + 1));
+}
+
+//------------------------------------------------------------------------------
+/// Configure the MCI CLKDIV in the MCI_MR register. The max. for MCI clock is
+/// MCK/2 and corresponds to CLKDIV = 0
+/// \param pMci Pointer to the low level MCI driver.
+/// \param mciSpeed MCI clock speed in Hz.
+/// \param mciLimit MCI clock limit in Hz, if not limit, set mciLimit to zero.
+/// \param mck MCK to generate MCI Clock, in Hz
+/// \return The actual speed used, 0 for fail.
+//------------------------------------------------------------------------------
+unsigned int MCI_SetSpeed(Mci *pMci,
+ unsigned int mciSpeed,
+ unsigned int mciLimit,
+ unsigned int mck)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ unsigned int mciMr;
+ unsigned int clkdiv;
+ unsigned int divLimit = 0;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMci->pMciHw);
+
+ mciMr = READ_MCI(pMciHw, MCI_MR) & (~(unsigned int)AT91C_MCI_CLKDIV);
+
+ // Multimedia Card Interface clock (MCCK or MCI_CK) is Master Clock (MCK)
+ // divided by (2*(CLKDIV+1))
+ // mciSpeed = MCK / (2*(CLKDIV+1))
+ if (mciLimit) {
+ divLimit = (mck / 2 / mciLimit);
+ if ((mck / 2) % mciLimit) divLimit ++;
+ }
+ if (mciSpeed > 0) {
+ clkdiv = (mck / 2 / mciSpeed);
+ if (mciLimit && clkdiv < divLimit)
+ clkdiv = divLimit;
+ if (clkdiv > 0)
+ clkdiv -= 1;
+ ASSERT( (clkdiv & 0xFFFFFF00) == 0, "mciSpeed too small");
+ }
+ else clkdiv = 0;
+
+ // Actual MCI speed
+ mciSpeed = mck / 2 / (clkdiv + 1);
+
+ // Set the Data Timeout Register & Completion Timeout
+ // Data timeout is 500ms, completion timeout 1s.
+ //MCI_SetTimeout(pMciHw, mciSpeed / 2, mciSpeed);
+
+ WRITE_MCI(pMciHw, MCI_MR, mciMr | clkdiv);
+ return (mciSpeed);
+}
+
+//------------------------------------------------------------------------------
+/// Configure the MCI_CFG to enable the HS mode (MCI2 only)
+/// \param pMci Pointer to the low level MCI driver.
+/// \param hsEnable 1 to enable, 0 to disable HS mode.
+//------------------------------------------------------------------------------
+void MCI_EnableHsMode(Mci *pMci, unsigned char hsEnable)
+{
+}
+
+//------------------------------------------------------------------------------
+/// Configure the MCI SDCBUS in the MCI_SDCR register. Only two modes available
+///
+/// \param pMci Pointer to the low level MCI driver.
+/// \param busWidth MCI bus width mode.
+//------------------------------------------------------------------------------
+void MCI_SetBusWidth(Mci *pMci, unsigned char busWidth)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ unsigned int mciSdcr;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMci->pMciHw);
+
+ mciSdcr = (READ_MCI(pMciHw, MCI_SDCR) & ~((unsigned int)AT91C_MCI_SCDBUS));
+
+ WRITE_MCI(pMciHw, MCI_SDCR, mciSdcr | busWidth);
+}
+
+//------------------------------------------------------------------------------
+/// Starts a MCI transfer. This is a non blocking function. It will return
+/// as soon as the transfer is started.
+/// Return 0 if successful; otherwise returns MCI_ERROR_LOCK if the driver is
+/// already in use.
+/// \param pMci Pointer to an MCI driver instance.
+/// \param pCommand Pointer to the command to execute.
+//------------------------------------------------------------------------------
+unsigned char MCI_SendCommand(Mci *pMci, MciCmd *pCommand)
+{
+ AT91PS_MCI pMciHw = pMci->pMciHw;
+ unsigned int mciIer, mciMr;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMciHw);
+ SANITY_CHECK(pCommand);
+
+ // Try to acquire the MCI semaphore
+ if (pMci->semaphore == 0) {
+
+ return MCI_ERROR_LOCK;
+ }
+ pMci->semaphore--;
+ // TRACE_DEBUG("MCI_SendCommand %x %d\n\r", READ_MCI(pMciHw, MCI_SR), pCommand->cmd & 0x3f);
+
+ // Command is now being executed
+ pMci->pCommand = pCommand;
+ pCommand->status = MCI_STATUS_PENDING;
+
+ // Enable the MCI Peripheral clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pMci->mciId));
+
+ // Disable MCI clock
+ //MCI_DISABLE(pMciHw);
+
+ // Init PDC direction or (SR status bits error occure)
+ if (pCommand->isRead)
+ WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTEN);
+ else
+ WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_TXTEN);
+
+ // Disable transmitter and receiver
+ WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+
+ mciMr = READ_MCI(pMciHw, MCI_MR) & (~( AT91C_MCI_WRPROOF
+ | AT91C_MCI_RDPROOF
+ | AT91C_MCI_BLKLEN
+ | AT91C_MCI_PDCMODE));
+
+ // Command with DATA stage
+ if (pCommand->blockSize && pCommand->nbBlock) {
+
+ #if defined(AT91C_MCI_PDCFBYTE)
+ // Force byte mode is block size is not 4n
+ if ((pCommand->blockSize & 0x3)) {
+ mciMr |= AT91C_MCI_PDCFBYTE;
+
+ // Set byte count
+ WRITE_MCI(pMciHw, MCI_BLKR, (READ_MCI(pMciHw, MCI_BLKR)
+ & (~(unsigned int)AT91C_MCI_BCNT))
+ | pCommand->nbBlock);
+ }
+ #endif
+
+ // Enable PDC mode and set block size
+ if(pCommand->tranType != MCI_CONTINUE_TRANSFER) {
+
+
+ WRITE_MCI(pMciHw, MCI_MR, mciMr | AT91C_MCI_PDCMODE
+ | AT91C_MCI_RDPROOF
+ | AT91C_MCI_WRPROOF
+ |(pCommand->blockSize << 16));
+ }
+
+ // Sanity check
+ if (pCommand->nbBlock == 0)
+ pCommand->nbBlock = 1;
+
+ // DATA transfer from card to host
+ if (pCommand->isRead) {
+ WRITE_MCI(pMciHw, MCI_RPR, (int) pCommand->pData);
+
+ // Update the PDC counter
+ #if defined(AT91C_MCI_PDCFBYTE)
+ if ((pCommand->blockSize & 0x3) != 0) {
+ // Force byte read
+ WRITE_MCI(pMciHw, MCI_RCR, (pCommand->nbBlock * pCommand->blockSize));
+ }
+ else
+ #endif
+ {
+ WRITE_MCI(pMciHw, MCI_RCR, (pCommand->nbBlock * pCommand->blockSize) / 4);
+ }
+ WRITE_MCI(pMciHw, MCI_RNCR, 0);
+
+ WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTEN);
+ mciIer = AT91C_MCI_ENDRX | STATUS_ERRORS;
+ }
+
+ // DATA transfer from host to card
+ else {
+
+ WRITE_MCI(pMciHw, MCI_TPR, (int) pCommand->pData);
+ // Update the PDC counter
+ #if defined(AT91C_MCI_PDCFBYTE)
+ if ((pCommand->blockSize & 0x3) != 0) {
+ // Force byte write
+ WRITE_MCI(pMciHw, MCI_TCR, (pCommand->nbBlock * pCommand->blockSize));
+ }
+ else
+ #endif
+ {
+ WRITE_MCI(pMciHw, MCI_TCR, (pCommand->nbBlock * pCommand->blockSize) / 4);
+ }
+ WRITE_MCI(pMciHw, MCI_TNCR, 0);
+ // MCI_BLKE notifies the end of Multiblock command
+ mciIer = AT91C_MCI_ENDTX | STATUS_ERRORS;
+ }
+ }
+ // Start an infinite block transfer (but no data in current command)
+ else if (pCommand->dataTran) {
+ // Set block size
+ WRITE_MCI(pMciHw, MCI_MR, mciMr | AT91C_MCI_RDPROOF
+ | AT91C_MCI_WRPROOF
+ |(pCommand->blockSize << 16));
+ // Set data length: 0, no PDC operation
+ mciIer = AT91C_MCI_CMDRDY | STATUS_ERRORS;
+ }
+ // No data transfer: stop at the end of the command
+ else {
+ WRITE_MCI(pMciHw, MCI_MR, mciMr);
+ mciIer = AT91C_MCI_CMDRDY | STATUS_ERRORS;
+ }
+ // Enable MCI clock
+ MCI_ENABLE(pMciHw);
+
+ // Send the command
+ if((pCommand->tranType != MCI_CONTINUE_TRANSFER)
+ || (pCommand->blockSize == 0)) {
+
+ WRITE_MCI(pMciHw, MCI_ARGR, pCommand->arg);
+ WRITE_MCI(pMciHw, MCI_CMDR, pCommand->cmd);
+ }
+
+ // In case of transmit, the PDC shall be enabled after sending the command
+ if (pCommand->blockSize > 0) {
+ if (!pCommand->isRead) {
+ WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_TXTEN);
+ }
+ }
+
+ // Ignore CRC error for R3 & R4
+ if (pCommand->resType == 3 || pCommand->resType == 4) {
+ mciIer &= ~((unsigned int)AT91C_MCI_RCRCE);
+ }
+ // Ignore data error on stop command :)
+ if (pCommand->tranType == MCI_STOP_TRANSFER) {
+ mciIer &= ~(unsigned int)(AT91C_MCI_DTOE | AT91C_MCI_DCRCE);
+ }
+
+ // Ignore data error
+ mciIer &= ~(unsigned int)(AT91C_MCI_UNRE | AT91C_MCI_OVRE
+ | AT91C_MCI_DTOE | AT91C_MCI_DCRCE);
+
+ // Interrupt enable shall be done after PDC TXTEN and RXTEN
+ WRITE_MCI(pMciHw, MCI_IER, mciIer);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Check NOTBUSY and DTIP bits of status register on the given MCI driver.
+/// Return value, 0 for bus ready, 1 for bus busy
+/// \param pMci Pointer to a MCI driver instance.
+//------------------------------------------------------------------------------
+unsigned char MCI_CheckBusy(Mci *pMci)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ unsigned int status;
+
+ // Enable MCI clock
+ PERIPH_ENABLE(pMci->mciId);
+ MCI_ENABLE(pMciHw);
+
+ status = READ_MCI(pMciHw, MCI_SR);
+ // TRACE_DEBUG("status %x\n\r",status);
+
+ if(((status & AT91C_MCI_NOTBUSY)!=0)
+ && ((status & AT91C_MCI_DTIP)==0)) {
+
+ // Disable MCI clock
+ MCI_DISABLE(pMciHw);
+ PERIPH_DISABLE(pMci->mciId);
+
+ return 0;
+ }
+ else {
+ return 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Processes pending events on the given MCI driver.
+/// \param pMci Pointer to a MCI driver instance.
+//------------------------------------------------------------------------------
+void MCI_Handler(Mci *pMci)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ MciCmd *pCommand = pMci->pCommand;
+ unsigned int status, status0, mask;
+ unsigned char i;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMciHw);
+ SANITY_CHECK(pCommand);
+
+ // Read the status register
+ status0 = READ_MCI(pMciHw, MCI_SR);
+ mask = READ_MCI(pMciHw, MCI_IMR);
+ status = status0 & mask;
+ TRACE_DEBUG("status %x & %x, %x\n\r", status0, mask, status);
+
+ // Check if an error has occured
+ if ((status & STATUS_ERRORS) != 0) {
+
+ // Check error code
+ if ((status & STATUS_ERRORS) == AT91C_MCI_RTOE) {
+
+ pCommand->status = MCI_STATUS_NORESPONSE;
+ }
+ // if the command is SEND_OP_COND the CRC error flag is always present
+ // (cf : R3 response)
+ else if (((status & STATUS_ERRORS) != AT91C_MCI_RCRCE)
+ || ((pCommand->cmd != SDCARD_APP_OP_COND_CMD)
+ && (pCommand->cmd != MMC_SEND_OP_COND_CMD))) {
+
+ pCommand->status = MCI_STATUS_ERROR;
+ }
+ }
+
+ // Check if writing end
+ if (((status & AT91C_MCI_ENDTX) != 0)
+ || ((status & AT91C_MCI_TXBUFE) != 0)) {
+ WRITE_MCI(pMciHw, MCI_IDR, (AT91C_MCI_ENDTX|AT91C_MCI_TXBUFE));
+ if ((status0 & AT91C_MCI_BLKE) == 0)
+ WRITE_MCI(pMciHw, MCI_IER, AT91C_MCI_BLKE);
+ else
+ status |= AT91C_MCI_BLKE;
+ }
+
+ // Check if a transfer has been completed
+ if (((status & AT91C_MCI_CMDRDY) != 0)
+ || ((status & AT91C_MCI_ENDRX) != 0)
+ || ((status & AT91C_MCI_RXBUFF) != 0)
+ || ((status & AT91C_MCI_BLKE) != 0)
+ || ((status & AT91C_MCI_RTOE) != 0)) {
+
+ // Store the card response in the provided buffer
+ if (pCommand->pResp) {
+ unsigned char resSize;
+
+ switch (pCommand->resType) {
+ case 2:
+ resSize = 4;
+ break;
+
+ case 1: case 3: case 4: case 5: case 6: case 7:
+ resSize = 1;
+ break;
+
+ default:
+ resSize = 0;
+ break;
+ }
+ for (i=0; i < resSize; i++) {
+
+ pCommand->pResp[i] = READ_MCI(pMciHw, MCI_RSPR[0]);
+ }
+ }
+
+ TRACE_DEBUG(" ** CmdE\n\r");
+ Delay(1000);
+
+ // If no RD proof, FIFO may have dummy bytes
+ // Reset the MCI to clear these dummy data
+ #if (AT91C_MCI_RDPROOF == 0)
+ if ((pCommand->cmd & AT91C_MCI_TRCMD_STOP) != 0) {
+ MCI_Reset(pMciHw, 1);
+ }
+ #endif
+
+ // Disable MCI
+ MCI_DISABLE(pMciHw);
+
+ // Stop PDC
+ WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+
+ // If no error occured, the transfer is successful
+ if (pCommand->status == MCI_STATUS_PENDING) {
+ pCommand->status = 0;
+ }
+ // If data in progress, reset MCI
+ else if (pCommand->dataTran) {
+ WRITE_MCI(pMciHw, MCI_TCR, 0);
+ WRITE_MCI(pMciHw, MCI_RCR, 0);
+ // Clear BUSY ... How ?
+ MCI_Reset(pMciHw, 1);
+ }
+#if 0
+ if ((status & AT91C_MCI_CMDRDY) != 0)
+ TRACE_DEBUG_WP(".");
+ if ((status & AT91C_MCI_ENDRX) != 0)
+ TRACE_DEBUG_WP("<");
+ if ((status & AT91C_MCI_ENDTX) != 0)
+ TRACE_DEBUG_WP("-");
+ if ((status & AT91C_MCI_BLKE) != 0)
+ TRACE_DEBUG_WP(">");
+ TRACE_DEBUG_WP("\n\r");
+#endif
+
+ // Disable interrupts
+ WRITE_MCI(pMciHw, MCI_IDR, 0xFFFFFFFF);
+
+ // Disable peripheral
+ PERIPH_DISABLE(pMci->mciId);
+
+ // Release the semaphore
+ pMci->semaphore++;
+
+ // Invoke the callback associated with the current command (if any)
+ if (pCommand->callback) {
+ (pCommand->callback)(pCommand->status, pCommand);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the given MCI transfer is complete; otherwise returns 0.
+/// \param pCommand Pointer to a MciCmd instance.
+//------------------------------------------------------------------------------
+unsigned char MCI_IsTxComplete(Mci *pMci)
+{
+ MciCmd *pCommand = pMci->pCommand;
+
+ if(pMci->bPolling == MCI_POLLING_MODE) {
+ MCI_Handler(pMci);
+ }
+
+ if (pCommand->status != MCI_STATUS_PENDING) {
+ if (pCommand->status != 0) {
+ TRACE_DEBUG("MCI_IsTxComplete %d\n\r", pCommand->status);
+ }
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
diff --git a/peripherals/mci/mci.dir b/peripherals/mci/mci.dir new file mode 100644 index 0000000..28b8c85 --- /dev/null +++ b/peripherals/mci/mci.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the peripheral API for the MultiMedia Card Interface (MCI).
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/mci/mci.h b/peripherals/mci/mci.h new file mode 100644 index 0000000..5f39ec6 --- /dev/null +++ b/peripherals/mci/mci.h @@ -0,0 +1,227 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "mci"
+///
+/// !Purpose
+///
+/// This file provides a basic API for MCI configuration and send command from host through MCI.
+/// User can control device such as SD memory card, SDIO, MMC card through these interface.
+///
+/// !Usage
+///
+/// -# Use MCI_Init() to initialize MCI controller.
+/// -# Use MCI_SetSpeed() to set the MCI clock.
+/// -# Use MCI_SetBusWidth() to set the bus width between MCI controller and device.
+/// -# MCI_SendCommand() is used for host to send command to device through MCI interface.
+/// -# MCI_Handler() is the interrupt service routine.
+///
+/// !Functions
+///
+/// -# MCI_Init: Initializes a MCI driver instance and the underlying peripheral.
+/// -# MCI_SetSpeed : Configure the MCI CLKDIV in the MCI_MR register.
+/// -# MCI_SendCommand: Starts a MCI transfer.
+/// -# MCI_Handler : Interrupt handler which is called by ISR handler.
+/// -# MCI_SetBusWidth : Configure the MCI SDCBUS in the MCI_SDCR register.
+//------------------------------------------------------------------------------
+
+
+#ifndef MCI_H
+#define MCI_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+#define MCI_BUSY_CHECK_FIX 0
+
+#if defined(AT91C_MCI_TRTYP_SDIO_BLOCK) && defined(AT91C_MCI_TRTYP_SDIO_BYTE)
+#define MCI_SDIO_ENABLE 1
+#else
+#define MCI_SDIO_ENABLE 0
+#endif
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+/// Transfer is pending.
+#define MCI_STATUS_PENDING 1
+/// Transfer has been aborted because an error occured.
+#define MCI_STATUS_ERROR 2
+/// Card did not answer command.
+#define MCI_STATUS_NORESPONSE 3
+
+/// MCI driver is currently in use.
+#define MCI_ERROR_LOCK 1
+
+/// MCI configuration with 1-bit data bus on slot A (for MMC cards).
+#define MCI_MMC_SLOTA (AT91C_MCI_SCDSEL_SLOTA | AT91C_MCI_SCDBUS_1BIT)
+/// MCI configuration with 4-bit data bus on slot A (for SD cards).
+#define MCI_SD_SLOTA (AT91C_MCI_SCDSEL_SLOTA | AT91C_MCI_SCDBUS_4BITS)
+#ifdef AT91C_MCI_SCDBUS_8BITS
+/// MCI configuration with 1-bit data bus on slot A (for MMC cards).
+#define MCI_MMC4_SLOTA (AT91C_MCI_SCDSEL_SLOTA | AT91C_MCI_SCDBUS_8BITS)
+#endif
+#ifdef AT91C_MCI_SCDSEL_SLOTB
+/// MCI configuration with 1-bit data bus on slot B (for MMC cards).
+#define MCI_MMC_SLOTB (AT91C_MCI_SCDSEL_SLOTB | AT91C_MCI_SCDBUS_1BIT)
+/// MCI configuration with 4-bit data bus on slot B (for SD cards).
+#define MCI_SD_SLOTB (AT91C_MCI_SCDSEL_SLOTB | AT91C_MCI_SCDBUS_4BITS)
+#ifdef AT91C_MCI_SCDBUS_8BITS
+/// MCI configuration with 1-bit data bus on slot A (for MMC cards).
+#define MCI_MMC4_SLOTB (AT91C_MCI_SCDSEL_SLOTB | AT91C_MCI_SCDBUS_8BITS)
+#endif
+#else
+#define MCI_MMC_SLOTB MCI_MMC_SLOTA
+#define MCI_SD_SLOTB MCI_SD_SLOTA
+#endif
+
+/// Start new data transfer
+#define MCI_NEW_TRANSFER 0
+/// Continue data transfer
+#define MCI_CONTINUE_TRANSFER 1
+/// Stop data transfer
+#define MCI_STOP_TRANSFER 2
+
+
+/// MCI SD Bus Width 1-bit
+#define MCI_SDCBUS_1BIT (0 << 7)
+/// MCI SD Bus Width 4-bit
+#define MCI_SDCBUS_4BIT (1 << 7)
+/// MCI SD Bus Width 8-bit
+#define MCI_SDCBUS_8BIT (3 << 6)
+
+/// The MCI Clock Speed after initialize (400K)
+#define MCI_INITIAL_SPEED 400000
+
+#define MCI_INTERRUPT_MODE 0
+#define MCI_POLLING_MODE 1
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// MCI end-of-transfer callback function.
+typedef void (*MciCallback)(unsigned char status, void *pCommand);
+
+//------------------------------------------------------------------------------
+/// MCI Transfer Request prepared by the application upper layer. This structure
+/// is sent to the MCI_SendCommand function to start the transfer. At the end of
+/// the transfer, the callback is invoked by the interrupt handler.
+//------------------------------------------------------------------------------
+typedef struct _MciCmd {
+
+ /// Command code.
+ unsigned int cmd;
+ /// Command argument.
+ unsigned int arg;
+ /// Data buffer.
+ unsigned char *pData;
+ /// Size of data block in bytes.
+ unsigned short blockSize;
+ /// Number of blocks to be transfered
+ unsigned short nbBlock;
+ /// Response buffer.
+ unsigned int *pResp;
+ /// Optional user-provided callback function.
+ MciCallback callback;
+ /// Optional argument to the callback function.
+ void *pArg;
+
+ /// SD card response type.
+ unsigned char resType;
+ /// Indicate if there is data transfer
+ unsigned char dataTran;
+ /// Indicate if continue to transfer data
+ unsigned char tranType;
+ /// Indicates if the command is a read operation.
+ unsigned char isRead;
+
+ /// Command status.
+ volatile int status;
+} MciCmd;
+
+//------------------------------------------------------------------------------
+/// MCI driver structure. Holds the internal state of the MCI driver and
+/// prevents parallel access to a MCI peripheral.
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// Pointer to a MCI peripheral.
+ AT91S_MCI *pMciHw;
+ /// Pointer to currently executing command.
+ MciCmd *pCommand;
+ /// MCI peripheral identifier.
+ unsigned char mciId;
+ /// MCI HW support mode
+ unsigned char mciMode;
+ /// Mutex.
+ volatile char semaphore;
+ /// interrupt or polling mode
+ unsigned int bPolling;
+} Mci;
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void MCI_Init(
+ Mci *pMci,
+ AT91PS_MCI pMciHw,
+ unsigned char mciId,
+ unsigned int mode,
+ unsigned int bPolling);
+
+extern unsigned int MCI_GetSpeed(Mci *pMci, unsigned int *mciDiv);
+
+extern unsigned int MCI_SetSpeed(Mci *pMci,
+ unsigned int mciSpeed,
+ unsigned int mciLimit,
+ unsigned int mck);
+
+extern unsigned char MCI_SendCommand(Mci *pMci, MciCmd *pMciCmd);
+
+extern void MCI_Handler(Mci *pMci);
+
+extern unsigned char MCI_IsTxComplete(Mci *pMci);
+
+extern unsigned char MCI_CheckBusy(Mci *pMci);
+
+extern void MCI_Close(Mci *pMci);
+
+extern void MCI_EnableHsMode(Mci * pMci, unsigned char hsEnable);
+
+extern void MCI_SetBusWidth(Mci *pMci, unsigned char busWidth);
+
+#endif //#ifndef MCI_H
+
diff --git a/peripherals/mci/mci_hs.c b/peripherals/mci/mci_hs.c new file mode 100644 index 0000000..d7c45ed --- /dev/null +++ b/peripherals/mci/mci_hs.c @@ -0,0 +1,1283 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "mci_hs.h"
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+#include <dmad/dmad.h>
+#include <dma/dma.h>
+
+//------------------------------------------------------------------------------
+// Local constants
+//------------------------------------------------------------------------------
+
+/// Bit mask for status register errors.
+#define STATUS_ERRORS ((unsigned int)(AT91C_MCI_UNRE \
+ | AT91C_MCI_OVRE \
+ | AT91C_MCI_BLKOVRE \
+ | AT91C_MCI_CSTOE \
+ | AT91C_MCI_DTOE \
+ | AT91C_MCI_DCRCE \
+ | AT91C_MCI_RTOE \
+ | AT91C_MCI_RENDE \
+ | AT91C_MCI_RCRCE \
+ | AT91C_MCI_RDIRE \
+ | AT91C_MCI_RINDE))
+
+#define STATUS_ERRORS_RESP ((unsigned int)(AT91C_MCI_CSTOE \
+ | AT91C_MCI_RTOE \
+ | AT91C_MCI_RENDE \
+ | AT91C_MCI_RCRCE \
+ | AT91C_MCI_RDIRE \
+ | AT91C_MCI_RINDE))
+
+#define STATUS_ERRORS_DATA ((unsigned int)(AT91C_MCI_UNRE \
+ | AT91C_MCI_OVRE \
+ | AT91C_MCI_BLKOVRE \
+ | AT91C_MCI_CSTOE \
+ | AT91C_MCI_DTOE \
+ | AT91C_MCI_DCRCE))
+
+
+/// MCI data timeout configuration with 1048576 MCK cycles between 2 data transfers.
+#define DTOR_1MEGA_CYCLES (AT91C_MCI_DTOCYC | AT91C_MCI_DTOMUL)
+
+/// MCI MR: disable MCI Clock when FIFO is full
+#ifndef AT91C_MCI_WRPROOF
+ #define AT91C_MCI_WRPROOF 0
+#endif
+#ifndef AT91C_MCI_RDPROOF
+ #define AT91C_MCI_RDPROOF 0
+#endif
+
+#define SDCARD_APP_OP_COND_CMD (41 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_NO )
+#define MMC_SEND_OP_COND_CMD (1 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_OPDCMD)
+#define SDIO_SEND_OP_COND_CMD (5 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_OPDCMD)
+
+
+#define DISABLE 0 // Disable MCI interface
+#define ENABLE 1 // Enable MCI interface
+
+
+//------------------------------------------------------------------------------
+// Local macros
+//------------------------------------------------------------------------------
+
+/// Used to write in PMC registers.
+#define WRITE_PMC(pPmc, regName, value) pPmc->regName = (value)
+
+/// Used to write in MCI registers.
+#define WRITE_MCI(pMci, regName, value) pMci->regName = (value)
+
+/// Used to read from MCI registers.
+#define READ_MCI(pMci, regName) (pMci->regName)
+
+/// Enable MCI Peripheral
+#define PERIPH_ENABLE(mciId) WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << mciId))
+/// Disable MCI Peripheral
+#define PERIPH_DISABLE(mciId) WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << mciId))
+
+/// Enable MCI
+#define MCI_ENABLE(pMciHw) WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIEN)
+/// Disable MCI
+#define MCI_DISABLE(pMciHw) WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS)
+/// Reset MCI
+#define MCI_RESET(pMciHw) WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST)
+
+/// Return word count from byte count
+#define toHWCOUNT(byteCnt) (((byteCnt)&0x1) ? (((byteCnt)/2)+1) : ((byteCnt)/2))
+#define toWCOUNT(byteCnt) (((byteCnt)&0x3) ? (((byteCnt)/4)+1) : ((byteCnt)/4))
+
+//------------------------------------------------------------------------------
+// Local variables
+//------------------------------------------------------------------------------
+
+//static unsigned char perChunkSize = 1;
+//static unsigned char memChunkSize = 1;
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+#if defined(MCI_DMA_ENABLE)
+#define MCI_RD_FIFO_LIMIT 1
+
+#define MCI_FIFO_SIZE (0x4000-0x400) // 15.5K
+static unsigned short xfredBlocks = 0xFFFF;
+static unsigned char dmaLastLliNdx = 0;
+
+#define DMA_XFR_SIZE (0xF00) // SAM3: 0xFFF, 9M10: 0xFFFF
+#define NUM_LLI (5)
+#define DMA_TOTAL (DMA_XFR_SIZE*NUM_LLI)
+static DmaLinkList LLI_MCI [NUM_LLI]; // Max: > 64K Bytes
+
+#define LAST_ROW 0x100
+static void AT91F_Prepare_Multiple_Transfer(unsigned int Channel,
+ unsigned int LLI_rownumber,
+ unsigned int LLI_Last_Row,
+ unsigned int From_add,
+ unsigned int To_add,
+ unsigned int Ctrla,
+ unsigned int Ctrlb)
+{
+ LLI_MCI[LLI_rownumber].sourceAddress = From_add;
+ LLI_MCI[LLI_rownumber].destAddress = To_add;
+ LLI_MCI[LLI_rownumber].controlA = Ctrla;
+ LLI_MCI[LLI_rownumber].controlB = Ctrlb;
+ if (LLI_Last_Row != LAST_ROW)
+ LLI_MCI[LLI_rownumber].descriptor =
+ (unsigned int)&LLI_MCI[LLI_rownumber + 1] + 0;
+ else {
+ dmaLastLliNdx = LLI_rownumber;
+ LLI_MCI[LLI_rownumber].descriptor = 0;
+ }
+}
+
+// trans_size: number of transfers in SRC side
+// forceByte: 1 - byte count, 0 - word count
+static unsigned int DMACH_MCI_P2M(unsigned int channel_index,
+ unsigned char* src_addr,
+ unsigned char* dest_addr,
+ unsigned int trans_size,
+ unsigned char addrIncMode,
+ unsigned char forceByte)
+{
+ unsigned int srcAddress;
+ unsigned int destAddress;
+ unsigned int buffSize;
+ unsigned int LLI_rownumber = 0;
+ unsigned int srcAddressMode = addrIncMode ?
+ (AT91C_HDMA_SRC_ADDRESS_MODE_INCR)
+ : (AT91C_HDMA_SRC_ADDRESS_MODE_FIXED);
+ unsigned int scSize, dcSize, mWidth, perWidth, addrInc;
+
+ // Disable dma channel
+ DMA_DisableChannel(channel_index);
+
+ // DMA channel configuration
+ srcAddress = (unsigned int)src_addr; // Set the data start address
+ destAddress = (unsigned int)dest_addr; //(unsigned int)SSC_THR_ADD;
+ buffSize = trans_size;
+
+ // Memory width can be WORD if address is aligned
+ mWidth = ((destAddress & 0x3) == 0) ? AT91C_HDMA_DST_WIDTH_WORD
+ : AT91C_HDMA_DST_WIDTH_BYTE;
+ // Peripheral width is byte if FBYTE mode
+ perWidth = forceByte ? AT91C_HDMA_SRC_WIDTH_BYTE
+ : AT91C_HDMA_SRC_WIDTH_WORD;
+ addrInc = forceByte ? 1 : 4;
+ #if MCI_RD_FIFO_LIMIT
+ if(buffSize >= DMA_TOTAL){
+ TRACE_WARNING("SD DMA, size too big %d\n\r", buffSize);
+ buffSize = DMA_TOTAL;
+ }
+ #endif
+ // Set DMA channel source address
+ DMA_SetSourceAddr(channel_index, srcAddress);
+
+ // Set DMA channel destination address
+ DMA_SetDestinationAddr(channel_index,destAddress);
+
+ // Set DMA channel DSCR
+ DMA_SetDescriptorAddr(channel_index, (unsigned int)&LLI_MCI[0]);
+
+ // Set DMA channel control A
+ DMA_SetSourceBufferSize(channel_index, buffSize,
+ (perWidth >> 24),
+ (mWidth >> 28), 0);
+
+ //Set DMA channel control B
+ DMA_SetSourceBufferMode(channel_index, DMA_TRANSFER_LLI,
+ srcAddressMode >> 24);
+ DMA_SetDestBufferMode(channel_index, DMA_TRANSFER_LLI,
+ (AT91C_HDMA_DST_ADDRESS_MODE_INCR >> 28));
+
+ // Set DMA channel config
+ DMA_SetConfiguration(channel_index, BOARD_SD_DMA_HW_SRC_REQ_ID \
+ | BOARD_SD_DMA_HW_DEST_REQ_ID \
+ | AT91C_HDMA_SRC_H2SEL_HW \
+ | AT91C_HDMA_DST_H2SEL_HW \
+ | AT91C_HDMA_SOD_DISABLE \
+ | AT91C_HDMA_FIFOCFG_ENOUGHSPACE);
+
+ //scSize = (perChunkSize == 4) ? AT91C_HDMA_SCSIZE_4 : AT91C_HDMA_SCSIZE_1;
+ //dcSize = (memChunkSize == 4) ? AT91C_HDMA_DCSIZE_4 : AT91C_HDMA_DCSIZE_1;
+ scSize = AT91C_HDMA_SCSIZE_1; dcSize = AT91C_HDMA_DCSIZE_4;
+
+ // Set link list
+ buffSize *= addrInc; // convert size to byte count
+ while(destAddress < ((unsigned int)(dest_addr + buffSize))) {
+ if(((unsigned int)(dest_addr + buffSize)) - destAddress <= (DMA_XFR_SIZE*addrInc) )
+ {
+ AT91F_Prepare_Multiple_Transfer(channel_index, LLI_rownumber, LAST_ROW,
+ srcAddress,
+ destAddress,
+ (((((unsigned int)(dest_addr + buffSize))
+ - destAddress)/addrInc)
+ | perWidth
+ | mWidth
+ | scSize
+ | dcSize
+ ),
+ ( AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_DST_ADDRESS_MODE_INCR
+ | AT91C_HDMA_SRC_DSCR_FETCH_DISABLE
+ | srcAddressMode
+ | AT91C_HDMA_FC_PER2MEM));
+ }
+ else
+ {
+ AT91F_Prepare_Multiple_Transfer(channel_index, LLI_rownumber, 0,
+ srcAddress,
+ destAddress,
+ ( (DMA_XFR_SIZE)
+ | perWidth
+ | mWidth
+ | scSize
+ | dcSize
+ ),
+ ( AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_DST_ADDRESS_MODE_INCR
+ | AT91C_HDMA_SRC_DSCR_FETCH_DISABLE
+ | srcAddressMode
+ | AT91C_HDMA_FC_PER2MEM));
+
+ }
+
+ destAddress += DMA_XFR_SIZE*addrInc;
+
+ LLI_rownumber++;
+ }
+
+ return 0;
+}
+
+// trans_size: number of transfers in SRC side
+// forceByte: 1 - byte count, 0 - word count
+static unsigned int DMACH_MCI_M2P(unsigned int channel_index,
+ unsigned char* src_addr,
+ unsigned char* dest_addr,
+ unsigned int trans_size,
+ unsigned char addrIncMode,
+ unsigned char forceByte)
+{
+ unsigned int srcAddress;
+ unsigned int destAddress;
+ unsigned int buffSize;
+ unsigned int LLI_rownumber = 0;
+ unsigned int dstAddressMode = addrIncMode ?
+ (AT91C_HDMA_DST_ADDRESS_MODE_INCR)
+ : (AT91C_HDMA_DST_ADDRESS_MODE_FIXED);
+ unsigned int dcSize, scSize, mWidth, perWidth, addrInc;
+
+ // Disable dma channel
+ DMA_DisableChannel(channel_index);
+
+ buffSize = trans_size;
+ if(buffSize >= DMA_TOTAL){
+ TRACE_WARNING("SD DMA, size too big %d\n\r", buffSize);
+ buffSize = DMA_TOTAL;
+ }
+
+ // DMA channel configuration
+ srcAddress = (unsigned int)src_addr; // Set the data start address
+ destAddress = (unsigned int)dest_addr;
+
+ // Memory width
+ mWidth = ((srcAddress & 0x3) == 0) ? AT91C_HDMA_SRC_WIDTH_WORD
+ : AT91C_HDMA_SRC_WIDTH_BYTE;
+ // One Transfer size (1 or 4)
+ perWidth = forceByte ? AT91C_HDMA_DST_WIDTH_BYTE
+ : AT91C_HDMA_DST_WIDTH_WORD;
+ //addrInc = forceByte ? 1 : 4;
+ if (mWidth == AT91C_HDMA_SRC_WIDTH_BYTE) {
+ addrInc = 1;
+ if (!forceByte) buffSize *= 4;
+ }
+ else
+ addrInc = 4;
+
+ // Set DMA channel source address
+ DMA_SetSourceAddr(channel_index, srcAddress);
+
+ // Set DMA channel destination address
+ DMA_SetDestinationAddr(channel_index,destAddress);
+
+ // Set DMA channel DSCR
+ DMA_SetDescriptorAddr(channel_index, (unsigned int)&LLI_MCI[0]);
+
+ // Set DMA channel control A
+ DMA_SetSourceBufferSize(channel_index, buffSize,
+ (mWidth >> 24),
+ (perWidth >> 28), 0);
+
+ //Set DMA channel control B
+ DMA_SetSourceBufferMode(channel_index,
+ DMA_TRANSFER_LLI,
+ (AT91C_HDMA_SRC_ADDRESS_MODE_INCR >> 24));
+ DMA_SetDestBufferMode(channel_index,
+ DMA_TRANSFER_LLI,
+ dstAddressMode >> 28);
+
+ // Set DMA channel config
+ DMA_SetConfiguration(channel_index, BOARD_SD_DMA_HW_SRC_REQ_ID \
+ | BOARD_SD_DMA_HW_DEST_REQ_ID \
+ | AT91C_HDMA_SRC_H2SEL_SW \
+ | AT91C_HDMA_DST_H2SEL_HW \
+ | AT91C_HDMA_SOD_DISABLE \
+ | AT91C_HDMA_FIFOCFG_LARGESTBURST);
+ //dcSize = (perChunkSize == 4) ? AT91C_HDMA_DCSIZE_4 : AT91C_HDMA_DCSIZE_1;
+ //scSize = (memChunkSize == 4) ? AT91C_HDMA_SCSIZE_4 : AT91C_HDMA_SCSIZE_1;
+ dcSize = AT91C_HDMA_DCSIZE_1; scSize = AT91C_HDMA_SCSIZE_4;
+
+ // Set link list
+ buffSize *= addrInc; // convert to byte address
+ while(srcAddress < ((unsigned int)(src_addr + buffSize)))
+ {
+ if(((unsigned int)(src_addr + buffSize)) - srcAddress <= (DMA_XFR_SIZE*addrInc) )
+ {
+ AT91F_Prepare_Multiple_Transfer(channel_index, LLI_rownumber, LAST_ROW,
+ srcAddress,
+ destAddress,
+ (((((unsigned int)(src_addr + buffSize))
+ - srcAddress)/addrInc)
+ | mWidth
+ | perWidth
+ | scSize
+ | dcSize
+ ),
+ ( AT91C_HDMA_DST_DSCR_FETCH_DISABLE
+ | dstAddressMode
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_SRC_ADDRESS_MODE_INCR
+ | AT91C_HDMA_FC_MEM2PER));
+ }
+ else
+ {
+ AT91F_Prepare_Multiple_Transfer(channel_index, LLI_rownumber, 0,
+ srcAddress,
+ destAddress,
+ ( (DMA_XFR_SIZE)
+ | mWidth
+ | perWidth
+ | scSize
+ | dcSize
+ ),
+ ( AT91C_HDMA_DST_DSCR_FETCH_DISABLE
+ | dstAddressMode
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_SRC_ADDRESS_MODE_INCR
+ | AT91C_HDMA_FC_MEM2PER));
+
+ }
+
+ srcAddress += DMA_XFR_SIZE*addrInc;
+
+
+ LLI_rownumber++;
+ }
+
+ return 0;
+}
+
+static inline void DMACH_EnableIt(AT91S_MCI *pMciHw,
+ unsigned int channel)
+{
+ unsigned int intFlag;
+
+ intFlag = DMA_GetInterruptMask();
+ intFlag |= (AT91C_HDMA_BTC0 << channel);
+ DMA_EnableIt(intFlag);
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Reset MCI interface and disable it.
+/// \param keepSettings Keep old register settings, including _MR, _SDCR, _DTOR
+//------------------------------------------------------------------------------
+void MCI_Reset(AT91PS_MCI pMciHw, unsigned int keepSettings)
+{
+ if (keepSettings) {
+
+ unsigned int mciMr, mciSdcr, mciDtor, mciCstor;
+ unsigned int mciDma, mciCfg;
+
+ mciMr = READ_MCI(pMciHw, MCI_MR);
+ mciSdcr = READ_MCI(pMciHw, MCI_SDCR);
+ mciDtor = READ_MCI(pMciHw, MCI_DTOR);
+ mciCstor = READ_MCI(pMciHw, MCI_CSTOR);
+
+ mciDma = READ_MCI(pMciHw, MCI_DMA);
+ mciCfg = READ_MCI(pMciHw, MCI_CFG);
+
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST);
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS);
+
+ WRITE_MCI(pMciHw, MCI_MR, mciMr);
+ WRITE_MCI(pMciHw, MCI_SDCR, mciSdcr);
+ WRITE_MCI(pMciHw, MCI_DTOR, mciDtor);
+ WRITE_MCI(pMciHw, MCI_CSTOR, mciCstor);
+
+ WRITE_MCI(pMciHw, MCI_DMA, mciDma);
+ WRITE_MCI(pMciHw, MCI_CFG, mciCfg);
+ }
+ else {
+
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST);
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Enable/disable a MCI driver instance.
+/// \param pMci Pointer to a MCI driver instance.
+/// \param enb 0 for disable MCI and 1 for enable MCI.
+//------------------------------------------------------------------------------
+void MCI_Enable(Mci *pMci, unsigned char enb)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMci->pMciHw);
+
+ // Set the Control Register: Enable/Disable MCI interface clock
+ if(enb == DISABLE) {
+ MCI_DISABLE(pMciHw);
+ }
+ else {
+ MCI_ENABLE(pMciHw);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Initializes a MCI driver instance and the underlying peripheral.
+/// \param pMci Pointer to a MCI driver instance.
+/// \param pMciHw Pointer to a MCI peripheral.
+/// \param mciId MCI peripheral identifier.
+/// \param mode Slot and type of supported card (max bus width).
+//------------------------------------------------------------------------------
+void MCI_Init(
+ Mci *pMci,
+ AT91PS_MCI pMciHw,
+ unsigned char mciId,
+ unsigned int mode,
+ unsigned int bPolling)
+{
+ unsigned short clkDiv;
+ unsigned int mciCfg = 0;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMciHw);
+ SANITY_CHECK( (mode == MCI_MMC_SLOTA) || (mode == MCI_SD_SLOTA)
+ || (mode == MCI_MMC_SLOTB) || (mode == MCI_SD_SLOTB)
+ || (mode == MCI_MMC4_SLOTA) || (mode == MCI_MMC4_SLOTB));
+
+#if MCI_BUSY_CHECK_FIX
+ pMci->pPinDAT0 = 0;
+#endif
+
+ // Initialize the MCI driver structure
+ pMci->pMciHw = pMciHw;
+ pMci->mciId = mciId;
+ pMci->mciMode = mode;
+ pMci->bPolling = bPolling;
+ pMci->semaphore = 1;
+ pMci->pCommand = 0;
+
+#if !defined(OP_BOOTSTRAP_MCI_on)
+ // Enable the MCI clock
+ PERIPH_ENABLE(mciId);
+
+ // Reset the MCI
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST);
+
+ // Disable the MCI
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS);
+
+ // Disable all the interrupts
+ WRITE_MCI(pMciHw, MCI_IDR, 0xFFFFFFFF);
+
+ // Set the Data Timeout Register
+ WRITE_MCI(pMciHw, MCI_DTOR, DTOR_1MEGA_CYCLES);
+
+ // Set the Mode Register: 400KHz for MCK = 48MHz (CLKDIV = 58)
+ clkDiv = (BOARD_MCK / (MCI_INITIAL_SPEED * 2)) - 1;
+ WRITE_MCI(pMciHw, MCI_MR, (clkDiv | (AT91C_MCI_PWSDIV & (0x7 << 8))));
+
+ // Set the SDCard Register
+ WRITE_MCI(pMciHw, MCI_SDCR, mode);
+
+ // Enable the MCI and the Power Saving
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIEN);
+
+ // Disable the DMA interface
+ WRITE_MCI(pMciHw, MCI_DMA, AT91C_MCI_DMAEN_DISABLE);
+
+ // Configure MCI
+ mciCfg = AT91C_MCI_FIFOMODE_AMOUNTDATA | AT91C_MCI_FERRCTRL_RWCMD;
+ //mciCfg = AT91C_MCI_FIFOMODE_ONEDATA | AT91C_MCI_FERRCTRL_RWCMD;
+
+ WRITE_MCI(pMciHw, MCI_CFG, mciCfg);
+
+ // Disable the MCI peripheral clock.
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << mciId));
+#else
+ // Assume ROM code initialize the MCI already
+ TRACE_INFO("SD bootstrap not init mci!\n\r");
+#endif
+
+}
+
+#if MCI_BUSY_CHECK_FIX
+/// Invoked after MCI_Init to enable busy line fix
+void MCI_SetBusyFix(Mci *pMci, const Pin * pDAT0)
+{
+ pMci->pPinDAT0 = pDAT0;
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Close a MCI driver instance and the underlying peripheral.
+/// \param pMci Pointer to a MCI driver instance.
+/// \param pMciHw Pointer to a MCI peripheral.
+/// \param mciId MCI peripheral identifier.
+//------------------------------------------------------------------------------
+void MCI_Close(Mci *pMci)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+
+ SANITY_CHECK(pMci);
+ if (!pMciHw) return;
+
+ // Disable all the interrupts
+ WRITE_MCI(pMciHw, MCI_IDR, 0xFFFFFFFF);
+
+ // Disable the MCI
+ WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS);
+
+ // Disable the MCI peripheral clock.
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pMci->mciId));
+
+ // Initialize the MCI driver structure
+ pMci->semaphore = 1;
+ pMci->pCommand = 0;
+}
+
+//------------------------------------------------------------------------------
+/// Get the MCI CLKDIV in the MCI_MR register. The max. for MCI clock is
+/// MCK/2 and corresponds to CLKDIV = 0
+/// \param pMci Pointer to the low level MCI driver.
+/// \param mciSpeed MCI clock speed in Hz.
+//------------------------------------------------------------------------------
+unsigned int MCI_GetSpeed(Mci *pMci, unsigned int *mciDiv)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ unsigned int mciMr;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMci->pMciHw);
+
+ // Get the Mode Register
+ mciMr = READ_MCI(pMciHw, MCI_MR);
+ mciMr &= AT91C_MCI_CLKDIV;
+ if (mciDiv) *mciDiv = mciMr;
+ return (BOARD_MCK / 2 / (mciMr + 1));
+}
+
+//------------------------------------------------------------------------------
+/// Configure the MCI CLKDIV in the MCI_MR register. The max. for MCI clock is
+/// MCK/2 and corresponds to CLKDIV = 0
+/// \param pMci Pointer to the low level MCI driver.
+/// \param mciSpeed MCI clock speed in Hz.
+/// \param mciLimit MCI clock limit in Hz, if not limit, set mciLimit to zero.
+/// \param mck MCK to generate MCI Clock, in Hz
+/// \return The actual speed used, 0 for fail.
+//------------------------------------------------------------------------------
+unsigned int MCI_SetSpeed(Mci *pMci,
+ unsigned int mciSpeed,
+ unsigned int mciLimit,
+ unsigned int mck)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ unsigned int mciMr;
+ unsigned int clkdiv;
+ unsigned int divLimit = 0;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMci->pMciHw);
+
+ mciMr = READ_MCI(pMciHw, MCI_MR) & (~(unsigned int)AT91C_MCI_CLKDIV);
+
+ // Multimedia Card Interface clock (MCCK or MCI_CK) is Master Clock (MCK)
+ // divided by (2*(CLKDIV+1))
+ // mciSpeed = MCK / (2*(CLKDIV+1))
+ if (mciLimit) {
+ divLimit = (mck / 2 / mciLimit);
+ if ((mck / 2) % mciLimit) divLimit ++;
+ }
+ if (mciSpeed > 0) {
+ clkdiv = (mck / 2 / mciSpeed);
+ if (mciLimit && clkdiv < divLimit)
+ clkdiv = divLimit;
+ if (clkdiv > 0)
+ clkdiv -= 1;
+ ASSERT( (clkdiv & 0xFFFFFF00) == 0, "mciSpeed too small");
+ }
+ else clkdiv = 0;
+
+ // Actual MCI speed
+ mciSpeed = mck / 2 / (clkdiv + 1);
+
+ // Set the Data Timeout Register & Completion Timeout
+ // Data timeout is 500ms, completion timeout 1s.
+ //MCI_SetTimeout(pMciHw, mciSpeed / 2, mciSpeed);
+
+ WRITE_MCI(pMciHw, MCI_MR, mciMr | clkdiv);
+ return (mciSpeed);
+}
+
+//------------------------------------------------------------------------------
+/// Configure the MCI_CFG to enable the HS mode
+/// \param pMci Pointer to the low level MCI driver.
+/// \param hsEnable 1 to enable, 0 to disable HS mode.
+//------------------------------------------------------------------------------
+void MCI_EnableHsMode(Mci *pMci, unsigned char hsEnable)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ unsigned int cfgr;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMci->pMciHw);
+
+ cfgr = READ_MCI(pMciHw, MCI_CFG);
+ if (hsEnable) cfgr |= AT91C_MCI_HSMODE_ENABLE;
+ else cfgr &= ~(unsigned int)AT91C_MCI_HSMODE_ENABLE;
+ WRITE_MCI(pMciHw, MCI_CFG, cfgr);
+}
+
+//------------------------------------------------------------------------------
+/// Configure the MCI SDCBUS in the MCI_SDCR register. Only two modes available
+///
+/// \param pMci Pointer to the low level MCI driver.
+/// \param busWidth MCI bus width mode.
+//------------------------------------------------------------------------------
+void MCI_SetBusWidth(Mci *pMci, unsigned char busWidth)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ unsigned int mciSdcr;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMci->pMciHw);
+
+ mciSdcr = (READ_MCI(pMciHw, MCI_SDCR) & ~((unsigned int)AT91C_MCI_SCDBUS));
+
+ WRITE_MCI(pMciHw, MCI_SDCR, mciSdcr | busWidth);
+}
+
+//------------------------------------------------------------------------------
+/// Starts a MCI transfer. This is a non blocking function. It will return
+/// as soon as the transfer is started.
+/// Return 0 if successful; otherwise returns MCI_ERROR_LOCK if the driver is
+/// already in use.
+/// \param pMci Pointer to an MCI driver instance.
+/// \param pCommand Pointer to the command to execute.
+//------------------------------------------------------------------------------
+unsigned char MCI_SendCommand(Mci *pMci, MciCmd *pCommand)
+{
+ AT91PS_MCI pMciHw = pMci->pMciHw;
+ unsigned int mciIer, mciMr;
+ unsigned int transSize;
+ unsigned int mciBlkr;
+
+ #if defined(MCI_DMA_ENABLE)
+ unsigned int mciDma;
+ #endif
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMciHw);
+ SANITY_CHECK(pCommand);
+
+ // Try to acquire the MCI semaphore
+ if (pMci->semaphore == 0) {
+
+ return MCI_ERROR_LOCK;
+ }
+ pMci->semaphore--;
+
+ // Command is now being executed
+ pMci->pCommand = pCommand;
+ pCommand->status = MCI_STATUS_PENDING;
+
+ // Enable the MCI peripheral clock
+ PERIPH_ENABLE(pMci->mciId);
+
+ // Set Default Mode register value
+ mciMr = READ_MCI(pMciHw, MCI_MR) & (~( AT91C_MCI_WRPROOF
+ |AT91C_MCI_RDPROOF
+ |AT91C_MCI_BLKLEN));
+ // Command with DATA stage
+ if (pCommand->blockSize && pCommand->nbBlock) {
+ // Enable dma
+ #if defined(MCI_DMA_ENABLE)
+ mciDma = READ_MCI(pMciHw, MCI_DMA) | AT91C_MCI_DMAEN_ENABLE;
+ WRITE_MCI(pMciHw, MCI_DMA, mciDma);
+ #endif
+
+ transSize = (pCommand->nbBlock * pCommand->blockSize);
+ #if defined(MCI_DMA_ENABLE)
+ if (pCommand->isRead) {
+ #if MCI_RD_FIFO_LIMIT
+ if (transSize > MCI_FIFO_SIZE) {
+ xfredBlocks = MCI_FIFO_SIZE/pCommand->blockSize;
+ transSize = MCI_FIFO_SIZE;
+ }
+ else
+ #endif
+ {
+ xfredBlocks = pCommand->nbBlock;
+ }
+ }
+ else {
+ xfredBlocks = pCommand->nbBlock;
+ }
+ #endif
+ if ((pCommand->blockSize & 0x3) != 0) {
+ // Force byte, DataReg & DMA should be BYTE based
+ mciMr |= AT91C_MCI_PDCFBYTE;
+ }
+ else
+ transSize = toWCOUNT(transSize);
+
+ // New transfer
+ if(pCommand->tranType == MCI_NEW_TRANSFER)
+ {
+
+ // Set block size
+ WRITE_MCI(pMciHw, MCI_MR, mciMr | AT91C_MCI_RDPROOF
+ | AT91C_MCI_WRPROOF
+ |(pCommand->blockSize << 16));
+
+ mciBlkr = READ_MCI(pMciHw, MCI_BLKR)
+ & (~(unsigned int)AT91C_MCI_BCNT);
+ WRITE_MCI(pMciHw, MCI_BLKR, mciBlkr
+ | (transSize/pCommand->blockSize));
+ }
+
+ // DATA transfer from card to host
+ if (pCommand->isRead) {
+
+ #if defined(MCI_DMA_ENABLE)
+ DMACH_MCI_P2M(BOARD_MCI_DMA_CHANNEL,
+ (unsigned char*)&pMciHw->MCI_FIFO,
+ (unsigned char*) pCommand->pData,
+ transSize, 0,
+ (mciMr & AT91C_MCI_PDCFBYTE) > 0);
+ DMACH_EnableIt(pMciHw, BOARD_MCI_DMA_CHANNEL);
+ DMA_EnableChannel(BOARD_MCI_DMA_CHANNEL);
+ mciIer = AT91C_MCI_DMADONE | STATUS_ERRORS;
+ #else
+ mciIer = AT91C_MCI_CMDRDY | STATUS_ERRORS;
+ #endif
+ }
+ // DATA transfer from host to card
+ else {
+
+ #if defined(MCI_DMA_ENABLE)
+ if ((mciMr & AT91C_MCI_PDCFBYTE) > 0) {
+ #if 1
+ // Still using WORD mode to write FIFO
+ DMACH_MCI_M2P(BOARD_MCI_DMA_CHANNEL,
+ (unsigned char*) pCommand->pData,
+ (unsigned char*)&pMciHw->MCI_FIFO,
+ toWCOUNT(transSize), 0,
+ 0);
+ #else
+ // Still write to TDR with WORD!
+ DMACH_MCI_M2P(BOARD_MCI_DMA_CHANNEL,
+ (unsigned char*) pCommand->pData,
+ (unsigned char*)&pMciHw->MCI_TDR,
+ toWCOUNT(transSize), 0,
+ 0);
+ #endif
+ }
+ else {
+ DMACH_MCI_M2P(BOARD_MCI_DMA_CHANNEL,
+ (unsigned char*) pCommand->pData,
+ (unsigned char*)&pMciHw->MCI_FIFO,
+ transSize, 0,
+ 0);
+ }
+ DMACH_EnableIt(pMciHw, BOARD_MCI_DMA_CHANNEL);
+ DMA_EnableChannel(BOARD_MCI_DMA_CHANNEL);
+ mciIer = AT91C_MCI_DMADONE | STATUS_ERRORS;
+ #else
+ mciIer = AT91C_MCI_CMDRDY | STATUS_ERRORS;
+ #endif
+ }
+ }
+ // Start an infinite block transfer (but no data in current command)
+ else if (pCommand->dataTran) {
+ // Set block size
+ WRITE_MCI(pMciHw, MCI_MR, mciMr | AT91C_MCI_RDPROOF
+ | AT91C_MCI_WRPROOF
+ |(pCommand->blockSize << 16));
+ // Set data length: 0
+ mciBlkr = READ_MCI(pMciHw, MCI_BLKR) & (~(unsigned int)AT91C_MCI_BCNT);
+ WRITE_MCI(pMciHw, MCI_BLKR, mciBlkr);
+ mciIer = AT91C_MCI_CMDRDY | STATUS_ERRORS;
+ }
+ // No data transfer: stop at the end of the command
+ else{
+ WRITE_MCI(pMciHw, MCI_MR, mciMr);
+ mciIer = AT91C_MCI_CMDRDY | STATUS_ERRORS;
+ }
+
+ // Enable MCI
+ MCI_ENABLE(pMciHw);
+
+ // Send the command
+ if((pCommand->tranType != MCI_CONTINUE_TRANSFER)
+ || (pCommand->blockSize == 0)) {
+
+ WRITE_MCI(pMciHw, MCI_ARGR, pCommand->arg);
+ WRITE_MCI(pMciHw, MCI_CMDR, pCommand->cmd);
+ }
+
+ // Ignore CRC error for R3 & R4
+ if (pCommand->resType == 3 || pCommand->resType == 4) {
+ mciIer &= ~((unsigned int)AT91C_MCI_RCRCE);
+ }
+ // Ignore errors for stop command :)
+ if (pCommand->tranType == MCI_STOP_TRANSFER) {
+ mciIer &= ~((unsigned int)(AT91C_MCI_DCRCE
+ |AT91C_MCI_BLKOVRE
+ |AT91C_MCI_DTOE
+ |AT91C_MCI_CSTOE));
+ }
+
+ // Ignore data error
+ mciIer &= ~( 0
+ | AT91C_MCI_UNRE
+ | AT91C_MCI_OVRE
+ | AT91C_MCI_DTOE
+ | AT91C_MCI_DCRCE
+ | AT91C_MCI_BLKOVRE
+ | AT91C_MCI_CSTOE
+ );
+
+ // Interrupt enable shall be done after PDC TXTEN and RXTEN
+ WRITE_MCI(pMciHw, MCI_IER, mciIer);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Check NOTBUSY and DTIP bits of status register on the given MCI driver.
+/// Return value, 0 for bus ready, 1 for bus busy
+/// \param pMci Pointer to a MCI driver instance.
+//------------------------------------------------------------------------------
+unsigned char MCI_CheckBusy(Mci *pMci)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ volatile unsigned int status;
+
+ // Enable MCI clock
+ PERIPH_ENABLE(pMci->mciId);
+ MCI_ENABLE(pMciHw);
+
+ status = READ_MCI(pMciHw, MCI_SR);
+
+#if MCI_BUSY_CHECK_FIX
+ if ((status & AT91C_MCI_DTIP) == 0) {
+ unsigned char isBusy = 1;
+ if (pMci->pPinDAT0) {
+ Pin pinBsy;
+ pinBsy.mask = pMci->pPinDAT0->mask;
+ pinBsy.pio = pMci->pPinDAT0->pio;
+ pinBsy.id = pMci->pPinDAT0->id;
+ pinBsy.type = PIO_INPUT;
+ pinBsy.attribute = PIO_PULLUP;
+ PIO_Configure(&pinBsy, 1);
+ isBusy = (PIO_Get(&pinBsy) == 0);
+ PIO_Configure(pMci->pPinDAT0, 1);
+ }
+ else {
+ isBusy = ((status & AT91C_MCI_NOTBUSY) == 0);
+ }
+ if (isBusy == 0) {
+ MCI_DISABLE(pMciHw);
+ PERIPH_DISABLE(pMci->mciId);
+ }
+ return isBusy;
+ }
+
+ return 1;
+#else
+
+ if( ((status & AT91C_MCI_NOTBUSY)!=0)
+ && ((status & AT91C_MCI_DTIP)==0)
+ ) {
+
+ // Disable MCI clock
+ MCI_DISABLE(pMciHw);
+ PERIPH_DISABLE(pMci->mciId);
+ return 0;
+ }
+ else {
+ return 1;
+ }
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Processes pending events on the given MCI driver.
+/// \param pMci Pointer to a MCI driver instance.
+//------------------------------------------------------------------------------
+void MCI_Handler(Mci *pMci)
+{
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ MciCmd *pCommand = pMci->pCommand;
+ volatile unsigned int status;
+ unsigned int status0, mask;
+ unsigned char i;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pMciHw);
+ SANITY_CHECK(pCommand);
+
+ // Read the status register
+ status0 = READ_MCI(pMciHw, MCI_SR);
+ mask = READ_MCI(pMciHw, MCI_IMR);
+ //TRACE_INFO("iST %x\n\r", status);
+ status = status0 & mask;
+ //TRACE_INFO("iSM %x\n\r", status);
+
+ // Check if an error has occured
+ if ((status & STATUS_ERRORS) != 0) {
+
+ // Check error code
+ if ((status & STATUS_ERRORS) == AT91C_MCI_RTOE) {
+
+ pCommand->status = MCI_STATUS_NORESPONSE;
+ }
+ else {
+
+ pCommand->status = MCI_STATUS_ERROR;
+ }
+ TRACE_INFO("iErr%x\n\r", (status & STATUS_ERRORS));
+ }
+ mask &= ~STATUS_ERRORS;
+
+ // Check if a command has been completed
+ if (status & AT91C_MCI_CMDRDY) {
+
+ WRITE_MCI(pMciHw, MCI_IDR, AT91C_MCI_CMDRDY);
+ if (pCommand->isRead == 0 &&
+ pCommand->tranType == MCI_STOP_TRANSFER) {
+ if (status0 & AT91C_MCI_XFRDONE) {
+ MCI_DISABLE(pMciHw);
+ }
+ else {
+ WRITE_MCI(pMciHw, MCI_IER, AT91C_MCI_XFRDONE);
+ }
+ }
+ else {
+ mask &= ~(unsigned int)AT91C_MCI_CMDRDY;
+ if (pCommand->dataTran == 0) {
+ MCI_DISABLE(pMciHw);
+ }
+ }
+ }
+
+ // Check if transfer stopped
+ if (status & AT91C_MCI_XFRDONE) {
+ mask &= ~(unsigned int)AT91C_MCI_XFRDONE;
+ MCI_DISABLE(pMciHw);
+ }
+
+#if defined(MCI_DMA_ENABLE)
+
+ // Check FIFOEMPTY
+ if (status & AT91C_MCI_FIFOEMPTY) {
+
+ WRITE_MCI(pMciHw, MCI_IDR, AT91C_MCI_FIFOEMPTY);
+ if ( pCommand->isRead == 0 &&
+ (status0 & AT91C_MCI_BLKE) == 0 ) {
+ WRITE_MCI(pMciHw, MCI_IER, AT91C_MCI_BLKE);
+ }
+ else {
+ mask &= ~(unsigned int)AT91C_MCI_FIFOEMPTY;
+ MCI_DISABLE(pMciHw);
+ }
+ }
+ if (status & AT91C_MCI_BLKE) {
+ mask &= ~(unsigned int)AT91C_MCI_BLKE;
+ MCI_DISABLE(pMciHw);
+ }
+
+ // Check if a DMA transfer has been completed
+ if ( (status & AT91C_MCI_DMADONE)
+ && (LLI_MCI[dmaLastLliNdx].controlA & AT91C_HDMA_DONE)) {
+
+ unsigned int intFlag;
+ intFlag = DMA_GetInterruptMask();
+ intFlag = ~intFlag;
+ intFlag |= (AT91C_HDMA_BTC0 << BOARD_MCI_DMA_CHANNEL);
+ DMA_DisableIt(intFlag);
+
+ // All data transferred
+ if (xfredBlocks >= pCommand->nbBlock) {
+
+ WRITE_MCI(pMciHw, MCI_IDR, AT91C_MCI_DMADONE);
+ if ( pCommand->isRead == 0 &&
+ (status0 & AT91C_MCI_FIFOEMPTY) == 0 ) {
+ WRITE_MCI(pMciHw, MCI_IER, AT91C_MCI_FIFOEMPTY);
+ }
+ else {
+ MCI_DISABLE(pMciHw);
+ mask &= ~(unsigned int)AT91C_MCI_DMADONE;
+ }
+ }
+ // Start later part of DMA
+ else {
+ unsigned int transSize;
+ unsigned char* p;
+ p = &pCommand->pData[xfredBlocks*pCommand->blockSize];
+ transSize = ((pCommand->nbBlock - xfredBlocks)
+ * pCommand->blockSize);
+ if (transSize > MCI_FIFO_SIZE) {
+ transSize = MCI_FIFO_SIZE;
+ xfredBlocks += MCI_FIFO_SIZE/pCommand->blockSize;
+ }
+ else {
+ xfredBlocks = pCommand->nbBlock;
+ }
+ #if 0
+ WRITE_MCI(pMciHw, MCI_BLKR, (READ_MCI(pMciHw, MCI_BLKR)
+ & (~(unsigned int)AT91C_MCI_BCNT))
+ | (transSize/pCommand->blockSize));
+ #endif
+ if ((pCommand->blockSize & 0x3) == 0) {
+ transSize = toWCOUNT(transSize);
+ }
+ DMACH_MCI_P2M(BOARD_MCI_DMA_CHANNEL,
+ (unsigned char*)&pMciHw->MCI_FIFO,
+ (unsigned char*) p,
+ transSize, 0,
+ (pCommand->blockSize & 0x3) > 0);
+ DMA_EnableChannel(BOARD_MCI_DMA_CHANNEL);
+ }
+ }
+#endif
+
+ // All non-error mask done, complete the command
+ if (!mask || pCommand->status != MCI_STATUS_PENDING) {
+
+ // Store the card response in the provided buffer
+ if (pCommand->pResp) {
+ unsigned char resSize;
+ switch (pCommand->resType) {
+ case 1: case 3: case 4: case 5: case 6: case 7:
+ resSize = 1; break;
+ case 2: resSize = 4; break;
+ default: resSize = 0; break;
+ }
+ for (i=0; i < resSize; i++) {
+ pCommand->pResp[i] = READ_MCI(pMciHw, MCI_RSPR[0]);
+ }
+ }
+
+ // If no error occured, the transfer is successful
+ if (pCommand->status == MCI_STATUS_PENDING)
+ pCommand->status = 0;
+ // Any error, reset registers
+ else {
+ MCI_Reset(pMciHw, 1);
+ }
+
+ // Disable interrupts
+ WRITE_MCI(pMciHw, MCI_IDR, READ_MCI(pMciHw, MCI_IMR));
+ #if defined(MCI_DMA_ENABLE)
+ DMA_DisableChannel(BOARD_MCI_DMA_CHANNEL);
+ #endif
+
+ // Disable peripheral
+ PERIPH_DISABLE(pMci->mciId);
+
+ // Release the semaphore
+ pMci->semaphore++;
+
+ // Invoke the callback associated with the current command (if any)
+ if (pCommand->callback) {
+ (pCommand->callback)(pCommand->status, (void*)pCommand);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the given MCI transfer is complete; otherwise returns 0.
+/// \param pCommand Pointer to a MciCmd instance.
+//------------------------------------------------------------------------------
+unsigned char MCI_IsTxComplete(Mci *pMci)
+{
+ MciCmd *pCommand = pMci->pCommand;
+
+ if(pMci->bPolling == MCI_POLLING_MODE) {
+ MCI_Handler(pMci);
+ }
+
+ if (pCommand->status != MCI_STATUS_PENDING) {
+ if (pCommand->status != 0) {
+ TRACE_DEBUG("MCI_IsTxComplete %d\n\r", pCommand->status);
+ }
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Check whether the MCI is using the FIFO transfer mode
+/// \param pMci Pointer to a Mci instance.
+/// \param pCommand Pointer to a MciCmd instance.
+//------------------------------------------------------------------------------
+unsigned int MCI_FifoTransfer(Mci *pMci, MciCmd *pCommand)
+{
+ // If using DMA mode, return
+#if defined(MCI_DMA_ENABLE)
+ return 0;
+#else
+
+ unsigned int status=0;
+ unsigned int nbTransfer=0;
+ unsigned int i;
+ AT91S_MCI *pMciHw = pMci->pMciHw;
+ unsigned int *pMem;
+
+ SANITY_CHECK(pMci);
+ SANITY_CHECK(pCommand);
+
+
+ TRACE_DEBUG("MCIFifo:%d,%d\n\r", pCommand->isRead, pCommand->nbBlock);
+
+ if (pCommand->nbBlock == 0 || pCommand->blockSize == 0)
+ return 0;
+
+ pMem = (unsigned int*)pCommand->pData;
+
+ // Get transfer size
+ nbTransfer = (pCommand->blockSize) * (pCommand->nbBlock) / 4;
+ if((pCommand->blockSize) * (pCommand->nbBlock) % 4) {
+ nbTransfer++;
+ }
+
+ if (pCommand->isRead) {
+
+ // Read RDR loop
+ for(i=0; i<nbTransfer; i++) {
+ while(1) {
+ status = READ_MCI(pMciHw, MCI_SR);
+ if (status & AT91C_MCI_RXRDY)
+ break;
+ #if 1
+ if (status & STATUS_ERRORS_DATA) {
+ TRACE_ERROR("MCI_FifoTransfer.R: 0x%x\n\r", status);
+ return status;
+ }
+ #endif
+ }
+ *pMem = READ_MCI(pMciHw, MCI_RDR);
+ pMem++;
+ }
+ }
+ else {
+
+ // Write TDR loop
+ for(i=0; i<nbTransfer; i++) {
+ while(1) {
+ status = READ_MCI(pMciHw, MCI_SR);
+ if (status & (AT91C_MCI_TXRDY | AT91C_MCI_NOTBUSY))
+ break;
+ #if 0
+ if (status & STATUS_ERRORS_DATA) {
+ TRACE_ERROR("MCI_FifoTransfer.W: 0x%x\n\r", status);
+ return status;
+ }
+ #endif
+ }
+ WRITE_MCI(pMciHw, MCI_TDR, *pMem);
+ pMem++;
+ }
+ }
+
+ status = READ_MCI(pMciHw, MCI_SR);
+ TRACE_DEBUG("MCI_FifoTransfer : All status %x\n\r", status);
+ status &= READ_MCI(pMciHw, MCI_IMR);
+ TRACE_DEBUG("MCI_FifoTransfer : Masked status %x\n\r", status);
+
+ #if 0
+ { unsigned int old = status;
+ while(status & AT91C_MCI_DTIP) {
+ status = READ_MCI(pMciHw, MCI_SR);
+ if (status != old) {
+ old = status;
+ TRACE_DEBUG_WP(" -> %x", status);
+ }
+ }
+ TRACE_DEBUG_WP("\n\r");
+ TRACE_DEBUG(" DPIT 0 stat %x\n\r", status);
+ while((status & (AT91C_MCI_FIFOEMPTY
+ | AT91C_MCI_BLKE
+ | AT91C_MCI_XFRDONE)) == 0) {
+ status = READ_MCI(pMciHw, MCI_SR);
+ }
+ TRACE_DEBUG(" FIFO EMPTY stat %x\n\r", status);
+ }
+ #endif
+
+ return status;
+#endif
+}
diff --git a/peripherals/mci/mci_hs.h b/peripherals/mci/mci_hs.h new file mode 100644 index 0000000..90e8385 --- /dev/null +++ b/peripherals/mci/mci_hs.h @@ -0,0 +1,236 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "mci"
+///
+/// !Purpose
+///
+/// mci-interface driver
+///
+/// !Usage
+///
+/// -# MCI_Init: Initializes a MCI driver instance and the underlying peripheral.
+/// -# MCI_SetSpeed : Configure the MCI CLKDIV in the MCI_MR register.
+/// -# MCI_SendCommand: Starts a MCI transfer.
+/// -# MCI_Handler : Interrupt handler which is called by ISR handler.
+/// -# MCI_SetBusWidth : Configure the MCI SDCBUS in the MCI_SDCR register.
+//------------------------------------------------------------------------------
+
+
+#ifndef MCI_HS_H
+#define MCI_HS_H
+
+//------------------------------------------------------------------------------
+// Compile Options
+//------------------------------------------------------------------------------
+
+/// MCI using DMA?
+#define MCI_DMA_ENABLE 1
+
+/// MCI BUSY Check Fix
+#define MCI_BUSY_CHECK_FIX 0
+
+/// MCI support SDIO
+#define MCI_SDIO_ENABLE 1
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#if MCI_BUSY_CHECK_FIX
+#include <pio/pio.h>
+#endif
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+/// Transfer is pending.
+#define MCI_STATUS_PENDING 1
+/// Transfer has been aborted because an error occured.
+#define MCI_STATUS_ERROR 2
+/// Card did not answer command.
+#define MCI_STATUS_NORESPONSE 3
+
+/// MCI driver is currently in use.
+#define MCI_ERROR_LOCK 1
+
+/// MCI configuration with 1-bit data bus on slot A (for MMC cards).
+#define MCI_MMC_SLOTA (AT91C_MCI_SCDSEL_SLOTA | AT91C_MCI_SCDBUS_1BIT)
+/// MCI configuration with 4-bit data bus on slot A (for SD cards).
+#define MCI_SD_SLOTA (AT91C_MCI_SCDSEL_SLOTA | AT91C_MCI_SCDBUS_4BITS)
+#ifdef AT91C_MCI_SCDBUS_8BITS
+/// MCI configuration with 1-bit data bus on slot A (for MMC cards).
+#define MCI_MMC4_SLOTA (AT91C_MCI_SCDSEL_SLOTA | AT91C_MCI_SCDBUS_8BITS)
+#endif
+#ifdef AT91C_MCI_SCDSEL_SLOTB
+/// MCI configuration with 1-bit data bus on slot B (for MMC cards).
+#define MCI_MMC_SLOTB (AT91C_MCI_SCDSEL_SLOTB | AT91C_MCI_SCDBUS_1BIT)
+/// MCI configuration with 4-bit data bus on slot B (for SD cards).
+#define MCI_SD_SLOTB (AT91C_MCI_SCDSEL_SLOTB | AT91C_MCI_SCDBUS_4BITS)
+#ifdef AT91C_MCI_SCDBUS_8BITS
+/// MCI configuration with 1-bit data bus on slot A (for MMC cards).
+#define MCI_MMC4_SLOTB (AT91C_MCI_SCDSEL_SLOTB | AT91C_MCI_SCDBUS_8BITS)
+#endif
+#else
+#define MCI_MMC_SLOTB MCI_MMC_SLOTA
+#define MCI_SD_SLOTB MCI_SD_SLOTA
+#endif
+
+/// Start new data transfer
+#define MCI_NEW_TRANSFER 0
+/// Continue data transfer
+#define MCI_CONTINUE_TRANSFER 1
+/// Stop data transfer
+#define MCI_STOP_TRANSFER 2
+
+/// MCI SD Bus Width 1-bit
+#define MCI_SDCBUS_1BIT (0 << 7)
+/// MCI SD Bus Width 4-bit
+#define MCI_SDCBUS_4BIT (1 << 7)
+/// MCI SD Bus Width 8-bit
+#define MCI_SDCBUS_8BIT (3 << 6)
+
+/// The MCI Clock Speed after initialize (400K)
+#define MCI_INITIAL_SPEED 400000
+
+#define MCI_INTERRUPT_MODE 0
+#define MCI_POLLING_MODE 1
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// MCI end-of-transfer callback function.
+typedef void (*MciCallback)(unsigned char status, void *pCommand);
+
+//------------------------------------------------------------------------------
+/// MCI Transfer Request prepared by the application upper layer. This structure
+/// is sent to the MCI_SendCommand function to start the transfer. At the end of
+/// the transfer, the callback is invoked by the interrupt handler.
+//------------------------------------------------------------------------------
+typedef struct _MciCmd {
+
+ /// Command code.
+ unsigned int cmd;
+ /// Command argument.
+ unsigned int arg;
+ /// Data buffer, with MCI_DMA_ENABLE defined 1, the buffer can be
+ /// 1, 2 or 4 bytes aligned. It has to be 4 byte aligned if no DMA.
+ unsigned char *pData;
+ /// Size of data block in bytes.
+ unsigned short blockSize;
+ /// Number of blocks to be transfered
+ unsigned short nbBlock;
+ /// Response buffer.
+ unsigned int *pResp;
+ /// Optional user-provided callback function.
+ MciCallback callback;
+ /// Optional argument to the callback function.
+ void *pArg;
+ /// SD card response type.
+ unsigned char resType;
+ /// Indicate if there is data transfer
+ unsigned char dataTran;
+ /// Indicate if continue to transfer data
+ unsigned char tranType;
+ /// Indicates if the command is a read operation.
+ unsigned char isRead;
+
+ /// Command status.
+ volatile int status;
+} MciCmd;
+
+//------------------------------------------------------------------------------
+/// MCI driver structure. Holds the internal state of the MCI driver and
+/// prevents parallel access to a MCI peripheral.
+//------------------------------------------------------------------------------
+typedef struct {
+
+#if MCI_BUSY_CHECK_FIX
+ /// MCI DAT0 Pin (Assign it to enable PIO mode DAT0 check)
+ /// The pin is configured as peripheral
+ const Pin *pPinDAT0;
+#endif
+ /// Pointer to a MCI peripheral.
+ AT91S_MCI *pMciHw;
+ /// Pointer to currently executing command.
+ MciCmd *pCommand;
+ /// MCI peripheral identifier.
+ unsigned char mciId;
+ /// MCI HW mode
+ unsigned char mciMode;
+ /// Mutex.
+ volatile char semaphore;
+ /// interrupt or polling mode
+ unsigned int bPolling;
+} Mci;
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void MCI_Init(
+ Mci *pMci,
+ AT91PS_MCI pMciHw,
+ unsigned char mciId,
+ unsigned int mode,
+ unsigned int bPolling);
+
+extern unsigned int MCI_GetSpeed(Mci *pMci, unsigned int *mciDiv);
+
+extern unsigned int MCI_SetSpeed(Mci *pMci,
+ unsigned int mciSpeed,
+ unsigned int mciLimit,
+ unsigned int mck);
+
+extern unsigned char MCI_SendCommand(Mci *pMci, MciCmd *pMciCmd);
+
+extern void MCI_Handler(Mci *pMci);
+
+extern unsigned char MCI_IsTxComplete(Mci *pMci);
+
+extern unsigned char MCI_CheckBusy(Mci *pMci);
+
+extern void MCI_Close(Mci *pMci);
+
+extern void MCI_EnableHsMode(Mci * pMci, unsigned char hsEnable);
+
+extern void MCI_SetBusWidth(Mci *pMci, unsigned char busWidth);
+
+extern unsigned int MCI_FifoTransfer(Mci * pMci, MciCmd * pCommand);
+
+#if MCI_BUSY_CHECK_FIX
+extern void MCI_SetBusyFix(Mci *pMci, const Pin * pDAT0);
+#endif
+
+#endif //#ifndef MCI_HS_H
+
diff --git a/peripherals/peripherals.dir b/peripherals/peripherals.dir new file mode 100644 index 0000000..464b743 --- /dev/null +++ b/peripherals/peripherals.dir @@ -0,0 +1,47 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !!!Purpose
+///
+/// The #peripherals# directory stores a collection of basic APIs for each of
+/// the peripherals available on AT91 microcontrollers.
+///
+/// !!!Contents
+/// Each subdirectory inside this one provides code for a single peripheral. The
+/// directory is named according to the short-handed name of the peripheral, as
+/// written in the product datasheet (e.g. Advanced Interrupt Controller code
+/// is located in the #aic# directory).
+///
+/// Peripheral APIs provide low-level functions to simplify the use of
+/// AT91 peripherals. However, they do not provide fully-fledged drivers; such
+/// code can be found in the #drivers# directory of at91lib.
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/pio/pio.c b/peripherals/pio/pio.c new file mode 100644 index 0000000..288e6bb --- /dev/null +++ b/peripherals/pio/pio.c @@ -0,0 +1,382 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "pio.h"
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Local Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// 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(
+ AT91S_PIO *pio,
+ unsigned int mask,
+ unsigned char enablePullUp)
+{
+#if !defined(AT91C_PIOA_ASR)
+ unsigned int abmr;
+#endif
+
+ // Disable interrupts on the pin(s)
+ pio->PIO_IDR = mask;
+
+ // Enable the pull-up(s) if necessary
+ if (enablePullUp) {
+
+ pio->PIO_PPUER = mask;
+ }
+ else {
+
+ pio->PIO_PPUDR = mask;
+ }
+
+ // Configure pin
+#if defined(AT91C_PIOA_ASR)
+ pio->PIO_ASR = mask;
+#else
+ abmr = pio->PIO_ABSR;
+ pio->PIO_ABSR &= (~mask & abmr);
+#endif
+ pio->PIO_PDR = mask;
+}
+
+//------------------------------------------------------------------------------
+/// 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(
+ AT91S_PIO *pio,
+ unsigned int mask,
+ unsigned char enablePullUp)
+{
+#if !defined(AT91C_PIOA_BSR)
+ unsigned int abmr;
+#endif
+
+ // Disable interrupts on the pin(s)
+ pio->PIO_IDR = mask;
+
+ // Enable the pull-up(s) if necessary
+ if (enablePullUp) {
+
+ pio->PIO_PPUER = mask;
+ }
+ else {
+
+ pio->PIO_PPUDR = mask;
+ }
+
+ // Configure pin
+#if defined(AT91C_PIOA_BSR)
+ pio->PIO_BSR = mask;
+#else
+ abmr = pio->PIO_ABSR;
+ pio->PIO_ABSR = mask | abmr;
+#endif
+ pio->PIO_PDR = mask;
+}
+
+#if defined(AT91C_PIOA_IFDGSR) //Glitch or Debouncing filter selection supported
+//------------------------------------------------------------------------------
+/// Configures Glitch or Debouncing filter for input
+/// \param pio Pointer to a PIO controller.
+/// \param mask Bitmask for filter selection.
+/// each of 32 bit field, 0 is Glitch, 1 is Debouncing
+/// \param clkDiv Clock divider if Debouncing select, using the lowest 14 bits
+/// common for all PIO line of selecting deboucing filter
+//------------------------------------------------------------------------------
+static void PIO_SetFilter(
+ AT91S_PIO *pio,
+ unsigned int filterSel,
+ unsigned int clkDiv)
+{
+ pio->PIO_DIFSR = filterSel;//set Debouncing, 0 bit field no effect
+ pio->PIO_SCIFSR = ~filterSel;//set Glitch, 0 bit field no effect
+
+ pio->PIO_SCDR = clkDiv & 0x3FFF;//the lowest 14 bits work
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// 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(
+ AT91S_PIO *pio,
+ unsigned int mask,
+ unsigned char enablePullUp,
+ unsigned char enableFilter)
+{
+ // Disable interrupts
+ pio->PIO_IDR = mask;
+
+ // Enable pull-up(s) if necessary
+ if (enablePullUp) {
+
+ pio->PIO_PPUER = mask;
+ }
+ else {
+
+ pio->PIO_PPUDR = mask;
+ }
+
+ // Enable filter(s) if necessary
+ if (enableFilter) {
+
+ pio->PIO_IFER = mask;
+ }
+ else {
+
+ pio->PIO_IFDR = mask;
+ }
+
+ // Configure pin as input
+ pio->PIO_ODR = mask;
+ pio->PIO_PER = mask;
+}
+
+//------------------------------------------------------------------------------
+/// 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(
+ AT91S_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_PPUER = mask;
+ }
+ else {
+
+ pio->PIO_PPUDR = 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
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// 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.
+//------------------------------------------------------------------------------
+unsigned char PIO_Configure(const Pin *list, unsigned int 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_INPUT:
+ AT91C_BASE_PMC->PMC_PCER = 1 << list->id;
+ PIO_SetInput(list->pio,
+ list->mask,
+ (list->attribute & PIO_PULLUP) ? 1 : 0,
+ (list->attribute & PIO_DEGLITCH)? 1 : 0);
+
+ #if defined(AT91C_PIOA_IFDGSR) //PIO3 with Glitch or Debouncing selection
+ //if glitch input filter enabled, set it
+ if(list->attribute & PIO_DEGLITCH)//Glitch input filter enabled
+ PIO_SetFilter(list->pio,
+ list->inFilter.filterSel,
+ list->inFilter.clkDivider);
+ #endif
+ 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;
+}
+
+//------------------------------------------------------------------------------
+/// 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;
+}
+
+//------------------------------------------------------------------------------
+/// 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;
+}
+
+//------------------------------------------------------------------------------
+/// 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;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+/// 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;
+ }
+}
diff --git a/peripherals/pio/pio.dir b/peripherals/pio/pio.dir new file mode 100644 index 0000000..9496672 --- /dev/null +++ b/peripherals/pio/pio.dir @@ -0,0 +1,50 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// This directory contains an API for configuring the Peripheral Input/Output
+/// (PIO) controllers.
+///
+/// !!!Contents
+///
+/// The code is separated into two components:
+/// - pio.c contains code for PIO initialisation, as well as set/clear/get
+/// methods that can be used with user-controlled pins.
+/// - pio_it.h provides a convenient interface for configuring, enabling or
+/// disabling interrupts on one pin or a group of pins.
+///
+/// The reasoning behing this division is that pio_it.c requires the aic
+/// peripheral, which generates useless includes for project which do not use
+/// PIO interrupts.
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/pio/pio.h b/peripherals/pio/pio.h new file mode 100644 index 0000000..2c78d73 --- /dev/null +++ b/peripherals/pio/pio.h @@ -0,0 +1,225 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !!!Purpose
+///
+/// This file provides a basic API for PIO configuration and usage of
+/// user-controlled pins. Please refer to the board.h file for a list of
+/// available pin definitions.
+///
+/// !!!Usage
+///
+/// -# Define a constant pin description array such as the following one, using
+/// the existing definitions provided by the board.h file if possible:
+/// \code
+/// const Pin pPins[] = {PIN_USART0_TXD, PIN_USART0_RXD};
+/// \endcode
+/// Alternatively, it is possible to add new pins by provided the full Pin
+/// structure:
+/// \code
+/// // Pin instance to configure PA10 & PA11 as inputs with the internal
+/// // pull-up enabled.
+/// const Pin pPins = {
+/// (1 << 10) | (1 << 11),
+/// AT91C_BASE_PIOA,
+/// AT91C_ID_PIOA,
+/// PIO_INPUT,
+/// PIO_PULLUP
+/// };
+/// \endcode
+/// -# Configure a pin array by calling PIO_Configure() with a pointer to the
+/// array and its size (which is computed using the PIO_LISTSIZE macro).
+/// -# Change and get the value of a user-controlled pin using the PIO_Set,
+/// PIO_Clear and PIO_Get methods.
+/// -# Get the level being currently output by a user-controlled pin configured
+/// as an output using PIO_GetOutputDataStatus().
+//------------------------------------------------------------------------------
+
+#ifndef PIO_H
+#define PIO_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Global Definitions
+//------------------------------------------------------------------------------
+
+/// The pin is controlled by the associated signal of peripheral A.
+#define PIO_PERIPH_A 0
+/// The pin is controlled by the associated signal of peripheral B.
+#define PIO_PERIPH_B 1
+/// The pin is an input.
+#define PIO_INPUT 2
+/// The pin is an output and has a default level of 0.
+#define PIO_OUTPUT_0 3
+/// The pin is an output and has a default level of 1.
+#define PIO_OUTPUT_1 4
+
+/// Default pin configuration (no attribute).
+#define PIO_DEFAULT (0 << 0)
+/// The internal pin pull-up is active.
+#define PIO_PULLUP (1 << 0)
+/// The internal glitch filter is active.
+#define PIO_DEGLITCH (1 << 1)
+/// The pin is open-drain.
+#define PIO_OPENDRAIN (1 << 2)
+
+//------------------------------------------------------------------------------
+// Global Macros
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Calculates the size of an array of Pin instances. The array must be defined
+/// locally (i.e. not a pointer), otherwise the computation will not be correct.
+/// \param pPins Local array of Pin instances.
+/// \return Number of elements in array.
+//------------------------------------------------------------------------------
+#define PIO_LISTSIZE(pPins) (sizeof(pPins) / sizeof(Pin))
+
+//------------------------------------------------------------------------------
+// Global Types
+//------------------------------------------------------------------------------
+typedef struct _ExtIntMode {
+ ///indicate which pin to enable/disable additional Interrupt mode
+ ///each of 32 bit field represents one PIO line.
+ unsigned int itMask;
+ ///select Edge or level interrupt detection source
+ ///each of 32 bit field represents one PIO line, 0 is Edge, 1 is Level
+ unsigned int edgeLvlSel;
+ ///select rising/high or falling/low detection event
+ ///each of 32 bit field represents one PIO line:
+ ///0 is Falling Edge detection event (if selected Edge interrupt
+ /// detection source, or Low Level detection (if selected
+ /// Level interrupt detection source;
+ ///1 is Rising Edge detection(if selected Edge interrupt
+ /// source, or Low Level detection event(if selected Level
+ /// interrupt detection source.
+ unsigned int lowFallOrRiseHighSel;
+
+} ExtIntMode;
+
+typedef struct _GlitchDeBounceFilter {
+ ///Select Glitch/Debounce filtering for PIO input
+ ///each of 32 bit field represents one PIO line
+ ///0 is Glitch, 1 is Debouncing
+ unsigned int filterSel;
+ ///slow clock divider selection for Debouncing filter
+ unsigned int clkDivider:14;
+
+} GlitchDebounceFilter;
+
+//------------------------------------------------------------------------------
+/// Describes the type and attribute of one PIO pin or a group of similar pins.
+/// The #type# field can have the following values:
+/// - PIO_PERIPH_A
+/// - PIO_PERIPH_B
+/// - PIO_OUTPUT_0
+/// - PIO_OUTPUT_1
+/// - PIO_INPUT
+///
+/// The #attribute# field is a bitmask that can either be set to PIO_DEFAULt,
+/// or combine (using bitwise OR '|') any number of the following constants:
+/// - PIO_PULLUP
+/// - PIO_DEGLITCH
+/// - PIO_OPENDRAIN
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// Bitmask indicating which pin(s) to configure.
+ unsigned int mask;
+ /// Pointer to the PIO controller which has the pin(s).
+ AT91S_PIO *pio;
+ /// Peripheral ID of the PIO controller which has the pin(s).
+ unsigned char id;
+ /// Pin type.
+ unsigned char type;
+ /// Pin attribute.
+ unsigned char attribute;
+#if defined(AT91C_PIOA_AIMMR)
+ ///Additional Interrupt Mode
+ ExtIntMode itMode;
+#endif
+
+#if defined(AT91C_PIOA_IFDGSR)
+ ///Glitch/Debouncing filter
+ GlitchDebounceFilter inFilter;
+#endif
+
+} Pin;
+
+//------------------------------------------------------------------------------
+// Global Access Macros
+//------------------------------------------------------------------------------
+
+//Get Glitch input filter enable/disable status
+#define PIO_GetIFSR(pPin) ((pPin)->pio->PIO_IFSR)
+
+//Get Glitch/Deboucing selection status
+#define PIO_GetIFDGSR(pPin) ((pPin)->pio->PIO_IFDGSR)
+
+//Get Additional PIO interrupt mode mask status
+#define PIO_GetAIMMR(pPin) ((pPin)->pio->PIO_AIMMR)
+
+//Get Interrupt status
+#define PIO_GetISR(pPin) ((pPin)->pio->PIO_ISR)
+
+//Get Edge or Level selection status
+#define PIO_GetELSR(pPin) ((pPin)->pio->PIO_ELSR)
+
+//Get Fall/Rise or Low/High selection status
+#define PIO_GetFRLHSR(pPin) ((pPin)->pio->PIO_FRLHSR)
+
+//Get PIO Lock Status
+#define PIO_GetLockStatus(pPin) ((pPin)->pio->PIO_LOCKSR)
+
+//------------------------------------------------------------------------------
+// Global Functions
+//------------------------------------------------------------------------------
+
+extern unsigned char PIO_Configure(const Pin *list, unsigned int size);
+
+extern void PIO_Set(const Pin *pin);
+
+extern void PIO_Clear(const Pin *pin);
+
+extern unsigned char PIO_Get(const Pin *pin);
+
+//extern unsigned int PIO_GetISR(const Pin *pin);
+
+extern unsigned char PIO_GetOutputDataStatus(const Pin *pin);
+
+#endif //#ifndef PIO_H
+
diff --git a/peripherals/pio/pio_it.c b/peripherals/pio/pio_it.c new file mode 100644 index 0000000..cdd8a0b --- /dev/null +++ b/peripherals/pio/pio_it.c @@ -0,0 +1,461 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+/// Disable traces for this file
+#undef TRACE_LEVEL
+#define TRACE_LEVEL 0
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "pio_it.h"
+#include "pio.h"
+#include <board.h>
+#include <irq/irq.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Local definitions
+//------------------------------------------------------------------------------
+
+/// \exclude
+/// 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
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \exclude
+/// Describes a PIO interrupt source, including the PIO instance triggering the
+/// interrupt and the associated interrupt handler.
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// Pointer to the source pin instance.
+ const Pin *pPin;
+
+ /// Interrupt handler.
+ void (*handler)(const Pin *);
+
+} InterruptSource;
+
+//------------------------------------------------------------------------------
+// Local variables
+//------------------------------------------------------------------------------
+
+/// List of interrupt sources.
+static InterruptSource pSources[MAX_INTERRUPT_SOURCES];
+
+/// Number of currently defined interrupt sources.
+static unsigned int numSources;
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Handles all interrupts on the given PIO controller.
+/// \param id PIO controller ID.
+/// \param pPio PIO controller base address.
+//------------------------------------------------------------------------------
+static void PioInterruptHandler(unsigned int id, AT91S_PIO *pPio)
+{
+ unsigned int status;
+ unsigned int 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 #%d\n\r", id);
+
+ // Find triggering source
+ i = 0;
+ while (status != 0) {
+
+ // There cannot be an unconfigured source enabled.
+ SANITY_CHECK(i < numSources);
+
+ // Source is configured on the same controller
+ if (pSources[i].pPin->id == id) {
+
+ // Source has PIOs whose statuses have changed
+ if ((status & pSources[i].pPin->mask) != 0) {
+
+ TRACE_DEBUG("Interrupt source #%d triggered\n\r", i);
+
+ pSources[i].handler(pSources[i].pPin);
+ status &= ~(pSources[i].pPin->mask);
+ }
+ }
+ i++;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Generic PIO interrupt handler. Single entry point for interrupts coming
+/// from any PIO controller (PIO A, B, C ...). Dispatches the interrupt to
+/// the user-configured handlers.
+//------------------------------------------------------------------------------
+void PIO_IT_InterruptHandler(void)
+{
+#if defined(AT91C_ID_PIOA)
+ // Treat PIOA interrupts
+ PioInterruptHandler(AT91C_ID_PIOA, AT91C_BASE_PIOA);
+#endif
+
+#if defined(AT91C_ID_PIOB)
+ // Treat PIOB interrupts
+ PioInterruptHandler(AT91C_ID_PIOB, AT91C_BASE_PIOB);
+#endif
+
+#if defined(AT91C_ID_PIOC)
+ // Treat PIOC interrupts
+ PioInterruptHandler(AT91C_ID_PIOC, AT91C_BASE_PIOC);
+#endif
+
+#if defined(AT91C_ID_PIOD)
+ // Treat PIOD interrupts
+ PioInterruptHandler(AT91C_ID_PIOD, AT91C_BASE_PIOD);
+#endif
+
+#if defined(AT91C_ID_PIOE)
+ // Treat PIOE interrupts
+ PioInterruptHandler(AT91C_ID_PIOE, AT91C_BASE_PIOE);
+#endif
+
+#if defined(AT91C_ID_PIOABCD)
+ // Treat PIOABCD interrupts
+ #if !defined(AT91C_ID_PIOA)
+ PioInterruptHandler(AT91C_ID_PIOABCD, AT91C_BASE_PIOA);
+ #endif
+ #if !defined(AT91C_ID_PIOB)
+ PioInterruptHandler(AT91C_ID_PIOABCD, AT91C_BASE_PIOB);
+ #endif
+ #if !defined(AT91C_ID_PIOC)
+ PioInterruptHandler(AT91C_ID_PIOABCD, AT91C_BASE_PIOC);
+ #endif
+ #if !defined(AT91C_ID_PIOD)
+ PioInterruptHandler(AT91C_ID_PIOABCD, AT91C_BASE_PIOD);
+ #endif
+#endif
+
+#if defined(AT91C_ID_PIOABCDE)
+ // Treat PIOABCDE interrupts
+ #if !defined(AT91C_ID_PIOA)
+ PioInterruptHandler(AT91C_ID_PIOABCDE, AT91C_BASE_PIOA);
+ #endif
+ #if !defined(AT91C_ID_PIOB)
+ PioInterruptHandler(AT91C_ID_PIOABCDE, AT91C_BASE_PIOB);
+ #endif
+ #if !defined(AT91C_ID_PIOC)
+ PioInterruptHandler(AT91C_ID_PIOABCDE, AT91C_BASE_PIOC);
+ #endif
+ #if !defined(AT91C_ID_PIOD)
+ PioInterruptHandler(AT91C_ID_PIOABCDE, AT91C_BASE_PIOD);
+ #endif
+ #if !defined(AT91C_ID_PIOE)
+ PioInterruptHandler(AT91C_ID_PIOABCDE, AT91C_BASE_PIOE);
+ #endif
+#endif
+
+#if defined(AT91C_ID_PIOCDE)
+ // Treat PIOCDE interrupts
+ #if !defined(AT91C_ID_PIOC)
+ PioInterruptHandler(AT91C_ID_PIOCDE, AT91C_BASE_PIOC);
+ #endif
+ #if !defined(AT91C_ID_PIOD)
+ PioInterruptHandler(AT91C_ID_PIOCDE, AT91C_BASE_PIOD);
+ #endif
+ #if !defined(AT91C_ID_PIOE)
+ PioInterruptHandler(AT91C_ID_PIOCDE, AT91C_BASE_PIOE);
+ #endif
+#endif
+}
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// 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.
+//------------------------------------------------------------------------------
+void PIO_InitializeInterrupts(unsigned int priority)
+{
+ TRACE_DEBUG("PIO_Initialize()\n\r");
+
+// SANITY_CHECK((priority & ~AT91C_AIC_PRIOR) == 0);
+
+ // Reset sources
+ numSources = 0;
+
+#ifdef AT91C_ID_PIOA
+ // Configure PIO interrupt sources
+ TRACE_DEBUG("PIO_Initialize: Configuring PIOA\n\r");
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOA;
+ AT91C_BASE_PIOA->PIO_ISR;
+ AT91C_BASE_PIOA->PIO_IDR = 0xFFFFFFFF;
+ IRQ_ConfigureIT(AT91C_ID_PIOA, priority, PIO_IT_InterruptHandler);
+ IRQ_EnableIT(AT91C_ID_PIOA);
+#endif
+
+#ifdef AT91C_ID_PIOB
+ TRACE_DEBUG("PIO_Initialize: Configuring PIOB\n\r");
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOB;
+ AT91C_BASE_PIOB->PIO_ISR;
+ AT91C_BASE_PIOB->PIO_IDR = 0xFFFFFFFF;
+ IRQ_ConfigureIT(AT91C_ID_PIOB, priority, PIO_IT_InterruptHandler);
+ IRQ_EnableIT(AT91C_ID_PIOB);
+#endif
+
+#ifdef AT91C_ID_PIOC
+ TRACE_DEBUG("PIO_Initialize: Configuring PIOC\n\r");
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOC;
+ AT91C_BASE_PIOC->PIO_ISR;
+ AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF;
+ IRQ_ConfigureIT(AT91C_ID_PIOC, priority, PIO_IT_InterruptHandler);
+ IRQ_EnableIT(AT91C_ID_PIOC);
+#endif
+
+#ifdef AT91C_ID_PIOD
+ TRACE_DEBUG("PIO_Initialize: Configuring PIOD\n\r");
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOD;
+ AT91C_BASE_PIOC->PIO_ISR;
+ AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF;
+ IRQ_ConfigureIT(AT91C_ID_PIOD, priority, PIO_IT_InterruptHandler);
+ IRQ_EnableIT(AT91C_ID_PIOD);
+#endif
+
+#ifdef AT91C_ID_PIOE
+ TRACE_DEBUG("PIO_Initialize: Configuring PIOE\n\r");
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOE;
+ AT91C_BASE_PIOC->PIO_ISR;
+ AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF;
+ IRQ_ConfigureIT(AT91C_ID_PIOE, priority, PIO_IT_InterruptHandler);
+ IRQ_EnableIT(AT91C_ID_PIOE);
+#endif
+
+#if defined(AT91C_ID_PIOABCD)
+ // Treat PIOABCD interrupts
+ #if !defined(AT91C_ID_PIOA) \
+ && !defined(AT91C_ID_PIOB) \
+ && !defined(AT91C_ID_PIOC) \
+ && !defined(AT91C_ID_PIOD)
+
+ TRACE_DEBUG("PIO_Initialize: Configuring PIOABCD\n\r");
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOABCD;
+ AT91C_BASE_PIOA->PIO_ISR;
+ AT91C_BASE_PIOA->PIO_IDR = 0xFFFFFFFF;
+ IRQ_ConfigureIT(AT91C_ID_PIOABCD, priority, PIO_IT_InterruptHandler);
+ IRQ_EnableIT(AT91C_ID_PIOABCD);
+ #endif
+#endif
+
+#if defined(AT91C_ID_PIOABCDE)
+ // Treat PIOABCDE interrupts
+ #if !defined(AT91C_ID_PIOA) \
+ && !defined(AT91C_ID_PIOB) \
+ && !defined(AT91C_ID_PIOC) \
+ && !defined(AT91C_ID_PIOD) \
+ && !defined(AT91C_ID_PIOE)
+
+ TRACE_DEBUG("PIO_Initialize: Configuring PIOABCDE\n\r");
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOABCDE;
+ AT91C_BASE_PIOA->PIO_ISR;
+ AT91C_BASE_PIOA->PIO_IDR = 0xFFFFFFFF;
+ IRQ_ConfigureIT(AT91C_ID_PIOABCDE, priority, PIO_IT_InterruptHandler);
+ IRQ_EnableIT(AT91C_ID_PIOABCDE);
+ #endif
+#endif
+
+#if defined(AT91C_ID_PIOCDE)
+ // Treat PIOCDE interrupts
+ #if !defined(AT91C_ID_PIOC) \
+ && !defined(AT91C_ID_PIOD) \
+ && !defined(AT91C_ID_PIOE)
+
+ TRACE_DEBUG("PIO_Initialize: Configuring PIOC\n\r");
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOCDE;
+ AT91C_BASE_PIOC->PIO_ISR;
+ AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF;
+ IRQ_ConfigureIT(AT91C_ID_PIOCDE, priority, PIO_IT_InterruptHandler);
+ IRQ_EnableIT(AT91C_ID_PIOCDE);
+ #endif
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// 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.
+//------------------------------------------------------------------------------
+void PIO_ConfigureIt(const Pin *pPin, void (*handler)(const Pin *))
+{
+ InterruptSource *pSource;
+
+ TRACE_DEBUG("PIO_ConfigureIt()\n\r");
+
+ SANITY_CHECK(pPin);
+ ASSERT(numSources < MAX_INTERRUPT_SOURCES,
+ "-F- PIO_ConfigureIt: Increase MAX_INTERRUPT_SOURCES\n\r");
+
+ // Define new source
+ TRACE_DEBUG("PIO_ConfigureIt: Defining new source #%d.\n\r", numSources);
+
+ pSource = &(pSources[numSources]);
+ pSource->pPin = pPin;
+ pSource->handler = handler;
+ numSources++;
+}
+
+//------------------------------------------------------------------------------
+/// 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.
+//------------------------------------------------------------------------------
+void PIO_EnableIt(const Pin *pPin)
+{
+ TRACE_DEBUG("PIO_EnableIt()\n\r");
+
+ SANITY_CHECK(pPin);
+
+#ifndef NOASSERT
+ unsigned int i = 0;
+ unsigned char found = 0;
+ while ((i < numSources) && !found) {
+
+ if (pSources[i].pPin == pPin) {
+
+ found = 1;
+ }
+ i++;
+ }
+ ASSERT(found, "-F- PIO_EnableIt: Interrupt source has not been configured\n\r");
+#endif
+
+ pPin->pio->PIO_ISR;
+ pPin->pio->PIO_IER = pPin->mask;
+
+
+#if defined(AT91C_PIOA_AIMMR)
+ //PIO3 with additional interrupt support
+ //configure additional interrupt mode registers
+ if(pPin->mask&pPin->itMode.itMask) {
+
+ //enable additional interrupt mode
+ pPin->pio->PIO_AIMER = pPin->itMode.itMask;
+
+ if(pPin->mask&pPin->itMode.edgeLvlSel)
+ //if bit field of selected pin is 1, set as Level detection source
+ pPin->pio->PIO_LSR = pPin->itMode.edgeLvlSel;
+ else
+ //if bit field of selected pin is 0, set as Edge detection source
+ pPin->pio->PIO_ESR = ~(pPin->itMode.edgeLvlSel);
+
+ if(pPin->mask&pPin->itMode.lowFallOrRiseHighSel)
+ //if bit field of selected pin is 1, set as Rising Edge/High level detection event
+ pPin->pio->PIO_REHLSR = pPin->itMode.lowFallOrRiseHighSel;
+ else
+ //if bit field of selected pin is 0, set as Falling Edge/Low level detection event
+ pPin->pio->PIO_FELLSR = ~(pPin->itMode.lowFallOrRiseHighSel);
+ }
+
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Disables a given interrupt source, with no added side effects.
+/// \param pPin Interrupt source to disable.
+//------------------------------------------------------------------------------
+void PIO_DisableIt(const Pin *pPin)
+{
+ SANITY_CHECK(pPin);
+
+ TRACE_DEBUG("PIO_DisableIt()\n\r");
+
+ pPin->pio->PIO_IDR = pPin->mask;
+#if defined(AT91C_PIOA_AIMMR)
+ if(pPin->mask & pPin->itMode.itMask)
+ //disable additional interrupt mode
+ pPin->pio->PIO_AIMDR = pPin->mask & pPin->itMode.itMask;
+#endif
+
+}
+
+#if defined(cortexm3)
+//------------------------------------------------------------------------------
+/// Override cortex-m3's default PIOA irq handler
+//------------------------------------------------------------------------------
+void PIOA_IrqHandler(void)
+{
+ #if defined(AT91C_ID_PIOA)
+ // Treat PIOA interrupts
+ PioInterruptHandler(AT91C_ID_PIOA, AT91C_BASE_PIOA);
+ #endif
+}
+
+//------------------------------------------------------------------------------
+/// Override cortex-m3's default PIOB irq handler
+//------------------------------------------------------------------------------
+void PIOB_IrqHandler(void)
+{
+ #if defined(AT91C_ID_PIOB)
+ // Treat PIOA interrupts
+ PioInterruptHandler(AT91C_ID_PIOB, AT91C_BASE_PIOB);
+ #endif
+}
+
+//------------------------------------------------------------------------------
+/// Override cortex-m3's default PIOC irq handler
+//------------------------------------------------------------------------------
+void PIOC_IrqHandler(void)
+{
+ #if defined(AT91C_ID_PIOC)
+ // Treat PIOA interrupts
+ PioInterruptHandler(AT91C_ID_PIOC, AT91C_BASE_PIOC);
+ #endif
+}
+#endif
diff --git a/peripherals/pio/pio_it.h b/peripherals/pio/pio_it.h new file mode 100644 index 0000000..782e911 --- /dev/null +++ b/peripherals/pio/pio_it.h @@ -0,0 +1,85 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !!!Purpose
+///
+/// Configuration and handling of interrupts on PIO status changes. The API
+/// provided here have several advantages over the traditional PIO interrupt
+/// configuration approach:
+/// - It is highly portable
+/// - It automatically demultiplexes interrupts when multiples pins have been
+/// configured on a single PIO controller
+/// - It allows a group of pins to share the same interrupt
+///
+/// However, it also has several minor drawbacks that may prevent from using it
+/// in particular applications:
+/// - It enables the clocks of all PIO controllers
+/// - PIO controllers all share the same interrupt handler, which does the
+/// demultiplexing and can be slower than direct configuration
+/// - It reserves space for a fixed number of interrupts, which can be
+/// increased by modifying the appropriate constant in pio_it.c.
+///
+/// !!!Usage
+///
+/// -# Initialize the PIO interrupt mechanism using PIO_InitializeInterrupts()
+/// with the desired priority (0 ... 7).
+/// -# Configure a status change interrupt on one or more pin(s) with
+/// PIO_ConfigureIt().
+/// -# Enable & disable interrupts on pins using PIO_EnableIt() and
+/// PIO_DisableIt().
+//------------------------------------------------------------------------------
+
+#ifndef PIO_IT_H
+#define PIO_IT_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "pio.h"
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void PIO_InitializeInterrupts(unsigned int priority);
+
+extern void PIO_ConfigureIt(const Pin *pPin, void (*handler)(const Pin *));
+
+extern void PIO_EnableIt(const Pin *pPin);
+
+extern void PIO_DisableIt(const Pin *pPin);
+
+extern void PIO_IT_InterruptHandler(void);
+
+#endif //#ifndef PIO_IT_H
+
diff --git a/peripherals/pio/pio_keypad.c b/peripherals/pio/pio_keypad.c new file mode 100644 index 0000000..e617289 --- /dev/null +++ b/peripherals/pio/pio_keypad.c @@ -0,0 +1,147 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include "pio.h"
+#include "pio_keypad.h"
+
+
+//------------------------------------------------------------------------------
+// Global Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configures keypad controller
+/// \param pPIO Pointer to a PIO instance
+/// \param config Configuration data for given pin,see head file for detail
+//------------------------------------------------------------------------------
+void PIO_KeyPadConfig(AT91S_PIO *pPIO, KeyPadConfig *config)
+{
+ //enable/disable keypad controller
+ pPIO->PIO_KER = config->enable;
+
+ //if enable, set keypad matrix and debouncing
+ if(config->enable == TRUE) {
+ //set key matrix
+ pPIO->PIO_KRCR = (config->row | config->col<<8) ;
+
+ //set debouncing
+ pPIO->PIO_KDR = config->debouncing;
+
+ }
+}
+
+
+//------------------------------------------------------------------------------
+/// Get Key Press/Release status
+/// \param pPIO Pointer to a PIO instance
+/// \param event Pointer to a instance of KeyEvent for storing keypad status
+//------------------------------------------------------------------------------
+void PIO_GetKeyStatus(AT91S_PIO *pPIO, KeyEvent *event)
+{
+ int i,j;
+
+ //get key press event
+ event->kdEvent.press = (pPIO->KSR&0x1)?TRUE:FALSE;
+ event->kdEvent.keyPressNum = (pPIO->KSR>>8)&0x3;
+ j=event->kdEvent.keyPressNum+1;
+ for(i=0; i<j; i++) {
+ event->kdEvent.preKeyMatrix[i].row = ((pPIO->KKPR) >> (8*i)) & 0x7;
+ event->kdEvent.preKeyMatrix[i].col = ((pPIO->KKPR) >> (8*i+4)) & 0x7;
+ }
+
+ //get key release event
+ event->kuEvent.release = ((pPIO->KSR>>1) & 0x1)?TRUE:FALSE;
+ event->kuEvent.keyRelNum = (pPIO->KSR>>16)&0x3;
+ j=event->kdEvent.keyPressNum+1;
+ for(i=0;i<j;i++) {
+ event->kuEvent.relKeyMatrix[i].row = ((pPIO->KKRR) >> (8*i)) & 0x7;
+ event->kuEvent.relKeyMatrix[i].col = ((pPIO->KKRR) >> (8*i+4)) & 0x7;
+ }
+
+}
+
+
+//------------------------------------------------------------------------------
+/// Enable keypad interrupt as Key Press Interrupt or Key Release Interrupt or both
+/// \param pPIO Pointer to a PIO instance
+/// \param mode Select key interrupt mode to enable,
+/// 0x1 Key Press Interrupt
+/// 0x2 Key Release Interrupt
+/// 0x3 both of two type
+//------------------------------------------------------------------------------
+void PIO_KeypadEnableIt(AT91S_PIO *pPIO, unsigned int mode)
+{
+ switch(mode){
+ case 1:PIO_KeyPadEnableKPIt(pPIO);
+ break;
+
+ case 2:PIO_KeyPadEnableKRIt(pPIO);
+ break;
+
+ case 3:PIO_KeyPadEnableKPIt(pPIO);
+ PIO_KeyPadEnableKRIt(pPIO);
+ break;
+
+ default:break;
+ }
+
+}
+
+//------------------------------------------------------------------------------
+/// Disable Key Press Interrupt or Key Release Interrupt or both of them
+/// \param pPIO Pointer to a PIO instance
+/// \param mode Select key interrupt mode to disable,
+/// 0x1 Key Press Interrupt
+/// 0x2 Key Release Interrupt
+/// 0x3 both of two type
+//------------------------------------------------------------------------------
+void PIO_KeypadDisableIt(AT91S_PIO *pPIO, unsigned int mode)
+{
+ switch(mode){
+ case 1:PIO_KeyPadDisableKPIt(pPIO);
+ break;
+
+ case 2:PIO_KeyPadDisableKRIt(pPIO);
+ break;
+
+ case 3:PIO_KeyPadDisableKPIt(pPIO);
+ PIO_KeyPadDisableKRIt(pPIO);
+ break;
+
+ default:break;
+ }
+
+}
+
+
diff --git a/peripherals/pio/pio_keypad.h b/peripherals/pio/pio_keypad.h new file mode 100644 index 0000000..166f066 --- /dev/null +++ b/peripherals/pio/pio_keypad.h @@ -0,0 +1,153 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef PIO_KEYPAD_H
+#define PIO_KEYPAD_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Global Definitions
+//------------------------------------------------------------------------------
+
+
+
+
+//------------------------------------------------------------------------------
+// Global Macros
+//------------------------------------------------------------------------------
+//enable keypad press interrupt
+#define PIO_KeyPadEnableKPIt(pPIO) ((pPIO)->KIER = 1<<0)
+
+//enable keypad release interrupt
+#define PIO_KeyPadEnableKRIt(pPIO) ((pPIO)->KIER = 1<<1)
+
+//disable keypad press interrupt
+#define PIO_KeyPadDisableKPIt(pPIO) ((pPIO)->KIDR = 1<<0)
+
+//disable keypad release interrupt
+#define PIO_KeyPadDisableKRIt(pPIO) ((pPIO)->KIDR = 1<<1)
+
+//enable keypad controller interrupt
+#define PIO_KeyPadEnableIt(pPIO, mode) {switch(mode):\
+ case 1:PIO_KeyPadEnableKPIt(pPIO);break;\
+ case 2:PIO_KeyPadEnableKRIt(pPIO);break;\
+ case 3:PIO_KeyPadEnableKPIt(pPIO);\
+ PIO_KeyPadEnableKRIt(pPIO);break;\
+ default:break;\
+ }
+
+//disable keypad controller interrupt
+#define PIO_KeyPadDisableIt(pPIO, mode) {switch(mode):\
+ case 1:PIO_KeyPadDisableKPIt(pPIO);break;\
+ case 2:PIO_KeyPadDisableKRIt(pPIO);break;\
+ case 3:PIO_KeyPadDisableKPIt(pPIO);\
+ PIO_KeyPadDisableKRIt(pPIO);break;\
+ default:break;\
+ }
+
+//get keypad controller interrupt mask
+#define PIO_KeyPadGetItMask(pPIO) ((pPIO)->PIO_KIMR)
+
+
+//------------------------------------------------------------------------------
+/// Calculates the size of an array of Pin instances. The array must be defined
+/// locally (i.e. not a pointer), otherwise the computation will not be correct.
+/// \param pPins Local array of Pin instances.
+/// \return Number of elements in array.
+//------------------------------------------------------------------------------
+#define PIO_LISTSIZE(pPins) (sizeof(pPins) / sizeof(Pin))
+
+//------------------------------------------------------------------------------
+// Global Types
+//------------------------------------------------------------------------------
+typedef enum {
+ FALSE,
+ TRUE
+} bool;
+
+typedef struct _KeyPadConfig {
+ bool enable;//keypad controller enable or disable
+ unsigned char col:3;//config column size
+ unsigned char row:3;//config row size
+ unsigned int debouncing;//config debouncing
+} KeyPadConfig;
+
+
+typedef struct _KeyColRow {
+ unsigned char row:3;
+ unsigned char col:3;
+} KeyColRow;
+
+
+typedef struct _KeyDownEvent {
+ bool press;//at least 1 pressed key detected, or 0
+ unsigned char keyPressNum;//simultaneously pressed key number
+ KeyColRow preKeyMatrix[4];//pressed key matrix
+} KeyDownEvent;
+
+
+
+typedef struct _KeyUpEvent {
+ bool release;//at least 1 released key detected, or 0
+ unsigned char keyRelNum;//simultaneously released key number
+ KeyColRow relKeyMatrix[4];//released key matrix
+} KeyUpEvent;
+
+
+
+typedef struct _KeyEvent {
+ KeyDownEvent kdEvent;
+ KeyUpEvent kuEvent;
+} KeyEvent;
+
+//------------------------------------------------------------------------------
+// Global Access Macros
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// Global Functions
+//------------------------------------------------------------------------------
+
+void PIO_KeyPadConfig(AT91S_PIO *pPIO, KeyPadConfig *config);
+
+void PIO_GetKeyStatus(AT91S_PIO *pPIO, KeyEvent *event);
+
+void PIO_KeypadEnableIt(AT91S_PIO *pio, unsigned int mode);
+
+void PIO_KeypadDisableIt(AT91S_PIO *pio, unsigned int mode);
+
+
+#endif //#ifndef PIO_KEYPAD_H
+
diff --git a/peripherals/pit/pit.c b/peripherals/pit/pit.c new file mode 100644 index 0000000..f15610c --- /dev/null +++ b/peripherals/pit/pit.c @@ -0,0 +1,122 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "pit.h"
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initialize the Periodic Interval Timer to generate a tick at the specified
+/// period, given the current master clock frequency.
+/// \param period Period in µsecond.
+/// \param pit_frequency Master clock frequency in MHz.
+//------------------------------------------------------------------------------
+void PIT_Init(unsigned int period, unsigned int pit_frequency)
+{
+ AT91C_BASE_PITC->PITC_PIMR = period? (period * pit_frequency + 8) >> 4 : 0;
+ AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITEN;
+}
+
+//------------------------------------------------------------------------------
+/// Set the Periodic Interval Value of the PIT.
+/// \param piv PIV value to set.
+//------------------------------------------------------------------------------
+void PIT_SetPIV(unsigned int piv)
+{
+ AT91C_BASE_PITC->PITC_PIMR = (AT91C_BASE_PITC->PITC_PIMR & AT91C_PITC_PIV)
+ | piv;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the PIT if this is not already the case.
+//------------------------------------------------------------------------------
+void PIT_Enable(void)
+{
+ AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITEN;
+}
+
+//----------------------------------------------------------------------------
+/// Enable the PIT periodic interrupt.
+//----------------------------------------------------------------------------
+void PIT_EnableIT(void)
+{
+ AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITIEN;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the PIT periodic interrupt.
+//------------------------------------------------------------------------------
+void PIT_DisableIT(void)
+{
+ AT91C_BASE_PITC->PITC_PIMR &= ~AT91C_PITC_PITIEN;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the value of the PIT mode register.
+/// \return PIT_MR value.
+//------------------------------------------------------------------------------
+unsigned int PIT_GetMode(void)
+{
+ return AT91C_BASE_PITC->PITC_PIMR;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the value of the PIT status register, clearing it as a side effect.
+/// \return PIT_SR value.
+//------------------------------------------------------------------------------
+unsigned int PIT_GetStatus(void)
+{
+ return AT91C_BASE_PITC->PITC_PISR;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the value of the PIT Image Register, to read PICNT and CPIV without
+/// clearing the current values.
+/// \return PIT_PIIR value.
+//------------------------------------------------------------------------------
+unsigned int PIT_GetPIIR(void)
+{
+ return AT91C_BASE_PITC->PITC_PIIR;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the value of the PIT Value Register, clearing it as a side effect.
+/// \return PIT_PIVR value.
+//------------------------------------------------------------------------------
+unsigned int PIT_GetPIVR(void)
+{
+ return AT91C_BASE_PITC->PITC_PIVR;
+}
diff --git a/peripherals/pit/pit.dir b/peripherals/pit/pit.dir new file mode 100644 index 0000000..d90695c --- /dev/null +++ b/peripherals/pit/pit.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the peripheral API for the Periodic Interval Timer (PIT).
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/pit/pit.h b/peripherals/pit/pit.h new file mode 100644 index 0000000..12aad31 --- /dev/null +++ b/peripherals/pit/pit.h @@ -0,0 +1,77 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the Periodic Interval Timer (PIT) peripheral.
+///
+/// !Usage
+///
+/// -# Initialize the PIT with the desired period using PIT_Init().
+/// Alternatively, the Periodic Interval Value (PIV) can be configured
+/// manually using PIT_SetPIV().
+/// -# Start the PIT counting using PIT_Enable().
+/// -# Enable & disable the PIT interrupt using PIT_EnableIT() and
+/// PIT_DisableIT().
+/// -# Retrieve the current status of the PIT using PIT_GetStatus().
+/// -# To get the current value of the internal counter and the number of ticks
+/// that have occurred, use either PIT_GetPIVR() or PIT_GetPIIR() depending
+/// on whether you want the values to be cleared or not.
+//------------------------------------------------------------------------------
+
+#ifndef PIT_H
+#define PIT_H
+
+//------------------------------------------------------------------------------
+// Global Functions
+//------------------------------------------------------------------------------
+
+extern void PIT_Init(unsigned int period, unsigned int pit_frequency);
+
+extern void PIT_SetPIV(unsigned int piv);
+
+extern void PIT_Enable(void);
+
+extern void PIT_EnableIT(void);
+
+extern void PIT_DisableIT(void);
+
+extern unsigned int PIT_GetMode(void);
+
+extern unsigned int PIT_GetStatus(void);
+
+extern unsigned int PIT_GetPIIR(void);
+
+extern unsigned int PIT_GetPIVR(void);
+
+#endif //#ifndef PIT_H
+
diff --git a/peripherals/pmc/pmc.c b/peripherals/pmc/pmc.c new file mode 100644 index 0000000..d464d51 --- /dev/null +++ b/peripherals/pmc/pmc.c @@ -0,0 +1,188 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "pmc.h"
+#include <board.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+#ifdef CP15_PRESENT
+#include <cp15/cp15.h>
+#endif
+
+#define MASK_STATUS 0x3FFFFFFC
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+#if defined(at91sam7l64) || defined(at91sam7l128)
+//------------------------------------------------------------------------------
+/// Sets the fast wake-up inputs that can get the device out of Wait mode.
+/// \param inputs Fast wake-up inputs to enable.
+//------------------------------------------------------------------------------
+void PMC_SetFastWakeUpInputs(unsigned int inputs)
+{
+ SANITY_CHECK((inputs & ~0xFF) == 0);
+ AT91C_BASE_PMC->PMC_FSMR = inputs;
+}
+
+#if !defined(__ICCARM__)
+__attribute__ ((section (".ramfunc"))) // GCC
+#endif
+//------------------------------------------------------------------------------
+/// Disables the main oscillator, making the device enter Wait mode.
+//------------------------------------------------------------------------------
+void PMC_DisableMainOscillatorForWaitMode(void)
+{
+ AT91C_BASE_PMC->PMC_MOR = 0x37 << 16;
+ while ((AT91C_BASE_PMC->PMC_MOR & AT91C_PMC_MAINSELS) != AT91C_PMC_MAINSELS);
+}
+
+#endif
+
+#if defined(at91sam7l)
+//------------------------------------------------------------------------------
+/// Disables the main oscillator when NOT running on it.
+//------------------------------------------------------------------------------
+void PMC_DisableMainOscillator(void)
+{
+ AT91C_BASE_PMC->PMC_MOR = 0x37 << 16;
+ while ((AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MAINSELS) == AT91C_PMC_MAINSELS);
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Disables the processor clock
+//------------------------------------------------------------------------------
+void PMC_DisableProcessorClock(void)
+{
+ AT91C_BASE_PMC->PMC_SCDR = AT91C_PMC_PCK;
+ while ((AT91C_BASE_PMC->PMC_SCSR & AT91C_PMC_PCK) != AT91C_PMC_PCK);
+}
+
+//------------------------------------------------------------------------------
+/// Enables the clock of a peripheral. The peripheral ID (AT91C_ID_xxx) is used
+/// to identify which peripheral is targetted.
+/// Note that the ID must NOT be shifted (i.e. 1 << AT91C_ID_xxx).
+/// \param id Peripheral ID (AT91C_ID_xxx).
+//------------------------------------------------------------------------------
+void PMC_EnablePeripheral(unsigned int id)
+{
+ SANITY_CHECK(id < 32);
+
+ if ((AT91C_BASE_PMC->PMC_PCSR & (1 << id)) == (1 << id)) {
+
+ TRACE_INFO("PMC_EnablePeripheral: clock of peripheral"
+ " %u is already enabled\n\r",
+ id);
+ }
+ else {
+
+ AT91C_BASE_PMC->PMC_PCER = 1 << id;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Disables the clock of a peripheral. The peripheral ID (AT91C_ID_xxx) is used
+/// to identify which peripheral is targetted.
+/// Note that the ID must NOT be shifted (i.e. 1 << AT91C_ID_xxx).
+/// \param id Peripheral ID (AT91C_ID_xxx).
+//------------------------------------------------------------------------------
+void PMC_DisablePeripheral(unsigned int id)
+{
+ SANITY_CHECK(id < 32);
+
+ if ((AT91C_BASE_PMC->PMC_PCSR & (1 << id)) != (1 << id)) {
+
+ TRACE_INFO("PMC_DisablePeripheral: clock of peripheral"
+ " %u is not enabled\n\r",
+ id);
+ }
+ else {
+
+ AT91C_BASE_PMC->PMC_PCDR = 1 << id;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Enable all the periph clock via PMC
+/// (Becareful of the last 2 bits, it is not periph clock)
+//------------------------------------------------------------------------------
+void PMC_EnableAllPeripherals(void)
+{
+ AT91C_BASE_PMC->PMC_PCER = MASK_STATUS;
+ while( (AT91C_BASE_PMC->PMC_PCSR & MASK_STATUS) != MASK_STATUS);
+ TRACE_INFO("Enable all periph clocks\n\r");
+}
+
+//------------------------------------------------------------------------------
+/// Disable all the periph clock via PMC
+/// (Becareful of the last 2 bits, it is not periph clock)
+//------------------------------------------------------------------------------
+void PMC_DisableAllPeripherals(void)
+{
+ AT91C_BASE_PMC->PMC_PCDR = MASK_STATUS;
+ while((AT91C_BASE_PMC->PMC_PCSR & MASK_STATUS) != 0);
+ TRACE_INFO("Disable all periph clocks\n\r");
+}
+
+//-----------------------------------------------------------------------------
+/// Get Periph Status
+//-----------------------------------------------------------------------------
+unsigned int PMC_IsAllPeriphEnabled(void)
+{
+ return (AT91C_BASE_PMC->PMC_PCSR == MASK_STATUS);
+}
+
+//-----------------------------------------------------------------------------
+/// Get Periph Status
+//-----------------------------------------------------------------------------
+unsigned int PMC_IsPeriphEnabled(unsigned int id)
+{
+ return (AT91C_BASE_PMC->PMC_PCSR & (1 << id));
+}
+//------------------------------------------------------------------------------
+/// Put the CPU in Idle Mode for lower consumption
+//------------------------------------------------------------------------------
+void PMC_CPUInIdleMode(void)
+{
+#ifndef CP15_PRESENT
+ PMC_DisableProcessorClock();
+#else
+ AT91C_BASE_PMC->PMC_SCDR = AT91C_PMC_PCK;
+ CP15_WaitForInterrupt();
+#endif
+}
+
+
diff --git a/peripherals/pmc/pmc.h b/peripherals/pmc/pmc.h new file mode 100644 index 0000000..a53b365 --- /dev/null +++ b/peripherals/pmc/pmc.h @@ -0,0 +1,62 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef PMC_H
+#define PMC_H
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+#if defined(at91sam7l64) || defined(at91sam7l128)
+extern void PMC_SetFastWakeUpInputs(unsigned int inputs);
+extern void PMC_DisableMainOscillator(void);
+extern
+#ifdef __ICCARM__
+__ramfunc
+#endif //__ICCARM__
+void PMC_DisableMainOscillatorForWaitMode(void);
+#endif // at91sam7l64 at91sam7l128
+
+extern void PMC_DisableProcessorClock(void);
+extern void PMC_EnablePeripheral(unsigned int id);
+extern void PMC_DisablePeripheral(unsigned int id);
+extern void PMC_CPUInIdleMode(void);
+
+
+extern void PMC_EnableAllPeripherals(void);
+
+extern void PMC_DisableAllPeripherals(void);
+
+extern unsigned int PMC_IsAllPeriphEnabled(void);
+
+extern unsigned int PMC_IsPeriphEnabled(unsigned int id);
+
+#endif //#ifndef PMC_H
+
diff --git a/peripherals/pwmc/pwmc.c b/peripherals/pwmc/pwmc.c new file mode 100644 index 0000000..98ca5cf --- /dev/null +++ b/peripherals/pwmc/pwmc.c @@ -0,0 +1,245 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "pwmc.h"
+#include <board.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Finds a prescaler/divisor couple to generate the desired frequency from
+/// MCK.
+/// Returns the value to enter in PWMC_MR or 0 if the configuration cannot be
+/// met.
+/// \param frequency Desired frequency in Hz.
+/// \param mck Master clock frequency in Hz.
+//------------------------------------------------------------------------------
+static unsigned short FindClockConfiguration(
+ unsigned int frequency,
+ unsigned int mck)
+{
+ unsigned int divisors[11] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
+ unsigned char divisor = 0;
+ unsigned int prescaler;
+
+ SANITY_CHECK(frequency < mck);
+
+ // Find prescaler and divisor values
+ prescaler = (mck / divisors[divisor]) / frequency;
+ while ((prescaler > 255) && (divisor < 11)) {
+
+ divisor++;
+ prescaler = (mck / divisors[divisor]) / frequency;
+ }
+
+ // Return result
+ if (divisor < 11) {
+
+ TRACE_DEBUG("Found divisor=%u and prescaler=%u for freq=%uHz\n\r",
+ divisors[divisor], prescaler, frequency);
+ return prescaler | (divisor << 8);
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configures PWM a channel with the given parameters.
+/// The PWM controller must have been clocked in the PMC prior to calling this
+/// function.
+/// Beware: this function disables the channel. It waits until disable is effective.
+/// \param channel Channel number.
+/// \param prescaler Channel prescaler.
+/// \param alignment Channel alignment.
+/// \param polarity Channel polarity.
+//------------------------------------------------------------------------------
+void PWMC_ConfigureChannel(
+ unsigned char channel,
+ unsigned int prescaler,
+ unsigned int alignment,
+ unsigned int polarity)
+{
+ SANITY_CHECK(prescaler < AT91C_PWMC_CPRE_MCKB);
+ SANITY_CHECK((alignment & ~AT91C_PWMC_CALG) == 0);
+ SANITY_CHECK((polarity & ~AT91C_PWMC_CPOL) == 0);
+
+ // Disable channel (effective at the end of the current period)
+ if ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) != 0) {
+ AT91C_BASE_PWMC->PWMC_DIS = 1 << channel;
+ while ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) != 0);
+ }
+
+ // Configure channel
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CMR = prescaler | alignment | polarity;
+}
+
+//------------------------------------------------------------------------------
+/// Configures PWM clocks A & B to run at the given frequencies. This function
+/// finds the best MCK divisor and prescaler values automatically.
+/// \param clka Desired clock A frequency (0 if not used).
+/// \param clkb Desired clock B frequency (0 if not used).
+/// \param mck Master clock frequency.
+//------------------------------------------------------------------------------
+void PWMC_ConfigureClocks(unsigned int clka, unsigned int clkb, unsigned int mck)
+{
+ unsigned int mode = 0;
+ unsigned int result;
+
+ // Clock A
+ if (clka != 0) {
+
+ result = FindClockConfiguration(clka, mck);
+ ASSERT(result != 0, "-F- Could not generate the desired PWM frequency (%uHz)\n\r", clka);
+ mode |= result;
+ }
+
+ // Clock B
+ if (clkb != 0) {
+
+ result = FindClockConfiguration(clkb, mck);
+ ASSERT(result != 0, "-F- Could not generate the desired PWM frequency (%uHz)\n\r", clkb);
+ mode |= (result << 16);
+ }
+
+ // Configure clocks
+ TRACE_DEBUG("Setting PWMC_MR = 0x%08X\n\r", mode);
+ AT91C_BASE_PWMC->PWMC_MR = mode;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the period value used by a PWM channel. This function writes directly
+/// to the CPRD register if the channel is disabled; otherwise, it uses the
+/// update register CUPD.
+/// \param channel Channel number.
+/// \param period Period value.
+//------------------------------------------------------------------------------
+void PWMC_SetPeriod(unsigned char channel, unsigned short period)
+{
+ // If channel is disabled, write to CPRD
+ if ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) == 0) {
+
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CPRDR = period;
+ }
+ // Otherwise use update register
+ else {
+
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CMR |= AT91C_PWMC_CPD;
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CUPDR = period;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the duty cycle used by a PWM channel. This function writes directly to
+/// the CDTY register if the channel is disabled; otherwise it uses the
+/// update register CUPD.
+/// Note that the duty cycle must always be inferior or equal to the channel
+/// period.
+/// \param channel Channel number.
+/// \param duty Duty cycle value.
+//------------------------------------------------------------------------------
+void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty)
+{
+ SANITY_CHECK(duty <= AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CPRDR);
+
+ // SAM7S errata
+#if defined(at91sam7s16) || defined(at91sam7s161) || defined(at91sam7s32) \
+ || defined(at91sam7s321) || defined(at91sam7s64) || defined(at91sam7s128) \
+ || defined(at91sam7s256) || defined(at91sam7s512)
+ ASSERT(duty > 0, "-F- Duty cycle value 0 is not permitted on SAM7S chips.\n\r");
+ ASSERT((duty > 1) || (AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CMR & AT91C_PWMC_CALG),
+ "-F- Duty cycle value 1 is not permitted in left-aligned mode on SAM7S chips.\n\r");
+#endif
+
+ // If channel is disabled, write to CDTY
+ if ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) == 0) {
+
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CDTYR = duty;
+ }
+ // Otherwise use update register
+ else {
+
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CMR &= ~AT91C_PWMC_CPD;
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CUPDR = duty;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Enables the given PWM channel. This does NOT enable the corresponding pin;
+/// this must be done in the user code.
+/// \param channel Channel number.
+//------------------------------------------------------------------------------
+void PWMC_EnableChannel(unsigned char channel)
+{
+ AT91C_BASE_PWMC->PWMC_ENA = 1 << channel;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the given PWM channel.
+/// Beware, channel will be effectively disabled at the end of the current period.
+/// Application can check channel is disabled using the following wait loop:
+/// while ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) != 0);
+/// \param channel Channel number.
+//------------------------------------------------------------------------------
+void PWMC_DisableChannel(unsigned char channel)
+{
+ AT91C_BASE_PWMC->PWMC_DIS = 1 << channel;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the period interrupt for the given PWM channel.
+/// \param channel Channel number.
+//------------------------------------------------------------------------------
+void PWMC_EnableChannelIt(unsigned char channel)
+{
+ AT91C_BASE_PWMC->PWMC_IER = 1 << channel;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the period interrupt for the given PWM channel.
+/// \param channel Channel number.
+//------------------------------------------------------------------------------
+void PWMC_DisableChannelIt(unsigned char channel)
+{
+ AT91C_BASE_PWMC->PWMC_IDR = 1 << channel;
+}
+
diff --git a/peripherals/pwmc/pwmc.dir b/peripherals/pwmc/pwmc.dir new file mode 100644 index 0000000..a163809 --- /dev/null +++ b/peripherals/pwmc/pwmc.dir @@ -0,0 +1,35 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !!!Purpose
+///
+/// Contains the peripheral API for Pulse Width Modulation Controller (PWM).
+//------------------------------------------------------------------------------
diff --git a/peripherals/pwmc/pwmc.h b/peripherals/pwmc/pwmc.h new file mode 100644 index 0000000..fe2b440 --- /dev/null +++ b/peripherals/pwmc/pwmc.h @@ -0,0 +1,83 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the Pulse Width Modulation Controller (PWM) peripheral.
+///
+/// !Usage
+///
+/// -# Configures PWM clocks A & B to run at the given frequencies using
+/// PWMC_ConfigureClocks().
+/// -# Configure PWMC channel using PWMC_ConfigureChannel(), PWMC_SetPeriod()
+/// and PWMC_SetDutyCycle().
+/// -# Enable & disable channel using PWMC_EnableChannel() and
+/// PWMC_DisableChannel().
+/// -# Enable & disable the period interrupt for the given PWM channel using
+/// PWMC_EnableChannelIt() and PWMC_DisableChannelIt().
+///
+/// Please refer to the list of functions in the #Overview# tab of this unit
+/// for more detailed information.
+//------------------------------------------------------------------------------
+
+#ifndef PWMC_H
+#define PWMC_H
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void PWMC_ConfigureChannel(
+ unsigned char channel,
+ unsigned int prescaler,
+ unsigned int alignment,
+ unsigned int polarity);
+
+extern void PWMC_ConfigureClocks
+ (unsigned int clka,
+ unsigned int clkb,
+ unsigned int mck);
+
+extern void PWMC_SetPeriod(unsigned char channel, unsigned short period);
+
+extern void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty);
+
+extern void PWMC_EnableChannel(unsigned char channel);
+
+extern void PWMC_DisableChannel(unsigned char channel);
+
+extern void PWMC_EnableChannelIt(unsigned char channel);
+
+extern void PWMC_DisableChannelIt(unsigned char channel);
+
+#endif //#ifndef PWMC_H
+
diff --git a/peripherals/pwmc/pwmc2.c b/peripherals/pwmc/pwmc2.c new file mode 100644 index 0000000..e225e73 --- /dev/null +++ b/peripherals/pwmc/pwmc2.c @@ -0,0 +1,589 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "pwmc2.h"
+#include <board.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Finds a prescaler/divisor couple to generate the desired frequency from
+/// MCK.
+/// Returns the value to enter in PWMC_MR or 0 if the configuration cannot be
+/// met.
+/// \param frequency Desired frequency in Hz.
+/// \param mck Master clock frequency in Hz.
+//------------------------------------------------------------------------------
+static unsigned short FindClockConfiguration(
+ unsigned int frequency,
+ unsigned int mck)
+{
+ unsigned int divisors[11] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
+ unsigned char divisor = 0;
+ unsigned int prescaler;
+
+ SANITY_CHECK(frequency < mck);
+
+ // Find prescaler and divisor values
+ prescaler = (mck / divisors[divisor]) / frequency;
+ while ((prescaler > 255) && (divisor < 11)) {
+
+ divisor++;
+ prescaler = (mck / divisors[divisor]) / frequency;
+ }
+
+ // Return result
+ if (divisor < 11) {
+
+ TRACE_DEBUG("Found divisor=%u and prescaler=%u for freq=%uHz\n\r",
+ divisors[divisor], prescaler, frequency);
+ return prescaler | (divisor << 8);
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configures PWM a channel with the given parameters, basic configure function.
+/// The PWM controller must have been clocked in the PMC prior to calling this
+/// function.
+/// Beware: this function disables the channel. It waits until disable is effective.
+/// \param channel Channel number.
+/// \param prescaler Channel prescaler.
+/// \param alignment Channel alignment.
+/// \param polarity Channel polarity.
+//------------------------------------------------------------------------------
+void PWMC_ConfigureChannel(
+ unsigned char channel,
+ unsigned int prescaler,
+ unsigned int alignment,
+ unsigned int polarity)
+{
+ SANITY_CHECK(prescaler < AT91C_PWMC_CPRE_MCKB);
+ SANITY_CHECK((alignment & ~AT91C_PWMC_CALG) == 0);
+ SANITY_CHECK((polarity & ~AT91C_PWMC_CPOL) == 0);
+
+ // Disable channel (effective at the end of the current period)
+ if ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) != 0) {
+ AT91C_BASE_PWMC->PWMC_DIS = 1 << channel;
+ while ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) != 0);
+ }
+
+ // Configure channel
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CMR = prescaler | alignment | polarity;
+}
+
+//------------------------------------------------------------------------------
+/// Configures PWM a channel with the given parameters, extend configure function.
+/// The PWM controller must have been clocked in the PMC prior to calling this
+/// function.
+/// Beware: this function disables the channel. It waits until disable is effective.
+/// \param channel Channel number.
+/// \param prescaler Channel prescaler.
+/// \param alignment Channel alignment.
+/// \param polarity Channel polarity.
+/// \param countEventSelect Channel counter event selection.
+/// \param DTEnable Channel dead time generator enable.
+/// \param DTHInverte Channel Dead-Time PWMHx output Inverted.
+/// \param DTLInverte Channel Dead-Time PWMHx output Inverted.
+//------------------------------------------------------------------------------
+void PWMC_ConfigureChannelExt(
+ unsigned char channel,
+ unsigned int prescaler,
+ unsigned int alignment,
+ unsigned int polarity,
+ unsigned int countEventSelect,
+ unsigned int DTEnable,
+ unsigned int DTHInverte,
+ unsigned int DTLInverte)
+{
+ SANITY_CHECK(prescaler < AT91C_PWMC_CPRE_MCKB);
+ SANITY_CHECK((alignment & ~AT91C_PWMC_CALG) == 0);
+ SANITY_CHECK((polarity & ~AT91C_PWMC_CPOL) == 0);
+ SANITY_CHECK((countEventSelect & ~AT91C_PWMC_CES) == 0);
+ SANITY_CHECK((DTEnable & ~AT91C_PWMC_DTE) == 0);
+ SANITY_CHECK((DTHInverte & ~AT91C_PWMC_DTHI) == 0);
+ SANITY_CHECK((DTLInverte & ~AT91C_PWMC_DTLI) == 0);
+
+ // Disable channel (effective at the end of the current period)
+ if ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) != 0) {
+ AT91C_BASE_PWMC->PWMC_DIS = 1 << channel;
+ while ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) != 0);
+ }
+
+ // Configure channel
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CMR = prescaler | alignment | polarity |
+ countEventSelect | DTEnable | DTHInverte | DTLInverte;
+}
+
+//------------------------------------------------------------------------------
+/// Configures PWM clocks A & B to run at the given frequencies. This function
+/// finds the best MCK divisor and prescaler values automatically.
+/// \param clka Desired clock A frequency (0 if not used).
+/// \param clkb Desired clock B frequency (0 if not used).
+/// \param mck Master clock frequency.
+//------------------------------------------------------------------------------
+void PWMC_ConfigureClocks(unsigned int clka, unsigned int clkb, unsigned int mck)
+{
+ unsigned int mode = 0;
+ unsigned int result;
+
+ // Clock A
+ if (clka != 0) {
+
+ result = FindClockConfiguration(clka, mck);
+ ASSERT(result != 0, "-F- Could not generate the desired PWM frequency (%uHz)\n\r", clka);
+ mode |= result;
+ }
+
+ // Clock B
+ if (clkb != 0) {
+
+ result = FindClockConfiguration(clkb, mck);
+ ASSERT(result != 0, "-F- Could not generate the desired PWM frequency (%uHz)\n\r", clkb);
+ mode |= (result << 16);
+ }
+
+ // Configure clocks
+ TRACE_DEBUG("Setting PWMC_MR = 0x%08X\n\r", mode);
+ AT91C_BASE_PWMC->PWMC_MR = mode;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the period value used by a PWM channel. This function writes directly
+/// to the CPRD register if the channel is disabled; otherwise, it uses the
+/// update register CUPD.
+/// \param channel Channel number.
+/// \param period Period value.
+//------------------------------------------------------------------------------
+void PWMC_SetPeriod(unsigned char channel, unsigned short period)
+{
+ // If channel is disabled, write to CPRD
+ if ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) == 0) {
+
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CPRDR = period;
+ }
+ // Otherwise use update register
+ else {
+
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CPRDUPDR = period;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the duty cycle used by a PWM channel. This function writes directly to
+/// the CDTY register if the channel is disabled; otherwise it uses the
+/// update register CUPD.
+/// Note that the duty cycle must always be inferior or equal to the channel
+/// period.
+/// \param channel Channel number.
+/// \param duty Duty cycle value.
+//------------------------------------------------------------------------------
+void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty)
+{
+ SANITY_CHECK(duty <= AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CPRDR);
+
+ // SAM7S errata
+#if defined(at91sam7s16) || defined(at91sam7s161) || defined(at91sam7s32) \
+ || defined(at91sam7s321) || defined(at91sam7s64) || defined(at91sam7s128) \
+ || defined(at91sam7s256) || defined(at91sam7s512)
+ ASSERT(duty > 0, "-F- Duty cycle value 0 is not permitted on SAM7S chips.\n\r");
+ ASSERT((duty > 1) || (AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CMR & AT91C_PWMC_CALG),
+ "-F- Duty cycle value 1 is not permitted in left-aligned mode on SAM7S chips.\n\r");
+#endif
+
+ // If channel is disabled, write to CDTY
+ if ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) == 0) {
+
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CDTYR = duty;
+ }
+ // Otherwise use update register
+ else {
+
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CDTYUPDR = duty;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the dead time used by a PWM channel. This function writes directly to
+/// the DTR register if the channel is disabled; otherwise it uses the
+/// update register DTUPDR.
+/// Note that the dead time must always be inferior or equal to the channel
+/// period.
+/// \param channel Channel number.
+/// \param timeH Dead time value for PWMHx output.
+/// \param timeL Dead time value for PWMLx output.
+//------------------------------------------------------------------------------
+void PWMC_SetDeadTime(unsigned char channel, unsigned short timeH, unsigned short timeL)
+{
+ SANITY_CHECK(timeH <= AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CPRDR);
+ SANITY_CHECK(timeL <= AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CPRDR);
+
+ // If channel is disabled, write to DTR
+ if ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) == 0) {
+
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_DTR = timeH | (timeL << 16);
+ }
+ // Otherwise use update register
+ else {
+ AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_DTUPDR = timeH | (timeL << 16);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Configures Syncronous channel with the given parameters.
+/// Beware: At this time, the channels should be disabled.
+/// \param channels Bitwise OR of Syncronous channels.
+/// \param updateMode Syncronous channel update mode.
+/// \param requestMode PDC transfer request mode.
+/// \param requestComparisonSelect PDC transfer request comparison selection.
+//------------------------------------------------------------------------------
+void PWMC_ConfigureSyncChannel(
+ unsigned int channels,
+ unsigned int updateMode,
+ unsigned int requestMode,
+ unsigned int requestComparisonSelect)
+{
+ AT91C_BASE_PWMC->PWMC_SYNC = channels | updateMode | requestMode
+ | requestComparisonSelect;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the update period of the synchronous channels.
+/// This function writes directly to
+/// the SCUP register if the channel #0 is disabled; otherwise it uses the
+/// update register SCUPUPD.
+/// \param period update period.
+//------------------------------------------------------------------------------
+void PWMC_SetSyncChannelUpdatePeriod(unsigned char period)
+{
+ // If channel is disabled, write to SCUP
+ if ((AT91C_BASE_PWMC->PWMC_SR & (1 << 0)) == 0) {
+
+ AT91C_BASE_PWMC->PWMC_SCUP = period;
+ }
+ // Otherwise use update register
+ else {
+
+ AT91C_BASE_PWMC->PWMC_SCUPUPD = period;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets synchronous channels update unlock.
+/// Note: If the UPDM field is set to 0, writing the UPDULOCK bit to 1
+/// triggers the update of the period value, the duty-cycle and
+/// the dead-time values of synchronous channels at the beginning
+/// of the next PWM period. If the field UPDM is set to 1 or 2,
+/// writing the UPDULOCK bit to 1 triggers only the update of
+/// the period value and of the dead-time values of synchronous channels.
+/// This bit is automatically reset when the update is done.
+//------------------------------------------------------------------------------
+void PWMC_SetSyncChannelUpdateUnlock(void)
+{
+ AT91C_BASE_PWMC->PWMC_UPCR = AT91C_PWMC_UPDULOCK;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the given PWM channel. This does NOT enable the corresponding pin;
+/// this must be done in the user code.
+/// \param channel Channel number.
+//------------------------------------------------------------------------------
+void PWMC_EnableChannel(unsigned char channel)
+{
+ AT91C_BASE_PWMC->PWMC_ENA = 1 << channel;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the given PWM channel.
+/// Beware, channel will be effectively disabled at the end of the current period.
+/// Application can check channel is disabled using the following wait loop:
+/// while ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) != 0);
+/// \param channel Channel number.
+//------------------------------------------------------------------------------
+void PWMC_DisableChannel(unsigned char channel)
+{
+ AT91C_BASE_PWMC->PWMC_DIS = 1 << channel;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the period interrupt for the given PWM channel.
+/// \param channel Channel number.
+//------------------------------------------------------------------------------
+void PWMC_EnableChannelIt(unsigned char channel)
+{
+ AT91C_BASE_PWMC->PWMC_IER1 = 1 << channel;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the period interrupt for the given PWM channel.
+/// \param channel Channel number.
+//------------------------------------------------------------------------------
+void PWMC_DisableChannelIt(unsigned char channel)
+{
+ AT91C_BASE_PWMC->PWMC_IDR1 = 1 << channel;
+}
+
+//-----------------------------------------------------------------------------
+/// Enables the selected interrupts sources on a PWMC peripheral.
+/// \param sources1 Bitwise OR of selected interrupt sources of PWMC_IER1.
+/// \param sources2 Bitwise OR of selected interrupt sources of PWMC_IER2.
+//-----------------------------------------------------------------------------
+void PWMC_EnableIt(unsigned int sources1, unsigned int sources2)
+{
+ AT91C_BASE_PWMC->PWMC_IER1 = sources1;
+ AT91C_BASE_PWMC->PWMC_IER2 = sources2;
+}
+
+//-----------------------------------------------------------------------------
+/// Disables the selected interrupts sources on a PWMC peripheral.
+/// \param sources1 Bitwise OR of selected interrupt sources of PWMC_IDR1.
+/// \param sources2 Bitwise OR of selected interrupt sources of PWMC_IDR2.
+//-----------------------------------------------------------------------------
+void PWMC_DisableIt(unsigned int sources1, unsigned int sources2)
+{
+ AT91C_BASE_PWMC->PWMC_IDR1 = sources1;
+ AT91C_BASE_PWMC->PWMC_IDR2 = sources2;
+}
+
+//------------------------------------------------------------------------------
+/// Sends the contents of buffer through a PWMC peripheral, using the PDC to
+/// take care of the transfer.
+/// Note: Duty cycle of syncronous channels can update by PDC
+/// when the field UPDM (Update Mode) in the PWM_SCM register is set to 2.
+/// \param pwmc Pointer to an AT91S_PWMC instance.
+/// \param buffer Data buffer to send.
+/// \param length Length of the data buffer.
+//------------------------------------------------------------------------------
+unsigned char PWMC_WriteBuffer(AT91S_PWMC *pwmc,
+ void *buffer,
+ unsigned int length)
+{
+ // Check if first bank is free
+ if (pwmc->PWMC_TCR == 0) {
+
+ pwmc->PWMC_TPR = (unsigned int) buffer;
+ pwmc->PWMC_TCR = length;
+ pwmc->PWMC_PTCR = AT91C_PDC_TXTEN;
+ return 1;
+ }
+ // Check if second bank is free
+ else if (pwmc->PWMC_TNCR == 0) {
+
+ pwmc->PWMC_TNPR = (unsigned int) buffer;
+ pwmc->PWMC_TNCR = length;
+ return 1;
+ }
+
+ // No free banks
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+/// Set PWM output override value
+/// \param value Bitwise OR of output override value.
+//-----------------------------------------------------------------------------
+void PWMC_SetOverrideValue(unsigned int value)
+{
+ AT91C_BASE_PWMC->PWMC_OOV = value;
+}
+
+//-----------------------------------------------------------------------------
+/// Enalbe override output.
+/// \param value Bitwise OR of output selection.
+/// \param sync 0: enable the output asyncronously, 1: enable it syncronously
+//-----------------------------------------------------------------------------
+void PWMC_EnableOverrideOutput(unsigned int value, unsigned int sync)
+{
+ if (sync) {
+
+ AT91C_BASE_PWMC->PWMC_OSSUPD = value;
+ } else {
+
+ AT91C_BASE_PWMC->PWMC_OSS = value;
+ }
+}
+
+//-----------------------------------------------------------------------------
+/// Disalbe override output.
+/// \param value Bitwise OR of output selection.
+/// \param sync 0: enable the output asyncronously, 1: enable it syncronously
+//-----------------------------------------------------------------------------
+void PWMC_DisableOverrideOutput(unsigned int value, unsigned int sync)
+{
+ if (sync) {
+
+ AT91C_BASE_PWMC->PWMC_OSCUPD = value;
+ } else {
+
+ AT91C_BASE_PWMC->PWMC_OSC = value;
+ }
+}
+
+//-----------------------------------------------------------------------------
+/// Set PWM fault mode.
+/// \param mode Bitwise OR of fault mode.
+//-----------------------------------------------------------------------------
+void PWMC_SetFaultMode(unsigned int mode)
+{
+ AT91C_BASE_PWMC->PWMC_FMR = mode;
+}
+
+//-----------------------------------------------------------------------------
+/// PWM fault clear.
+/// \param fault Bitwise OR of fault to clear.
+//-----------------------------------------------------------------------------
+void PWMC_FaultClear(unsigned int fault)
+{
+ AT91C_BASE_PWMC->PWMC_FCR = fault;
+}
+
+//-----------------------------------------------------------------------------
+/// Set PWM fault protection value.
+/// \param value Bitwise OR of fault protection value.
+//-----------------------------------------------------------------------------
+void PWMC_SetFaultProtectionValue(unsigned int value)
+{
+ AT91C_BASE_PWMC->PWMC_FPV = value;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable PWM fault protection.
+/// \param value Bitwise OR of FPEx[y].
+//-----------------------------------------------------------------------------
+void PWMC_EnableFaultProtection(unsigned int value)
+{
+ AT91C_BASE_PWMC->PWMC_FPER1 = value;
+}
+
+//-----------------------------------------------------------------------------
+/// Configure comparison unit.
+/// \param x comparison x index
+/// \param value comparison x value.
+/// \param mode comparison x mode
+//-----------------------------------------------------------------------------
+void PWMC_ConfigureComparisonUnit(unsigned int x, unsigned int value, unsigned int mode)
+{
+ // If channel is disabled, write to CMPxM & CMPxV
+ if ((AT91C_BASE_PWMC->PWMC_SR & (1 << 0)) == 0) {
+ if (x == 0) {
+ AT91C_BASE_PWMC->PWMC_CMP0M = mode;
+ AT91C_BASE_PWMC->PWMC_CMP0V = value;
+ } else if (x == 1) {
+ AT91C_BASE_PWMC->PWMC_CMP1M = mode;
+ AT91C_BASE_PWMC->PWMC_CMP1V = value;
+ } else if (x == 2) {
+ AT91C_BASE_PWMC->PWMC_CMP2M = mode;
+ AT91C_BASE_PWMC->PWMC_CMP2V = value;
+ } else if (x == 3) {
+ AT91C_BASE_PWMC->PWMC_CMP3M = mode;
+ AT91C_BASE_PWMC->PWMC_CMP3V = value;
+ } else if (x == 4) {
+ AT91C_BASE_PWMC->PWMC_CMP4M = mode;
+ AT91C_BASE_PWMC->PWMC_CMP4V = value;
+ } else if (x == 5) {
+ AT91C_BASE_PWMC->PWMC_CMP5M = mode;
+ AT91C_BASE_PWMC->PWMC_CMP5V = value;
+ } else if (x == 6) {
+ AT91C_BASE_PWMC->PWMC_CMP6M = mode;
+ AT91C_BASE_PWMC->PWMC_CMP6V = value;
+ } else if (x == 7) {
+ AT91C_BASE_PWMC->PWMC_CMP7M = mode;
+ AT91C_BASE_PWMC->PWMC_CMP7V = value;
+ }
+ }
+ // Otherwise use update register
+ else {
+ if (x == 0) {
+ AT91C_BASE_PWMC->PWMC_CMP0MUPD = mode;
+ AT91C_BASE_PWMC->PWMC_CMP0VUPD = value;
+ } else if (x == 1) {
+ AT91C_BASE_PWMC->PWMC_CMP1MUPD = mode;
+ AT91C_BASE_PWMC->PWMC_CMP1VUPD = value;
+ } else if (x == 2) {
+ AT91C_BASE_PWMC->PWMC_CMP2MUPD = mode;
+ AT91C_BASE_PWMC->PWMC_CMP2VUPD = value;
+ } else if (x == 3) {
+ AT91C_BASE_PWMC->PWMC_CMP3MUPD = mode;
+ AT91C_BASE_PWMC->PWMC_CMP3VUPD = value;
+ } else if (x == 4) {
+ AT91C_BASE_PWMC->PWMC_CMP4MUPD = mode;
+ AT91C_BASE_PWMC->PWMC_CMP4VUPD = value;
+ } else if (x == 5) {
+ AT91C_BASE_PWMC->PWMC_CMP5MUPD = mode;
+ AT91C_BASE_PWMC->PWMC_CMP5VUPD = value;
+ } else if (x == 6) {
+ AT91C_BASE_PWMC->PWMC_CMP6MUPD = mode;
+ AT91C_BASE_PWMC->PWMC_CMP6VUPD = value;
+ } else if (x == 7) {
+ AT91C_BASE_PWMC->PWMC_CMP7MUPD = mode;
+ AT91C_BASE_PWMC->PWMC_CMP7VUPD = value;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+/// Configure event line mode.
+/// \param x Line x
+/// \param mode Bitwise OR of line mode selection
+//-----------------------------------------------------------------------------
+void PWMC_ConfigureEventLineMode(unsigned int x, unsigned int mode)
+{
+ if (x == 0) {
+ AT91C_BASE_PWMC->PWMC_EL0MR = mode;
+ } else if (x == 1) {
+ AT91C_BASE_PWMC->PWMC_EL1MR = mode;
+ } else if (x == 2) {
+ AT91C_BASE_PWMC->PWMC_EL2MR = mode;
+ } else if (x == 3) {
+ AT91C_BASE_PWMC->PWMC_EL3MR = mode;
+ } else if (x == 4) {
+ AT91C_BASE_PWMC->PWMC_EL4MR = mode;
+ } else if (x == 5) {
+ AT91C_BASE_PWMC->PWMC_EL5MR = mode;
+ } else if (x == 6) {
+ AT91C_BASE_PWMC->PWMC_EL6MR = mode;
+ } else if (x == 7) {
+ AT91C_BASE_PWMC->PWMC_EL7MR = mode;
+ }
+}
diff --git a/peripherals/pwmc/pwmc2.h b/peripherals/pwmc/pwmc2.h new file mode 100644 index 0000000..d9d979d --- /dev/null +++ b/peripherals/pwmc/pwmc2.h @@ -0,0 +1,143 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the Pulse Width Modulation Controller (PWM) peripheral.
+///
+/// !Usage
+///
+/// -# Configures PWM clocks A & B to run at the given frequencies using
+/// PWMC_ConfigureClocks().
+/// -# Configure PWMC channel using PWMC_ConfigureChannel(), PWMC_ConfigureChannelExt()
+/// PWMC_SetPeriod(), PWMC_SetDutyCycle() and PWMC_SetDeadTime().
+/// -# Enable & disable channel using PWMC_EnableChannel() and
+/// PWMC_DisableChannel().
+/// -# Enable & disable the period interrupt for the given PWM channel using
+/// PWMC_EnableChannelIt() and PWMC_DisableChannelIt().
+/// -# Enable & disable the selected interrupts sources on a PWMC peripheral
+/// using PWMC_EnableIt() and PWMC_DisableIt().
+/// -# Control syncronous channel using PWMC_ConfigureSyncChannel(),
+/// PWMC_SetSyncChannelUpdatePeriod() and PWMC_SetSyncChannelUpdateUnlock().
+/// -# Control PWM override output using PWMC_SetOverrideValue(),
+/// PWMC_EnableOverrideOutput() and PWMC_DisableOverrideOutput().
+/// -# Send data through the transmitter using PWMC_WriteBuffer().
+///
+/// Please refer to the list of functions in the #Overview# tab of this unit
+/// for more detailed information.
+//------------------------------------------------------------------------------
+
+#ifndef PWMC2_H
+#define PWMC2_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void PWMC_ConfigureChannel(
+ unsigned char channel,
+ unsigned int prescaler,
+ unsigned int alignment,
+ unsigned int polarity);
+
+extern void PWMC_ConfigureChannelExt(
+ unsigned char channel,
+ unsigned int prescaler,
+ unsigned int alignment,
+ unsigned int polarity,
+ unsigned int countEventSelect,
+ unsigned int DTEnable,
+ unsigned int DTHInverte,
+ unsigned int DTLInverte);
+
+extern void PWMC_ConfigureClocks
+ (unsigned int clka,
+ unsigned int clkb,
+ unsigned int mck);
+
+extern void PWMC_SetPeriod(unsigned char channel, unsigned short period);
+
+extern void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty);
+
+extern void PWMC_SetDeadTime(unsigned char channel, unsigned short timeH, unsigned short timeL);
+
+extern void PWMC_ConfigureSyncChannel(
+ unsigned int channels,
+ unsigned int updateMode,
+ unsigned int requestMode,
+ unsigned int requestComparisonSelect);
+
+extern void PWMC_SetSyncChannelUpdatePeriod(unsigned char period);
+
+extern void PWMC_SetSyncChannelUpdateUnlock(void);
+
+extern void PWMC_EnableChannel(unsigned char channel);
+
+extern void PWMC_DisableChannel(unsigned char channel);
+
+extern void PWMC_EnableChannelIt(unsigned char channel);
+
+extern void PWMC_DisableChannelIt(unsigned char channel);
+
+extern void PWMC_EnableIt(unsigned int sources1, unsigned int sources2);
+
+extern void PWMC_DisableIt(unsigned int sources1, unsigned int sources2);
+
+extern unsigned char PWMC_WriteBuffer(AT91S_PWMC *pwmc,
+ void *buffer,
+ unsigned int length);
+
+extern void PWMC_SetOverrideValue(unsigned int value);
+
+extern void PWMC_EnableOverrideOutput(unsigned int value, unsigned int sync);
+
+extern void PWMC_DisableOverrideOutput(unsigned int value, unsigned int sync);
+
+extern void PWMC_SetFaultMode(unsigned int mode);
+
+extern void PWMC_FaultClear(unsigned int fault);
+
+extern void PWMC_SetFaultProtectionValue(unsigned int value);
+
+extern void PWMC_EnableFaultProtection(unsigned int value);
+
+extern void PWMC_ConfigureComparisonUnit(unsigned int x, unsigned int value, unsigned int mode);
+
+extern void PWMC_ConfigureEventLineMode(unsigned int x, unsigned int mode);
+#endif //#ifndef PWMC2_H
+
diff --git a/peripherals/rstc/rstc.c b/peripherals/rstc/rstc.c new file mode 100644 index 0000000..7f6ceca --- /dev/null +++ b/peripherals/rstc/rstc.c @@ -0,0 +1,176 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//-----------------------------------------------------------------------------
+// Headers
+//-----------------------------------------------------------------------------
+
+#include <board.h>
+
+//-----------------------------------------------------------------------------
+// Defines
+//-----------------------------------------------------------------------------
+
+/// Keywords to write to the reset registers
+#define RSTC_KEY_PASSWORD (0xA5 << 24)
+
+//-----------------------------------------------------------------------------
+// Exported functions
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+/// Configure the mode of the RSTC peripheral.
+/// The configuration is computed by the lib (AT91C_RSTC_*).
+/// \param rmr Desired mode configuration.
+//-----------------------------------------------------------------------------
+void RSTC_ConfigureMode(unsigned int rmr)
+{
+ rmr &= ~AT91C_RSTC_KEY;
+ AT91C_BASE_RSTC->RSTC_RMR = rmr | RSTC_KEY_PASSWORD;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable/Disable the detection of a low level on the pin NRST as User Reset
+/// \param enable 1 to enable & 0 to disable.
+//-----------------------------------------------------------------------------
+void RSTC_SetUserResetEnable(unsigned char enable)
+{
+ unsigned int rmr = AT91C_BASE_RSTC->RSTC_RMR & (~AT91C_RSTC_KEY);
+ if (enable) {
+
+ rmr |= AT91C_RSTC_URSTEN;
+ }
+ else {
+
+ rmr &= ~AT91C_RSTC_URSTEN;
+ }
+ AT91C_BASE_RSTC->RSTC_RMR = rmr | RSTC_KEY_PASSWORD;
+}
+
+//-----------------------------------------------------------------------------
+/// Enable/Disable the interrupt of a User Reset (USRTS bit in RSTC_RST).
+/// \param enable 1 to enable & 0 to disable.
+//-----------------------------------------------------------------------------
+void RSTC_SetUserResetInterruptEnable(unsigned char enable)
+{
+ unsigned int rmr = AT91C_BASE_RSTC->RSTC_RMR & (~AT91C_RSTC_KEY);
+ if (enable) {
+
+ rmr |= AT91C_RSTC_URSTIEN;
+ }
+ else {
+
+ rmr &= ~AT91C_RSTC_URSTIEN;
+ }
+ AT91C_BASE_RSTC->RSTC_RMR = rmr | RSTC_KEY_PASSWORD;
+}
+
+//-----------------------------------------------------------------------------
+/// Setup the external reset length. The length is asserted during a time of
+/// pow(2, powl+1) Slow Clock(32KHz). The duration is between 60us and 2s.
+/// \param powl Power length defined.
+//-----------------------------------------------------------------------------
+void RSTC_SetExtResetLength(unsigned char powl)
+{
+ unsigned int rmr = AT91C_BASE_RSTC->RSTC_RMR;
+ rmr &= ~(AT91C_RSTC_KEY | AT91C_RSTC_ERSTL);
+ rmr |= (powl << 8) & AT91C_RSTC_ERSTL;
+ AT91C_BASE_RSTC->RSTC_RMR = rmr | RSTC_KEY_PASSWORD;
+}
+
+
+//-----------------------------------------------------------------------------
+/// Resets the processor.
+//-----------------------------------------------------------------------------
+void RSTC_ProcessorReset(void)
+{
+ AT91C_BASE_RSTC->RSTC_RCR = AT91C_RSTC_PROCRST | RSTC_KEY_PASSWORD;
+}
+
+//-----------------------------------------------------------------------------
+/// Resets the peripherals.
+//-----------------------------------------------------------------------------
+void RSTC_PeripheralReset(void)
+{
+ AT91C_BASE_RSTC->RSTC_RCR = AT91C_RSTC_PERRST | RSTC_KEY_PASSWORD;
+}
+
+//-----------------------------------------------------------------------------
+/// Asserts the NRST pin for external resets.
+//-----------------------------------------------------------------------------
+void RSTC_ExtReset(void)
+{
+ AT91C_BASE_RSTC->RSTC_RCR = AT91C_RSTC_EXTRST | RSTC_KEY_PASSWORD;
+}
+
+//-----------------------------------------------------------------------------
+/// Return NRST pin level ( 1 or 0 ).
+//-----------------------------------------------------------------------------
+unsigned char RSTC_GetNrstLevel(void)
+{
+ if (AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_NRSTL) {
+
+ return 1;
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+/// Returns 1 if at least one high-to-low transition of NRST (User Reset) has
+/// been detected since the last read of RSTC_RSR.
+//-----------------------------------------------------------------------------
+unsigned char RSTC_IsUserResetDetected(void)
+{
+ if (AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_URSTS) {
+
+ return 1;
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+/// Return 1 if a software reset command is being performed by the reset
+/// controller. The reset controller is busy.
+//-----------------------------------------------------------------------------
+unsigned char RSTC_IsBusy(void)
+{
+ if (AT91C_BASE_RSTC->RSTC_RSR & AT91C_RSTC_SRCMP) {
+
+ return 1;
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+/// Get the status
+//-----------------------------------------------------------------------------
+unsigned char RSTC_GetStatus(void)
+{
+ return (AT91C_BASE_RSTC->RSTC_RSR);
+}
diff --git a/peripherals/rstc/rstc.h b/peripherals/rstc/rstc.h new file mode 100644 index 0000000..d3dbb16 --- /dev/null +++ b/peripherals/rstc/rstc.h @@ -0,0 +1,58 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef _RSTC_H
+#define _RSTC_H
+
+//-----------------------------------------------------------------------------
+// Exported functions
+//-----------------------------------------------------------------------------
+
+extern void RSTC_ConfigureMode(unsigned int rmr);
+
+extern void RSTC_SetUserResetEnable(unsigned char enable);
+
+extern void RSTC_SetUserResetInterruptEnable(unsigned char enable);
+
+extern void RSTC_SetExtResetLength(unsigned char powl);
+
+extern void RSTC_ProcessorReset(void);
+
+extern void RSTC_PeripheralReset(void);
+
+extern void RSTC_ExtReset(void);
+
+extern unsigned char RSTC_GetNrstLevel(void);
+
+extern unsigned char RSTC_IsUserResetDetected(void);
+
+extern unsigned char RSTC_IsBusy(void);
+
+
+#endif // #ifndef _RSTC_H
diff --git a/peripherals/rtc/rtc.c b/peripherals/rtc/rtc.c new file mode 100644 index 0000000..be23c96 --- /dev/null +++ b/peripherals/rtc/rtc.c @@ -0,0 +1,405 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "rtc.h"
+#include <board.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Sets the RTC in either 12- or 24-hour mode.
+/// \param mode Hour mode.
+//------------------------------------------------------------------------------
+void RTC_SetHourMode(unsigned int mode)
+{
+ SANITY_CHECK((mode & 0xFFFFFFFE) == 0);
+
+ TRACE_DEBUG("RTC_SetHourMode()\n\r");
+
+ AT91C_BASE_RTC->RTC_MR = mode;
+}
+
+//------------------------------------------------------------------------------
+/// Gets the RTC mode.
+/// \return Hour mode.
+//------------------------------------------------------------------------------
+unsigned int RTC_GetHourMode()
+{
+ unsigned int hmode;
+
+ TRACE_DEBUG("RTC_SetHourMode()\n\r");
+
+ hmode = AT91C_BASE_RTC->RTC_MR;
+ hmode &= 0xFFFFFFFE;
+
+ return hmode;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the selected interrupt sources of the RTC.
+/// \param sources Interrupt sources to enable.
+//------------------------------------------------------------------------------
+void RTC_EnableIt(unsigned int sources)
+{
+ SANITY_CHECK((sources & ~0x1F) == 0);
+
+ TRACE_DEBUG("RTC_EnableIt()\n\r");
+
+ AT91C_BASE_RTC->RTC_IER = sources;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the selected interrupt sources of the RTC.
+/// \param sources Interrupt sources to disable.
+//------------------------------------------------------------------------------
+void RTC_DisableIt(unsigned int sources)
+{
+ SANITY_CHECK((sources & ~0x1F) == 0);
+
+ TRACE_DEBUG("RTC_DisableIt()\n\r");
+
+ AT91C_BASE_RTC->RTC_IDR = sources;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the current time in the RTC.
+/// \param hour Current hour in 24 hour mode.
+/// \param minute Current minute.
+/// \param second Current second.
+/// \return 0 sucess, 1 fail to set
+//------------------------------------------------------------------------------
+int RTC_SetTime(unsigned char hour, unsigned char minute, unsigned char second)
+{
+ unsigned int time=0;
+ unsigned char hour_bcd;
+ unsigned char min_bcd;
+ unsigned char sec_bcd;
+
+ TRACE_DEBUG("RTC_SetTime(%02d:%02d:%02d)\n\r", hour, minute, second);
+
+ // if 12-hour mode, set AMPM bit
+ if ((AT91C_BASE_RTC->RTC_MR & AT91C_RTC_HRMOD) == AT91C_RTC_HRMOD) {
+
+ if (hour > 12) {
+
+ hour -= 12;
+ time |= AT91C_RTC_AMPM;
+ }
+ }
+ hour_bcd = (hour%10) | ((hour/10)<<4);
+ min_bcd = (minute%10) | ((minute/10)<<4);
+ sec_bcd = (second%10) | ((second/10)<<4);
+
+ //value overflow
+ if((hour_bcd & (unsigned char)(~RTC_HOUR_BIT_LEN_MASK)) |
+ (min_bcd & (unsigned char)(~RTC_MIN_BIT_LEN_MASK)) |
+ (sec_bcd & (unsigned char)(~RTC_SEC_BIT_LEN_MASK)))
+ return 1;
+
+ time = sec_bcd | (min_bcd << 8) | (hour_bcd<<16);
+
+// time |= ((hour % 10) << 16) | ((hour / 10) << 20);
+
+ // Set time
+ //if((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_SECEV) != AT91C_RTC_SECEV) return 1;
+ while ((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_SECEV) != AT91C_RTC_SECEV);//wait from previous set
+ AT91C_BASE_RTC->RTC_CR |= AT91C_RTC_UPDTIM;
+ while ((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_ACKUPD) != AT91C_RTC_ACKUPD);
+ AT91C_BASE_RTC->RTC_SCCR = AT91C_RTC_ACKUPD;
+ AT91C_BASE_RTC->RTC_TIMR = time;
+ AT91C_BASE_RTC->RTC_CR &= ~AT91C_RTC_UPDTIM;
+ AT91C_BASE_RTC->RTC_SCCR |= AT91C_RTC_SECEV;//clear SECENV in SCCR
+
+ return (int)(AT91C_BASE_RTC->RTC_VER & AT91C_RTC_NVTIM);
+}
+
+//------------------------------------------------------------------------------
+/// Retrieves the current time as stored in the RTC in several variables.
+/// \param pHour If not null, current hour is stored in this variable.
+/// \param pMinute If not null, current minute is stored in this variable.
+/// \param pSecond If not null, current second is stored in this variable.
+//------------------------------------------------------------------------------
+void RTC_GetTime(
+ unsigned char *pHour,
+ unsigned char *pMinute,
+ unsigned char *pSecond)
+{
+ unsigned int time;
+
+ TRACE_DEBUG("RTC_GetTime()\n\r");
+
+ // Get current RTC time
+ time = AT91C_BASE_RTC->RTC_TIMR;
+ while (time != AT91C_BASE_RTC->RTC_TIMR) {
+
+ time = AT91C_BASE_RTC->RTC_TIMR;
+ }
+
+ // Hour
+ if (pHour) {
+
+ *pHour = ((time & 0x00300000) >> 20) * 10
+ + ((time & 0x000F0000) >> 16);
+ if ((time & AT91C_RTC_AMPM) == AT91C_RTC_AMPM) {
+
+ *pHour += 12;
+ }
+ }
+
+ // Minute
+ if (pMinute) {
+
+ *pMinute = ((time & 0x00007000) >> 12) * 10
+ + ((time & 0x00000F00) >> 8);
+ }
+
+ // Second
+ if (pSecond) {
+
+ *pSecond = ((time & 0x00000070) >> 4) * 10
+ + (time & 0x0000000F);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets a time alarm on the RTC. The match is performed only on the provided
+/// variables; setting all pointers to 0 disables the time alarm.
+/// Note: in AM/PM mode, the hour value must have bit #7 set for PM, cleared for
+/// AM (as expected in the time registers).
+/// \param pHour If not null, the time alarm will hour-match this value.
+/// \param pMinute If not null, the time alarm will minute-match this value.
+/// \param pSecond If not null, the time alarm will second-match this value.
+/// \return 0 success, 1 fail to set
+//------------------------------------------------------------------------------
+int RTC_SetTimeAlarm(
+ unsigned char *pHour,
+ unsigned char *pMinute,
+ unsigned char *pSecond)
+{
+ unsigned int alarm = 0;
+
+ TRACE_DEBUG("RTC_SetTimeAlarm()\n\r");
+
+ // Hour
+ if (pHour) {
+
+ alarm |= AT91C_RTC_HOUREN | ((*pHour / 10) << 20) | ((*pHour % 10) << 16);
+ }
+
+ // Minute
+ if (pMinute) {
+
+ alarm |= AT91C_RTC_MINEN | ((*pMinute / 10) << 12) | ((*pMinute % 10) << 8);
+ }
+
+ // Second
+ if (pSecond) {
+
+ alarm |= AT91C_RTC_SECEN | ((*pSecond / 10) << 4) | (*pSecond % 10);
+ }
+
+ AT91C_BASE_RTC->RTC_TIMALR = alarm;
+
+ return (int)(AT91C_BASE_RTC->RTC_VER & AT91C_RTC_NVTIMALR);
+}
+
+//------------------------------------------------------------------------------
+/// Retrieves the current year, month and day from the RTC. Month, day and week
+/// values are numbered starting at 1.
+/// \param pYear Current year (optional).
+/// \param pMonth Current month (optional).
+/// \param pDay Current day (optional).
+/// \param pWeek Current day in current week (optional).
+//------------------------------------------------------------------------------
+void RTC_GetDate(
+ unsigned short *pYear,
+ unsigned char *pMonth,
+ unsigned char *pDay,
+ unsigned char *pWeek)
+{
+ unsigned int date;
+
+ // Get current date (multiple reads are necessary to insure a stable value)
+ do {
+
+ date = AT91C_BASE_RTC->RTC_CALR;
+ }
+ while (date != AT91C_BASE_RTC->RTC_CALR);
+
+ // Retrieve year
+ if (pYear) {
+
+ *pYear = (((date >> 4) & 0x7) * 1000)
+ + ((date & 0xF) * 100)
+ + (((date >> 12) & 0xF) * 10)
+ + ((date >> 8) & 0xF);
+ }
+
+ // Retrieve month
+ if (pMonth) {
+
+ *pMonth = (((date >> 20) & 1) * 10) + ((date >> 16) & 0xF);
+ }
+
+ // Retrieve day
+ if (pDay) {
+
+ *pDay = (((date >> 28) & 0x3) * 10) + ((date >> 24) & 0xF);
+ }
+
+ // Retrieve week
+ if (pWeek) {
+
+ *pWeek = ((date >> 21) & 0x7);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the current year, month and day in the RTC. Month, day and week values
+/// must be numbered starting from 1.
+/// \param year Current year.
+/// \param month Current month.
+/// \param day Current day.
+/// \param week Day number in current week.
+/// \return 0 success, 1 fail to set
+//------------------------------------------------------------------------------
+int RTC_SetDate(
+ unsigned short year,
+ unsigned char month,
+ unsigned char day,
+ unsigned char week)
+{
+ unsigned int date;
+ unsigned char cent_bcd;
+ unsigned char year_bcd;
+ unsigned char month_bcd;
+ unsigned char day_bcd;
+ unsigned char week_bcd;
+
+ cent_bcd = ((year/100)%10) | ((year/1000)<<4);
+ year_bcd = (year%10) | (((year/10)%10)<<4);
+ month_bcd = ((month%10) | (month/10)<<4);
+ day_bcd = ((day%10) | (day/10)<<4);
+ week_bcd = ((week%10) | (week/10)<<4);
+
+ //value over flow
+ if((cent_bcd & (unsigned char)(~RTC_CENT_BIT_LEN_MASK)) |
+ (year_bcd & (unsigned char)(~RTC_YEAR_BIT_LEN_MASK)) |
+ (month_bcd & (unsigned char)(~RTC_MONTH_BIT_LEN_MASK)) |
+ (week_bcd & (unsigned char)(~RTC_WEEK_BIT_LEN_MASK)) |
+ (day_bcd & (unsigned char)(~RTC_DATE_BIT_LEN_MASK)))
+ return 1;
+
+
+ // Convert values to date register value
+ date = cent_bcd |
+ (year_bcd << 8) |
+ (month_bcd << 16) |
+ (week_bcd << 21) |
+ (day_bcd << 24);
+
+
+ // Update calendar register
+ //if((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_SECEV) != AT91C_RTC_SECEV) return 1;
+ while ((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_SECEV) != AT91C_RTC_SECEV);//wait from previous set
+ AT91C_BASE_RTC->RTC_CR |= AT91C_RTC_UPDCAL;
+ while ((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_ACKUPD) != AT91C_RTC_ACKUPD);
+ AT91C_BASE_RTC->RTC_SCCR = AT91C_RTC_ACKUPD;
+ AT91C_BASE_RTC->RTC_CALR = date;
+ AT91C_BASE_RTC->RTC_CR &= ~AT91C_RTC_UPDCAL;
+ AT91C_BASE_RTC->RTC_SCCR |= AT91C_RTC_SECEV;//clear SECENV in SCCR
+
+ return (int)(AT91C_BASE_RTC->RTC_VER & AT91C_RTC_NVCAL);
+}
+
+//------------------------------------------------------------------------------
+/// Sets a date alarm in the RTC. The alarm will match only the provided values;
+/// passing a null-pointer disables the corresponding field match.
+/// \param pMonth If not null, the RTC alarm will month-match this value.
+/// \param pDay If not null, the RTC alarm will day-match this value.
+/// \return 0 success, 1 fail to set
+//------------------------------------------------------------------------------
+int RTC_SetDateAlarm(unsigned char *pMonth, unsigned char *pDay)
+{
+ unsigned int alarm;
+
+ alarm = ((pMonth) || (pDay)) ? (0) : (0x01010000);
+
+ TRACE_DEBUG("RTC_SetDateAlarm()\n\r");
+
+ // Compute alarm field value
+ if (pMonth) {
+
+ alarm |= AT91C_RTC_MONTHEN | ((*pMonth / 10) << 20) | ((*pMonth % 10) << 16);
+ }
+ if (pDay) {
+
+ alarm |= AT91C_RTC_DATEEN | ((*pDay / 10) << 28) | ((*pDay % 10) << 24);
+ }
+
+ // Set alarm
+ AT91C_BASE_RTC->RTC_CALALR = alarm;
+
+ return (int)(AT91C_BASE_RTC->RTC_VER & AT91C_RTC_NVCALALR);
+}
+
+//------------------------------------------------------------------------------
+/// Clear flag bits of status clear command register in the RTC.
+/// \param mask Bits mask of cleared events
+//------------------------------------------------------------------------------
+void RTC_ClearSCCR(unsigned int mask)
+{
+ // Clear all flag bits in status clear command register
+ mask &= AT91C_RTC_ACKUPD | AT91C_RTC_ALARM | AT91C_RTC_SECEV | \
+ AT91C_RTC_TIMEV | AT91C_RTC_CALEV;
+
+ AT91C_BASE_RTC->RTC_SCCR = mask;
+}
+
+//------------------------------------------------------------------------------
+/// Get flag bits of status register in the RTC.
+/// \param mask Bits mask of Status Register
+/// \return Status register & mask
+//------------------------------------------------------------------------------
+unsigned int RTC_GetSR(unsigned int mask)
+{
+ unsigned int event;
+
+ event = AT91C_BASE_RTC->RTC_SR;
+
+ return (event & mask);
+}
diff --git a/peripherals/rtc/rtc.h b/peripherals/rtc/rtc.h new file mode 100644 index 0000000..e98890f --- /dev/null +++ b/peripherals/rtc/rtc.h @@ -0,0 +1,90 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef RTC_H
+#define RTC_H
+
+//------------------------------------------------------------------------------
+// Macro used
+//------------------------------------------------------------------------------
+#define RTC_HOUR_BIT_LEN_MASK 0x3F
+#define RTC_MIN_BIT_LEN_MASK 0x7F
+#define RTC_SEC_BIT_LEN_MASK 0x7F
+#define RTC_CENT_BIT_LEN_MASK 0x7F
+#define RTC_YEAR_BIT_LEN_MASK 0xFF
+#define RTC_MONTH_BIT_LEN_MASK 0x1F
+#define RTC_DATE_BIT_LEN_MASK 0x3F
+#define RTC_WEEK_BIT_LEN_MASK 0x07
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void RTC_SetHourMode(unsigned int mode);
+
+extern unsigned int RTC_GetHourMode();
+
+extern void RTC_EnableIt(unsigned int sources);
+
+extern void RTC_DisableIt(unsigned int sources);
+
+extern int RTC_SetTime(
+ unsigned char hour,
+ unsigned char minute,
+ unsigned char second);
+
+extern void RTC_GetTime(
+ unsigned char *pHour,
+ unsigned char *pMinute,
+ unsigned char *pSecond);
+
+extern int RTC_SetTimeAlarm(
+ unsigned char *pHour,
+ unsigned char *pMinute,
+ unsigned char *pSecond);
+
+void RTC_GetDate(
+ unsigned short *pYear,
+ unsigned char *pMonth,
+ unsigned char *pDay,
+ unsigned char *pWeek);
+
+extern int RTC_SetDate(
+ unsigned short year,
+ unsigned char month,
+ unsigned char day,
+ unsigned char week);
+
+extern int RTC_SetDateAlarm(unsigned char *pMonth, unsigned char *pDay);
+
+extern void RTC_ClearSCCR(unsigned int mask);
+
+extern unsigned int RTC_GetSR(unsigned int mask);
+#endif //#ifndef RTC_H
+
diff --git a/peripherals/rtt/rtt.c b/peripherals/rtt/rtt.c new file mode 100644 index 0000000..5322108 --- /dev/null +++ b/peripherals/rtt/rtt.c @@ -0,0 +1,93 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "rtt.h"
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Changes the prescaler value of the given RTT and restarts it. This function
+/// disables RTT interrupt sources.
+/// \param rtt Pointer to a AT91S_RTTC instance.
+/// \param prescaler Prescaler value for the RTT.
+//------------------------------------------------------------------------------
+void RTT_SetPrescaler(AT91S_RTTC *rtt, unsigned short prescaler)
+{
+ rtt->RTTC_RTMR = (prescaler | AT91C_RTTC_RTTRST);
+}
+
+//------------------------------------------------------------------------------
+/// Returns the current value of the RTT timer value.
+/// \param rtt Pointer to a AT91S_RTTC instance.
+//------------------------------------------------------------------------------
+unsigned int RTT_GetTime(AT91S_RTTC *rtt)
+{
+ return rtt->RTTC_RTVR;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the specified RTT interrupt sources.
+/// \param rtt Pointer to a AT91S_RTTC instance.
+/// \param sources Bitmask of interrupts to enable.
+//------------------------------------------------------------------------------
+void RTT_EnableIT(AT91S_RTTC *rtt, unsigned int sources)
+{
+ ASSERT((sources & 0x0004FFFF) == 0,
+ "RTT_EnableIT: Wrong sources value.\n\r");
+ rtt->RTTC_RTMR |= sources;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the status register value of the given RTT.
+/// \param rtt Pointer to an AT91S_RTTC instance.
+//------------------------------------------------------------------------------
+unsigned int RTT_GetStatus(AT91S_RTTC *rtt)
+{
+ return rtt->RTTC_RTSR;
+}
+
+//------------------------------------------------------------------------------
+/// Configures the RTT to generate an alarm at the given time.
+/// \param pRtt Pointer to an AT91S_RTTC instance.
+/// \param time Alarm time.
+//------------------------------------------------------------------------------
+void RTT_SetAlarm(AT91S_RTTC *pRtt, unsigned int time)
+{
+ SANITY_CHECK(time > 0);
+
+ pRtt->RTTC_RTAR = time - 1;
+}
+
diff --git a/peripherals/rtt/rtt.dir b/peripherals/rtt/rtt.dir new file mode 100644 index 0000000..1f91775 --- /dev/null +++ b/peripherals/rtt/rtt.dir @@ -0,0 +1,39 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !!!Purpose
+///
+/// The #rtt# directory stores a collection of basic APIs to build Real Time Timer
+/// applications with Atmel AT91 microcontrollers.
+///
+///
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/rtt/rtt.h b/peripherals/rtt/rtt.h new file mode 100644 index 0000000..54843c4 --- /dev/null +++ b/peripherals/rtt/rtt.h @@ -0,0 +1,76 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//-----------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Implementation of RTT Real Time Timer controller.
+///
+/// !Contents
+///
+/// Please refer to the list of functions in the #Overview# tab of this unit
+/// for more detailed information.
+//-----------------------------------------------------------------------------
+
+
+#ifndef RTT_H
+#define RTT_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+#ifndef AT91C_BASE_RTTC
+ #define AT91C_BASE_RTTC AT91C_BASE_RTTC0
+#endif
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void RTT_SetPrescaler(AT91S_RTTC *rtt, unsigned short prescaler);
+
+extern unsigned int RTT_GetTime(AT91S_RTTC *rtt);
+
+extern void RTT_EnableIT(AT91S_RTTC *rtt, unsigned int sources);
+
+extern unsigned int RTT_GetStatus(AT91S_RTTC *rtt);
+
+extern void RTT_SetAlarm(AT91S_RTTC *pRtt, unsigned int time);
+
+#endif //#ifndef RTT_H
+
diff --git a/peripherals/shdwc/shdwc.c b/peripherals/shdwc/shdwc.c new file mode 100644 index 0000000..c8f4b38 --- /dev/null +++ b/peripherals/shdwc/shdwc.c @@ -0,0 +1,67 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "shdwc.h"
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configure the Shut Down and do it
+/// \param rtt_enable
+/// \param wk0_mode
+/// \param wk0_debounce
+//------------------------------------------------------------------------------
+void SHDWC_DoShutDown(
+ unsigned char rtt_enable,
+ unsigned char wk0_mode,
+ unsigned char wk0_debounce
+ )
+{
+ AT91C_BASE_SHDWC->SHDWC_SHMR = (rtt_enable << 16) |
+ wk0_mode | ( (wk0_debounce & 0xF) << 4);
+
+ AT91C_BASE_SHDWC->SHDWC_SHCR = (0xA5 << 24) | 1;
+}
+
+//------------------------------------------------------------------------------
+/// Get Status
+//------------------------------------------------------------------------------
+unsigned int SHDWC_GetStatus(void)
+{
+ return AT91C_BASE_SHDWC->SHDWC_SHSR;
+}
+
diff --git a/peripherals/shdwc/shdwc.h b/peripherals/shdwc/shdwc.h new file mode 100644 index 0000000..f89f6e1 --- /dev/null +++ b/peripherals/shdwc/shdwc.h @@ -0,0 +1,43 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef SHDWC_H
+#define SHDWC_H
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void SHDWC_DoShutDown(unsigned char rtt_enable,
+ unsigned char wk0_mode,
+ unsigned char wk0_debounce);
+
+unsigned int SHDWC_GetStatus(void);
+
+#endif //#ifndef SHDWC_H
diff --git a/peripherals/slcdc/slcdc.c b/peripherals/slcdc/slcdc.c new file mode 100644 index 0000000..59fc238 --- /dev/null +++ b/peripherals/slcdc/slcdc.c @@ -0,0 +1,192 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "slcdc.h"
+#include <board.h>
+#include <utility/assert.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Local definitions
+//------------------------------------------------------------------------------
+
+/// Size of SLCDC buffer in bytes.
+#define BUFFER_SIZE 320
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes the Segment LCD controller.
+/// \param commons Number of commons used by the display.
+/// \param segments Number of segments used by the display.
+/// \param bias Bias value.
+/// \param timeSetting Buffer timing value.
+//------------------------------------------------------------------------------
+void SLCDC_Configure(
+ unsigned int commons,
+ unsigned int segments,
+ unsigned int bias,
+ unsigned int timeSetting)
+{
+ SANITY_CHECK((commons > 0) && (commons <= 10));
+ SANITY_CHECK((segments > 0) && (segments <= 40));
+ SANITY_CHECK((bias & ~AT91C_SLCDC_BIAS) == 0);
+ SANITY_CHECK((timeSetting & ~(0xF << 16)) == 0);
+ SANITY_CHECK((timeSetting >> 16) < 0x0A);
+
+ // Enable peripheral clock
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_SLCD;
+ AT91C_BASE_SLCDC->SLCDC_MR = (commons - 1) | ((segments - 1) << 8) | bias | timeSetting;
+}
+
+//------------------------------------------------------------------------------
+/// Clears the SLCD display buffer.
+//------------------------------------------------------------------------------
+void SLCDC_Clear(void)
+{
+ memset((void *) AT91C_BASE_SLCDC->SLCDC_MEM, 0, BUFFER_SIZE);
+}
+
+//------------------------------------------------------------------------------
+/// Enables the SLCD controller.
+//------------------------------------------------------------------------------
+void SLCDC_Enable(void)
+{
+ AT91C_BASE_SLCDC->SLCDC_CR = AT91C_SLCDC_LCDEN;
+ while (AT91C_BASE_SLCDC -> SLCDC_SR != AT91C_SLCDC_ENA);
+}
+
+//------------------------------------------------------------------------------
+/// Disables the SLCD controller.
+//------------------------------------------------------------------------------
+void SLCDC_Disable(void)
+{
+ AT91C_BASE_SLCDC->SLCDC_CR = AT91C_SLCDC_LCDDIS;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the SLCD low power mode.
+//------------------------------------------------------------------------------
+void SLCDC_EnableLowPowerMode(void)
+{
+ unsigned int value;
+
+ value = AT91C_BASE_SLCDC->SLCDC_MR;
+ value &= ~AT91C_SLCDC_LPMODE;
+ value |=AT91C_SLCDC_LPMODE;
+ AT91C_BASE_SLCDC->SLCDC_MR = value;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the SLCD low power mode
+//------------------------------------------------------------------------------
+void SLCDC_DisableLowPowerMode(void)
+{
+ unsigned int value;
+
+ value = AT91C_BASE_SLCDC->SLCDC_MR;
+ value &= ~AT91C_SLCDC_LPMODE;
+ AT91C_BASE_SLCDC->SLCDC_MR = value;
+}
+
+//------------------------------------------------------------------------------
+/// Adjusts the frame frequency. Frequency = FsCLK / (prescaler * divider . NCOM)
+/// \param prescalerValue Prescaler value
+/// \param dividerValue Divider value
+//------------------------------------------------------------------------------
+void SLCDC_SetFrameFreq(unsigned int prescalerValue, unsigned int dividerValue)
+{
+ SANITY_CHECK((prescalerValue & ~AT91C_SLCDC_PRESC) == 0);
+ SANITY_CHECK((dividerValue & (~(0x07 << 8))) == 0);
+
+ AT91C_BASE_SLCDC->SLCDC_FRR = prescalerValue | dividerValue;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the display mode (normal/force off/force on/blinking).
+/// \param mode Display mode to be set
+//------------------------------------------------------------------------------
+void SLCDC_SetDisplayMode(unsigned int mode)
+{
+ unsigned int value;
+
+ SANITY_CHECK(mode < 8);
+
+ value = AT91C_BASE_SLCDC->SLCDC_DR;
+ value &= ~AT91C_SLCDC_DISPMODE;
+ value |= mode;
+ AT91C_BASE_SLCDC->SLCDC_DR = value;
+}
+
+//------------------------------------------------------------------------------
+/// Adjusts the display blinking frequency.
+/// Blinking frequency = Frame Frequency / LCDBLKFREQ.
+/// \param frequency Frequency value.
+//------------------------------------------------------------------------------
+void SLCDC_SetBlinkFreq(unsigned int frequency)
+{
+ unsigned int value;
+
+ SANITY_CHECK((frequency & ~(0xFF << 8)) == 0);
+
+ value = AT91C_BASE_SLCDC->SLCDC_DR;
+ value &= ~AT91C_SLCDC_BLKFREQ;
+ value |= frequency;
+ AT91C_BASE_SLCDC->SLCDC_DR = frequency;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the selected SLCDC interrupt sources.
+/// \param sources Interrupt sources to enable.
+//------------------------------------------------------------------------------
+void SLCDC_EnableInterrupts(unsigned int sources)
+{
+ SANITY_CHECK((sources & 0xFFFFFFFA) == 0);
+
+ AT91C_BASE_SLCDC->SLCDC_IER = sources;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the selected SLCDC interrupt sources.
+/// \param sources Interrupt sources to disable.
+//------------------------------------------------------------------------------
+void SLCDC_DisableInterrupts(unsigned int sources)
+{
+ SANITY_CHECK((sources & 0xFFFFFFFA) == 0);
+
+ AT91C_BASE_SLCDC->SLCDC_IDR = sources;
+}
+
diff --git a/peripherals/slcdc/slcdc.dir b/peripherals/slcdc/slcdc.dir new file mode 100644 index 0000000..08baa6f --- /dev/null +++ b/peripherals/slcdc/slcdc.dir @@ -0,0 +1,35 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !!!Purpose
+///
+/// Contains the peripheral API for Segment LCD Controller (SLCDC) controller.
+//------------------------------------------------------------------------------
diff --git a/peripherals/slcdc/slcdc.h b/peripherals/slcdc/slcdc.h new file mode 100644 index 0000000..2b18960 --- /dev/null +++ b/peripherals/slcdc/slcdc.h @@ -0,0 +1,93 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the Segment LCD Controller (SLCDC) peripheral.
+///
+/// !Usage
+///
+/// -# Initializes the Segment LCD controller using SLCDC_Configure().
+/// -# Clears the SLCD display buffer using SLCDC_Clear().
+/// -# Enable & disable SLCD controller using SLCDC_Enable() and SLCDC_Disable().
+/// -# Enables & disable the SLCD low power mode using SLCDC_EnableLowPowerMode ()
+/// and SLCDC_DisableLowPowerMode().
+/// -# Adjusts the frame frequency using SLCDC_SetFrameFreq().
+/// -# Sets the display mode (normal/force off/force on/blinking) using
+/// SLCDC_SetDisplayMode().
+/// -# Adjusts the display blinking frequency using SLCDC_SetBlinkFreq().
+/// -# Enables & disable the selected SLCDC interrupt sources using
+/// SLCDC_EnableInterrupts() and SLCDC_DisableInterrupts().
+//------------------------------------------------------------------------------
+
+#ifndef SLCDC_H
+#define SLCDC_H
+
+//------------------------------------------------------------------------------
+// Global definitions
+//------------------------------------------------------------------------------
+
+/// Number of segments in SLCD.
+#define S7LEKLCD_NUM_SEGMENTS 40
+/// Number of commons in SLCD.
+#define S7LEKLCD_NUM_COMMONS 10
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void SLCDC_Configure(
+ unsigned int commons,
+ unsigned int segments,
+ unsigned int bias,
+ unsigned int timeSetting);
+
+extern void SLCDC_Clear(void);
+
+extern void SLCDC_Enable(void);
+
+extern void SLCDC_Disable(void);
+
+extern void SLCDC_SetFrameFreq(
+ unsigned int prescalerValue,
+ unsigned int dividerValue);
+
+extern void SLCDC_SetDisplayMode(unsigned int mode);
+
+extern void SLCDC_SetBlinkFreq(unsigned int frequency);
+
+extern void SLCDC_EnableInterrupts(unsigned int sources);
+
+extern void SLCDC_DisableInterrupts(unsigned int sources);
+
+#endif //#ifndef SLCDC_H
+
diff --git a/peripherals/slck/slck.c b/peripherals/slck/slck.c new file mode 100644 index 0000000..c6b3d15 --- /dev/null +++ b/peripherals/slck/slck.c @@ -0,0 +1,524 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "slck.h"
+#include <board.h>
+#if defined(at91sam3u)
+#include <board_lowlevel.h>
+#endif
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Local definitions
+//------------------------------------------------------------------------------
+
+/// Start Up Time Slow Clock 32K Oscillator // see DC characteritics in Datasheet
+#define T_ST_SLCK_32K_IN_MS 1200
+
+/// Start Up Time Slow Clock RC Oscillator // see DC characteritics in Datasheet
+#define T_ST_SLCK_RC_IN_US 75
+
+#define FREQ_SLCK_32K 32768 // see DC characteritics in Datasheet
+#define MIN_FREQ_SLCK_RC 20000 // see DC characteritics in Datasheet
+
+#define TIME_5_CYCLES_32K_IN_US ((2 * 5 * 1000000) / FREQ_SLCK_32K)
+#define TIME_5_CYCLES_RC_IN_US ((2 * 5 * 1000000) / MIN_FREQ_SLCK_RC)
+
+// Define clock timeout
+#define CLOCK_TIMEOUT 0xFFFFFFFF
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+#if defined(at91cap7) || defined(at91cap9)
+//------------------------------------------------------------------------------
+/// Wait time in ms
+//------------------------------------------------------------------------------
+// not precise, depends on the compiler and on the options
+static void WaitTimeInMs(unsigned int pck, unsigned int time_ms)
+{
+ register unsigned int i = 0;
+ i = (pck / 1000) * time_ms;
+ i = i / 4;
+ while(i--);
+}
+
+//------------------------------------------------------------------------------
+/// Wait time in us
+//------------------------------------------------------------------------------
+// not precise, depends on the compiler and on the options
+static void WaitTimeInUs(unsigned int pck, unsigned int time_us)
+{
+ volatile unsigned int i = 0;
+ i = (pck / 1000000) * time_us;
+ i = i / 4;
+ while(i--);
+}
+#endif
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+#if defined(at91cap7)
+//------------------------------------------------------------------------------
+/// Return 1 if the slow clock is 32k
+//------------------------------------------------------------------------------
+unsigned char SLCK_Is32k(void)
+{
+ return ((*AT91C_PMC_SR & AT91C_PMC_OSC_SEL) != 0);
+ //return ((*AT91C_SYS_SYS_OSCMR & AT91C_OSC32K_SEL) != 0);
+
+}
+
+//------------------------------------------------------------------------------
+/// Configure the 32kHz oscillator for the slow clock
+//------------------------------------------------------------------------------
+void SLCK_RCto32k(void)
+{
+ // Check that the master clock has a different source than slow clock. If no,
+ if( (AT91C_BASE_PMC->PMC_MCKR & AT91C_PMC_CSS) == 0)
+ {
+ TRACE_WARNING("The master clock use the slow clock. " \
+ "Not possible to change Slow clock\n\r");
+ return;
+ }
+
+ // Check that the slow clock source is RC
+ if( SLCK_Is32k() )
+ {
+ TRACE_WARNING("The slow clock is already the external 32.768kHz crystal\n\r");
+ return;
+ }
+
+ // Enable the 32,768 Hz oscillator by setting the bit OSC32K_XT_EN to 1.
+ *AT91C_SYS_SYS_OSCMR |= AT91C_OSC32K_XT_EN;
+
+ // Wait 32,768 Hz Startup Time for clock stabilization (software loop).
+ WaitTimeInMs(BOARD_MCK, /*T_ST_SLCK_32K_IN_MS*/10);
+
+ // Switch from internal RC to 32,768 Hz oscillator by setting the bit OSC32K_SEL to 1.
+ *AT91C_SYS_SYS_OSCMR |= AT91C_OSC32K_SEL;
+
+ TRACE_INFO("The slow clock is now the external 32.768kHz crystal\n\r");
+}
+
+
+//------------------------------------------------------------------------------
+/// Configure the RC oscillator for the slow clock
+//------------------------------------------------------------------------------
+void SLCK_32ktoRC(void)
+{
+ // Check that the master clock has a different source than slow clock.
+ if( (AT91C_BASE_PMC->PMC_MCKR & AT91C_PMC_CSS) == 0)
+ {
+ TRACE_WARNING("The master clock use the slow clock. " \
+ "Not possible to change Slow clock\n\r");
+ return;
+ }
+
+ // Check that the slow clock source is RC
+ if( !SLCK_Is32k() )
+ {
+ TRACE_WARNING("The slow clock is already the internal RC oscillator\n\r");
+ return;
+ }
+
+ // Enable the internal RC oscillator by setting the bit OSC32K_RC_EN to 1
+ *AT91C_SYS_SYS_OSCMR |= AT91C_OSC32K_RC_EN;
+
+ // Wait internal RC Startup Time for clock stabilization (software loop).
+ WaitTimeInUs(BOARD_MCK, T_ST_SLCK_RC_IN_US);
+
+ // Switch from 32768 Hz oscillator to internal RC by setting the bit OSC32K_SEL to 0.
+ *AT91C_SYS_SYS_OSCMR &= (0xFFFFFFFF ^ AT91C_OSC32K_SEL);
+
+ TRACE_INFO("The slow clock is now the internal RC oscillator\n\r");
+}
+
+//------------------------------------------------------------------------------
+/// by pass the 32kHz oscillator (*** not supported in CAP7 ***)
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// set Slow Clock Mode
+//------------------------------------------------------------------------------
+void SLCK_UtilSetSlowClockMode(unsigned int timeInSlowClockMode)
+{
+ unsigned int oldPll;
+ unsigned int oldMck;
+ unsigned int timeout = 0;
+
+ // Save previous values for PLL A and Master Clock configuration
+ oldPll = AT91C_BASE_CKGR->CKGR_PLLAR;
+ oldMck = AT91C_BASE_PMC->PMC_MCKR;
+
+ // Slow clock is selected for Master Clock
+ // 32kKz / 64 = 500Hz
+ // PCK = 500Hz, MCK = 500 Hz
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK | AT91C_PMC_PRES_CLK_64;
+ timeout = 0;
+ while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) && timeout++ < CLOCK_TIMEOUT);
+
+ // Stop PLL A
+ // MULA: PLL A Multiplier 0 = The PLL A is deactivated.
+ AT91C_BASE_CKGR->CKGR_PLLAR = 0x00003f00;
+
+ // Stop Main Oscillator
+ AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR & (~AT91C_CKGR_MOSCEN);
+
+ // Wait a while. The clock is at 500Hz...
+ while( timeInSlowClockMode-- );
+ // End !
+
+ // Restart Main Oscillator
+ AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR | (AT91C_CKGR_OSCOUNT & (0x32<<8) );
+ AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR | (AT91C_CKGR_MOSCEN);
+
+ // Restart PLL A
+ AT91C_BASE_CKGR->CKGR_PLLAR = oldPll;
+ timeout = 0;
+ while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA) && timeout++ < CLOCK_TIMEOUT);
+
+ // Selection of Master Clock MCK (so Processor Clock PCK)
+ AT91C_BASE_PMC->PMC_MCKR = oldMck;
+ timeout = 0;
+ while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) && timeout++ < CLOCK_TIMEOUT);
+
+ // Reconfigure DBGU
+ TRACE_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK);
+}
+
+//------------------------------------------------------------------------------
+/// get the slow clock frequency
+//------------------------------------------------------------------------------
+unsigned int SLCK_UtilGetFreq(void)
+{
+ unsigned int freq = 0;
+
+ SLCK_UtilSetSlowClockMode(0);
+
+ if(AT91C_BASE_PMC->PMC_MCFR & (1<<16)) {
+ freq = BOARD_MAINOSC / (AT91C_BASE_PMC->PMC_MCFR & 0x0000FFFF);
+ freq *= 16;
+ }
+ return freq;
+}
+
+//#endif //#if defined(at91cap7)
+#elif defined(at91cap9)
+//------------------------------------------------------------------------------
+/// Return 1 if the slow clock is 32k
+//------------------------------------------------------------------------------
+unsigned char SLCK_Is32k(void)
+{
+ return ((*AT91C_SYS_SLCKSEL & AT91C_SLCKSEL_OSCSEL) != 0);
+}
+
+//------------------------------------------------------------------------------
+/// Configure the 32kHz oscillator for the slow clock
+//------------------------------------------------------------------------------
+void SLCK_RCto32k(void)
+{
+ // Check that the master clock has a different source than slow clock. If no,
+ if( (AT91C_BASE_PMC->PMC_MCKR & AT91C_PMC_CSS) == 0)
+ {
+ TRACE_WARNING("The master clock use the slow clock. " \
+ "Not possible to change Slow clock\n\r");
+ return;
+ }
+
+ // Check that the slow clock source is RC
+ if( SLCK_Is32k() )
+ {
+ TRACE_WARNING("The slow clock is already the external 32.768kHz crystal\n\r");
+ return;
+ }
+
+ // Enable the 32,768 Hz oscillator by setting the bit OSC32EN to 1.
+ *AT91C_SYS_SLCKSEL |= AT91C_SLCKSEL_OSC32EN;
+
+ // Wait 32,768 Hz Startup Time for clock stabilization (software loop).
+ WaitTimeInMs(BOARD_MCK*2, /*T_ST_SLCK_32K_IN_MS*/10);
+
+ // Switch from internal RC to 32,768 Hz oscillator by setting the bit OSCSEL to 1.
+ *AT91C_SYS_SLCKSEL |= AT91C_SLCKSEL_OSCSEL;
+
+ // Wait 5 slow clock cycles for internal resynchronization.
+ WaitTimeInUs(BOARD_MCK*2, TIME_5_CYCLES_32K_IN_US);
+
+ // Disable the RC oscillator by setting the bit RCEN to 0.
+ *AT91C_SYS_SLCKSEL &= (0xFFFFFFFF ^ AT91C_SLCKSEL_RCEN);
+
+ TRACE_INFO("The slow clock is now the external 32.768kHz crystal\n\r");
+}
+
+
+//------------------------------------------------------------------------------
+/// Configure the RC oscillator for the slow clock
+//------------------------------------------------------------------------------
+void SLCK_32ktoRC(void)
+{
+ // Check that the master clock has a different source than slow clock.
+ if( (AT91C_BASE_PMC->PMC_MCKR & AT91C_PMC_CSS) == 0)
+ {
+ TRACE_WARNING("The master clock use the slow clock. " \
+ "Not possible to change Slow clock\n\r");
+ return;
+ }
+
+ // Check that the slow clock source is RC
+ if( !SLCK_Is32k() )
+ {
+ TRACE_WARNING("The slow clock is already the internal RC oscillator\n\r");
+ return;
+ }
+
+ // Enable the internal RC oscillator by setting the bit RCEN to 1
+ *AT91C_SYS_SLCKSEL |= AT91C_SLCKSEL_RCEN;
+
+ // Wait internal RC Startup Time for clock stabilization (software loop).
+ WaitTimeInUs(BOARD_MCK*2, T_ST_SLCK_RC_IN_US);
+
+ // Switch from 32768 Hz oscillator to internal RC by setting the bit OSCSEL to 0.
+ *AT91C_SYS_SLCKSEL &= (0xFFFFFFFF ^ AT91C_SLCKSEL_OSCSEL);
+
+ // Wait 5 slow clock cycles for internal resynchronization.
+ WaitTimeInUs(BOARD_MCK*2, TIME_5_CYCLES_RC_IN_US);
+
+ // Disable the 32768 Hz oscillator by setting the bit OSC32EN to 0.
+ *AT91C_SYS_SLCKSEL &= (0xFFFFFFFF ^ AT91C_SLCKSEL_OSC32EN);
+
+ TRACE_INFO("The slow clock is now the internal RC oscillator\n\r");
+}
+
+//------------------------------------------------------------------------------
+/// by pass the 32kHz oscillator
+//------------------------------------------------------------------------------
+void SLCK_bypass32Kosc(void)
+{
+ // Enable the bypass path OSC32BYP bit set to 1
+ *AT91C_SYS_SLCKSEL |= AT91C_SLCKSEL_OSC32BYP;
+
+ // Disable the 32,768 Hz oscillator by setting the bit OSC32EN to 0
+ *AT91C_SYS_SLCKSEL &= (0xFFFFFFFF ^ AT91C_SLCKSEL_OSC32EN);
+}
+
+//------------------------------------------------------------------------------
+/// set Slow Clock Mode
+//------------------------------------------------------------------------------
+void SLCK_UtilSetSlowClockMode(unsigned int timeInSlowClockMode)
+{
+ unsigned int oldPll;
+ unsigned int oldMck;
+ unsigned int timeout = 0;
+
+ // Save previous values for PLL A and Master Clock configuration
+ oldPll = AT91C_BASE_CKGR->CKGR_PLLAR;
+ oldMck = AT91C_BASE_PMC->PMC_MCKR;
+
+ // Slow clock is selected for Master Clock
+ // 32kKz / 64 = 500Hz
+ // PCK = 500Hz, MCK = 250 Hz
+ AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_CSS_SLOW_CLK | AT91C_PMC_PRES_CLK_64 | AT91C_PMC_MDIV_2;
+ timeout = 0;
+ while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) && timeout++ < CLOCK_TIMEOUT);
+
+ // Stop PLL A
+ // MULA: PLL A Multiplier 0 = The PLL A is deactivated.
+ AT91C_BASE_CKGR->CKGR_PLLAR = 0x00003f00;
+
+ // Stop Main Oscillator
+ AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR & (~AT91C_CKGR_MOSCEN);
+
+ // Wait a while. The clock is at 500Hz...
+ while( timeInSlowClockMode-- );
+ // End !
+
+ // Restart Main Oscillator
+ AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR | (AT91C_CKGR_OSCOUNT & (0x32<<8) );
+ AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR | (AT91C_CKGR_MOSCEN);
+
+ // Restart PLL A
+ AT91C_BASE_CKGR->CKGR_PLLAR = oldPll;
+ timeout = 0;
+ while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA) && timeout++ < CLOCK_TIMEOUT);
+
+ // Selection of Master Clock MCK (so Processor Clock PCK)
+ AT91C_BASE_PMC->PMC_MCKR = oldMck;
+ timeout = 0;
+ while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) && timeout++ < CLOCK_TIMEOUT);
+
+ // Reconfigure DBGU
+ TRACE_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK);
+}
+
+//------------------------------------------------------------------------------
+/// get the slow clock frequency
+//------------------------------------------------------------------------------
+unsigned int SLCK_UtilGetFreq(void)
+{
+ unsigned int freq = 0;
+
+ SLCK_UtilSetSlowClockMode(0);
+
+ if(AT91C_BASE_PMC->PMC_MCFR & (1<<16)) {
+ freq = BOARD_MAINOSC / (AT91C_BASE_PMC->PMC_MCFR & 0x0000FFFF);
+ freq *= 16;
+ }
+ return freq;
+}
+
+//#endif //#if defined(at91cap9)
+#elif defined(at91sam3u)
+
+//------------------------------------------------------------------------------
+/// Return 1 if the slow clock is 32k
+//------------------------------------------------------------------------------
+unsigned char SLCK_Is32k(void)
+{
+ return ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_SR_OSCSEL_CRYST) != 0);
+}
+
+//------------------------------------------------------------------------------
+/// Configure the 32kHz oscillator for the slow clock
+//------------------------------------------------------------------------------
+void SLCK_RCto32k(void)
+{
+ unsigned int timeout = 0;
+
+ // Check that the master clock has a different source than slow clock. If no,
+ if( (AT91C_BASE_PMC->PMC_MCKR & AT91C_PMC_CSS) == 0)
+ {
+ TRACE_WARNING("The master clock use the slow clock. " \
+ "Not possible to change Slow clock\n\r");
+ return;
+ }
+
+ // Check that the slow clock source is RC
+ if( SLCK_Is32k() )
+ {
+ TRACE_WARNING("The slow clock is already the external 32.768kHz crystal\n\r");
+ return;
+ }
+
+ // Select the internal RC oscillator by set XTALSEL to 1.
+ AT91C_BASE_SUPC->SUPC_CR = AT91C_SUPC_CR_XTALSEL_CRYSTAL_SEL | (0xA5 << 24);
+ timeout = 0;
+ while (!(AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_SR_OSCSEL_CRYST) && (timeout++ < CLOCK_TIMEOUT));
+
+ TRACE_INFO("The slow clock is now the external 32.768kHz crystal\n\r");
+}
+
+//------------------------------------------------------------------------------
+/// Configure the RC oscillator for the slow clock
+//------------------------------------------------------------------------------
+void SLCK_32ktoRC(void)
+{
+ TRACE_INFO("Switch to the internal RC oscillator is not possible for SAM3U!!!\n\r");
+}
+
+//------------------------------------------------------------------------------
+/// by pass the 32kHz oscillator
+//------------------------------------------------------------------------------
+void SLCK_bypass32Kosc(void)
+{
+ // Enable the bypass path OSCBYPASS by set to 1.
+ AT91C_BASE_SUPC->SUPC_MR |= AT91C_SUPC_MR_OSCBYPASS_BYPASS;
+}
+
+void SLCK_UtilSetSlowClockMode(unsigned int timeInSlowClockMode)
+{
+ unsigned int oldPll;
+ unsigned int oldMck;
+ unsigned int timeout = 0;
+
+ // Save previous values for PLL A and Master Clock configuration
+ oldPll = AT91C_BASE_CKGR->CKGR_PLLAR;
+ oldMck = AT91C_BASE_PMC->PMC_MCKR;
+
+ // Slow clock is selected for Master Clock
+ // 32kKz / 64 = 500Hz
+ // PCK = 500Hz, MCK = 500 Hz
+ AT91C_BASE_PMC->PMC_MCKR = (oldMck & AT91C_PMC_PRES) | AT91C_PMC_CSS_SLOW_CLK;
+ timeout = 0;
+ while ( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) && timeout++ < CLOCK_TIMEOUT);
+
+ // Stop PLL A
+ // MULA: PLL A Multiplier 0 = The PLL A is deactivated.
+ AT91C_BASE_CKGR->CKGR_PLLAR = 0x00003f00;
+
+ // Stop Main Oscillator
+ AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR & (~AT91C_CKGR_MOSCXTEN);
+
+ // Wait a while. The clock is at 500Hz...
+ while( timeInSlowClockMode-- );
+ // End !
+
+ // Restart Main Oscillator
+ AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR | (AT91C_CKGR_MOSCXTST & (0x32<<8) );
+ AT91C_BASE_CKGR->CKGR_MOR = AT91C_BASE_CKGR->CKGR_MOR | (AT91C_CKGR_MOSCXTEN);
+
+ // Restart PLL A
+ AT91C_BASE_CKGR->CKGR_PLLAR = oldPll;
+ timeout = 0;
+ while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA) && timeout++ < CLOCK_TIMEOUT);
+
+ // Selection of Master Clock MCK (so Processor Clock PCK)
+ AT91C_BASE_PMC->PMC_MCKR = oldMck;
+ timeout = 0;
+ while( !(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY) && timeout++ < CLOCK_TIMEOUT);
+
+ // Reconfigure DBGU
+ TRACE_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK);
+}
+
+//------------------------------------------------------------------------------
+/// get the slow clock frequency
+//------------------------------------------------------------------------------
+unsigned int SLCK_UtilGetFreq(void)
+{
+ unsigned int freq = 0;
+
+ SetFlashWaitState(3);
+ SLCK_UtilSetSlowClockMode(0);
+
+ if(AT91C_BASE_PMC->PMC_MCFR & (1<<16)) {
+ freq = BOARD_MAINOSC / (AT91C_BASE_PMC->PMC_MCFR & 0x0000FFFF);
+ freq *= 16;
+ }
+ return freq;
+}
+
+#endif // endof at91sam3u
+
diff --git a/peripherals/slck/slck.dir b/peripherals/slck/slck.dir new file mode 100644 index 0000000..5210a1e --- /dev/null +++ b/peripherals/slck/slck.dir @@ -0,0 +1,35 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !!!Purpose
+///
+/// Contains the peripheral API for Supply Controller (SUPC) respect with slow clock .
+//------------------------------------------------------------------------------
diff --git a/peripherals/slck/slck.h b/peripherals/slck/slck.h new file mode 100644 index 0000000..5814492 --- /dev/null +++ b/peripherals/slck/slck.h @@ -0,0 +1,49 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef SLCK_H
+#define SLCK_H
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern unsigned char SLCK_Is32k(void);
+
+extern void SLCK_RCto32k(void);
+
+extern void SLCK_32ktoRC(void);
+
+extern void SLCK_bypass32Kosc(void);
+
+extern void SLCK_UtilSetSlowClockMode(unsigned int timeInSlowClockMode);
+
+extern unsigned int SLCK_UtilGetFreq(void);
+
+#endif //#ifndef SLCK_H
diff --git a/peripherals/spi/spi.c b/peripherals/spi/spi.c new file mode 100644 index 0000000..16eba71 --- /dev/null +++ b/peripherals/spi/spi.c @@ -0,0 +1,194 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "spi.h"
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// Enables a SPI peripheral
+/// \param spi Pointer to an AT91S_SPI instance.
+//------------------------------------------------------------------------------
+void SPI_Enable(AT91S_SPI *spi)
+{
+ spi->SPI_CR = AT91C_SPI_SPIEN;
+}
+
+//------------------------------------------------------------------------------
+/// Disables a SPI peripheral.
+/// \param spi Pointer to an AT91S_SPI instance.
+//------------------------------------------------------------------------------
+void SPI_Disable(AT91S_SPI *spi)
+{
+ spi->SPI_CR = AT91C_SPI_SPIDIS;
+}
+
+//------------------------------------------------------------------------------
+/// Configures a SPI peripheral as specified. The configuration can be computed
+/// using several macros (see "SPI configuration macros") and the constants
+/// defined in LibV3 (AT91C_SPI_*).
+/// \param spi Pointer to an AT91S_SPI instance.
+/// \param id Peripheral ID of the SPI.
+/// \param configuration Value of the SPI configuration register.
+//------------------------------------------------------------------------------
+void SPI_Configure(AT91S_SPI *spi,
+ unsigned int id,
+ unsigned int configuration)
+{
+ AT91C_BASE_PMC->PMC_PCER = 1 << id;
+ spi->SPI_CR = AT91C_SPI_SPIDIS;
+ // Execute a software reset of the SPI twice
+ spi->SPI_CR = AT91C_SPI_SWRST;
+ spi->SPI_CR = AT91C_SPI_SWRST;
+ spi->SPI_MR = configuration;
+}
+
+//------------------------------------------------------------------------------
+/// Configures a chip select of a SPI peripheral. The chip select configuration
+/// is computed using the definition provided by the LibV3 (AT91C_SPI_*).
+/// \param spi Pointer to an AT91S_SPI instance.
+/// \param npcs Chip select to configure (1, 2, 3 or 4).
+/// \param configuration Desired chip select configuration.
+//------------------------------------------------------------------------------
+void SPI_ConfigureNPCS(AT91S_SPI *spi,
+ unsigned int npcs,
+ unsigned int configuration)
+{
+ spi->SPI_CSR[npcs] = configuration;
+}
+
+//------------------------------------------------------------------------------
+/// 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 AT91S_SPI instance.
+/// \param npcs Chip select of the component to address (1, 2, 3 or 4).
+/// \param data Word of data to send.
+//------------------------------------------------------------------------------
+void SPI_Write(AT91S_SPI *spi, unsigned int npcs, unsigned short data)
+{
+ // Discard contents of RDR register
+ //volatile unsigned int discard = spi->SPI_RDR;
+
+ // Send data
+ while ((spi->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
+ spi->SPI_TDR = data | SPI_PCS(npcs);
+ while ((spi->SPI_SR & AT91C_SPI_TDRE) == 0);
+}
+
+//------------------------------------------------------------------------------
+/// Sends the contents of buffer through a SPI peripheral, using the PDC to
+/// take care of the transfer.
+/// \param spi Pointer to an AT91S_SPI instance.
+/// \param buffer Data buffer to send.
+/// \param length Length of the data buffer.
+//------------------------------------------------------------------------------
+unsigned char SPI_WriteBuffer(AT91S_SPI *spi,
+ void *buffer,
+ unsigned int length)
+{
+#if !defined(CHIP_SPI_DMA)
+ // Check if first bank is free
+ if (spi->SPI_TCR == 0) {
+
+ spi->SPI_TPR = (unsigned int) buffer;
+ spi->SPI_TCR = length;
+ spi->SPI_PTCR = AT91C_PDC_TXTEN;
+ return 1;
+ }
+ // Check if second bank is free
+ else if (spi->SPI_TNCR == 0) {
+
+ spi->SPI_TNPR = (unsigned int) buffer;
+ spi->SPI_TNCR = length;
+ return 1;
+ }
+#endif
+ // No free banks
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if there is no pending write operation on the SPI; otherwise
+/// returns 0.
+/// \param pSpi Pointer to an AT91S_SPI instance.
+//------------------------------------------------------------------------------
+unsigned char SPI_IsFinished(AT91S_SPI *pSpi)
+{
+ return ((pSpi->SPI_SR & AT91C_SPI_TXEMPTY) != 0);
+}
+
+//------------------------------------------------------------------------------
+/// 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 AT91S_SPI instance.
+//------------------------------------------------------------------------------
+unsigned short SPI_Read(AT91S_SPI *spi)
+{
+ while ((spi->SPI_SR & AT91C_SPI_RDRF) == 0);
+ return spi->SPI_RDR & 0xFFFF;
+}
+
+//------------------------------------------------------------------------------
+/// 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 AT91S_SPI instance.
+/// \param buffer Data buffer to store incoming bytes.
+/// \param length Length in bytes of the data buffer.
+//------------------------------------------------------------------------------
+unsigned char SPI_ReadBuffer(AT91S_SPI *spi,
+ void *buffer,
+ unsigned int length)
+{
+#if !defined(CHIP_SPI_DMA)
+ // Check if the first bank is free
+ if (spi->SPI_RCR == 0) {
+
+ spi->SPI_RPR = (unsigned int) buffer;
+ spi->SPI_RCR = length;
+ spi->SPI_PTCR = AT91C_PDC_RXTEN;
+ return 1;
+ }
+ // Check if second bank is free
+ else if (spi->SPI_RNCR == 0) {
+
+ spi->SPI_RNPR = (unsigned int) buffer;
+ spi->SPI_RNCR = length;
+ return 1;
+ }
+#endif
+ // No free bank
+ return 0;
+}
+
diff --git a/peripherals/spi/spi.h b/peripherals/spi/spi.h new file mode 100644 index 0000000..f4e2557 --- /dev/null +++ b/peripherals/spi/spi.h @@ -0,0 +1,114 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !Purpose
+///
+/// Definitions for SPI peripheral usage.
+///
+/// !Usage
+///
+/// -# Enable the SPI pins required by the application (see pio.h).
+/// -# Configure the SPI using the SPI_Configure function. This enables the
+/// peripheral clock. The mode register is loaded with the given value.
+/// -# Configure all the necessary chip selects with SPI_ConfigureNPCS.
+/// -# Enable the SPI by calling SPI_Enable.
+/// -# Send/receive data using SPI_Write and SPI_Read. Note that SPI_Read
+/// must be called after SPI_Write to retrieve the last value read.
+/// -# Send/receive data using the PDC with the SPI_WriteBuffer and
+/// SPI_ReadBuffer functions.
+/// -# Disable the SPI by calling SPI_Disable.
+//------------------------------------------------------------------------------
+
+#ifndef SPI_H
+#define SPI_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "SPI configuration macros"
+/// This page lists several macros which should be used when configuring a SPI
+/// peripheral.
+///
+/// !Macros
+/// - SPI_PCS
+/// - SPI_SCBR
+/// - SPI_DLYBS
+/// - SPI_DLYBCT
+
+/// Calculate the PCS field value given the chip select NPCS value
+#define SPI_PCS(npcs) ((~(1 << npcs) & 0xF) << 16)
+
+/// Calculates the value of the CSR SCBR field given the baudrate and MCK.
+#define SPI_SCBR(baudrate, masterClock) \
+ ((unsigned int) (masterClock / baudrate) << 8)
+
+/// Calculates the value of the CSR DLYBS field given the desired delay (in ns)
+#define SPI_DLYBS(delay, masterClock) \
+ ((unsigned int) (((masterClock / 1000000) * delay) / 1000) << 16)
+
+/// Calculates the value of the CSR DLYBCT field given the desired delay (in ns)
+#define SPI_DLYBCT(delay, masterClock) \
+ ((unsigned int) (((masterClock / 1000000) * delay) / 32000) << 24)
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+extern void SPI_Enable(AT91S_SPI *spi);
+extern void SPI_Disable(AT91S_SPI *spi);
+extern void SPI_Configure(AT91S_SPI *spi,
+ unsigned int id,
+ unsigned int configuration);
+extern void SPI_ConfigureNPCS(AT91S_SPI *spi,
+ unsigned int npcs,
+ unsigned int configuration);
+extern void SPI_Write(AT91S_SPI *spi, unsigned int npcs, unsigned short data);
+extern unsigned char SPI_WriteBuffer(AT91S_SPI *spi,
+ void *buffer,
+ unsigned int length);
+
+extern unsigned char SPI_IsFinished(AT91S_SPI *pSpi);
+
+extern unsigned short SPI_Read(AT91S_SPI *spi);
+extern unsigned char SPI_ReadBuffer(AT91S_SPI *spi,
+ void *buffer,
+ unsigned int length);
+
+#endif //#ifndef SPI_H
+
diff --git a/peripherals/ssc/ssc.c b/peripherals/ssc/ssc.c new file mode 100644 index 0000000..52a8566 --- /dev/null +++ b/peripherals/ssc/ssc.c @@ -0,0 +1,413 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "ssc.h"
+#include <utility/trace.h>
+#if defined(CHIP_SSC_DMA)
+#include <dma/dma.h>
+#include <dmad/dmad.h>
+#endif
+
+//------------------------------------------------------------------------------
+// Local variables
+//------------------------------------------------------------------------------
+#if defined(CHIP_SSC_DMA)
+static DmaLinkList LLI_CH [MAX_SSC_LLI_SIZE];
+#endif
+
+//------------------------------------------------------------------------------
+// Local macros
+//------------------------------------------------------------------------------
+#if defined(CHIP_SSC_DMA)
+#define LAST_ROW 0x100
+#endif
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+#if defined(CHIP_SSC_DMA)
+static void AT91F_Prepare_Multiple_Transfer(unsigned int Channel,
+ unsigned int LLI_rownumber,
+ unsigned int LLI_Last_Row,
+ unsigned int From_add,
+ unsigned int To_add,
+ unsigned int Ctrla,
+ unsigned int Ctrlb)
+{
+ LLI_CH[LLI_rownumber].sourceAddress = From_add;
+ LLI_CH[LLI_rownumber].destAddress = To_add;
+ LLI_CH[LLI_rownumber].controlA = Ctrla;
+ LLI_CH[LLI_rownumber].controlB = Ctrlb;
+ if (LLI_Last_Row != LAST_ROW)
+ LLI_CH[LLI_rownumber].descriptor =
+ (unsigned int)&LLI_CH[LLI_rownumber + 1] + 0;
+ else
+ LLI_CH[LLI_rownumber].descriptor = 0;
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// Configures a SSC peripheral. If the divided clock is not used, the master
+/// clock frequency can be set to 0.
+/// \note The emitter and transmitter are disabled by this function.
+/// \param ssc Pointer to an AT91S_SSC instance.
+/// \param id Peripheral ID of the SSC.
+//------------------------------------------------------------------------------
+void SSC_Configure(AT91S_SSC *ssc,
+ unsigned int id,
+ unsigned int bitRate,
+ unsigned int masterClock)
+{
+ // Enable SSC peripheral clock
+ AT91C_BASE_PMC->PMC_PCER = 1 << id;
+
+ // Reset, disable receiver & transmitter
+ ssc->SSC_CR = AT91C_SSC_RXDIS | AT91C_SSC_TXDIS | AT91C_SSC_SWRST;
+
+ #if !defined(CHIP_SSC_DMA)
+ ssc->SSC_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
+ #endif
+
+ // Configure clock frequency
+ if (bitRate != 0) {
+
+ ssc->SSC_CMR = masterClock / (2 * bitRate);
+ }
+ else {
+
+ ssc->SSC_CMR = 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Configures the transmitter of a SSC peripheral. Several macros can be used
+/// to compute the values of the Transmit Clock Mode Register (TCMR) and the
+/// Transmit Frame Mode Register (TFMR) (see "SSC configuration macros").
+/// \param ssc Pointer to a AT91S_SSC instance.
+/// \param tcmr Transmit Clock Mode Register value.
+/// \param tfmr Transmit Frame Mode Register value.
+//------------------------------------------------------------------------------
+void SSC_ConfigureTransmitter(AT91S_SSC *ssc,
+ unsigned int tcmr,
+ unsigned int tfmr)
+{
+ ssc->SSC_TCMR = tcmr;
+ ssc->SSC_TFMR = tfmr;
+}
+
+//------------------------------------------------------------------------------
+/// Configures the receiver of a SSC peripheral. Several macros can be used
+/// to compute the values of the Receive Clock Mode Register (TCMR) and the
+/// Receive Frame Mode Register (TFMR) (see "SSC configuration macros").
+/// \param ssc Pointer to a AT91S_SSC instance.
+/// \param rcmr Receive Clock Mode Register value.
+/// \param rfmr Receive Frame Mode Register value.
+//------------------------------------------------------------------------------
+void SSC_ConfigureReceiver(AT91S_SSC *ssc,
+ unsigned int rcmr,
+ unsigned int rfmr)
+{
+ ssc->SSC_RCMR = rcmr;
+ ssc->SSC_RFMR = rfmr;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the transmitter of a SSC peripheral.
+/// \param ssc Pointer to an AT91S_SSC instance.
+//------------------------------------------------------------------------------
+void SSC_EnableTransmitter(AT91S_SSC *ssc)
+{
+ ssc->SSC_CR = AT91C_SSC_TXEN;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the transmitter of a SSC peripheral.
+/// \param ssc Pointer to an AT91S_SSC instance.
+//------------------------------------------------------------------------------
+void SSC_DisableTransmitter(AT91S_SSC *ssc)
+{
+ ssc->SSC_CR = AT91C_SSC_TXDIS;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the receiver of a SSC peripheral.
+/// \param ssc Pointer to an AT91S_SSC instance.
+//------------------------------------------------------------------------------
+void SSC_EnableReceiver(AT91S_SSC *ssc)
+{
+ ssc->SSC_CR = AT91C_SSC_RXEN;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the receiver of a SSC peripheral.
+/// \param ssc Pointer to an AT91S_SSC instance.
+//------------------------------------------------------------------------------
+void SSC_DisableReceiver(AT91S_SSC *ssc)
+{
+ ssc->SSC_CR = AT91C_SSC_RXDIS;
+}
+
+//------------------------------------------------------------------------------
+/// Enables one or more interrupt sources of a SSC peripheral.
+/// \param ssc Pointer to an AT91S_SSC instance.
+/// \param sources Interrupt sources to enable.
+//------------------------------------------------------------------------------
+void SSC_EnableInterrupts(AT91S_SSC *ssc, unsigned int sources)
+{
+ ssc->SSC_IER = sources;
+}
+
+//------------------------------------------------------------------------------
+/// Disables one or more interrupt sources of a SSC peripheral.
+/// \param ssc Pointer to an AT91S_SSC instance.
+/// \param sources Interrupt source to disable.
+//------------------------------------------------------------------------------
+void SSC_DisableInterrupts(AT91S_SSC *ssc, unsigned int sources)
+{
+ ssc->SSC_IDR = sources;
+}
+
+//------------------------------------------------------------------------------
+/// Sends one data frame through a SSC peripheral. If another frame is currently
+/// being sent, this function waits for the previous transfer to complete.
+/// \param ssc Pointer to an AT91S_SSC instance.
+/// \param frame Data frame to send.
+//------------------------------------------------------------------------------
+void SSC_Write(AT91S_SSC *ssc, unsigned int frame)
+{
+ while ((ssc->SSC_SR & AT91C_SSC_TXRDY) == 0);
+ ssc->SSC_THR = frame;
+}
+
+//------------------------------------------------------------------------------
+/// Sends the contents of a data buffer a SSC peripheral, using the PDC. Returns
+/// true if the buffer has been queued for transmission; otherwise returns
+/// false.
+/// \param ssc Pointer to an AT91S_SSC instance.
+/// \param buffer Data buffer to send.
+/// \param length Size of the data buffer.
+//------------------------------------------------------------------------------
+unsigned char SSC_WriteBuffer(AT91S_SSC *ssc,
+ void *buffer,
+ unsigned int length)
+{
+#if !defined(CHIP_SSC_DMA)
+ // Check if first bank is free
+ if (ssc->SSC_TCR == 0) {
+
+ ssc->SSC_TPR = (unsigned int) buffer;
+ ssc->SSC_TCR = length;
+ ssc->SSC_PTCR = AT91C_PDC_TXTEN;
+ return 1;
+ }
+ // Check if second bank is free
+ else if (ssc->SSC_TNCR == 0) {
+
+ ssc->SSC_TNPR = (unsigned int) buffer;
+ ssc->SSC_TNCR = length;
+ return 1;
+ }
+#else
+
+ #if defined(SSC_DMA_WORD)
+ unsigned int* startSourceAddr;
+ unsigned int* startDestAddr;
+ #elif defined(SSC_DMA_HALFWORD)
+ unsigned short* startSourceAddr;
+ unsigned short* startDestAddr;
+ #endif
+ unsigned int srcAddress;
+ unsigned int destAddress;
+ unsigned int buffSize;
+ unsigned int LLI_rownumber = 0;
+ unsigned int ctrla;
+
+ #if defined(SSC_DMA_WORD)
+ startSourceAddr = (unsigned int*)(buffer);
+ startDestAddr = (unsigned int*)(&ssc->SSC_THR);
+ #elif defined(SSC_DMA_HALFWORD)
+ startSourceAddr = (unsigned short*)(buffer);
+ startDestAddr = (unsigned short*)(&ssc->SSC_THR);
+ #endif
+ srcAddress = (unsigned int)startSourceAddr; // Set the data start address
+ destAddress = (unsigned int)startDestAddr;
+ buffSize = length;
+ if(buffSize > 0x8000){
+ TRACE_WARNING("SSC DMA, size too big %d\n\r", buffSize);
+ buffSize = 0x8000;
+ }
+
+ // Set DMA channel DSCR
+ DMA_SetDescriptorAddr(BOARD_SSC_DMA_CHANNEL, (unsigned int)&LLI_CH[0]);
+
+ // Clear any pending interrupts
+ DMA_GetStatus();
+
+ //Set DMA channel control B
+ DMA_SetSourceBufferMode(BOARD_SSC_DMA_CHANNEL, DMA_TRANSFER_LLI,
+ (AT91C_HDMA_SRC_ADDRESS_MODE_INCR >> 24));
+ DMA_SetDestBufferMode(BOARD_SSC_DMA_CHANNEL, DMA_TRANSFER_LLI,
+ (AT91C_HDMA_DST_ADDRESS_MODE_FIXED >> 28));
+ DMA_SetFlowControl(BOARD_SSC_DMA_CHANNEL, AT91C_HDMA_FC_MEM2PER >> 21);
+
+ // Set DMA channel config
+ DMA_SetConfiguration(BOARD_SSC_DMA_CHANNEL, BOARD_SSC_DMA_HW_SRC_REQ_ID \
+ | BOARD_SSC_DMA_HW_DEST_REQ_ID \
+ | AT91C_HDMA_SRC_H2SEL_SW \
+ | AT91C_HDMA_DST_H2SEL_HW \
+ | AT91C_HDMA_SOD_DISABLE \
+ | AT91C_HDMA_FIFOCFG_LARGESTBURST);
+
+ // Set link list
+ while(srcAddress < ((unsigned int)(startSourceAddr + buffSize)))
+ {
+ if(((unsigned int)(startSourceAddr + buffSize)) - srcAddress <= (BOARD_SSC_DMA_FIFO_SIZE) )
+ {
+
+ #if defined(SSC_DMA_WORD)
+ ctrla = (((((unsigned int)(startSourceAddr + buffSize))
+ - srcAddress)/4)
+ | AT91C_HDMA_SRC_WIDTH_WORD
+ | AT91C_HDMA_DST_WIDTH_WORD
+ | AT91C_HDMA_SCSIZE_4
+ | AT91C_HDMA_DCSIZE_1
+ );
+ #elif defined(SSC_DMA_HALFWORD)
+ ctrla = (((((unsigned int)(startSourceAddr + buffSize))
+ - srcAddress)/2)
+ | AT91C_HDMA_SRC_WIDTH_HALFWORD
+ | AT91C_HDMA_DST_WIDTH_HALFWORD
+ | AT91C_HDMA_SCSIZE_1
+ | AT91C_HDMA_DCSIZE_1
+ );
+ #endif
+ AT91F_Prepare_Multiple_Transfer(BOARD_SSC_DMA_CHANNEL, LLI_rownumber, LAST_ROW,
+ srcAddress,
+ destAddress,
+ ctrla,
+ ( //| AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ AT91C_HDMA_DST_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_DST_ADDRESS_MODE_FIXED
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ //| AT91C_HDMA_SRC_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_SRC_ADDRESS_MODE_INCR
+ | AT91C_HDMA_FC_MEM2PER));
+ }
+ else
+ {
+
+ #if defined(SSC_DMA_WORD)
+ ctrla = (((BOARD_SSC_DMA_FIFO_SIZE)/4)
+ | AT91C_HDMA_SRC_WIDTH_WORD
+ | AT91C_HDMA_DST_WIDTH_WORD
+ | AT91C_HDMA_SCSIZE_4
+ | AT91C_HDMA_DCSIZE_1
+ );
+ #elif defined(SSC_DMA_HALFWORD)
+ ctrla = (((BOARD_SSC_DMA_FIFO_SIZE)/2)
+ | AT91C_HDMA_SRC_WIDTH_HALFWORD
+ | AT91C_HDMA_DST_WIDTH_HALFWORD
+ | AT91C_HDMA_SCSIZE_1
+ | AT91C_HDMA_DCSIZE_1
+ );
+ #endif
+ AT91F_Prepare_Multiple_Transfer(BOARD_SSC_DMA_CHANNEL, LLI_rownumber, 0,
+ srcAddress,
+ destAddress,
+ ctrla,
+ ( //| AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ AT91C_HDMA_DST_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_DST_ADDRESS_MODE_FIXED
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ //| AT91C_HDMA_SRC_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_SRC_ADDRESS_MODE_INCR
+ | AT91C_HDMA_FC_MEM2PER));
+
+ }
+
+ srcAddress += BOARD_SSC_DMA_FIFO_SIZE;
+
+
+ LLI_rownumber++;
+ }
+#endif
+ // No free banks
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Waits until one frame is received on a SSC peripheral, and returns it.
+/// \param ssc Pointer to an AT91S_SSC instance.
+//------------------------------------------------------------------------------
+unsigned int SSC_Read(AT91S_SSC *ssc)
+{
+ while ((ssc->SSC_SR & AT91C_SSC_RXRDY) == 0);
+ return ssc->SSC_RHR;
+}
+
+//------------------------------------------------------------------------------
+/// Reads data coming from a SSC peripheral receiver and stores it into the
+/// provided buffer. Returns true if the buffer has been queued for reception;
+/// otherwise returns false.
+/// \param ssc Pointer to an AT91S_SSC instance.
+/// \param buffer Data buffer used for reception.
+/// \param length Size in bytes of the data buffer.
+//------------------------------------------------------------------------------
+unsigned char SSC_ReadBuffer(AT91S_SSC *ssc,
+ void *buffer,
+ unsigned int length)
+{
+#if !defined(CHIP_SSC_DMA)
+ // Check if the first bank is free
+ if (ssc->SSC_RCR == 0) {
+
+ ssc->SSC_RPR = (unsigned int) buffer;
+ ssc->SSC_RCR = length;
+ ssc->SSC_PTCR = AT91C_PDC_RXTEN;
+ return 1;
+ }
+ // Check if second bank is free
+ else if (ssc->SSC_RNCR == 0) {
+
+ ssc->SSC_RNPR = (unsigned int) buffer;
+ ssc->SSC_RNCR = length;
+ return 1;
+ }
+#endif
+ // No free bank
+ return 0;
+}
+
diff --git a/peripherals/ssc/ssc.h b/peripherals/ssc/ssc.h new file mode 100644 index 0000000..78295bd --- /dev/null +++ b/peripherals/ssc/ssc.h @@ -0,0 +1,156 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !Purpose
+///
+/// Set of functions and definition for using a SSC peripheral.
+///
+/// !Usage
+///
+/// -# Enable the SSC interface pins (see pio & board.h).
+/// -# Configure the SSC to operate at a specific frequency by calling
+/// SSC_Configure(). This function enables the peripheral clock of the SSC,
+/// but not its PIOs.
+/// -# Configure the transmitter and/or the receiver using the
+/// SSC_ConfigureTransmitter() and SSC_ConfigureEmitter() functions.
+/// -# Enable the PIOs or the transmitter and/or the received.
+/// -# Enable the transmitter and/or the receiver using SSC_EnableTransmitter()
+/// and SSC_EnableReceiver()
+/// -# Send data through the transmitter using SSC_Write() and SSC_WriteBuffer()
+/// -# Receive data from the receiver using SSC_Read() and SSC_ReadBuffer()
+/// -# Disable the transmitter and/or the receiver using SSC_DisableTransmitter()
+/// and SSC_DisableReceiver()
+//------------------------------------------------------------------------------
+
+#ifndef SSC_H
+#define SSC_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "SSC configuration macros"
+/// This page lists several macros which are used when configuring a SSC
+/// peripheral.
+///
+/// !Macros
+/// - SSC_STTDLY
+/// - SSC_PERIOD
+/// - SSC_DATLEN
+/// - SSC_DATNB
+/// - SSC_FSLEN
+
+/// Calculates the value of the STTDLY field given the number of clock cycles
+/// before the first bit of a new frame is transmitted.
+#define SSC_STTDLY(bits) (bits << 16)
+
+/// Calculates the value of the PERIOD field of the Transmit Clock Mode Register
+/// of an SSC interface, given the desired clock divider.
+#define SSC_PERIOD(divider) (((divider / 2) - 1) << 24)
+
+/// Calculates the value of the DATLEN field of the Transmit Frame Mode Register
+/// of an SSC interface, given the number of bits in one sample.
+#define SSC_DATLEN(bits) (bits - 1)
+
+/// Calculates the value of the DATNB field of the Transmit Frame Mode Register
+/// of an SSC interface, given the number of samples in one frame.
+#define SSC_DATNB(samples) ((samples -1) << 8)
+
+/// Calculates the value of the FSLEN field of the Transmit Frame Mode Register
+/// of an SSC interface, given the number of transmit clock periods that the
+/// frame sync signal should take.
+#define SSC_FSLEN(periods) ((periods - 1) << 16)
+
+/// SSC DMA Fifo size
+#define BOARD_SSC_DMA_FIFO_SIZE (4*1024)
+
+/// SSC Linked list size
+#define MAX_SSC_LLI_SIZE 8
+
+#define SSC_DMA_WORD
+//#define SSC_DMA_HALFWORD
+
+#define AT91C_I2S_MASTER_TX_SETTING(nb_bit_by_slot, nb_slot_by_frame)( +\
+ AT91C_SSC_CKS_DIV +\
+ AT91C_SSC_CKO_CONTINOUS +\
+ AT91C_SSC_START_FALL_RF +\
+ ((1<<16) & AT91C_SSC_STTDLY) +\
+ ((((nb_bit_by_slot*nb_slot_by_frame)/2)-1) <<24))
+
+#define AT91C_I2S_TX_FRAME_SETTING(nb_bit_by_slot, nb_slot_by_frame)( +\
+ (nb_bit_by_slot-1) +\
+ AT91C_SSC_MSBF +\
+ (((nb_slot_by_frame-1)<<8) & AT91C_SSC_DATNB) +\
+ (((nb_bit_by_slot-1)<<16) & AT91C_SSC_FSLEN) +\
+ AT91C_SSC_FSOS_NEGATIVE)
+
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+extern void SSC_Configure(AT91S_SSC *ssc,
+ unsigned int id,
+ unsigned int bitRate,
+ unsigned int masterClock);
+extern void SSC_ConfigureTransmitter(AT91S_SSC *ssc,
+ unsigned int tcmr,
+ unsigned int tfmr);
+extern void SSC_ConfigureReceiver(AT91S_SSC *ssc,
+ unsigned int rcmr,
+ unsigned int rfmr);
+
+extern void SSC_EnableTransmitter(AT91S_SSC *ssc);
+extern void SSC_DisableTransmitter(AT91S_SSC *ssc);
+extern void SSC_EnableReceiver(AT91S_SSC *ssc);
+extern void SSC_DisableReceiver(AT91S_SSC *ssc);
+
+extern void SSC_EnableInterrupts(AT91S_SSC *ssc, unsigned int sources);
+extern void SSC_DisableInterrupts(AT91S_SSC *ssc, unsigned int sources);
+
+extern void SSC_Write(AT91S_SSC *ssc, unsigned int frame);
+extern unsigned char SSC_WriteBuffer(AT91S_SSC *ssc,
+ void *buffer,
+ unsigned int length);
+extern unsigned int SSC_Read(AT91S_SSC *ssc);
+extern unsigned char SSC_ReadBuffer(AT91S_SSC *ssc,
+ void *buffer,
+ unsigned int length);
+
+#endif //#ifndef SSC_H
+
diff --git a/peripherals/supc/supc.c b/peripherals/supc/supc.c new file mode 100644 index 0000000..b63194c --- /dev/null +++ b/peripherals/supc/supc.c @@ -0,0 +1,223 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "supc.h"
+#include <board.h>
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Local definitions
+//------------------------------------------------------------------------------
+
+/// Key value for the SUPC_MR register.
+#define SUPC_KEY ((unsigned int) (0xA5 << 24))
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Enables the SLCD power supply.
+/// \param internal If 1, the power supply is configured as internal; otherwise
+/// it is set at external.
+//------------------------------------------------------------------------------
+void SUPC_EnableSlcd(unsigned char internal)
+{
+ if (internal) {
+
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_LCDMODE) | AT91C_SUPC_LCDMODE_INTERNAL;
+ }
+ else {
+
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_LCDMODE) | AT91C_SUPC_LCDMODE_EXTERNAL;
+ }
+ while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_LCDS) != AT91C_SUPC_LCDS);
+}
+
+//------------------------------------------------------------------------------
+/// Disables the SLCD power supply.
+//------------------------------------------------------------------------------
+void SUPC_DisableSlcd(void)
+{
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_LCDMODE);
+ while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_LCDS) == AT91C_SUPC_LCDS);
+}
+
+//------------------------------------------------------------------------------
+/// Sets the output voltage of the SLCD charge pump.
+/// \param voltage Output voltage.
+//------------------------------------------------------------------------------
+void SUPC_SetSlcdVoltage(unsigned int voltage)
+{
+ SANITY_CHECK((voltage & ~AT91C_SUPC_LCDOUT) == 0);
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_LCDOUT) | voltage;
+}
+
+#if !defined(__ICCARM__)
+__attribute__ ((section (".ramfunc"))) // GCC
+#endif
+//------------------------------------------------------------------------------
+/// Enables the flash power supply with the given wake-up setting.
+/// \param time Wake-up time.
+//------------------------------------------------------------------------------
+void SUPC_EnableFlash(unsigned int time)
+{
+ AT91C_BASE_SUPC->SUPC_FWUTR = time;
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | AT91C_BASE_SUPC->SUPC_MR | AT91C_SUPC_FLASHON;
+ while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_FLASHS) != AT91C_SUPC_FLASHS);
+}
+
+#if !defined(__ICCARM__)
+__attribute__ ((section (".ramfunc"))) // GCC
+#endif
+//------------------------------------------------------------------------------
+/// Disables the flash power supply.
+//------------------------------------------------------------------------------
+void SUPC_DisableFlash(void)
+{
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_FLASHON);
+ while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_FLASHS) == AT91C_SUPC_FLASHS);
+}
+
+//------------------------------------------------------------------------------
+/// Sets the voltage regulator output voltage.
+/// \param voltage Voltage to set.
+//------------------------------------------------------------------------------
+void SUPC_SetVoltageOutput(unsigned int voltage)
+{
+ SANITY_CHECK((voltage & ~AT91C_SUPC_VRVDD) == 0);
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_VRVDD) | voltage;
+}
+
+//------------------------------------------------------------------------------
+/// Puts the voltage regulator in deep mode.
+//------------------------------------------------------------------------------
+void SUPC_EnableDeepMode(void)
+{
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | AT91C_BASE_SUPC->SUPC_MR | AT91C_SUPC_VRDEEP;
+}
+
+//------------------------------------------------------------------------------
+/// Puts the voltage regulator in normal mode.
+//------------------------------------------------------------------------------
+void SUPC_DisableDeepMode(void)
+{
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_VRDEEP);
+}
+
+//-----------------------------------------------------------------------------
+/// Enables the backup SRAM power supply, so its data is saved while the device
+/// is in backup mode.
+//-----------------------------------------------------------------------------
+void SUPC_EnableSram(void)
+{
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | AT91C_BASE_SUPC->SUPC_MR | AT91C_SUPC_SRAMON;
+}
+
+//-----------------------------------------------------------------------------
+/// Disables the backup SRAM power supply.
+//-----------------------------------------------------------------------------
+void SUPC_DisableSram(void)
+{
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_SRAMON);
+}
+
+//-----------------------------------------------------------------------------
+/// Enables the RTC power supply.
+//-----------------------------------------------------------------------------
+void SUPC_EnableRtc(void)
+{
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | AT91C_BASE_SUPC->SUPC_MR | AT91C_SUPC_RTCON;
+ while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_RTS) != AT91C_SUPC_RTS);
+}
+
+//-----------------------------------------------------------------------------
+/// Disables the RTC power supply.
+//-----------------------------------------------------------------------------
+void SUPC_DisableRtc(void)
+{
+ AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_RTCON);
+ while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_RTS) == AT91C_SUPC_RTS);
+}
+
+//-----------------------------------------------------------------------------
+/// Sets the BOD sampling mode (or disables it).
+/// \param mode BOD sampling mode.
+//-----------------------------------------------------------------------------
+void SUPC_SetBodSampling(unsigned int mode)
+{
+ SANITY_CHECK((mode & ~AT91C_SUPC_BODSMPL) == 0);
+ AT91C_BASE_SUPC->SUPC_BOMR &= ~AT91C_SUPC_BODSMPL;
+ AT91C_BASE_SUPC->SUPC_BOMR |= mode;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the voltage regulator, which makes the device enter backup mode.
+//------------------------------------------------------------------------------
+void SUPC_DisableVoltageRegulator(void)
+{
+ AT91C_BASE_SUPC->SUPC_CR = SUPC_KEY | AT91C_SUPC_VROFF;
+ while (1);
+}
+
+//------------------------------------------------------------------------------
+/// Shuts the device down so it enters Off mode.
+//------------------------------------------------------------------------------
+void SUPC_Shutdown(void)
+{
+ AT91C_BASE_SUPC->SUPC_CR = SUPC_KEY | AT91C_SUPC_SHDW;
+ while (1);
+}
+
+//------------------------------------------------------------------------------
+/// Sets the wake-up sources when in backup mode.
+/// \param sources Wake-up sources to enable.
+//------------------------------------------------------------------------------
+void SUPC_SetWakeUpSources(unsigned int sources)
+{
+ SANITY_CHECK((sources & ~0x0000000B) == 0);
+ AT91C_BASE_SUPC->SUPC_WUMR &= ~0x0000000B;
+ AT91C_BASE_SUPC->SUPC_WUMR |= sources;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the wake-up inputs when in backup mode.
+/// \param inputs Wake up inputs to enable.
+//------------------------------------------------------------------------------
+void SUPC_SetWakeUpInputs(unsigned int inputs)
+{
+ SANITY_CHECK((inputs & ~0xFFFF) == 0);
+ AT91C_BASE_SUPC->SUPC_WUIR &= ~0xFFFF;
+ AT91C_BASE_SUPC->SUPC_WUIR |= inputs;
+}
+
diff --git a/peripherals/supc/supc.h b/peripherals/supc/supc.h new file mode 100644 index 0000000..f90df93 --- /dev/null +++ b/peripherals/supc/supc.h @@ -0,0 +1,80 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef SUPC_H
+#define SUPC_H
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void SUPC_EnableSlcd(unsigned char internal);
+
+extern void SUPC_DisableSlcd(void);
+
+extern void SUPC_SetSlcdVoltage(unsigned int voltage);
+
+extern
+#ifdef __ICCARM__
+__ramfunc // IAR
+#endif
+void SUPC_EnableFlash(unsigned int time);
+
+extern
+#ifdef __ICCARM__
+__ramfunc // IAR
+#endif
+void SUPC_DisableFlash(void);
+
+extern void SUPC_SetVoltageOutput(unsigned int voltage);
+
+extern void SUPC_EnableDeepMode(void);
+
+extern void SUPC_EnableSram(void);
+
+extern void SUPC_DisableSram(void);
+
+extern void SUPC_EnableRtc(void);
+
+extern void SUPC_DisableRtc(void);
+
+extern void SUPC_SetBodSampling(unsigned int mode);
+
+extern void SUPC_DisableDeepMode(void);
+
+extern void SUPC_DisableVoltageRegulator(void);
+
+extern void SUPC_Shutdown(void);
+
+extern void SUPC_SetWakeUpSources(unsigned int sources);
+
+extern void SUPC_SetWakeUpInputs(unsigned int inputs);
+
+#endif //#ifndef SUPC_H
+
diff --git a/peripherals/systick/systick.c b/peripherals/systick/systick.c new file mode 100644 index 0000000..c5d2d15 --- /dev/null +++ b/peripherals/systick/systick.c @@ -0,0 +1,63 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "systick.h"
+
+//------------------------------------------------------------------------------
+/// Configures the SysTick in .
+/// \param countEnable Enable SysTick counting.
+/// \param reloadValue Value used for tick counter to reload.
+/// \param handler Interrupt handler function, 0 to disable interrupt.
+//------------------------------------------------------------------------------
+void SysTick_Configure(unsigned char countEnable,
+ unsigned int reloadValue,
+ void( *handler )( void ))
+{
+ unsigned int intEnable = handler ? AT91C_NVIC_STICKINT : 0;
+
+ // Disable the SysTick & using core source
+ AT91C_BASE_NVIC->NVIC_STICKCSR = AT91C_NVIC_STICKCLKSOURCE;
+
+ // Reset the current value
+ AT91C_BASE_NVIC->NVIC_STICKCVR &= ~(unsigned int)AT91C_NVIC_STICKCURRENT;
+
+ // Setup the reload value
+ AT91C_BASE_NVIC->NVIC_STICKRVR = reloadValue;
+
+ // Enable the SysTick
+ AT91C_BASE_NVIC->NVIC_STICKCSR = AT91C_NVIC_STICKCLKSOURCE
+ | AT91C_NVIC_STICKENABLE
+ | intEnable;
+
+}
+
diff --git a/peripherals/systick/systick.dir b/peripherals/systick/systick.dir new file mode 100644 index 0000000..a6bf46f --- /dev/null +++ b/peripherals/systick/systick.dir @@ -0,0 +1,36 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// This directory contains an API for Configure the System Tick for Cortex-M3
+//------------------------------------------------------------------------------
\ No newline at end of file diff --git a/peripherals/systick/systick.h b/peripherals/systick/systick.h new file mode 100644 index 0000000..a3a0544 --- /dev/null +++ b/peripherals/systick/systick.h @@ -0,0 +1,68 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Methods and definitions for configuring System Tick in Cortex-M3.
+///
+/// !Usage
+///
+/// -# Configure the System Tick with SysTick_Configure
+///
+//------------------------------------------------------------------------------
+
+#ifndef SYSTICK_H
+#define SYSTICK_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include <core_cm3.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// Vendor define it's own SysTickConfig function
+#define __Vendor_SysTickConfig 1
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void SysTick_Configure(unsigned char countEnable,
+ unsigned int reloadValue,
+ void( *handler )( void ));
+
+#endif //#ifndef SYSTICK_H
diff --git a/peripherals/tc/tc.c b/peripherals/tc/tc.c new file mode 100644 index 0000000..8a2b5af --- /dev/null +++ b/peripherals/tc/tc.c @@ -0,0 +1,144 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "tc.h"
+
+//------------------------------------------------------------------------------
+// Global Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// 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 an AT91S_TC instance.
+/// \param mode Operating mode (TC_CMR value).
+//------------------------------------------------------------------------------
+void TC_Configure(AT91S_TC *pTc, unsigned int mode)
+{
+ // Disable TC clock
+ pTc->TC_CCR = AT91C_TC_CLKDIS;
+
+ // Disable interrupts
+ pTc->TC_IDR = 0xFFFFFFFF;
+
+ // Clear status register
+ pTc->TC_SR;
+
+ // Set mode
+ pTc->TC_CMR = mode;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the timer clock and performs a software reset to start the counting.
+/// \param pTc Pointer to an AT91S_TC instance.
+//------------------------------------------------------------------------------
+void TC_Start(AT91S_TC *pTc)
+{
+ pTc->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the timer clock, stopping the counting.
+/// \param pTc Pointer to an AT91S_TC instance.
+//------------------------------------------------------------------------------
+void TC_Stop(AT91S_TC *pTc)
+{
+ pTc->TC_CCR = AT91C_TC_CLKDIS;
+}
+
+//------------------------------------------------------------------------------
+/// Finds the best MCK divisor given the timer frequency and MCK. The result
+/// is guaranteed to satisfy the following equation:
+/// \pre
+/// (MCK / (DIV * 65536)) <= freq <= (MCK / DIV)
+/// \endpre
+/// with DIV being the highest possible value.
+/// \param freq Desired timer frequency.
+/// \param mck Master clock frequency.
+/// \param div Divisor value.
+/// \param tcclks TCCLKS field value for divisor.
+/// \return 1 if a proper divisor has been found; otherwise 0.
+//------------------------------------------------------------------------------
+unsigned char TC_FindMckDivisor(
+ unsigned int freq,
+ unsigned int mck,
+ unsigned int *div,
+ unsigned int *tcclks)
+{
+ unsigned int index = 0;
+ unsigned int divisors[5] = {2, 8, 32, 128,
+#if defined(at91sam9260) || defined(at91sam9261) || defined(at91sam9g10) || defined(at91sam9263) \
+ || defined(at91sam9xe) || defined(at91sam9rl64) || defined(at91cap9) \
+ || defined(at91sam9m10) || defined(at91sam9g45) || defined(at91sam9m11) || defined(at91sam3u4)
+ 0};
+ divisors[4] = mck / 32768;
+#else
+ 1024};
+#endif
+
+ // Satisfy lower bound
+ while (freq < ((mck / divisors[index]) / 65536)) {
+
+ index++;
+
+ // If no divisor can be found, return 0
+ if (index == 5) {
+
+ return 0;
+ }
+ }
+
+ // Try to maximise DIV while satisfying upper bound
+ while (index < 4) {
+
+ if (freq > (mck / divisors[index + 1])) {
+
+ break;
+ }
+ index++;
+ }
+
+ // Store results
+ if (div) {
+
+ *div = divisors[index];
+ }
+ if (tcclks) {
+
+ *tcclks = index;
+ }
+
+ return 1;
+}
+
diff --git a/peripherals/tc/tc.dir b/peripherals/tc/tc.dir new file mode 100644 index 0000000..188b5cc --- /dev/null +++ b/peripherals/tc/tc.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the peripheral API for the Timer Counter (TC).
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/tc/tc.h b/peripherals/tc/tc.h new file mode 100644 index 0000000..ea71d54 --- /dev/null +++ b/peripherals/tc/tc.h @@ -0,0 +1,80 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// API for configuring and using Timer Counter (TC) peripherals.
+///
+/// !Usage
+/// -# Optionally, use TC_FindMckDivisor() to let the program find the best
+/// TCCLKS field value automatically.
+/// -# Configure a Timer Counter in the desired mode using TC_Configure().
+/// -# Start or stop the timer clock using TC_Start() and TC_Stop().
+//------------------------------------------------------------------------------
+
+#ifndef TC_H
+#define TC_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+#if defined(AT91C_ID_TC0)
+ // nothing to do
+#elif defined(AT91C_ID_TC012)
+ #define AT91C_ID_TC0 AT91C_ID_TC012
+#elif defined(AT91C_ID_TC)
+ #define AT91C_ID_TC0 AT91C_ID_TC
+#else
+ #error Pb define ID_TC
+#endif
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void TC_Configure(AT91S_TC *pTc, unsigned int mode);
+
+extern void TC_Start(AT91S_TC *pTc);
+
+extern void TC_Stop(AT91S_TC *pTc);
+
+extern unsigned char TC_FindMckDivisor(
+ unsigned int freq,
+ unsigned int mck,
+ unsigned int *div,
+ unsigned int *tcclks);
+
+#endif //#ifndef TC_H
+
diff --git a/peripherals/tdes/tdes.c b/peripherals/tdes/tdes.c new file mode 100644 index 0000000..4d78e1a --- /dev/null +++ b/peripherals/tdes/tdes.c @@ -0,0 +1,228 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "tdes.h"
+#include <board.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configures the triple-DES peripheral to cipher/decipher, use single-DES or
+/// triple-DES, use two or three keys (when in triple-DES mode), start manually,
+/// automatically or via the PDC and use the given operating mode (ECB, CBC,
+/// CFB or OFB).
+/// \param cipher Encrypts if 1, decrypts if 0.
+/// \param tdesmod Single- or triple-DES mode.
+/// \param keymod Use two or three keys (must be 0 in single-DES mode).
+/// \param smod Start mode.
+/// \param opmod Encryption/decryption mode.
+//------------------------------------------------------------------------------
+void TDES_Configure(
+ unsigned char cipher,
+ unsigned int tdesmod,
+ unsigned int keymod,
+ unsigned int smod,
+ unsigned int opmod)
+{
+ TRACE_DEBUG("TDES_Configure()\n\r");
+ SANITY_CHECK((cipher & 0xFFFFFFFE) == 0);
+ SANITY_CHECK((tdesmod & 0xFFFFFFFD) == 0);
+ SANITY_CHECK((keymod & 0xFFFFFFEF) == 0);
+ SANITY_CHECK((smod & 0xFFFFFCFF) == 0);
+ SANITY_CHECK((opmod & 0xFFFFCFFF) == 0);
+
+ // Reset peripheral
+ AT91C_BASE_TDES->TDES_CR = AT91C_TDES_SWRST;
+
+ // Configure mode register
+ AT91C_BASE_TDES->TDES_MR = cipher | tdesmod | keymod | smod | opmod;
+}
+
+//------------------------------------------------------------------------------
+/// Starts the encryption or decryption process if the TDES peripheral is
+/// configured in manual or PDC mode.
+//------------------------------------------------------------------------------
+void TDES_Start(void)
+{
+ TRACE_DEBUG("TDES_Start()\n\r");
+ SANITY_CHECK(((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_SMOD) == AT91C_TDES_SMOD_MANUAL)
+ || ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_SMOD) == AT91C_TDES_SMOD_PDC));
+
+ // Manual mode
+ if ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_SMOD) == AT91C_TDES_SMOD_MANUAL) {
+
+ AT91C_BASE_TDES->TDES_CR = AT91C_TDES_START;
+ }
+ // PDC mode
+ else {
+
+ AT91C_BASE_TDES->TDES_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns the current status register value of the TDES peripheral.
+//------------------------------------------------------------------------------
+unsigned int TDES_GetStatus(void)
+{
+ TRACE_DEBUG("TDES_GetStatus()\n\r");
+
+ return AT91C_BASE_TDES->TDES_ISR;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the 64-bits keys (one, two or three depending on the configuration)
+/// that shall be used by the TDES algorithm.
+/// \param pKey1 Pointer to key #1.
+/// \param pKey2 Pointer to key #2 (shall be 0 in single-DES mode).
+/// \param pKey3 Pointer to key #3 (shall be 0 when using two keys).
+//------------------------------------------------------------------------------
+void TDES_SetKeys(
+ const unsigned int *pKey1,
+ const unsigned int *pKey2,
+ const unsigned int *pKey3)
+{
+ TRACE_DEBUG("TDES_SetKeys()\n\r");
+ SANITY_CHECK(pKey1);
+ SANITY_CHECK((pKey2 && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == AT91C_TDES_TDESMOD))
+ || (!pKey2 && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == 0)));
+ SANITY_CHECK((pKey3
+ && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == AT91C_TDES_TDESMOD)
+ && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_KEYMOD) == 0))
+ ||
+ (!pKey3
+ && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == AT91C_TDES_TDESMOD)
+ && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_KEYMOD) == AT91C_TDES_KEYMOD))
+ ||
+ (!pKey3
+ && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == 0)
+ && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_KEYMOD) == 0)));
+
+ // Write key #1
+ if (pKey1) {
+
+ AT91C_BASE_TDES->TDES_KEY1WxR[0] = pKey1[0];
+ AT91C_BASE_TDES->TDES_KEY1WxR[1] = pKey1[1];
+ }
+
+ // Write key #2
+ if (pKey1) {
+
+ AT91C_BASE_TDES->TDES_KEY2WxR[0] = pKey2[0];
+ AT91C_BASE_TDES->TDES_KEY2WxR[1] = pKey2[1];
+ }
+
+ // Write key #2
+ if (pKey1) {
+
+ AT91C_BASE_TDES->TDES_KEY3WxR[0] = pKey3[0];
+ AT91C_BASE_TDES->TDES_KEY3WxR[1] = pKey3[1];
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the input data to encrypt/decrypt using TDES.
+/// \param pInput Pointer to the 64-bits input data.
+//------------------------------------------------------------------------------
+void TDES_SetInputData(const unsigned int *pInput)
+{
+ TRACE_DEBUG("TDES_SetInputData()\n\r");
+ SANITY_CHECK(pInput);
+
+ AT91C_BASE_TDES->TDES_IDATAxR[0] = pInput[0];
+ AT91C_BASE_TDES->TDES_IDATAxR[1] = pInput[1];
+}
+
+//------------------------------------------------------------------------------
+/// Sets the input data buffer to encrypt/decrypt when in PDC mode.
+/// \param pInput Pointer to the input data.
+/// \param size Size of buffer in bytes.
+//------------------------------------------------------------------------------
+void TDES_SetInputBuffer(const unsigned int *pInput, unsigned int size)
+{
+ TRACE_DEBUG("TDES_SetInputBuffer()\n\r");
+ SANITY_CHECK(pInput);
+ SANITY_CHECK((size > 0) && ((size % 8) == 0));
+
+ AT91C_BASE_TDES->TDES_TPR = (unsigned int) pInput;
+ AT91C_BASE_TDES->TDES_TCR = size / 4;
+}
+
+//------------------------------------------------------------------------------
+/// Stores the output data from the last TDES operation into the given 64-bits
+/// buffers.
+/// \param pOutput Pointer to a 64-bits output buffer.
+//------------------------------------------------------------------------------
+void TDES_GetOutputData(unsigned int *pOutput)
+{
+ TRACE_DEBUG("TDES_GetOutputData()\n\r");
+ SANITY_CHECK(pOutput);
+
+ pOutput[0] = AT91C_BASE_TDES->TDES_ODATAxR[0];
+ pOutput[1] = AT91C_BASE_TDES->TDES_ODATAxR[1];
+}
+
+//------------------------------------------------------------------------------
+/// Sets the output buffer which will receive the encrypted/decrypted data when
+/// using the PDC.
+/// \param pOutput Pointer to the output data.
+/// \param size Size of buffer in bytes.
+//------------------------------------------------------------------------------
+void TDES_SetOutputBuffer(unsigned int *pOutput, unsigned int size)
+{
+ TRACE_DEBUG("TDES_SetOutputBuffer()\n\r");
+ SANITY_CHECK(pOutput);
+ SANITY_CHECK((size > 0) && ((size % 8) == 0));
+
+ AT91C_BASE_TDES->TDES_RPR = (unsigned int) pOutput;
+ AT91C_BASE_TDES->TDES_RCR = size / 4;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the initialization vector to use when the TDES algorithm is configured
+/// in a chained block mode (CBC, CFB or OFB).
+/// \param pVector Pointer to the 64-bits vector.
+//------------------------------------------------------------------------------
+void TDES_SetVector(const unsigned int *pVector)
+{
+ TRACE_DEBUG("TDES_SetVector()\n\r");
+ SANITY_CHECK(pVector);
+
+ AT91C_BASE_TDES->TDES_IVxR[0] = pVector[0];
+ AT91C_BASE_TDES->TDES_IVxR[1] = pVector[1];
+}
+
diff --git a/peripherals/tdes/tdes.h b/peripherals/tdes/tdes.h new file mode 100644 index 0000000..cc0b9f6 --- /dev/null +++ b/peripherals/tdes/tdes.h @@ -0,0 +1,80 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef TDES_H
+#define TDES_H
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Methods to manage the Triple DES (3DES)
+///
+/// !Usage
+///
+/// -# Configure TDES
+/// -# Sets the key used by the TDES algorithm
+/// -# Sets the input data of the TDES algorithm
+/// -# Starts the encryption/decryption process
+/// -# Stores the result of the last TDES operation
+///
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void TDES_Configure(
+ unsigned char cipher,
+ unsigned int tdesmod,
+ unsigned int keymod,
+ unsigned int smod,
+ unsigned int opmod);
+
+extern void TDES_Start(void);
+
+extern unsigned int TDES_GetStatus(void);
+
+extern void TDES_SetKeys(
+ const unsigned int *pKey1,
+ const unsigned int *pKey2,
+ const unsigned int *pKey3);
+
+extern void TDES_SetInputData(const unsigned int *pInput);
+
+extern void TDES_SetInputBuffer(const unsigned int *pInput, unsigned int size);
+
+extern void TDES_GetOutputData(unsigned int *pOutput);
+
+extern void TDES_SetOutputBuffer(unsigned int *pOutput, unsigned int size);
+
+extern void TDES_SetVector(const unsigned int *pVector);
+
+#endif //#ifndef TDES_H
diff --git a/peripherals/tsadcc/tsadcc.c b/peripherals/tsadcc/tsadcc.c new file mode 100644 index 0000000..430ef8a --- /dev/null +++ b/peripherals/tsadcc/tsadcc.c @@ -0,0 +1,324 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+#ifdef AT91C_BASE_TSADC
+
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Local variables
+//------------------------------------------------------------------------------
+
+/// TSADC clock frequency in Hz.
+static unsigned int lAdcclk = 0;
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Sets the operating mode of the TSADCC peripheral. The mode value can be
+/// one of the following:
+/// - AT91C_TSADC_TSAMOD_ADC_ONLY_MODE
+/// - AT91C_TSADC_TSAMOD_TS_ONLY_MODE
+/// \param mode Desired mode for the TSADCC.
+//------------------------------------------------------------------------------
+void TSADCC_SetOperatingMode(unsigned int mode)
+{
+ SANITY_CHECK( (mode == AT91C_TSADC_TSAMOD_ADC_ONLY_MODE)
+ | (mode == AT91C_TSADC_TSAMOD_TS_ONLY_MODE));
+
+ AT91C_BASE_TSADC->TSADC_MR = (AT91C_BASE_TSADC->TSADC_MR
+ & ~AT91C_TSADC_TSAMOD)
+ | mode;
+}
+
+//------------------------------------------------------------------------------
+/// Enables or disables the low resolution precision on the TSADC.
+/// \param enable If true, low resolution (8 bit) is used; otherwise the TSADC
+/// will use a 10-bit resolution.
+//------------------------------------------------------------------------------
+void TSADCC_SetLowResolution(unsigned char enable)
+{
+ if (enable) {
+
+ AT91C_BASE_TSADC->TSADC_MR |= AT91C_TSADC_LOWRES;
+ }
+ else {
+
+ AT91C_BASE_TSADC->TSADC_MR &= ~AT91C_TSADC_LOWRES;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Enables or disable SLEEP mode on the TSADC.
+/// \param enable If true, the TSADC is put into sleep mode; in normal mode
+/// otherwise.
+//------------------------------------------------------------------------------
+void TSADCC_SetSleepMode(unsigned char enable)
+{
+ if (enable) {
+
+ AT91C_BASE_TSADC->TSADC_MR |= AT91C_TSADC_SLEEP;
+ }
+ else {
+
+ AT91C_BASE_TSADC->TSADC_MR &= ~AT91C_TSADC_SLEEP;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Enables or disables pen detection on the TSADC.
+/// \param enable If true, pen detection is enabled; otherwise it is disabled.
+//------------------------------------------------------------------------------
+void TSADCC_SetPenDetect(unsigned char enable)
+{
+ if (enable) {
+
+ AT91C_BASE_TSADC->TSADC_MR |= AT91C_TSADC_PENDET;
+ }
+ else {
+
+ AT91C_BASE_TSADC->TSADC_MR &= ~AT91C_TSADC_PENDET;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the TSADC clock to the desired frequency. The prescaler is calculated
+/// by this function so the resulting frequency is equal or inferior to the
+/// desired one.
+/// \param adcclk Desired ADC clock frequency in Hz.
+/// \param mck Master clock frequency in Hz.
+//------------------------------------------------------------------------------
+void TSADCC_SetAdcFrequency(unsigned int adcclk, unsigned int mck)
+{
+ unsigned int prescal;
+
+ // Formula for PRESCAL is:
+ // PRESCAL = (MCK / (2 * ADCCLK)) + 1
+ // First, we do the division, multiplied by 10 to get higher precision
+ // If the last digit is not zero, we round up to avoid generating a higher
+ // than required frequency.
+ prescal = (mck * 5) / adcclk;
+ if ((prescal % 10) > 0) {
+
+ prescal = (prescal / 10);
+ }
+ else {
+
+ SANITY_CHECK((prescal / 10) != 0);
+ prescal = (prescal / 10) - 1;
+ }
+ SANITY_CHECK(((prescal << 8) & ~AT91C_TSADC_PRESCAL) == 0);
+
+ AT91C_BASE_TSADC->TSADC_MR = ( AT91C_BASE_TSADC->TSADC_MR
+ & ~AT91C_TSADC_PRESCAL)
+ | (prescal << 8);
+
+ // Save clock frequency for further timing calculations
+ lAdcclk = adcclk;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the TSADC startup time. This function relies on the ADCCLK frequency
+/// that has been set using TSADCC_SetAdcFrequency(), so it must have been
+/// called first.
+/// \param time Startup time in µseconds.
+//------------------------------------------------------------------------------
+void TSADCC_SetStartupTime(unsigned int time)
+{
+ unsigned int startup;
+
+ SANITY_CHECK(lAdcclk != 0);
+
+ // Formula for STARTUP is:
+ // STARTUP = (time x ADCCLK) / (1000000 x 8) - 1
+ // Division multiplied by 10 for higher precision
+ startup = (time * lAdcclk) / (800000);
+ if ((startup % 10) > 0) {
+
+ startup /= 10;
+ }
+ else {
+
+ startup /= 10;
+ if (startup > 0) {
+
+ startup--;
+ }
+ }
+
+ SANITY_CHECK((startup & ~0x7F) == 0);
+ AT91C_BASE_TSADC->TSADC_MR = ( AT91C_BASE_TSADC->TSADC_MR
+ & ~AT91C_TSADC_STARTUP)
+ | (startup << 16);
+}
+
+//------------------------------------------------------------------------------
+/// Sets the TSADC track and hold time. This function relies on the ADCCLK
+/// frequency that has been set with TSADCC_SetAdcFrequency(), to it must be
+/// called first.
+/// This function also sets the track and hold time in the TSADC_TSR register.
+/// \param time Track and hold time in nanoseconds.
+//------------------------------------------------------------------------------
+void TSADCC_SetTrackAndHoldTime(unsigned int time)
+{
+ unsigned int shtim;
+
+ SANITY_CHECK(lAdcclk != 0);
+
+ // Formula for SHTIM:
+ // SHTIM = (time x ADCCLK) / 1000000000 - 1
+ // Since 1 billion is close to the maximum value for an integer, we first
+ // divide ADCCLK by 1000 to avoid an overflow
+ shtim = (time * (lAdcclk / 1000)) / 100000;
+ if ((shtim % 10) > 0) {
+
+ shtim /= 10;
+ }
+ else {
+
+ shtim /= 10;
+ if (shtim > 0) shtim--;
+ }
+
+ SANITY_CHECK((shtim & ~0xF) == 0);
+ AT91C_BASE_TSADC->TSADC_MR = ( AT91C_BASE_TSADC->TSADC_MR
+ & ~AT91C_TSADC_SHTIM)
+ | (shtim << 24);
+ AT91C_BASE_TSADC->TSADC_TSR = shtim << 24;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the TSADC debounce time. This function relies on the ADCCLK
+/// frequency that has been set with TSADCC_SetAdcFrequency(), to it must be
+/// called first.
+/// \param time Debounce time in nanoseconds (cannot be 0).
+//------------------------------------------------------------------------------
+void TSADCC_SetDebounceTime(unsigned int time)
+{
+ unsigned int divisor = 1000000000;
+ unsigned int clock = lAdcclk;
+ unsigned int pendbc = 0;
+ unsigned int targetValue;
+ unsigned int currentValue;
+
+ SANITY_CHECK(lAdcclk != 0);
+ SANITY_CHECK(time != 0);
+
+ // Divide time & ADCCLK first to avoid overflows
+ while ((divisor > 1) && ((time % 10) == 0)) {
+
+ time /= 10;
+ divisor /= 10;
+ }
+ while ((divisor > 1) && ((clock % 10) == 0)) {
+
+ clock /= 10;
+ divisor /= 10;
+ }
+
+ // Compute PENDBC value
+ targetValue = time * clock / divisor;
+ currentValue = 1;
+ while (currentValue < targetValue) {
+
+ pendbc++;
+ currentValue *= 2;
+ }
+
+ SANITY_CHECK((pendbc & ~0xF) == 0);
+ AT91C_BASE_TSADC->TSADC_MR = ( AT91C_BASE_TSADC->TSADC_MR
+ & ~AT91C_TSADC_PENDBC)
+ | (pendbc << 28);
+}
+
+//------------------------------------------------------------------------------
+/// Sets the trigger mode of the TSADCC to one of the following values:
+/// - AT91C_TSADC_TRGMOD_NO_TRIGGER
+/// - AT91C_TSADC_TRGMOD_EXTERNAL_TRIGGER_RE
+/// - AT91C_TSADC_TRGMOD_EXTERNAL_TRIGGER_FE
+/// - AT91C_TSADC_TRGMOD_EXTERNAL_TRIGGER_AE
+/// - AT91C_TSADC_TRGMOD_PENDET_TRIGGER
+/// - AT91C_TSADC_TRGMOD_PERIODIC_TRIGGER
+/// - AT91C_TSADC_TRGMOD_CONT_TRIGGER
+/// \param mode Trigger mode.
+//------------------------------------------------------------------------------
+void TSADCC_SetTriggerMode(unsigned int mode)
+{
+ SANITY_CHECK(((mode & ~AT91C_TSADC_TRGMOD) == 0)
+ | ((mode & AT91C_TSADC_TRGMOD) != 0x7));
+
+ AT91C_BASE_TSADC->TSADC_TRGR = (AT91C_BASE_TSADC->TSADC_TRGR
+ & ~AT91C_TSADC_TRGMOD)
+ | mode;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the trigger period when using the TSADCC in periodic trigger mode.
+/// As usual, this function requires TSADCC_SetAdcFrequency() to be called
+/// before it.
+/// \param period Trigger period in nanoseconds.
+//------------------------------------------------------------------------------
+void TSADCC_SetTriggerPeriod(unsigned int period)
+{
+ unsigned int trgper;
+ unsigned int divisor = 100000000;
+
+ while ((period >= 10) && (divisor >= 10)) {
+
+ period /= 10;
+ divisor /= 10;
+ }
+
+ trgper = (period * lAdcclk) / divisor;
+ if ((trgper % 10) > 0) {
+
+ trgper /= 10;
+ }
+ else {
+
+ trgper /= 10;
+ if (trgper > 0) trgper--;
+ }
+
+ SANITY_CHECK((trgper & ~0xFFFF) == 0);
+ AT91C_BASE_TSADC->TSADC_TRGR = (AT91C_BASE_TSADC->TSADC_TRGR
+ & ~AT91C_TSADC_TRGPER)
+ | (trgper << 16);
+}
+
+#endif //#ifdef AT91C_BASE_TSADC
diff --git a/peripherals/tsadcc/tsadcc.dir b/peripherals/tsadcc/tsadcc.dir new file mode 100644 index 0000000..a9a1e52 --- /dev/null +++ b/peripherals/tsadcc/tsadcc.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the peripheral API for the Touch Screen ADC controller (TSADC).
+//------------------------------------------------------------------------------
+
diff --git a/peripherals/tsadcc/tsadcc.h b/peripherals/tsadcc/tsadcc.h new file mode 100644 index 0000000..57dde4d --- /dev/null +++ b/peripherals/tsadcc/tsadcc.h @@ -0,0 +1,60 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef TSADCC_H
+#define TSADCC_H
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+#ifdef AT91C_BASE_TSADC
+
+extern void TSADCC_SetOperatingMode(unsigned int mode);
+
+extern void TSADCC_SetLowResolution(unsigned char enable);
+
+extern void TSADCC_SetSleepMode(unsigned char enable);
+
+extern void TSADCC_SetPenDetect(unsigned char enable);
+
+extern void TSADCC_SetAdcFrequency(unsigned int adcclk, unsigned int mck);
+
+extern void TSADCC_SetStartupTime(unsigned int time);
+
+extern void TSADCC_SetTrackAndHoldTime(unsigned int time);
+
+extern void TSADCC_SetDebounceTime(unsigned int time);
+
+extern void TSADCC_SetTriggerMode(unsigned int mode);
+
+extern void TSADCC_SetTriggerPeriod(unsigned int period);
+
+#endif //#ifdef AT91C_BASE_TSADC
+#endif //#ifndef TSADCC_H
diff --git a/peripherals/twi/twi.c b/peripherals/twi/twi.c new file mode 100644 index 0000000..6437b73 --- /dev/null +++ b/peripherals/twi/twi.c @@ -0,0 +1,372 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the Two Wire Interface (TWI) peripheral.
+///
+/// !Usage
+///
+/// -# Configures a TWI peripheral to operate in master mode, at the given
+/// frequency (in Hz) using TWI_Configure().
+/// -# Sends a STOP condition on the TWI using TWI_Stop().
+/// -# Starts a read operation on the TWI bus with the specified slave using
+/// TWI_StartRead(). Data must then be read using TWI_ReadByte() whenever
+/// a byte is available (poll using TWI_ByteReceived()).
+/// -# Starts a write operation on the TWI to access the selected slave using
+/// TWI_StartWrite(). A byte of data must be provided to start the write;
+/// other bytes are written next.
+/// -# Sends a byte of data to one of the TWI slaves on the bus using TWI_WriteByte().
+/// This function must be called once before TWI_StartWrite() with the first byte of data
+/// to send, then it shall be called repeatedly after that to send the remaining bytes.
+/// -# Check if a byte has been received and can be read on the given TWI
+/// peripheral using TWI_ByteReceived().
+/// Check if a byte has been sent using TWI_ByteSent().
+/// -# Check if the current transmission is complete (the STOP has been sent)
+/// using TWI_TransferComplete().
+/// -# Enables & disable the selected interrupts sources on a TWI peripheral
+/// using TWI_EnableIt() and TWI_DisableIt().
+/// -# Get current status register of the given TWI peripheral using
+/// TWI_GetStatus(). Get current status register of the given TWI peripheral, but
+/// masking interrupt sources which are not currently enabled using
+/// TWI_GetMaskedStatus().
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "twi.h"
+#include <utility/math.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configures a TWI peripheral to operate in master mode, at the given
+/// frequency (in Hz). The duty cycle of the TWI clock is set to 50%.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+/// \param twck Desired TWI clock frequency.
+/// \param mck Master clock frequency.
+//------------------------------------------------------------------------------
+void TWI_ConfigureMaster(AT91S_TWI *pTwi, unsigned int twck, unsigned int mck)
+{
+ unsigned int ckdiv = 0;
+ unsigned int cldiv;
+ unsigned char ok = 0;
+
+ TRACE_DEBUG("TWI_ConfigureMaster()\n\r");
+ SANITY_CHECK(pTwi);
+
+#ifdef AT91C_TWI_SVEN // TWI slave
+ // SVEN: TWI Slave Mode Enabled
+ pTwi->TWI_CR = AT91C_TWI_SVEN;
+#endif
+ // Reset the TWI
+ pTwi->TWI_CR = AT91C_TWI_SWRST;
+ pTwi->TWI_RHR;
+
+ // TWI Slave Mode Disabled, TWI Master Mode Disabled
+#ifdef AT91C_TWI_SVEN // TWI slave
+ pTwi->TWI_CR = AT91C_TWI_SVDIS;
+#endif
+ pTwi->TWI_CR = AT91C_TWI_MSDIS;
+
+ // Set master mode
+ pTwi->TWI_CR = AT91C_TWI_MSEN;
+
+ // Configure clock
+ while (!ok) {
+ cldiv = ((mck / (2 * twck)) - 3) / power(2, ckdiv);
+ if (cldiv <= 255) {
+
+ ok = 1;
+ }
+ else {
+
+ ckdiv++;
+ }
+ }
+
+ ASSERT(ckdiv < 8, "-F- Cannot find valid TWI clock parameters\n\r");
+ TRACE_DEBUG("Using CKDIV = %u and CLDIV/CHDIV = %u\n\r", ckdiv, cldiv);
+ pTwi->TWI_CWGR = 0;
+ pTwi->TWI_CWGR = (ckdiv << 16) | (cldiv << 8) | cldiv;
+}
+
+
+
+#ifdef AT91C_TWI_SVEN // TWI slave
+//------------------------------------------------------------------------------
+/// Configures a TWI peripheral to operate in slave mode
+/// \param pTwi Pointer to an AT91S_TWI instance.
+//------------------------------------------------------------------------------
+void TWI_ConfigureSlave(AT91S_TWI *pTwi, unsigned char slaveAddress)
+{
+ unsigned int i;
+
+ // TWI software reset
+ pTwi->TWI_CR = AT91C_TWI_SWRST;
+ pTwi->TWI_RHR;
+
+ // Wait at least 10 ms
+ for (i=0; i < 1000000; i++);
+
+ // TWI Slave Mode Disabled, TWI Master Mode Disabled
+ pTwi->TWI_CR = AT91C_TWI_SVDIS | AT91C_TWI_MSDIS;
+
+ // Slave Address
+ pTwi->TWI_SMR = 0;
+ pTwi->TWI_SMR = (slaveAddress << 16) & AT91C_TWI_SADR;
+
+ // SVEN: TWI Slave Mode Enabled
+ pTwi->TWI_CR = AT91C_TWI_SVEN;
+
+ // Wait at least 10 ms
+ for (i=0; i < 1000000; i++);
+ ASSERT( (pTwi->TWI_CR & AT91C_TWI_SVDIS)!=AT91C_TWI_SVDIS, "Problem slave mode");
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Sends a STOP condition on the TWI.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+//------------------------------------------------------------------------------
+void TWI_Stop(AT91S_TWI *pTwi)
+{
+ SANITY_CHECK(pTwi);
+
+ pTwi->TWI_CR = AT91C_TWI_STOP;
+}
+
+//------------------------------------------------------------------------------
+/// Starts a read operation on the TWI bus with the specified slave, and returns
+/// immediately. Data must then be read using TWI_ReadByte() whenever a byte is
+/// available (poll using TWI_ByteReceived()).
+/// \param pTwi Pointer to an AT91S_TWI instance.
+/// \param address Slave address on the bus.
+/// \param iaddress Optional internal address bytes.
+/// \param isize Number of internal address bytes.
+//-----------------------------------------------------------------------------
+void TWI_StartRead(
+ AT91S_TWI *pTwi,
+ unsigned char address,
+ unsigned int iaddress,
+ unsigned char isize)
+{
+ //TRACE_DEBUG("TWI_StartRead()\n\r");
+ SANITY_CHECK(pTwi);
+ SANITY_CHECK((address & 0x80) == 0);
+ SANITY_CHECK((iaddress & 0xFF000000) == 0);
+ SANITY_CHECK(isize < 4);
+
+ // Set slave address and number of internal address bytes
+ pTwi->TWI_MMR = 0;
+ pTwi->TWI_MMR = (isize << 8) | AT91C_TWI_MREAD | (address << 16);
+
+ // Set internal address bytes
+ pTwi->TWI_IADR = 0;
+ pTwi->TWI_IADR = iaddress;
+
+ // Send START condition
+ pTwi->TWI_CR = AT91C_TWI_START;
+}
+
+//-----------------------------------------------------------------------------
+/// Reads a byte from the TWI bus. The read operation must have been started
+/// using TWI_StartRead() and a byte must be available (check with
+/// TWI_ByteReceived()).
+/// Returns the byte read.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+//-----------------------------------------------------------------------------
+unsigned char TWI_ReadByte(AT91S_TWI *pTwi)
+{
+ SANITY_CHECK(pTwi);
+
+ return pTwi->TWI_RHR;
+}
+
+//-----------------------------------------------------------------------------
+/// Sends a byte of data to one of the TWI slaves on the bus. This function
+/// must be called once before TWI_StartWrite() with the first byte of data
+/// to send, then it shall be called repeatedly after that to send the
+/// remaining bytes.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+/// \param byte Byte to send.
+//-----------------------------------------------------------------------------
+void TWI_WriteByte(AT91S_TWI *pTwi, unsigned char byte)
+{
+ SANITY_CHECK(pTwi);
+
+ pTwi->TWI_THR = byte;
+}
+
+//-----------------------------------------------------------------------------
+/// Starts a write operation on the TWI to access the selected slave, then
+/// returns immediately. A byte of data must be provided to start the write;
+/// other bytes are written next.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+/// \param address Address of slave to acccess on the bus.
+/// \param iaddress Optional slave internal address.
+/// \param isize Number of internal address bytes.
+/// \param byte First byte to send.
+//-----------------------------------------------------------------------------
+void TWI_StartWrite(
+ AT91S_TWI *pTwi,
+ unsigned char address,
+ unsigned int iaddress,
+ unsigned char isize,
+ unsigned char byte)
+{
+ //TRACE_DEBUG("TWI_StartWrite()\n\r");
+ SANITY_CHECK(pTwi);
+ SANITY_CHECK((address & 0x80) == 0);
+ SANITY_CHECK((iaddress & 0xFF000000) == 0);
+ SANITY_CHECK(isize < 4);
+
+ // Set slave address and number of internal address bytes
+ pTwi->TWI_MMR = 0;
+ pTwi->TWI_MMR = (isize << 8) | (address << 16);
+
+ // Set internal address bytes
+ pTwi->TWI_IADR = 0;
+ pTwi->TWI_IADR = iaddress;
+
+ // Write first byte to send
+ TWI_WriteByte(pTwi, byte);
+}
+
+//-----------------------------------------------------------------------------
+/// Returns 1 if a byte has been received and can be read on the given TWI
+/// peripheral; otherwise, returns 0. This function resets the status register
+/// of the TWI.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+//-----------------------------------------------------------------------------
+unsigned char TWI_ByteReceived(AT91S_TWI *pTwi)
+{
+ return ((pTwi->TWI_SR & AT91C_TWI_RXRDY) == AT91C_TWI_RXRDY);
+}
+
+//-----------------------------------------------------------------------------
+/// Returns 1 if a byte has been sent, so another one can be stored for
+/// transmission; otherwise returns 0. This function clears the status register
+/// of the TWI.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+//-----------------------------------------------------------------------------
+unsigned char TWI_ByteSent(AT91S_TWI *pTwi)
+{
+ return ((pTwi->TWI_SR & AT91C_TWI_TXRDY) == AT91C_TWI_TXRDY);
+}
+
+//-----------------------------------------------------------------------------
+/// Returns 1 if the current transmission is complete (the STOP has been sent);
+/// otherwise returns 0.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+//-----------------------------------------------------------------------------
+unsigned char TWI_TransferComplete(AT91S_TWI *pTwi)
+{
+ return ((pTwi->TWI_SR & AT91C_TWI_TXCOMP) == AT91C_TWI_TXCOMP);
+}
+
+//-----------------------------------------------------------------------------
+/// Enables the selected interrupts sources on a TWI peripheral.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+/// \param sources Bitwise OR of selected interrupt sources.
+//-----------------------------------------------------------------------------
+void TWI_EnableIt(AT91S_TWI *pTwi, unsigned int sources)
+{
+ SANITY_CHECK(pTwi);
+ SANITY_CHECK((sources & 0xFFFFF088) == 0);
+
+ pTwi->TWI_IER = sources;
+}
+
+//-----------------------------------------------------------------------------
+/// Disables the selected interrupts sources on a TWI peripheral.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+/// \param sources Bitwise OR of selected interrupt sources.
+//-----------------------------------------------------------------------------
+void TWI_DisableIt(AT91S_TWI *pTwi, unsigned int sources)
+{
+ SANITY_CHECK(pTwi);
+ SANITY_CHECK((sources & 0xFFFFF088) == 0);
+
+ pTwi->TWI_IDR = sources;
+}
+
+//-----------------------------------------------------------------------------
+/// Returns the current status register of the given TWI peripheral. This
+/// resets the internal value of the status register, so further read may yield
+/// different values.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+//-----------------------------------------------------------------------------
+unsigned int TWI_GetStatus(AT91S_TWI *pTwi)
+{
+ SANITY_CHECK(pTwi);
+
+ return pTwi->TWI_SR;
+}
+
+//-----------------------------------------------------------------------------
+/// Returns the current status register of the given TWI peripheral, but
+/// masking interrupt sources which are not currently enabled.
+/// This resets the internal value of the status register, so further read may
+/// yield different values.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+//-----------------------------------------------------------------------------
+unsigned int TWI_GetMaskedStatus(AT91S_TWI *pTwi)
+{
+ unsigned int status;
+
+ SANITY_CHECK(pTwi);
+
+ status = pTwi->TWI_SR;
+ status &= pTwi->TWI_IMR;
+
+ return status;
+}
+//-----------------------------------------------------------------------------
+/// Sends a STOP condition. STOP Condition is sent just after completing
+/// the current byte transmission in master read mode.
+/// \param pTwi Pointer to an AT91S_TWI instance.
+//-----------------------------------------------------------------------------
+void TWI_SendSTOPCondition(AT91S_TWI *pTwi)
+{
+ SANITY_CHECK(pTwi);
+
+ pTwi->TWI_CR |= AT91C_TWI_STOP;
+}
+
diff --git a/peripherals/twi/twi.dir b/peripherals/twi/twi.dir new file mode 100644 index 0000000..99c1b6e --- /dev/null +++ b/peripherals/twi/twi.dir @@ -0,0 +1,35 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !!!Purpose
+///
+/// Contains the peripheral API for Two Wire Interface (TWI) controller.
+//------------------------------------------------------------------------------
diff --git a/peripherals/twi/twi.h b/peripherals/twi/twi.h new file mode 100644 index 0000000..721b7c5 --- /dev/null +++ b/peripherals/twi/twi.h @@ -0,0 +1,150 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the Two Wire Interface (TWI) peripheral.
+///
+/// !Usage
+///
+/// -# Configures a TWI peripheral to operate in master mode, at the given
+/// frequency (in Hz) using TWI_ConfigureMaster().
+/// -# or if hardware possible, configures a TWI peripheral to operate in
+/// slave mode, at the given frequency (in Hz) using TWI_ConfigureSlave().
+/// -# Sends a STOP condition on the TWI using TWI_Stop().
+/// -# Starts a read operation on the TWI bus with the specified slave using
+/// TWI_StartRead(). Data must then be read using TWI_ReadByte() whenever
+/// a byte is available (poll using TWI_ByteReceived()).
+/// -# Starts a write operation on the TWI to access the selected slave using
+/// TWI_StartWrite(). A byte of data must be provided to start the write;
+/// other bytes are written next.
+/// -# Sends a byte of data to one of the TWI slaves on the bus using TWI_WriteByte().
+/// This function must be called once before TWI_StartWrite() with the first byte of data
+/// to send, then it shall be called repeatedly after that to send the remaining bytes.
+/// -# Check if a byte has been received and can be read on the given TWI
+/// peripheral using TWI_ByteReceived().
+/// Check if a byte has been sent using TWI_ByteSent().
+/// -# Check if the current transmission is complete (the STOP has been sent)
+/// using TWI_TransferComplete().
+/// -# Enables & disable the selected interrupts sources on a TWI peripheral
+/// using TWI_EnableIt() and TWI_DisableIt().
+/// -# Get current status register of the given TWI peripheral using
+/// TWI_GetStatus(). Get current status register of the given TWI peripheral, but
+/// masking interrupt sources which are not currently enabled using
+/// TWI_GetMaskedStatus().
+//------------------------------------------------------------------------------
+
+#ifndef TWI_H
+#define TWI_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Global definitions
+//------------------------------------------------------------------------------
+
+// Missing AT91C_TWI_TXRDY definition.
+#ifndef AT91C_TWI_TXRDY
+ #define AT91C_TWI_TXRDY AT91C_TWI_TXRDY_MASTER
+#endif
+
+// Missing AT91C_TWI_TXCOMP definition.
+#ifndef AT91C_TWI_TXCOMP
+ #define AT91C_TWI_TXCOMP AT91C_TWI_TXCOMP_MASTER
+#endif
+
+//------------------------------------------------------------------------------
+// Global macros
+//------------------------------------------------------------------------------
+
+/// Returns 1 if the TXRDY bit (ready to transmit data) is set in the given
+/// status register value.
+#define TWI_STATUS_TXRDY(status) ((status & AT91C_TWI_TXRDY) == AT91C_TWI_TXRDY)
+
+/// Returns 1 if the RXRDY bit (ready to receive data) is set in the given
+/// status register value.
+#define TWI_STATUS_RXRDY(status) ((status & AT91C_TWI_RXRDY) == AT91C_TWI_RXRDY)
+
+/// Returns 1 if the TXCOMP bit (transfer complete) is set in the given
+/// status register value.
+#define TWI_STATUS_TXCOMP(status) ((status & AT91C_TWI_TXCOMP) == AT91C_TWI_TXCOMP)
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void TWI_ConfigureMaster(AT91S_TWI *pTwi, unsigned int twck, unsigned int mck);
+
+#ifdef AT91C_TWI_SVEN // TWI slave
+extern void TWI_ConfigureSlave(AT91S_TWI *pTwi, unsigned char slaveAddress);
+#endif
+
+extern void TWI_Stop(AT91S_TWI *pTwi);
+
+extern void TWI_StartRead(
+ AT91S_TWI *pTwi,
+ unsigned char address,
+ unsigned int iaddress,
+ unsigned char isize);
+
+extern unsigned char TWI_ReadByte(AT91S_TWI *pTwi);
+
+extern void TWI_WriteByte(AT91S_TWI *pTwi, unsigned char byte);
+
+extern void TWI_StartWrite(
+ AT91S_TWI *pTwi,
+ unsigned char address,
+ unsigned int iaddress,
+ unsigned char isize,
+ unsigned char byte);
+
+extern unsigned char TWI_ByteReceived(AT91S_TWI *pTwi);
+
+extern unsigned char TWI_ByteSent(AT91S_TWI *pTwi);
+
+extern unsigned char TWI_TransferComplete(AT91S_TWI *pTwi);
+
+extern void TWI_EnableIt(AT91S_TWI *pTwi, unsigned int sources);
+
+extern void TWI_DisableIt(AT91S_TWI *pTwi, unsigned int sources);
+
+extern unsigned int TWI_GetStatus(AT91S_TWI *pTwi);
+
+extern unsigned int TWI_GetMaskedStatus(AT91S_TWI *pTwi);
+
+extern void TWI_SendSTOPCondition(AT91S_TWI *pTwi);
+
+#endif //#ifndef TWI_H
diff --git a/peripherals/usart/usart.c b/peripherals/usart/usart.c new file mode 100644 index 0000000..bbd6df5 --- /dev/null +++ b/peripherals/usart/usart.c @@ -0,0 +1,313 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "usart.h"
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// 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(AT91S_USART *usart,
+ unsigned int mode,
+ unsigned int baudrate,
+ unsigned int masterClock)
+{
+ // Reset and disable receiver & transmitter
+ usart->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX
+ | AT91C_US_RXDIS | AT91C_US_TXDIS;
+
+ // Configure mode
+ usart->US_MR = mode;
+
+ // Configure baudrate
+ // Asynchronous, no oversampling
+ if (((mode & AT91C_US_SYNC) == 0)
+ && ((mode & AT91C_US_OVER) == 0)) {
+
+ usart->US_BRGR = (masterClock / baudrate) / 16;
+ }
+ // TODO other modes
+}
+
+//------------------------------------------------------------------------------
+/// 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(AT91S_USART *usart,
+ unsigned char enabled)
+{
+ if (enabled) {
+
+ usart->US_CR = AT91C_US_TXEN;
+ }
+ else {
+
+ usart->US_CR = AT91C_US_TXDIS;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// 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(AT91S_USART *usart,
+ unsigned char enabled)
+{
+ if (enabled) {
+
+ usart->US_CR = AT91C_US_RXEN;
+ }
+ else {
+
+ usart->US_CR = AT91C_US_RXDIS;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// 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(
+ AT91S_USART *usart,
+ unsigned short data,
+ volatile unsigned int timeOut)
+{
+ if (timeOut == 0) {
+
+ while ((usart->US_CSR & AT91C_US_TXEMPTY) == 0);
+ }
+ else {
+
+ while ((usart->US_CSR & AT91C_US_TXEMPTY) == 0) {
+
+ if (timeOut == 0) {
+
+ TRACE_ERROR("USART_Write: Timed out.\n\r");
+ return;
+ }
+ timeOut--;
+ }
+ }
+
+ usart->US_THR = data;
+}
+
+//------------------------------------------------------------------------------
+/// 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).
+//------------------------------------------------------------------------------
+unsigned char USART_WriteBuffer(
+ AT91S_USART *usart,
+ void *buffer,
+ unsigned int size)
+{
+ // Check if the first PDC bank is free
+ if ((usart->US_TCR == 0) && (usart->US_TNCR == 0)) {
+
+ usart->US_TPR = (unsigned int) buffer;
+ usart->US_TCR = size;
+ usart->US_PTCR = AT91C_PDC_TXTEN;
+
+ return 1;
+ }
+ // Check if the second PDC bank is free
+ else if (usart->US_TNCR == 0) {
+
+ usart->US_TNPR = (unsigned int) buffer;
+ usart->US_TNCR = size;
+
+ return 1;
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// 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).
+//------------------------------------------------------------------------------
+unsigned short USART_Read(
+ AT91S_USART *usart,
+ volatile unsigned int timeOut)
+{
+ if (timeOut == 0) {
+
+ while ((usart->US_CSR & AT91C_US_RXRDY) == 0);
+ }
+ else {
+
+ while ((usart->US_CSR & AT91C_US_RXRDY) == 0) {
+
+ if (timeOut == 0) {
+
+ TRACE_ERROR("USART_Read: Timed out.\n\r");
+ return 0;
+ }
+ timeOut--;
+ }
+ }
+
+ return usart->US_RHR;
+}
+
+//------------------------------------------------------------------------------
+/// 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).
+//------------------------------------------------------------------------------
+unsigned char USART_ReadBuffer(AT91S_USART *usart,
+ void *buffer,
+ unsigned int size)
+{
+ // Check if the first PDC bank is free
+ if ((usart->US_RCR == 0) && (usart->US_RNCR == 0)) {
+
+ usart->US_RPR = (unsigned int) buffer;
+ usart->US_RCR = size;
+ usart->US_PTCR = AT91C_PDC_RXTEN;
+
+ return 1;
+ }
+ // Check if the second PDC bank is free
+ else if (usart->US_RNCR == 0) {
+
+ usart->US_RNPR = (unsigned int) buffer;
+ usart->US_RNCR = size;
+
+ return 1;
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if some data has been received and can be read from an USART;
+/// otherwise returns 0.
+/// \param usart Pointer to an AT91S_USART instance.
+//------------------------------------------------------------------------------
+unsigned char USART_IsDataAvailable(AT91S_USART *usart)
+{
+ if ((usart->US_CSR & AT91C_US_RXRDY) != 0) {
+
+ return 1;
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the filter value for the IRDA demodulator.
+/// \param pUsart Pointer to an AT91S_USART instance.
+/// \param filter Filter value.
+//------------------------------------------------------------------------------
+void USART_SetIrdaFilter(AT91S_USART *pUsart, unsigned char filter)
+{
+ SANITY_CHECK(pUsart);
+
+ pUsart->US_IF = filter;
+}
+
+//------------------------------------------------------------------------------
+/// 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_PutChar(
+ AT91S_USART *usart,
+ unsigned char c)
+{
+ // Wait for the transmitter to be ready
+ while ((usart->US_CSR & AT91C_US_TXEMPTY) == 0);
+
+ // Send character
+ usart->US_THR = c;
+
+ // Wait for the transfer to complete
+ while ((usart->US_CSR & AT91C_US_TXEMPTY) == 0);
+}
+
+//------------------------------------------------------------------------------
+/// Return 1 if a character can be read in USART
+//------------------------------------------------------------------------------
+unsigned int USART_IsRxReady(AT91S_USART *usart)
+{
+ return (usart->US_CSR & AT91C_US_RXRDY);
+}
+
+//------------------------------------------------------------------------------
+/// Reads and returns a character from the USART.
+/// \note This function is synchronous (i.e. uses polling).
+/// \return Character received.
+//------------------------------------------------------------------------------
+unsigned char USART_GetChar(AT91S_USART *usart)
+{
+ while ((usart->US_CSR & AT91C_US_RXRDY) == 0);
+ return usart->US_RHR;
+}
\ No newline at end of file diff --git a/peripherals/usart/usart.h b/peripherals/usart/usart.h new file mode 100644 index 0000000..719b012 --- /dev/null +++ b/peripherals/usart/usart.h @@ -0,0 +1,125 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !Purpose
+///
+/// This module provides several definitions and methods for using an USART
+/// peripheral.
+///
+/// !Usage
+/// -# Enable the USART peripheral clock in the PMC.
+/// -# Enable the required USART PIOs (see pio.h).
+/// -# Configure the UART by calling USART_Configure.
+/// -# Enable the transmitter and/or the receiver of the USART using
+/// USART_SetTransmitterEnabled and USART_SetReceiverEnabled.
+/// -# Send data through the USART using the USART_Write and
+/// USART_WriteBuffer methods.
+/// -# Receive data from the USART using the USART_Read and
+/// USART_ReadBuffer functions; the availability of data can be polled
+/// with USART_IsDataAvailable.
+/// -# Disable the transmitter and/or the receiver of the USART with
+/// USART_SetTransmitterEnabled and USART_SetReceiverEnabled.
+//------------------------------------------------------------------------------
+
+#ifndef USART_H
+#define USART_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "USART modes"
+/// This page lists several common operating modes for an USART peripheral.
+///
+/// !Modes
+/// - USART_MODE_ASYNCHRONOUS
+/// - USART_MODE_IRDA
+
+/// Basic asynchronous mode, i.e. 8 bits no parity.
+#define USART_MODE_ASYNCHRONOUS (AT91C_US_CHRL_8_BITS | AT91C_US_PAR_NONE)
+
+/// IRDA mode
+#define USART_MODE_IRDA (AT91C_US_USMODE_IRDA | AT91C_US_CHRL_8_BITS | AT91C_US_PAR_NONE | AT91C_US_FILTER)
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void USART_Configure(
+ AT91S_USART *usart,
+ unsigned int mode,
+ unsigned int baudrate,
+ unsigned int masterClock);
+
+extern void USART_SetTransmitterEnabled(AT91S_USART *usart, unsigned char enabled);
+
+extern void USART_SetReceiverEnabled(AT91S_USART *usart, unsigned char enabled);
+
+extern void USART_Write(
+ AT91S_USART *usart,
+ unsigned short data,
+ volatile unsigned int timeOut);
+
+extern unsigned char USART_WriteBuffer(
+ AT91S_USART *usart,
+ void *buffer,
+ unsigned int size);
+
+extern unsigned short USART_Read(
+ AT91S_USART *usart,
+ volatile unsigned int timeOut);
+
+extern unsigned char USART_ReadBuffer(
+ AT91S_USART *usart,
+ void *buffer,
+ unsigned int size);
+
+extern unsigned char USART_IsDataAvailable(AT91S_USART *usart);
+
+extern void USART_SetIrdaFilter(AT91S_USART *pUsart, unsigned char filter);
+
+extern void USART_PutChar(AT91S_USART *usart, unsigned char c);
+
+extern unsigned int USART_IsRxReady(AT91S_USART *usart);
+
+extern unsigned char USART_GetChar(AT91S_USART *usart);
+
+
+#endif //#ifndef USART_H
+
diff --git a/peripherals/wdt/wdt.c b/peripherals/wdt/wdt.c new file mode 100644 index 0000000..1b60de0 --- /dev/null +++ b/peripherals/wdt/wdt.c @@ -0,0 +1,74 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "wdt.h"
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Set Mode
+//------------------------------------------------------------------------------
+void WDT_SetMode(AT91PS_WDTC pWDTC, unsigned int Mode)
+{
+ pWDTC->WDTC_WDMR = Mode;
+}
+
+//------------------------------------------------------------------------------
+/// Restart
+//------------------------------------------------------------------------------
+void WDT_Restart(AT91PS_WDTC pWDTC)
+{
+ pWDTC->WDTC_WDCR = 0xA5000001;
+}
+
+//------------------------------------------------------------------------------
+/// Get status
+//------------------------------------------------------------------------------
+unsigned int WDT_GetStatus(AT91PS_WDTC pWDTC)
+{
+ return(pWDTC->WDTC_WDSR & 0x3);
+}
+
+//------------------------------------------------------------------------------
+/// Get period
+//------------------------------------------------------------------------------
+unsigned int WDT_GetPeriod(unsigned int ms)
+{
+ if ((ms < 4) || (ms > 16000)) {
+ return 0;
+ }
+ return((ms << 8) / 1000);
+}
diff --git a/peripherals/wdt/wdt.dir b/peripherals/wdt/wdt.dir new file mode 100644 index 0000000..2f52a43 --- /dev/null +++ b/peripherals/wdt/wdt.dir @@ -0,0 +1,36 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the peripheral API for the Watchdog (WDT).
+//------------------------------------------------------------------------------
diff --git a/peripherals/wdt/wdt.h b/peripherals/wdt/wdt.h new file mode 100644 index 0000000..7c44adf --- /dev/null +++ b/peripherals/wdt/wdt.h @@ -0,0 +1,60 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// Interface for configuration the watchdod (WDT) peripheral.
+///
+//------------------------------------------------------------------------------
+
+#ifndef WDT_H
+#define WDT_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Global Functions
+//------------------------------------------------------------------------------
+
+extern void WDT_SetMode(AT91PS_WDTC pWDTC, unsigned int Mode);
+
+extern void WDT_Restart(AT91PS_WDTC pWDTC);
+
+extern unsigned int WDT_GetStatus(AT91PS_WDTC pWDTC);
+
+extern unsigned int WDT_GetPeriod(unsigned int ms);
+
+#endif //#ifndef WDT_H
|