SAMV71 Xplained Ultra Software Package 1.4

ili9488_spi_dma.c

Go to the documentation of this file.
00001 /* ----------------------------------------------------------------------------
00002  *         SAM Software Package License
00003  * ----------------------------------------------------------------------------
00004  * Copyright (c) 2014, Atmel Corporation
00005  *
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *
00011  * - Redistributions of source code must retain the above copyright notice,
00012  * this list of conditions and the disclaimer below.
00013  *
00014  * Atmel's name may not be used to endorse or promote products derived from
00015  * this software without specific prior written permission.
00016  *
00017  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
00020  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00022  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00023  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00024  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00025  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00026  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  * ----------------------------------------------------------------------------
00028  */
00029 
00030 /**
00031  * \file
00032  *
00033  * Implementation of ILI9488 SPI DMA driver.
00034  *
00035  */
00036 
00037 /*----------------------------------------------------------------------------
00038  *        Headers
00039  *----------------------------------------------------------------------------*/
00040 #include "board.h"
00041 
00042 #include <string.h>
00043 #include <stdio.h>
00044 
00045 #ifdef BOARD_LCD_ILI9488
00046 
00047 /*----------------------------------------------------------------------------
00048  *        Local variables
00049  *----------------------------------------------------------------------------*/
00050 /** Pins to configure for the application. */
00051 static const Pin lcd_spi_cds_pin = BOARD_SPI_LCD_PIN_CDS;
00052 
00053 static sIli9488Dma ili9488DmaSpiMode;
00054 static sIli9488DmaCtl  ili9488DmaCtlInSpiMode;
00055 
00056 /*----------------------------------------------------------------------------
00057  *        Local functions
00058  *----------------------------------------------------------------------------*/
00059 /**
00060  * \brief ILI9488_SPI xDMA Rx callback
00061  */ 
00062 static void _ILI9488_Spi_Rx_CB(void)
00063 {
00064     if(!ili9488DmaCtlInSpiMode.cmdOrDataFlag) {
00065         ili9488DmaCtlInSpiMode.rxDoneFlag = 1;
00066         memory_barrier()
00067     }
00068 }
00069 
00070 /**
00071  * \brief ILI9488_SPI xDMA Tx callback
00072  */ 
00073 static void _ILI9488_Spi_Tx_CB(void)
00074 {
00075     uint32_t i;
00076     if( ili9488DmaCtlInSpiMode.cmdOrDataFlag){
00077         PIO_Set(&lcd_spi_cds_pin);
00078         for(i = 0; i<0xFF; i++);
00079         ili9488DmaCtlInSpiMode.cmdOrDataFlag = 0;
00080     }
00081     ili9488DmaCtlInSpiMode.txDoneFlag = 1;
00082 }
00083 
00084 /**
00085  * \brief Initializes the ili9488DmaSpiMode structure and the corresponding DMA .
00086  * hardware.
00087  */
00088 static void _ILI9488_SpiDmaInitialize(sXdmad * dmad)
00089 {
00090     ili9488DmaCtlInSpiMode.cmdOrDataFlag = 1;
00091     ili9488DmaCtlInSpiMode.rxDoneFlag = 0;
00092     ili9488DmaCtlInSpiMode.txDoneFlag = 1;
00093 
00094     ili9488DmaSpiMode.xdmaD = dmad;
00095     ili9488DmaSpiMode.xdmaD->pXdmacs = XDMAC;
00096     ili9488DmaSpiMode.ili9488DmaTxChannel = 0;
00097     ili9488DmaSpiMode.ili9488DmaRxChannel = 0;
00098     ili9488DmaSpiMode.xdmaInt = 0;
00099     ili9488DmaSpiMode.pSpiHw = ILI9488_SPI;
00100     ili9488DmaSpiMode.spiId = ILI9488_SPI_ID;
00101 }
00102 
00103 /**
00104  * \brief This function initialize the appropriate DMA channel for Rx/Tx channel
00105  * of SPI or SMC
00106  * \returns             0 if the transfer has been started successfully; 
00107  * otherwise returns ILI9488_ERROR_XX is the driver is in use, 
00108  * or ILI9488_ERROR_XX if the command is not valid.
00109  */
00110 static uint8_t _ILI9488_SpiDmaConfigChannels(void)
00111 {
00112     uint32_t srcType,dstType;
00113 
00114     /* Driver initialize */
00115     XDMAD_Initialize(  ili9488DmaSpiMode.xdmaD, 0 );
00116 
00117     XDMAD_FreeChannel( ili9488DmaSpiMode.xdmaD, ili9488DmaSpiMode.ili9488DmaTxChannel);
00118     XDMAD_FreeChannel( ili9488DmaSpiMode.xdmaD, ili9488DmaSpiMode.ili9488DmaRxChannel);
00119 
00120     srcType = XDMAD_TRANSFER_MEMORY;
00121     dstType = ili9488DmaSpiMode.spiId;
00122 
00123     /* Allocate a DMA channel for  ILI9488_SPI TX. */
00124     ili9488DmaSpiMode.ili9488DmaTxChannel
00125                     = XDMAD_AllocateChannel( ili9488DmaSpiMode.xdmaD, srcType, dstType);
00126 
00127     if ( ili9488DmaSpiMode.ili9488DmaTxChannel == XDMAD_ALLOC_FAILED ) {
00128         return ILI9488_ERROR_DMA_ALLOCATE_CHANNEL;
00129     }
00130 
00131     /* Allocate a DMA channel for ILI9488_SPI  RX. */
00132     ili9488DmaSpiMode.ili9488DmaRxChannel 
00133                     = XDMAD_AllocateChannel( ili9488DmaSpiMode.xdmaD, dstType, srcType);
00134 
00135     if ( ili9488DmaSpiMode.ili9488DmaRxChannel == XDMAD_ALLOC_FAILED ) {
00136             return ILI9488_ERROR_DMA_ALLOCATE_CHANNEL; 
00137     }
00138 
00139     /* Setup callbacks for ILI9488_SPI RX */
00140     XDMAD_SetCallback(ili9488DmaSpiMode.xdmaD,
00141                     ili9488DmaSpiMode.ili9488DmaRxChannel, 
00142                     (XdmadTransferCallback)_ILI9488_Spi_Rx_CB,
00143                     &ili9488DmaSpiMode);
00144     if (XDMAD_PrepareChannel( 
00145         ili9488DmaSpiMode.xdmaD, ili9488DmaSpiMode.ili9488DmaRxChannel ))
00146         return ILI9488_ERROR_DMA_ALLOCATE_CHANNEL;
00147 
00148     /* Setup callbacks for ILI9488_SPI  TX (ignored) */
00149     XDMAD_SetCallback(ili9488DmaSpiMode.xdmaD,
00150                     ili9488DmaSpiMode.ili9488DmaTxChannel,
00151                     (XdmadTransferCallback)_ILI9488_Spi_Tx_CB,
00152                     &ili9488DmaSpiMode);
00153     if ( XDMAD_PrepareChannel( 
00154         ili9488DmaSpiMode.xdmaD, ili9488DmaSpiMode.ili9488DmaTxChannel ))
00155         return  ILI9488_ERROR_DMA_ALLOCATE_CHANNEL;
00156 
00157     /* Check if DMA IRQ is enable; if not Enable it */
00158     if(!(NVIC_GetActive(XDMAC_IRQn))) {
00159         NVIC_SetPriority( XDMAC_IRQn ,1);
00160         /* Enable interrupt  */ 
00161         NVIC_EnableIRQ(XDMAC_IRQn);
00162     }
00163     return 0;
00164 }
00165 
00166 /**
00167  * \brief Configure the SPI/SMC tx/rx DMA.
00168  * \returns 0 if the xDMA configuration successfully; otherwise returns
00169  * ILI9488_ERROR_XXX.
00170  */
00171 static uint8_t _ILI9488_SpiDmaConfigureRxTx(void)
00172 {
00173     uint32_t txAddress,rxAddress;
00174     sXdmad *pXdmad;
00175     pXdmad = ili9488DmaSpiMode.xdmaD;
00176 
00177     txAddress = (uint32_t)&ILI9488_SPI->SPI_TDR;
00178     rxAddress = (uint32_t)&ILI9488_SPI->SPI_RDR;
00179     
00180     /* Setup DMA TX channel */
00181     ili9488DmaSpiMode.xdmadTxCfg.mbr_sa = 0;
00182     ili9488DmaSpiMode.xdmadTxCfg.mbr_da = txAddress;
00183     ili9488DmaSpiMode.xdmadTxCfg.mbr_ubc = 0; 
00184 
00185     ili9488DmaSpiMode.xdmadTxCfg.mbr_cfg
00186                     = XDMAC_CC_TYPE_PER_TRAN 
00187                     | XDMAC_CC_MBSIZE_SINGLE 
00188                     | XDMAC_CC_DSYNC_MEM2PER
00189                     | XDMAC_CC_DWIDTH_BYTE 
00190                     | XDMAC_CC_CSIZE_CHK_1 
00191                     | XDMAC_CC_SIF_AHB_IF0 
00192                     | XDMAC_CC_DIF_AHB_IF1 
00193                     | XDMAC_CC_SAM_INCREMENTED_AM 
00194                     | XDMAC_CC_DAM_FIXED_AM 
00195                     | XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber
00196                         (ili9488DmaSpiMode.spiId, XDMAD_TRANSFER_TX ));
00197 
00198     ili9488DmaSpiMode.xdmadTxCfg.mbr_bc = 0;
00199     ili9488DmaSpiMode.xdmadTxCfg.mbr_sus = 0;
00200     ili9488DmaSpiMode.xdmadTxCfg.mbr_dus = 0;
00201 
00202     /* Setup RX DMA channel */
00203     ili9488DmaSpiMode.xdmadRxCfg.mbr_ubc  = 0; 
00204     ili9488DmaSpiMode.xdmadRxCfg.mbr_da = 0;
00205     ili9488DmaSpiMode.xdmadRxCfg.mbr_sa = rxAddress;
00206 
00207     ili9488DmaSpiMode.xdmadRxCfg.mbr_cfg = 
00208                     XDMAC_CC_TYPE_PER_TRAN 
00209                     | XDMAC_CC_MBSIZE_SINGLE 
00210                     | XDMAC_CC_DSYNC_PER2MEM
00211                     | XDMAC_CC_CSIZE_CHK_1 
00212                     | XDMAC_CC_DWIDTH_WORD
00213                     | XDMAC_CC_SIF_AHB_IF1 
00214                     | XDMAC_CC_DIF_AHB_IF0 
00215                     | XDMAC_CC_SAM_FIXED_AM 
00216                     | XDMAC_CC_DAM_INCREMENTED_AM
00217                     | XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber
00218                         (ili9488DmaSpiMode.spiId, XDMAD_TRANSFER_RX ));
00219     ili9488DmaSpiMode.xdmadRxCfg.mbr_bc = 0;
00220     ili9488DmaSpiMode.xdmadRxCfg.mbr_sus = 0;
00221     ili9488DmaSpiMode.xdmadRxCfg.mbr_dus =0;
00222 
00223     /* Put all interrupts on for non LLI list setup of DMA */
00224     ili9488DmaSpiMode.xdmaInt =  (XDMAC_CIE_BIE 
00225                         | XDMAC_CIE_RBIE
00226                         | XDMAC_CIE_WBIE
00227                         | XDMAC_CIE_ROIE);
00228 
00229     if (XDMAD_ConfigureTransfer( pXdmad, ili9488DmaSpiMode.ili9488DmaRxChannel,
00230                     &ili9488DmaSpiMode.xdmadRxCfg, 0, 0, ili9488DmaSpiMode.xdmaInt))
00231         return ILI9488_ERROR_DMA_CONFIGURE;
00232 
00233     if (XDMAD_ConfigureTransfer( pXdmad, ili9488DmaSpiMode.ili9488DmaTxChannel,
00234                     &ili9488DmaSpiMode.xdmadTxCfg, 0, 0, ili9488DmaSpiMode.xdmaInt))
00235         return ILI9488_ERROR_DMA_CONFIGURE;
00236     return 0;
00237 }
00238 
00239 /**
00240  * \brief Update Rx/Tx DMA configuration with new buffer address and buffer size.
00241  * \param pTxBuffer point to Tx buffer address
00242  * \param wTxSize  Tx buffer size in byte
00243  * \param pRxBuffer point to Rx buffer address
00244  * \param wRxSize Rx buffer size in byte
00245  * \returns 0 if the xDMA configuration successfully; otherwise returns
00246  * ILI9488_DMA_ERROR_XXX.
00247  */
00248 static uint8_t _ILI9488_SpiDmaUpdateBuffer(uint8_t *pTxBuffer,uint32_t wTxSize,
00249                 uint32_t *pRxBuffer,uint32_t wRxSize)
00250 {
00251     sXdmad *pXdmad;
00252     pXdmad = ili9488DmaSpiMode.xdmaD;
00253     
00254     ili9488DmaSpiMode.xdmadTxCfg.mbr_sa = (uint32_t)pTxBuffer;
00255     ili9488DmaSpiMode.xdmadTxCfg.mbr_ubc = wTxSize;
00256     if (wRxSize) {
00257         ili9488DmaSpiMode.xdmadRxCfg.mbr_da = (uint32_t)pRxBuffer;
00258         ili9488DmaSpiMode.xdmadRxCfg.mbr_ubc = wRxSize;
00259         if (XDMAD_ConfigureTransfer( pXdmad, ili9488DmaSpiMode.ili9488DmaRxChannel, 
00260                     &ili9488DmaSpiMode.xdmadRxCfg, 0, 0, ili9488DmaSpiMode.xdmaInt))
00261         return ILI9488_ERROR_DMA_CONFIGURE;
00262     }
00263     if (XDMAD_ConfigureTransfer( pXdmad, ili9488DmaSpiMode.ili9488DmaTxChannel, 
00264                     &ili9488DmaSpiMode.xdmadTxCfg, 0, 0, ili9488DmaSpiMode.xdmaInt))
00265         return ILI9488_ERROR_DMA_CONFIGURE;
00266     return 0;
00267 }
00268 
00269 /*----------------------------------------------------------------------------
00270  *        Exported functions
00271  *----------------------------------------------------------------------------*/
00272 /**
00273  * \brief Initialize ILI9488 driver with DMA support.
00274  * \returns 0 if the xDMA configuration successfully; otherwise returns
00275  * ILI9488_DMA_ERROR_XXX.
00276  */
00277 uint8_t ILI9488_SpiInitializeWithDma(sXdmad * dmad)
00278 {
00279     _ILI9488_SpiDmaInitialize(dmad);
00280     if (_ILI9488_SpiDmaConfigChannels()) return ILI9488_ERROR_DMA_ALLOCATE_CHANNEL;
00281     if(_ILI9488_SpiDmaConfigureRxTx()) return ILI9488_ERROR_DMA_CONFIGURE;
00282     return 0;
00283 }
00284 
00285 /**
00286  * \brief Start ILI9488 DMA transfer .
00287  * \param pTxBuffer point to Tx buffer address
00288  * \param wTxSize  Tx buffer size in byte
00289  * \returns 0 if the xDMA configuration successfully; otherwise returns
00290  * ILI9488_DMA_ERROR_XXX.
00291  */
00292 uint8_t ILI9488_SpiDmaTxTransfer( uint8_t *pTxBuffer, uint32_t wTxSize)
00293 {
00294     while(!ili9488DmaCtlInSpiMode.txDoneFlag);
00295     _ILI9488_SpiDmaUpdateBuffer(pTxBuffer, wTxSize, 0, 0);
00296     SCB_CleanInvalidateDCache();
00297     ili9488DmaCtlInSpiMode.txDoneFlag = 0;
00298     if (XDMAD_StartTransfer( 
00299         ili9488DmaSpiMode.xdmaD, ili9488DmaSpiMode.ili9488DmaTxChannel))
00300         return ILI9488_ERROR_DMA_TRANSFER;
00301     while(!ili9488DmaCtlInSpiMode.txDoneFlag);
00302     return 0;
00303 }
00304 
00305 /**
00306  * \brief Start ILI9488 DMA Rx transfer .
00307  * \param pRxBuffer point to Rx buffer address
00308  * \param wRxSize Rx buffer size in byte
00309  * \returns 0 if the xDMA transfer successfully; otherwise returns 
00310  * ILI9488_DMA_ERROR_XXX.
00311  */
00312 uint8_t ILI9488_SpiDmaRxTransfer(uint32_t *pRxBuffer,uint32_t wRxSize)
00313 {
00314     //_ILI9488_SpiDmaUpdateBuffer(dummyTxBuffer, wRxSize, pRxBuffer, wRxSize);
00315     _ILI9488_SpiDmaUpdateBuffer((uint8_t*)pRxBuffer,wRxSize, (uint32_t*)pRxBuffer, wRxSize);
00316     SCB_CleanInvalidateDCache();
00317     if (XDMAD_StartTransfer( ili9488DmaSpiMode.xdmaD, ili9488DmaSpiMode.ili9488DmaRxChannel))
00318         return ILI9488_ERROR_DMA_TRANSFER;
00319 
00320     if (XDMAD_StartTransfer( ili9488DmaSpiMode.xdmaD, ili9488DmaSpiMode.ili9488DmaTxChannel))
00321         return ILI9488_ERROR_DMA_TRANSFER;
00322     return 0;
00323 }
00324 
00325 /**
00326  * \brief Start ILI9488 DMA Rx transfer .
00327  * \param Instr Instruct 
00328  * \param pTxData point to Tx buffer address
00329  * \param pRxData point to Rx buffer address
00330  * \param ReadWrite Command/Write/Read access
00331  * \param Size buffer size in byte
00332  * \returns 0
00333  */
00334 uint8_t ILI9488_SpiSendCommand(uint8_t Instr, uint8_t *pTxData,
00335         uint32_t *pRxData, AccessIli_t ReadWrite, uint32_t size)
00336 {
00337     if(ReadWrite == AccessInst) {
00338         PIO_Clear(&lcd_spi_cds_pin);
00339         ili9488DmaCtlInSpiMode.cmdOrDataFlag = 1;
00340         return ILI9488_SpiDmaTxTransfer( &Instr, 1 );
00341     } else if (ReadWrite == AccessWrite) {
00342         PIO_Clear(&lcd_spi_cds_pin);
00343         ili9488DmaCtlInSpiMode.cmdOrDataFlag = 1;
00344         ILI9488_SpiDmaTxTransfer( &Instr, 1 );
00345         if(size == 0) return 0;
00346         ILI9488_SpiDmaTxTransfer( pTxData, size);
00347         return 0;
00348     } else {
00349         ili9488DmaCtlInSpiMode.rxDoneFlag = 0;
00350         ILI9488_SpiDmaRxTransfer( pRxData, size);
00351         while(!ili9488DmaCtlInSpiMode.rxDoneFlag);
00352     }
00353     return 0;
00354 }
00355 
00356 #endif  //BOARD_LCD_ILI9488
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines