From 044ad7c3987460ede48ff27afd6bdb0ca05a0432 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 4 Jul 2011 20:52:54 +0200 Subject: import at91lib from at91lib_20100901_softpack_1_9_v_1_0_svn_v15011 it's sad to see that atmel doesn't publish their svn repo or has a centralized location or even puts proper version/release info into the library itself --- peripherals/ac97c/ac97c.c | 692 ++++++++++++++++++++ peripherals/ac97c/ac97c.dir | 37 ++ peripherals/ac97c/ac97c.h | 168 +++++ peripherals/adc/adc.c | 346 ++++++++++ peripherals/adc/adc.dir | 37 ++ peripherals/adc/adc.h | 145 +++++ peripherals/adc/adc12.c | 196 ++++++ peripherals/adc/adc12.h | 142 +++++ peripherals/aes/aes_p.c | 231 +++++++ peripherals/aes/aes_p.h | 76 +++ peripherals/can/can.c | 1066 +++++++++++++++++++++++++++++++ peripherals/can/can.h | 113 ++++ peripherals/chipid/chipid.c | 301 +++++++++ peripherals/chipid/chipid.dir | 36 ++ peripherals/chipid/chipid.h | 109 ++++ peripherals/cp15/core.h | 88 +++ peripherals/cp15/cp15.c | 319 ++++++++++ peripherals/cp15/cp15.dir | 37 ++ peripherals/cp15/cp15.h | 195 ++++++ peripherals/cp15/cp15_asm_gcc.S | 607 ++++++++++++++++++ peripherals/cp15/cp15_asm_iar.s | 659 ++++++++++++++++++++ peripherals/cp15/cp15_asm_keil.s | 536 ++++++++++++++++ peripherals/dbgu/dbgu.c | 114 ++++ peripherals/dbgu/dbgu.dir | 37 ++ peripherals/dbgu/dbgu.h | 79 +++ peripherals/dma/dma.c | 393 ++++++++++++ peripherals/dma/dma.dir | 37 ++ peripherals/dma/dma.h | 190 ++++++ peripherals/eefc/eefc.c | 296 +++++++++ peripherals/eefc/eefc.dir | 37 ++ peripherals/eefc/eefc.h | 147 +++++ peripherals/efc/efc.c | 396 ++++++++++++ peripherals/efc/efc.dir | 37 ++ peripherals/efc/efc.h | 131 ++++ peripherals/emac/emac.c | 914 +++++++++++++++++++++++++++ peripherals/emac/emac.dir | 49 ++ peripherals/emac/emac.h | 178 ++++++ peripherals/hsmc4/hsmc.dir | 37 ++ peripherals/hsmc4/hsmc4.c | 247 ++++++++ peripherals/hsmc4/hsmc4.h | 73 +++ peripherals/hsmc4/hsmc4_ecc.c | 703 +++++++++++++++++++++ peripherals/hsmc4/hsmc4_ecc.h | 85 +++ peripherals/irq/aic.c | 91 +++ peripherals/irq/irq.dir | 38 ++ peripherals/irq/irq.h | 84 +++ peripherals/irq/nvic.c | 144 +++++ peripherals/irq/nvic.h | 55 ++ peripherals/isi/isi.c | 261 ++++++++ peripherals/isi/isi.dir | 42 ++ peripherals/isi/isi.h | 99 +++ peripherals/isi/isi2.c | 246 ++++++++ peripherals/lcd/lcd.c | 473 ++++++++++++++ peripherals/lcd/lcd.dir | 35 ++ peripherals/lcd/lcd.h | 124 ++++ peripherals/mci/mci.c | 712 +++++++++++++++++++++ peripherals/mci/mci.dir | 37 ++ peripherals/mci/mci.h | 227 +++++++ peripherals/mci/mci_hs.c | 1283 ++++++++++++++++++++++++++++++++++++++ peripherals/mci/mci_hs.h | 236 +++++++ peripherals/peripherals.dir | 47 ++ peripherals/pio/pio.c | 382 ++++++++++++ peripherals/pio/pio.dir | 50 ++ peripherals/pio/pio.h | 225 +++++++ peripherals/pio/pio_it.c | 461 ++++++++++++++ peripherals/pio/pio_it.h | 85 +++ peripherals/pio/pio_keypad.c | 147 +++++ peripherals/pio/pio_keypad.h | 153 +++++ peripherals/pit/pit.c | 122 ++++ peripherals/pit/pit.dir | 37 ++ peripherals/pit/pit.h | 77 +++ peripherals/pmc/pmc.c | 188 ++++++ peripherals/pmc/pmc.h | 62 ++ peripherals/pwmc/pwmc.c | 245 ++++++++ peripherals/pwmc/pwmc.dir | 35 ++ peripherals/pwmc/pwmc.h | 83 +++ peripherals/pwmc/pwmc2.c | 589 +++++++++++++++++ peripherals/pwmc/pwmc2.h | 143 +++++ peripherals/rstc/rstc.c | 176 ++++++ peripherals/rstc/rstc.h | 58 ++ peripherals/rtc/rtc.c | 405 ++++++++++++ peripherals/rtc/rtc.h | 90 +++ peripherals/rtt/rtt.c | 93 +++ peripherals/rtt/rtt.dir | 39 ++ peripherals/rtt/rtt.h | 76 +++ peripherals/shdwc/shdwc.c | 67 ++ peripherals/shdwc/shdwc.h | 43 ++ peripherals/slcdc/slcdc.c | 192 ++++++ peripherals/slcdc/slcdc.dir | 35 ++ peripherals/slcdc/slcdc.h | 93 +++ peripherals/slck/slck.c | 524 ++++++++++++++++ peripherals/slck/slck.dir | 35 ++ peripherals/slck/slck.h | 49 ++ peripherals/spi/spi.c | 194 ++++++ peripherals/spi/spi.h | 114 ++++ peripherals/ssc/ssc.c | 413 ++++++++++++ peripherals/ssc/ssc.h | 156 +++++ peripherals/supc/supc.c | 223 +++++++ peripherals/supc/supc.h | 80 +++ peripherals/systick/systick.c | 63 ++ peripherals/systick/systick.dir | 36 ++ peripherals/systick/systick.h | 68 ++ peripherals/tc/tc.c | 144 +++++ peripherals/tc/tc.dir | 37 ++ peripherals/tc/tc.h | 80 +++ peripherals/tdes/tdes.c | 228 +++++++ peripherals/tdes/tdes.h | 80 +++ peripherals/tsadcc/tsadcc.c | 324 ++++++++++ peripherals/tsadcc/tsadcc.dir | 37 ++ peripherals/tsadcc/tsadcc.h | 60 ++ peripherals/twi/twi.c | 372 +++++++++++ peripherals/twi/twi.dir | 35 ++ peripherals/twi/twi.h | 150 +++++ peripherals/usart/usart.c | 313 ++++++++++ peripherals/usart/usart.h | 125 ++++ peripherals/wdt/wdt.c | 74 +++ peripherals/wdt/wdt.dir | 36 ++ peripherals/wdt/wdt.h | 60 ++ 117 files changed, 23111 insertions(+) create mode 100644 peripherals/ac97c/ac97c.c create mode 100644 peripherals/ac97c/ac97c.dir create mode 100644 peripherals/ac97c/ac97c.h create mode 100644 peripherals/adc/adc.c create mode 100644 peripherals/adc/adc.dir create mode 100644 peripherals/adc/adc.h create mode 100644 peripherals/adc/adc12.c create mode 100644 peripherals/adc/adc12.h create mode 100644 peripherals/aes/aes_p.c create mode 100644 peripherals/aes/aes_p.h create mode 100644 peripherals/can/can.c create mode 100644 peripherals/can/can.h create mode 100644 peripherals/chipid/chipid.c create mode 100644 peripherals/chipid/chipid.dir create mode 100644 peripherals/chipid/chipid.h create mode 100644 peripherals/cp15/core.h create mode 100644 peripherals/cp15/cp15.c create mode 100644 peripherals/cp15/cp15.dir create mode 100644 peripherals/cp15/cp15.h create mode 100644 peripherals/cp15/cp15_asm_gcc.S create mode 100644 peripherals/cp15/cp15_asm_iar.s create mode 100644 peripherals/cp15/cp15_asm_keil.s create mode 100644 peripherals/dbgu/dbgu.c create mode 100644 peripherals/dbgu/dbgu.dir create mode 100644 peripherals/dbgu/dbgu.h create mode 100644 peripherals/dma/dma.c create mode 100644 peripherals/dma/dma.dir create mode 100644 peripherals/dma/dma.h create mode 100644 peripherals/eefc/eefc.c create mode 100644 peripherals/eefc/eefc.dir create mode 100644 peripherals/eefc/eefc.h create mode 100644 peripherals/efc/efc.c create mode 100644 peripherals/efc/efc.dir create mode 100644 peripherals/efc/efc.h create mode 100644 peripherals/emac/emac.c create mode 100644 peripherals/emac/emac.dir create mode 100644 peripherals/emac/emac.h create mode 100644 peripherals/hsmc4/hsmc.dir create mode 100644 peripherals/hsmc4/hsmc4.c create mode 100644 peripherals/hsmc4/hsmc4.h create mode 100644 peripherals/hsmc4/hsmc4_ecc.c create mode 100644 peripherals/hsmc4/hsmc4_ecc.h create mode 100644 peripherals/irq/aic.c create mode 100644 peripherals/irq/irq.dir create mode 100644 peripherals/irq/irq.h create mode 100644 peripherals/irq/nvic.c create mode 100644 peripherals/irq/nvic.h create mode 100644 peripherals/isi/isi.c create mode 100644 peripherals/isi/isi.dir create mode 100644 peripherals/isi/isi.h create mode 100644 peripherals/isi/isi2.c create mode 100644 peripherals/lcd/lcd.c create mode 100644 peripherals/lcd/lcd.dir create mode 100644 peripherals/lcd/lcd.h create mode 100644 peripherals/mci/mci.c create mode 100644 peripherals/mci/mci.dir create mode 100644 peripherals/mci/mci.h create mode 100644 peripherals/mci/mci_hs.c create mode 100644 peripherals/mci/mci_hs.h create mode 100644 peripherals/peripherals.dir create mode 100644 peripherals/pio/pio.c create mode 100644 peripherals/pio/pio.dir create mode 100644 peripherals/pio/pio.h create mode 100644 peripherals/pio/pio_it.c create mode 100644 peripherals/pio/pio_it.h create mode 100644 peripherals/pio/pio_keypad.c create mode 100644 peripherals/pio/pio_keypad.h create mode 100644 peripherals/pit/pit.c create mode 100644 peripherals/pit/pit.dir create mode 100644 peripherals/pit/pit.h create mode 100644 peripherals/pmc/pmc.c create mode 100644 peripherals/pmc/pmc.h create mode 100644 peripherals/pwmc/pwmc.c create mode 100644 peripherals/pwmc/pwmc.dir create mode 100644 peripherals/pwmc/pwmc.h create mode 100644 peripherals/pwmc/pwmc2.c create mode 100644 peripherals/pwmc/pwmc2.h create mode 100644 peripherals/rstc/rstc.c create mode 100644 peripherals/rstc/rstc.h create mode 100644 peripherals/rtc/rtc.c create mode 100644 peripherals/rtc/rtc.h create mode 100644 peripherals/rtt/rtt.c create mode 100644 peripherals/rtt/rtt.dir create mode 100644 peripherals/rtt/rtt.h create mode 100644 peripherals/shdwc/shdwc.c create mode 100644 peripherals/shdwc/shdwc.h create mode 100644 peripherals/slcdc/slcdc.c create mode 100644 peripherals/slcdc/slcdc.dir create mode 100644 peripherals/slcdc/slcdc.h create mode 100644 peripherals/slck/slck.c create mode 100644 peripherals/slck/slck.dir create mode 100644 peripherals/slck/slck.h create mode 100644 peripherals/spi/spi.c create mode 100644 peripherals/spi/spi.h create mode 100644 peripherals/ssc/ssc.c create mode 100644 peripherals/ssc/ssc.h create mode 100644 peripherals/supc/supc.c create mode 100644 peripherals/supc/supc.h create mode 100644 peripherals/systick/systick.c create mode 100644 peripherals/systick/systick.dir create mode 100644 peripherals/systick/systick.h create mode 100644 peripherals/tc/tc.c create mode 100644 peripherals/tc/tc.dir create mode 100644 peripherals/tc/tc.h create mode 100644 peripherals/tdes/tdes.c create mode 100644 peripherals/tdes/tdes.h create mode 100644 peripherals/tsadcc/tsadcc.c create mode 100644 peripherals/tsadcc/tsadcc.dir create mode 100644 peripherals/tsadcc/tsadcc.h create mode 100644 peripherals/twi/twi.c create mode 100644 peripherals/twi/twi.dir create mode 100644 peripherals/twi/twi.h create mode 100644 peripherals/usart/usart.c create mode 100644 peripherals/usart/usart.h create mode 100644 peripherals/wdt/wdt.c create mode 100644 peripherals/wdt/wdt.dir create mode 100644 peripherals/wdt/wdt.h (limited to 'peripherals') 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 +#include +#include +#include +#include + +//------------------------------------------------------------------------------ +// 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 +#include +#include +#include + +//----------------------------------------------------------------------------- +/// 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< + +//------------------------------------------------------------------------------ +// 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 +#include +#include +#include + + + +//------------------------------------------------------------------------------ +// 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< + +//------------------------------------------------------------------------------ +// 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 +#include +#include + +//------------------------------------------------------------------------------ +// 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 +#include +#include +#include +#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 +#include +#include + +//------------------------------------------------------------------------------ +// 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; iDBGU_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 + +//------------------------------------------------------------------------------ +// 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 + +#ifdef CP15_PRESENT + +#include +#include "cp15.h" + +#if defined(__ICCARM__) +#include +#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, , c2, c0, 0 +/// Write TTBR : MCR p15, 0, , 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, , c3, c0, 0 +/// Write domain access permissions : MCR p15, 0, , 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, , c5, c0, 0 ;read DFSR +/// MCR p15, 0, , c5, c0, 0 ;write DFSR +/// MRC p15, 0, , c5, c0, 1 ;read IFSR +/// MCR p15, 0, , 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, , c6, c0, 0 ; read FAR +/// MCR p15, 0, , 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, , , , , +//------------------------------------------------------------------------------ +/// Invalidate Icache and Dcache MCR p15, 0, , c7, c7, 0 +/// Invalidate Icache MCR p15, 0, , c7, c5, 0 +/// Invalidate Icache single entry (MVA) MVA MCR p15, 0, , c7, c5, 1 +/// Invalidate Icache single entry (Set/Way) Set/Way MCR p15, 0, , c7, c5, 2 +/// Prefetch Icache line (MVA) MVA MCR p15, 0, , c7, c13, 1 +/// Invalidate Dcache MCR p15, 0, , c7, c6, 0 +/// Invalidate Dcache single entry (MVA) MVA MCR p15, 0, , c7, c6, 1 +/// Invalidate Dcache single entry (Set/Way) Set/Way MCR p15, 0, , c7, c6, 2 +/// Clean Dcache single entry (MVA) MVA MCR p15, 0, , c7, c10, 1 +/// Clean Dcache single entry (Set/Way) Set/Way MCR p15, 0, , c7, c10, 2 +/// Test and clean Dcache - MRC p15, 0, , c7, c10, 3 +/// Clean and invalidate Dcache entry (MVA) MVA MCR p15, 0, , c7, c14, 1 +/// Clean and invalidate Dcache entry (Set/Way) Set/Way MCR p15, 0, , c7, c14, 2 +/// Test, clean, and invalidate Dcache - MRC p15, 0, , c7, c14, 3 +/// Drain write buffer SBZ MCR p15, 0, , c7, c10, 4 +/// Wait for interrupt SBZ MCR p15, 0, , 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, , 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, , 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, , c8, c7, 0 +/// Invalidate TLB single entry (MVA) MCR p15, 0, , c8, c7, 1 +/// Invalidate instruction TLB MCR p15, 0, , c8, c5, 0 +/// Invalidate instruction TLB single entry (MVA) MCR p15, 0, , c8, c5, 1 +/// Invalidate data TLB MCR p15, 0, , c8, c6, 0 +/// Invalidate data TLB single entry (MVA) MCR p15, 0, , 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,,c9,c0,0 +/// Write Dcache Lockdown Register MCR p15,0,,c9,c0,0 +/// Read Icache Lockdown Register MRC p15,0,,c9,c0,1 +/// Write Icache Lockdown Register MCR p15,0,,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,,c10,c0,0 +/// Write data TLB lockdown victim MCR p15,0,,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,,c13,c0, 0 +/// Write FCSE PID MCR p15,0,,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,,c13,c0, 1 +/// Write context ID MCR p15,0,,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, , c2, c0, 0 +/// Write TTBR : MCR p15, 0, , 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, , c3, c0, 0 +/// Write domain access permissions : MCR p15, 0, , 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, , c5, c0, 0 ;read DFSR +/// MCR p15, 0, , c5, c0, 0 ;write DFSR +/// MRC p15, 0, , c5, c0, 1 ;read IFSR +/// MCR p15, 0, , 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, , c6, c0, 0 ; read FAR +/// MCR p15, 0, , 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, , , , , +//------------------------------------------------------------------------------ +/// Invalidate Icache and Dcache MCR p15, 0, , c7, c7, 0 +/// Invalidate Icache MCR p15, 0, , c7, c5, 0 +/// Invalidate Icache single entry (MVA) MVA MCR p15, 0, , c7, c5, 1 +/// Invalidate Icache single entry (Set/Way) Set/Way MCR p15, 0, , c7, c5, 2 +/// Prefetch Icache line (MVA) MVA MCR p15, 0, , c7, c13, 1 +/// Invalidate Dcache MCR p15, 0, , c7, c6, 0 +/// Invalidate Dcache single entry (MVA) MVA MCR p15, 0, , c7, c6, 1 +/// Invalidate Dcache single entry (Set/Way) Set/Way MCR p15, 0, , c7, c6, 2 +/// Clean Dcache single entry (MVA) MVA MCR p15, 0, , c7, c10, 1 +/// Clean Dcache single entry (Set/Way) Set/Way MCR p15, 0, , c7, c10, 2 +/// Test and clean Dcache - MRC p15, 0, , c7, c10, 3 +/// Clean and invalidate Dcache entry (MVA) MVA MCR p15, 0, , c7, c14, 1 +/// Clean and invalidate Dcache entry (Set/Way) Set/Way MCR p15, 0, , c7, c14, 2 +/// Test, clean, and invalidate Dcache - MRC p15, 0, , c7, c14, 3 +/// Drain write buffer SBZ MCR p15, 0, , c7, c10, 4 +/// Wait for interrupt SBZ MCR p15, 0, , 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, , 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, , 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, , c8, c7, 0 +/// Invalidate TLB single entry (MVA) MCR p15, 0, , c8, c7, 1 +/// Invalidate instruction TLB MCR p15, 0, , c8, c5, 0 +/// Invalidate instruction TLB single entry (MVA) MCR p15, 0, , c8, c5, 1 +/// Invalidate data TLB MCR p15, 0, , c8, c6, 0 +/// Invalidate data TLB single entry (MVA) MCR p15, 0, , 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,,c9,c0,0 +/// Write Dcache Lockdown Register MCR p15,0,,c9,c0,0 +/// Read Icache Lockdown Register MRC p15,0,,c9,c0,1 +/// Write Icache Lockdown Register MCR p15,0,,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,,c10,c0,0 +/// Write data TLB lockdown victim MCR p15,0,,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,,c13,c0, 0 +/// Write FCSE PID MCR p15,0,,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,,c13,c0, 1 +/// Write context ID MCR p15,0,,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, , c2, c0, 0 +; Write TTBR : MCR p15, 0, , 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, , c3, c0, 0 +; Write domain access permissions : MCR p15, 0, , 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, , c5, c0, 0 ;read DFSR +; MCR p15, 0, , c5, c0, 0 ;write DFSR +; MRC p15, 0, , c5, c0, 1 ;read IFSR +; MCR p15, 0, , 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, , c6, c0, 0 ; read FAR +; MCR p15, 0, , 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, , , , , +;------------------------------------------------------------------------------ +; Invalidate Icache and Dcache MCR p15, 0, , c7, c7, 0 +; Invalidate Icache MCR p15, 0, , c7, c5, 0 +; Invalidate Icache single entry (MVA) MVA MCR p15, 0, , c7, c5, 1 +; Invalidate Icache single entry (Set/Way) Set/Way MCR p15, 0, , c7, c5, 2 +; Prefetch Icache line (MVA) MVA MCR p15, 0, , c7, c13, 1 +; Invalidate Dcache MCR p15, 0, , c7, c6, 0 +; Invalidate Dcache single entry (MVA) MVA MCR p15, 0, , c7, c6, 1 +; Invalidate Dcache single entry (Set/Way) Set/Way MCR p15, 0, , c7, c6, 2 +; Clean Dcache single entry (MVA) MVA MCR p15, 0, , c7, c10, 1 +; Clean Dcache single entry (Set/Way) Set/Way MCR p15, 0, , c7, c10, 2 +; Test and clean Dcache - MRC p15, 0, , c7, c10, 3 +; Clean and invalidate Dcache entry (MVA) MVA MCR p15, 0, , c7, c14, 1 +; Clean and invalidate Dcache entry (Set/Way) Set/Way MCR p15, 0, , c7, c14, 2 +; Test, clean, and invalidate Dcache - MRC p15, 0, , c7, c14, 3 +; Drain write buffer SBZ MCR p15, 0, , c7, c10, 4 +; Wait for interrupt SBZ MCR p15, 0, , 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, , 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, , 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, , c8, c7, 0 +; Invalidate TLB single entry (MVA) MCR p15, 0, , c8, c7, 1 +; Invalidate instruction TLB MCR p15, 0, , c8, c5, 0 +; Invalidate instruction TLB single entry (MVA) MCR p15, 0, , c8, c5, 1 +; Invalidate data TLB MCR p15, 0, , c8, c6, 0 +; Invalidate data TLB single entry (MVA) MCR p15, 0, , 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,,c9,c0,0 +; Write Dcache Lockdown Register MCR p15,0,,c9,c0,0 +; Read Icache Lockdown Register MRC p15,0,,c9,c0,1 +; Write Icache Lockdown Register MCR p15,0,,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,,c10,c0,0 +; Write data TLB lockdown victim MCR p15,0,,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,,c13,c0, 0 +; Write FCSE PID MCR p15,0,,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,,c13,c0, 1 +; Write context ID MCR p15,0,,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 + +//------------------------------------------------------------------------------ +// 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 +#include + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 +#include "eefc.h" + +#if !defined (CHIP_FLASH_EEFC) +#error eefc not supported +#endif + +#include +#include + +//------------------------------------------------------------------------------ +// 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 + +#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 +#include "efc.h" + +#if !defined (CHIP_FLASH_EFC) +#error efc not supported +#endif + +#include +#include + +//------------------------------------------------------------------------------ +// 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 + +#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 +#include "emac.h" +#include +#include +#include + +//------------------------------------------------------------------------------ +// 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 + +//----------------------------------------------------------------------------- +// 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 + +//------------------------------------------------------------------------------ +// 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 +#include + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 +#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 +#if defined(cortexm3) +#include +#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 + +/// 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 +#include +#include +#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 +#include +#include +#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 + +#if defined (AT91C_ID_LCDC) + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "lcd.h" +#include +#include + + +//------------------------------------------------------------------------------ +// 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 +#include + +//------------------------------------------------------------------------------ +// 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 + +#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 +#include + +#include +#include + +//------------------------------------------------------------------------------ +// 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 %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 +#if MCI_BUSY_CHECK_FIX +#include +#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 + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 +#include +#include +#include + +//------------------------------------------------------------------------------ +// 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 +#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; ikdEvent.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;ikuEvent.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 + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 +#include +#include + +#ifdef CP15_PRESENT +#include +#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 +#include +#include + +//------------------------------------------------------------------------------ +// 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 +#include +#include + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 + +//----------------------------------------------------------------------------- +// 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 +#include +#include + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 +#include + +//------------------------------------------------------------------------------ +// 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 +#include + +#include + +//------------------------------------------------------------------------------ +// 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 +#if defined(at91sam3u) +#include +#endif +#include +#include + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 +#if defined(CHIP_SSC_DMA) +#include +#include +#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 + +//------------------------------------------------------------------------------ +// 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 +#include + +//------------------------------------------------------------------------------ +// 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 +#include + +//------------------------------------------------------------------------------ +// 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 + +#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 +#include +#include + +//------------------------------------------------------------------------------ +// 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 + +#ifdef AT91C_BASE_TSADC + +#include +#include + +//------------------------------------------------------------------------------ +// 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 +#include +#include + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 +#include + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 + +//------------------------------------------------------------------------------ +// 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 -- cgit v1.2.3