SAMV71 Xplained Ultra Software Package 1.5

ili9488_spi_dma.c

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