diff options
Diffstat (limited to 'firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/SPI/spi.c')
-rw-r--r-- | firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/SPI/spi.c | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/SPI/spi.c b/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/SPI/spi.c new file mode 100644 index 0000000..d2b7ccd --- /dev/null +++ b/firmwares/wifishield/wifiHD/src/SOFTWARE_FRAMEWORK/DRIVERS/SPI/spi.c @@ -0,0 +1,443 @@ +/* This source file is part of the ATMEL AVR-UC3-SoftwareFramework-1.7.0 Release */ + +/*This file is prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief SPI driver for AVR32 UC3. + * + * This file defines a useful set of functions for the SPI interface on AVR32 + * devices. + * + * - Compiler: IAR EWAVR32 and GNU GCC for AVR32 + * - Supported devices: All AVR32 devices with an SPI module can be used. + * - AppNote: + * + * \author Atmel Corporation: http://www.atmel.com \n + * Support and FAQ: http://support.atmel.no/ + * + ******************************************************************************/ + +/* 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an Atmel + * AVR product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (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 "spi.h" + +#ifdef FREERTOS_USED + +#include "FreeRTOS.h" +#include "semphr.h" + +#endif + + +/*! \name SPI Writable Bit-Field Registers + */ +//! @{ + +typedef union +{ + unsigned long cr; + avr32_spi_cr_t CR; +} u_avr32_spi_cr_t; + +typedef union +{ + unsigned long mr; + avr32_spi_mr_t MR; +} u_avr32_spi_mr_t; + +typedef union +{ + unsigned long tdr; + avr32_spi_tdr_t TDR; +} u_avr32_spi_tdr_t; + +typedef union +{ + unsigned long ier; + avr32_spi_ier_t IER; +} u_avr32_spi_ier_t; + +typedef union +{ + unsigned long idr; + avr32_spi_idr_t IDR; +} u_avr32_spi_idr_t; + +typedef union +{ + unsigned long csr; + avr32_spi_csr0_t CSR; +} u_avr32_spi_csr_t; + +//! @} + + +#ifdef FREERTOS_USED + +//! The SPI mutex. +static xSemaphoreHandle xSPIMutex; + +#endif + + +/*! \brief Calculates the baudrate divider. + * + * \param options Pointer to a structure containing initialization options for + * an SPI channel. + * \param pba_hz SPI module input clock frequency (PBA clock, Hz). + * + * \return Divider or error code. + * \retval >=0 Success. + * \retval <0 Error. + */ +static int getBaudDiv(const spi_options_t *options, unsigned int pba_hz) +{ + int baudDiv = (pba_hz + options->baudrate / 2) / options->baudrate; + + if (baudDiv <= 0 || baudDiv > 255) { + return -1; + } + + return baudDiv; +} + + +void spi_reset(volatile avr32_spi_t *spi) +{ + spi->cr = AVR32_SPI_CR_SWRST_MASK; +} + + +spi_status_t spi_initSlave(volatile avr32_spi_t *spi, + unsigned char bits, + unsigned char spi_mode) +{ + if (spi_mode > 3 || + bits < 8 || bits > 16) { + return SPI_ERROR_ARGUMENT; + } + + // Reset. + spi->cr = AVR32_SPI_CR_SWRST_MASK; + + // Will use CSR0 offsets; these are the same for CSR0 to CSR3. + spi->csr0 = ((spi_mode >> 1) << AVR32_SPI_CSR0_CPOL_OFFSET) | + (((spi_mode & 0x1) ^ 0x1) << AVR32_SPI_CSR0_NCPHA_OFFSET) | + ((bits - 8) << AVR32_SPI_CSR0_BITS_OFFSET); + + return SPI_OK; +} + + +spi_status_t spi_initTest(volatile avr32_spi_t *spi) +{ + // Reset. + spi->cr = AVR32_SPI_CR_SWRST_MASK; + spi->mr |= AVR32_SPI_MR_MSTR_MASK | // Master Mode. + AVR32_SPI_MR_LLB_MASK; // Local Loopback. + + return SPI_OK; +} + + +spi_status_t spi_initMaster(volatile avr32_spi_t *spi, const spi_options_t *options) +{ + u_avr32_spi_mr_t u_avr32_spi_mr; + + if (options->modfdis > 1) { + return SPI_ERROR_ARGUMENT; + } + + // Reset. + spi->cr = AVR32_SPI_CR_SWRST_MASK; + + // Master Mode. + u_avr32_spi_mr.mr = spi->mr; + u_avr32_spi_mr.MR.mstr = 1; + u_avr32_spi_mr.MR.modfdis = options->modfdis; + u_avr32_spi_mr.MR.llb = 0; + u_avr32_spi_mr.MR.pcs = (1 << AVR32_SPI_MR_PCS_SIZE) - 1; + spi->mr = u_avr32_spi_mr.mr; + + return SPI_OK; +} + + +spi_status_t spi_selectionMode(volatile avr32_spi_t *spi, + unsigned char variable_ps, + unsigned char pcs_decode, + unsigned char delay) +{ + u_avr32_spi_mr_t u_avr32_spi_mr; + + if (variable_ps > 1 || + pcs_decode > 1) { + return SPI_ERROR_ARGUMENT; + } + + u_avr32_spi_mr.mr = spi->mr; + u_avr32_spi_mr.MR.ps = variable_ps; + u_avr32_spi_mr.MR.pcsdec = pcs_decode; + u_avr32_spi_mr.MR.dlybcs = delay; + spi->mr = u_avr32_spi_mr.mr; + + return SPI_OK; +} + + +spi_status_t spi_selectChip(volatile avr32_spi_t *spi, unsigned char chip) +{ +#ifdef FREERTOS_USED + while (pdFALSE == xSemaphoreTake(xSPIMutex, 20)); +#endif + + // Assert all lines; no peripheral is selected. + spi->mr |= AVR32_SPI_MR_PCS_MASK; + + if (spi->mr & AVR32_SPI_MR_PCSDEC_MASK) { + // The signal is decoded; allow up to 15 chips. + if (chip > 14) { + return SPI_ERROR_ARGUMENT; + } + + spi->mr &= ~AVR32_SPI_MR_PCS_MASK | (chip << AVR32_SPI_MR_PCS_OFFSET); + } else { + if (chip > 3) { + return SPI_ERROR_ARGUMENT; + } + + spi->mr &= ~(1 << (AVR32_SPI_MR_PCS_OFFSET + chip)); + } + + return SPI_OK; +} + + +spi_status_t spi_unselectChip(volatile avr32_spi_t *spi, unsigned char chip) +{ + unsigned int timeout = SPI_TIMEOUT; + + while (!(spi->sr & AVR32_SPI_SR_TXEMPTY_MASK)) { + if (!timeout--) { + return SPI_ERROR_TIMEOUT; + } + } + + // Assert all lines; no peripheral is selected. + spi->mr |= AVR32_SPI_MR_PCS_MASK; + + // Last transfer, so deassert the current NPCS if CSAAT is set. + spi->cr = AVR32_SPI_CR_LASTXFER_MASK; + +#ifdef FREERTOS_USED + xSemaphoreGive(xSPIMutex); +#endif + + return SPI_OK; +} + + +spi_status_t spi_setupChipReg(volatile avr32_spi_t *spi, + const spi_options_t *options, + unsigned int pba_hz) +{ + u_avr32_spi_csr_t u_avr32_spi_csr; + + if (options->spi_mode > 3 || + options->stay_act > 1 || + options->bits < 8 || options->bits > 16) { + return SPI_ERROR_ARGUMENT; + } + + int baudDiv = getBaudDiv(options, pba_hz); + + if (baudDiv < 0) { + return SPI_ERROR_ARGUMENT; + } + + // Will use CSR0 offsets; these are the same for CSR0 to CSR3. + u_avr32_spi_csr.csr = 0; + u_avr32_spi_csr.CSR.cpol = options->spi_mode >> 1; + u_avr32_spi_csr.CSR.ncpha = (options->spi_mode & 0x1) ^ 0x1; + u_avr32_spi_csr.CSR.csaat = options->stay_act; + u_avr32_spi_csr.CSR.bits = options->bits - 8; + u_avr32_spi_csr.CSR.scbr = baudDiv; + u_avr32_spi_csr.CSR.dlybs = options->spck_delay; + u_avr32_spi_csr.CSR.dlybct = options->trans_delay; + + switch(options->reg) { + case 0: + spi->csr0 = u_avr32_spi_csr.csr; + break; + case 1: + spi->csr1 = u_avr32_spi_csr.csr; + break; + case 2: + spi->csr2 = u_avr32_spi_csr.csr; + break; + case 3: + spi->csr3 = u_avr32_spi_csr.csr; + break; + default: + return SPI_ERROR_ARGUMENT; + } + +#ifdef FREERTOS_USED + if (!xSPIMutex) + { + // Create the SPI mutex. + vSemaphoreCreateBinary(xSPIMutex); + if (!xSPIMutex) + { + while(1); + } + } +#endif + + return SPI_OK; +} + + +void spi_enable(volatile avr32_spi_t *spi) +{ + spi->cr = AVR32_SPI_CR_SPIEN_MASK; +} + + +void spi_disable(volatile avr32_spi_t *spi) +{ + spi->cr = AVR32_SPI_CR_SPIDIS_MASK; +} + + +int spi_is_enabled(volatile avr32_spi_t *spi) +{ + return (spi->sr & AVR32_SPI_SR_SPIENS_MASK) != 0; +} + + +inline unsigned char spi_writeRegisterEmptyCheck(volatile avr32_spi_t *spi) +{ + return ((spi->sr & AVR32_SPI_SR_TDRE_MASK) != 0); +} + + +inline spi_status_t spi_write(volatile avr32_spi_t *spi, unsigned short data) +{ + unsigned int timeout = SPI_TIMEOUT; + + while (!(spi->sr & AVR32_SPI_SR_TDRE_MASK)) { + if (!timeout--) { + return SPI_ERROR_TIMEOUT; + } + } + + spi->tdr = data << AVR32_SPI_TDR_TD_OFFSET; + + return SPI_OK; +} + + +spi_status_t spi_variableSlaveWrite(volatile avr32_spi_t *spi, unsigned short data, + unsigned char pcs, unsigned char lastxfer) +{ + unsigned int timeout = SPI_TIMEOUT; + + if (pcs > 14 || lastxfer > 1) { + return SPI_ERROR_ARGUMENT; + } + + while (!(spi->sr & AVR32_SPI_SR_TDRE_MASK)) { + if (!timeout--) { + return SPI_ERROR_TIMEOUT; + } + } + + spi->tdr = (data << AVR32_SPI_TDR_TD_OFFSET) | + (pcs << AVR32_SPI_TDR_PCS_OFFSET) | + (lastxfer << AVR32_SPI_TDR_LASTXFER_OFFSET); + + return SPI_OK; +} + + +inline unsigned char spi_writeEndCheck(volatile avr32_spi_t *spi) +{ + return ((spi->sr & AVR32_SPI_SR_TXEMPTY_MASK) != 0); +} + + +unsigned char spi_readRegisterFullCheck(volatile avr32_spi_t *spi) +{ + return ((spi->sr & AVR32_SPI_SR_RDRF_MASK) != 0); +} + + +inline spi_status_t spi_read(volatile avr32_spi_t *spi, unsigned short *data) +{ + unsigned int timeout = SPI_TIMEOUT; + + while ((spi->sr & (AVR32_SPI_SR_RDRF_MASK | AVR32_SPI_SR_TXEMPTY_MASK)) != + (AVR32_SPI_SR_RDRF_MASK | AVR32_SPI_SR_TXEMPTY_MASK)) { + if (!timeout--) { + return SPI_ERROR_TIMEOUT; + } + } + + *data = spi->rdr >> AVR32_SPI_RDR_RD_OFFSET; + + return SPI_OK; +} + + +unsigned char spi_getStatus(volatile avr32_spi_t *spi) +{ + spi_status_t ret = SPI_OK; + unsigned long sr = spi->sr; + + if (sr & AVR32_SPI_SR_OVRES_MASK) { + ret = SPI_ERROR_OVERRUN; + } + + if (sr & AVR32_SPI_SR_MODF_MASK) { + ret += SPI_ERROR_MODE_FAULT; + } + + if (ret == (SPI_ERROR_OVERRUN + SPI_ERROR_MODE_FAULT)) { + return SPI_ERROR_OVERRUN_AND_MODE_FAULT; + } + else if (ret > 0) { + return ret; + } else { + return SPI_OK; + } +} |