spid.c
上传用户:xukun0987
上传日期:2022-07-16
资源大小:216k
文件大小:8k
源码类别:

微处理器开发

开发平台:

C/C++

  1. /* ----------------------------------------------------------------------------
  2.  *         ATMEL Microcontroller Software Support 
  3.  * ----------------------------------------------------------------------------
  4.  * Copyright (c) 2008, Atmel Corporation
  5.  *
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions are met:
  10.  *
  11.  * - Redistributions of source code must retain the above copyright notice,
  12.  * this list of conditions and the disclaimer below.
  13.  *
  14.  * Atmel's name may not be used to endorse or promote products derived from
  15.  * this software without specific prior written permission.
  16.  *
  17.  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  19.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
  20.  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  22.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  23.  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  24.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  25.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  26.  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  * ----------------------------------------------------------------------------
  28.  */
  29. //------------------------------------------------------------------------------
  30. //         Headers
  31. //------------------------------------------------------------------------------
  32. #include "spid.h"
  33. #include <board.h>
  34. //------------------------------------------------------------------------------
  35. //         Macros
  36. //------------------------------------------------------------------------------
  37. /// Write PMC register
  38. #define WRITE_PMC(pPmc, regName, value) pPmc->regName = (value)
  39. /// Write SPI register
  40. #define WRITE_SPI(pSpi, regName, value) pSpi->regName = (value)
  41. /// Read SPI registers
  42. #define READ_SPI(pSpi, regName) (pSpi->regName)
  43. //------------------------------------------------------------------------------
  44. //         Exported functions
  45. //------------------------------------------------------------------------------
  46. //------------------------------------------------------------------------------
  47. /// Initializes the Spid structure and the corresponding SPI hardware.
  48. /// Always returns 0.
  49. /// param pSpid  Pointer to a Spid instance.
  50. /// param pSpiHw  Associated SPI peripheral.
  51. /// param spiId  SPI peripheral identifier.
  52. //------------------------------------------------------------------------------
  53. unsigned char SPID_Configure(Spid *pSpid, AT91S_SPI *pSpiHw, unsigned char spiId)
  54. {
  55.     // Initialize the SPI structure
  56.     pSpid->pSpiHw = pSpiHw;
  57.     pSpid->spiId  = spiId;
  58.     pSpid->semaphore = 1;
  59.     pSpid->pCurrentCommand = 0;
  60.     // Enable the SPI clock
  61.     WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId));
  62.     
  63.     // Execute a software reset of the SPI twice
  64.     WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
  65.     WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
  66.     // Configure SPI in Master Mode with No CS selected !!!
  67.     WRITE_SPI(pSpiHw, SPI_MR, AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS);
  68.      
  69.     // Disable the PDC transfer    
  70.     WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
  71.     // Enable the SPI
  72.     WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIEN);
  73.     // Enable the SPI clock
  74.     WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId));
  75.     
  76.     return 0;
  77. }
  78. //------------------------------------------------------------------------------
  79. /// Configures the parameters for the device corresponding to the cs.
  80. /// param pSpid  Pointer to a Spid instance.
  81. /// param cs  number corresponding to the SPI chip select.
  82. /// param csr  SPI_CSR value to setup.
  83. //------------------------------------------------------------------------------
  84. void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr)
  85. {
  86.     AT91S_SPI *pSpiHw = pSpid->pSpiHw;
  87.     WRITE_SPI(pSpiHw, SPI_CSR[cs], csr);
  88. }
  89.     
  90. //------------------------------------------------------------------------------
  91. /// Starts a SPI master transfer. This is a non blocking function. It will
  92. /// return as soon as the transfer is started.
  93. /// Returns 0 if the transfer has been started successfully; otherwise returns
  94. /// SPID_ERROR_LOCK is the driver is in use, or SPID_ERROR if the command is not
  95. /// valid.
  96. /// param pSpid  Pointer to a Spid instance.
  97. /// param pCommand Pointer to the SPI command to execute.
  98. //------------------------------------------------------------------------------
  99. unsigned char SPID_SendCommand(Spid *pSpid, SpidCmd *pCommand)
  100. {
  101.     AT91S_SPI *pSpiHw = pSpid->pSpiHw;
  102.      unsigned int spiMr;
  103.          
  104.      // Try to get the dataflash semaphore
  105.      if (pSpid->semaphore == 0) {
  106.     
  107.          return SPID_ERROR_LOCK;
  108.     }
  109.      pSpid->semaphore--;
  110.     // Enable the SPI clock
  111.     WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId));
  112.     
  113.     // Disable transmitter and receiver
  114.     WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
  115.      // Write to the MR register
  116.      spiMr = READ_SPI(pSpiHw, SPI_MR);
  117.      spiMr |= AT91C_SPI_PCS;
  118.      spiMr &= ~((1 << pCommand->spiCs) << 16);
  119.     WRITE_SPI(pSpiHw, SPI_MR, spiMr);
  120.         
  121.     // Initialize the two SPI PDC buffer
  122.     WRITE_SPI(pSpiHw, SPI_RPR, (int) pCommand->pCmd);
  123.     WRITE_SPI(pSpiHw, SPI_RCR, pCommand->cmdSize);
  124.     WRITE_SPI(pSpiHw, SPI_TPR, (int) pCommand->pCmd);
  125.     WRITE_SPI(pSpiHw, SPI_TCR, pCommand->cmdSize);
  126.     
  127.     WRITE_SPI(pSpiHw, SPI_RNPR, (int) pCommand->pData);
  128.     WRITE_SPI(pSpiHw, SPI_RNCR, pCommand->dataSize);
  129.     WRITE_SPI(pSpiHw, SPI_TNPR, (int) pCommand->pData);
  130.     WRITE_SPI(pSpiHw, SPI_TNCR, pCommand->dataSize);
  131.     // Initialize the callback
  132.     pSpid->pCurrentCommand = pCommand;
  133.     
  134.     // Enable transmitter and receiver
  135.     WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTEN | AT91C_PDC_TXTEN);
  136.     // Enable buffer complete interrupt
  137.     WRITE_SPI(pSpiHw, SPI_IER, AT91C_SPI_RXBUFF);
  138.     
  139.     return 0;    
  140. }
  141. //------------------------------------------------------------------------------
  142. /// The SPI_Handler must be called by the SPI Interrupt Service Routine with the
  143. /// corresponding Spi instance.
  144. /// The SPI_Handler will unlock the Spi semaphore and invoke the upper application 
  145. /// callback.
  146. /// param pSpid  Pointer to a Spid instance.
  147. //------------------------------------------------------------------------------
  148. void SPID_Handler(Spid *pSpid)
  149. {
  150.     SpidCmd *pSpidCmd = pSpid->pCurrentCommand;
  151.     AT91S_SPI *pSpiHw = pSpid->pSpiHw;
  152.     volatile unsigned int spiSr;
  153.     
  154.     // Read the status register
  155.     spiSr = READ_SPI(pSpiHw, SPI_SR);    
  156.     if (spiSr & AT91C_SPI_RXBUFF) {
  157.         // Disable transmitter and receiver
  158.         WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
  159.         // Disable the SPI clock
  160.         WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId));
  161.         // Disable buffer complete interrupt
  162.         WRITE_SPI(pSpiHw, SPI_IDR, AT91C_SPI_RXBUFF);
  163.         // Release the dataflash semaphore
  164.         pSpid->semaphore++;
  165.             
  166.         // Invoke the callback associated with the current command
  167.         if (pSpidCmd && pSpidCmd->callback) {
  168.         
  169.             pSpidCmd->callback(0, pSpidCmd->pArgument);
  170.         }
  171.             
  172.         // Nothing must be done after. A new DF operation may have been started
  173.         // in the callback function.
  174.     }
  175. }
  176. //------------------------------------------------------------------------------
  177. /// Returns 1 if the SPI driver is currently busy executing a command; otherwise
  178. /// returns 0.
  179. /// param pSpid  Pointer to a SPI driver instance.
  180. //------------------------------------------------------------------------------
  181. unsigned char SPID_IsBusy(const Spid *pSpid)
  182. {
  183.     if (pSpid->semaphore == 0) {
  184.         return 1;
  185.     }
  186.     else {
  187.         return 0;
  188.     }
  189. }