SAMV71 Xplained Ultra Software Package 1.4

ili9488_ebi_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_ebi_cds_pin = BOARD_EBI_LCD_PIN_CDS;
00052 
00053 static sIli9488Dma         ili9488EbiDma;
00054 static sIli9488DmaCtl      ili9488DmaCtlInEbiMode;
00055 
00056 /*----------------------------------------------------------------------------
00057  *        Local functions
00058  *----------------------------------------------------------------------------*/
00059 /**
00060  * \brief Configure SMC timing for static memory (LCD)
00061  */
00062 static void _ILI9488_ConfigureSmc( void )
00063 {
00064     /* Enable peripheral clock */
00065     PMC_EnablePeripheral( ID_SMC ) ;
00066 
00067     /* Configure SMC, NCS3 is assigned to LCD */
00068 
00069     SMC->SMC_CS_NUMBER[SMC_EBI_LCD_CS].SMC_SETUP = SMC_SETUP_NWE_SETUP(2)
00070                                      | SMC_SETUP_NCS_WR_SETUP(0)
00071                                      | SMC_SETUP_NRD_SETUP(0)
00072                                      | SMC_SETUP_NCS_RD_SETUP(0);
00073 
00074     SMC->SMC_CS_NUMBER[SMC_EBI_LCD_CS].SMC_PULSE = SMC_PULSE_NWE_PULSE(6)
00075                                      | SMC_PULSE_NCS_WR_PULSE(0xA)
00076                                      | SMC_PULSE_NRD_PULSE(0xA)
00077                                      | SMC_PULSE_NCS_RD_PULSE(0xA);
00078 
00079     SMC->SMC_CS_NUMBER[SMC_EBI_LCD_CS].SMC_CYCLE = SMC_CYCLE_NWE_CYCLE(0xA)
00080                                      | SMC_CYCLE_NRD_CYCLE(0xA);
00081 
00082     SMC->SMC_CS_NUMBER[SMC_EBI_LCD_CS].SMC_MODE  = SMC_MODE_READ_MODE
00083                                      | SMC_MODE_WRITE_MODE
00084                                      | SMC_MODE_DBW_16_BIT
00085                                      | SMC_MODE_EXNW_MODE_DISABLED
00086                                      | SMC_MODE_TDF_CYCLES(0xF);
00087 }
00088 
00089 /**
00090  * \brief ILI9488_EBI xDMA Rx callback
00091  */ 
00092 static void _ILI9488_Ebi_Rx_CB(void)
00093 {
00094     if(!ili9488DmaCtlInEbiMode.cmdOrDataFlag){
00095         ili9488DmaCtlInEbiMode.rxDoneFlag = 1;
00096         memory_barrier()
00097     }
00098 }
00099 
00100 /**
00101  * \brief ILI9488_EBI xDMA Tx callback
00102  */ 
00103 static void _ILI9488_Ebi_Tx_CB(void)
00104 {
00105     volatile uint32_t i;
00106     if(ili9488DmaCtlInEbiMode.cmdOrDataFlag) {
00107         for(i = 0; i<0xF; i++);
00108         PIO_Set(&lcd_ebi_cds_pin);
00109         ili9488DmaCtlInEbiMode.cmdOrDataFlag = 0;
00110     }
00111     ili9488DmaCtlInEbiMode.txDoneFlag = 1;
00112 }
00113 
00114 /**
00115  * \brief Initializes the ILI9488 DMA structure and the corresponding DMA hardware.
00116  * select value.
00117  */
00118 static void _ILI9488_EbiDmaInitialize(sXdmad * dmad)
00119 {
00120     ili9488DmaCtlInEbiMode.cmdOrDataFlag = 1;
00121     ili9488DmaCtlInEbiMode.rxDoneFlag = 0;
00122     ili9488DmaCtlInEbiMode.txDoneFlag = 1;
00123 
00124     ili9488EbiDma.xdmaD = dmad;
00125     ili9488EbiDma.xdmaD->pXdmacs = XDMAC;
00126     ili9488EbiDma.ili9488DmaTxChannel = 0;
00127     ili9488EbiDma.ili9488DmaRxChannel = 0;
00128     ili9488EbiDma.xdmaInt = 0;
00129     ili9488EbiDma.pSpiHw = 0;
00130     ili9488EbiDma.spiId = 0;
00131 }
00132 
00133 /**
00134  * \brief This function initialize the appropriate DMA channel for Rx/Tx channel 
00135  * of SPI or SMC.
00136  * \returns             0 if the transfer has been started successfully;
00137  * otherwise returns
00138  * ILI9488_ERROR_XX is the driver is in use, or ILI9488_ERROR_XX if the command 
00139  * is not valid.
00140  */
00141 static uint8_t _ILI9488_EbiDmaConfigChannels(void)
00142 {
00143     uint32_t srcType,dstType;
00144 
00145     /* Driver initialize */
00146     XDMAD_Initialize(  ili9488EbiDma.xdmaD, 0 );
00147 
00148     XDMAD_FreeChannel( ili9488EbiDma.xdmaD, ili9488EbiDma.ili9488DmaTxChannel);
00149     XDMAD_FreeChannel( ili9488EbiDma.xdmaD, ili9488EbiDma.ili9488DmaRxChannel);
00150 
00151     srcType = XDMAD_TRANSFER_MEMORY;
00152     dstType = XDMAD_TRANSFER_MEMORY;
00153 
00154     /* Allocate a DMA channel for  ILI9488_SPI TX. */
00155     ili9488EbiDma.ili9488DmaTxChannel = 
00156         XDMAD_AllocateChannel( ili9488EbiDma.xdmaD, srcType, dstType);
00157     if ( ili9488EbiDma.ili9488DmaTxChannel == XDMAD_ALLOC_FAILED ) {
00158         return ILI9488_ERROR_DMA_ALLOCATE_CHANNEL;
00159     }
00160 
00161     /* Allocate a DMA channel for ILI9488_SPI  RX. */
00162     ili9488EbiDma.ili9488DmaRxChannel = 
00163         XDMAD_AllocateChannel( ili9488EbiDma.xdmaD, dstType, srcType);
00164     if ( ili9488EbiDma.ili9488DmaRxChannel == XDMAD_ALLOC_FAILED ) {
00165             return ILI9488_ERROR_DMA_ALLOCATE_CHANNEL; 
00166     }
00167 
00168     /* Setup callbacks for ILI9488_SPI RX */
00169     XDMAD_SetCallback(ili9488EbiDma.xdmaD, ili9488EbiDma.ili9488DmaRxChannel, 
00170         (XdmadTransferCallback)_ILI9488_Ebi_Rx_CB, &ili9488EbiDma);
00171     if (XDMAD_PrepareChannel( ili9488EbiDma.xdmaD, ili9488EbiDma.ili9488DmaRxChannel ))
00172         return ILI9488_ERROR_DMA_ALLOCATE_CHANNEL;
00173 
00174     /* Setup callbacks for ILI9488_SPI  TX (ignored) */
00175     XDMAD_SetCallback(ili9488EbiDma.xdmaD, ili9488EbiDma.ili9488DmaTxChannel, 
00176         (XdmadTransferCallback)_ILI9488_Ebi_Tx_CB, &ili9488EbiDma);
00177     if ( XDMAD_PrepareChannel( ili9488EbiDma.xdmaD, ili9488EbiDma.ili9488DmaTxChannel ))
00178         return  ILI9488_ERROR_DMA_ALLOCATE_CHANNEL;
00179 
00180     /* Check if DMA IRQ is enable; if not Enable it */
00181     if(!(NVIC_GetActive(XDMAC_IRQn))) {
00182         NVIC_SetPriority( XDMAC_IRQn ,1);
00183         /* Enable interrupt  */ 
00184         NVIC_EnableIRQ(XDMAC_IRQn);
00185     }
00186     return 0;
00187 }
00188 
00189 /**
00190  * \brief Configure the SPI/SMC tx/rx DMA in SMC mode.
00191  * \returns 0 if the xDMA configuration successfully; otherwise returns
00192  * ILI9488_ERROR_XXX.
00193  */
00194 static uint8_t _ILI9488_EbiDmaConfigureRxTx(void)
00195 {
00196     uint32_t txAddress,rxAddress;
00197     sXdmad *pXdmad;
00198     pXdmad = ili9488EbiDma.xdmaD;
00199 
00200     txAddress = rxAddress =(uint32_t)ILI9488_BASE_ADDRESS;
00201 
00202     /* Setup DMA TX channel */
00203     ili9488EbiDma.xdmadTxCfg.mbr_sa = 0;
00204     ili9488EbiDma.xdmadTxCfg.mbr_da = txAddress;
00205     ili9488EbiDma.xdmadTxCfg.mbr_ubc = 0;
00206 
00207     ili9488EbiDma.xdmadTxCfg.mbr_cfg = 
00208           XDMAC_CC_TYPE_MEM_TRAN 
00209         | XDMAC_CC_MBSIZE_SINGLE 
00210         | XDMAC_CC_CSIZE_CHK_1 
00211         | XDMAC_CC_DWIDTH_HALFWORD
00212         | XDMAC_CC_SIF_AHB_IF0 
00213         | XDMAC_CC_DIF_AHB_IF1 
00214         | XDMAC_CC_SAM_INCREMENTED_AM 
00215         | XDMAC_CC_DAM_FIXED_AM;
00216 
00217     ili9488EbiDma.xdmadTxCfg.mbr_bc = 0;
00218     ili9488EbiDma.xdmadTxCfg.mbr_sus = 0;
00219     ili9488EbiDma.xdmadTxCfg.mbr_dus = 0;
00220 
00221     /* Setup RX DMA channel */
00222     ili9488EbiDma.xdmadRxCfg.mbr_ubc = 
00223             XDMA_UBC_NVIEW_NDV0 | XDMA_UBC_NDE_FETCH_DIS | XDMA_UBC_NDEN_UPDATED ;
00224     ili9488EbiDma.xdmadRxCfg.mbr_da = 0;
00225     ili9488EbiDma.xdmadRxCfg.mbr_sa = rxAddress;
00226 
00227     ili9488EbiDma.xdmadRxCfg.mbr_cfg = 
00228                 XDMAC_CC_TYPE_MEM_TRAN 
00229                 | XDMAC_CC_MBSIZE_SINGLE 
00230                 | XDMAC_CC_CSIZE_CHK_1 
00231                 | XDMAC_CC_DWIDTH_WORD
00232                 | XDMAC_CC_SIF_AHB_IF1 
00233                 | XDMAC_CC_DIF_AHB_IF0 
00234                 | XDMAC_CC_SAM_FIXED_AM 
00235                 | XDMAC_CC_DAM_INCREMENTED_AM;
00236 
00237     ili9488EbiDma.xdmadRxCfg.mbr_bc = 0;
00238     ili9488EbiDma.xdmadRxCfg.mbr_sus = 0;
00239     ili9488EbiDma.xdmadRxCfg.mbr_dus =0;
00240 
00241     /* Put all interrupts on for non LLI list setup of DMA */
00242     ili9488EbiDma.xdmaInt =  (XDMAC_CIE_BIE 
00243                           | XDMAC_CIE_RBIE
00244                           | XDMAC_CIE_WBIE
00245                           | XDMAC_CIE_ROIE);
00246 
00247     if (XDMAD_ConfigureTransfer( pXdmad, ili9488EbiDma.ili9488DmaRxChannel, 
00248             &ili9488EbiDma.xdmadRxCfg, 0, 0, ili9488EbiDma.xdmaInt))
00249         return ILI9488_ERROR_DMA_CONFIGURE;
00250 
00251     if (XDMAD_ConfigureTransfer( pXdmad, ili9488EbiDma.ili9488DmaTxChannel, 
00252             &ili9488EbiDma.xdmadTxCfg, 0, 0, ili9488EbiDma.xdmaInt))
00253         return ILI9488_ERROR_DMA_CONFIGURE;
00254     return 0;
00255 }
00256 
00257 /**
00258  * \brief Update Rx/Tx DMA configuration with new buffer address and buffer size.
00259  * \param pTxBuffer point to Tx buffer address
00260  * \param wTxSize  Tx buffer size in byte
00261  * \param pRxBuffer point to Rx buffer address
00262  * \param wRxSize Rx buffer size in byte
00263  * \returns 0 if the xDMA configuration successfully; otherwise returns
00264  * ILI9488_DMA_ERROR_XXX.
00265  */
00266 static uint8_t _ILI9488_EbiDmaUpdateBuffer(uint16_t *pTxBuffer,uint32_t wTxSize, 
00267                                         uint32_t *pRxBuffer,uint32_t wRxSize)
00268 {
00269     sXdmad *pXdmad;
00270     pXdmad = ili9488EbiDma.xdmaD;
00271 
00272     ili9488EbiDma.xdmadTxCfg.mbr_sa = (uint32_t)pTxBuffer;
00273     ili9488EbiDma.xdmadTxCfg.mbr_ubc = wTxSize;
00274     if (wRxSize) {
00275         ili9488EbiDma.xdmadRxCfg.mbr_da = (uint32_t)pRxBuffer;
00276         ili9488EbiDma.xdmadRxCfg.mbr_ubc = wRxSize;
00277         if (XDMAD_ConfigureTransfer( pXdmad, ili9488EbiDma.ili9488DmaRxChannel, 
00278                 &ili9488EbiDma.xdmadRxCfg, 0, 0, ili9488EbiDma.xdmaInt))
00279             return ILI9488_ERROR_DMA_CONFIGURE;
00280     }
00281     if (XDMAD_ConfigureTransfer( pXdmad, ili9488EbiDma.ili9488DmaTxChannel, 
00282             &ili9488EbiDma.xdmadTxCfg, 0, 0, ili9488EbiDma.xdmaInt))
00283         return ILI9488_ERROR_DMA_CONFIGURE;
00284     return 0;
00285 }
00286 
00287 
00288 /*----------------------------------------------------------------------------
00289  *        Exported functions
00290  *----------------------------------------------------------------------------*/
00291 /**
00292  * \brief Initialize ILI9488 driver with DMA support.
00293  * \returns 0 if the xDMA configuration successfully; otherwise returns
00294  * ILI9488_DMA_ERROR_XXX.
00295  */
00296 uint8_t ILI9488_EbiInitializeWithDma(sXdmad * dmad)
00297 {
00298     _ILI9488_ConfigureSmc();
00299     _ILI9488_EbiDmaInitialize(dmad);
00300     if (_ILI9488_EbiDmaConfigChannels()) return ILI9488_ERROR_DMA_ALLOCATE_CHANNEL;
00301     if(_ILI9488_EbiDmaConfigureRxTx()) return ILI9488_ERROR_DMA_CONFIGURE;
00302     return 0;
00303 }
00304 
00305 /**
00306  * \brief Start ILI9488 DMA transfer in SMC mode.
00307  * \param pTxBuffer point to Tx buffer address
00308  * \param wTxSize  Tx buffer size in byte
00309  * \returns 0 if the xDMA configuration successfully; otherwise returns
00310  * ILI9488_DMA_ERROR_XXX.
00311  */
00312 uint8_t ILI9488_EbiDmaTxTransfer( uint16_t *pTxBuffer,uint32_t wTxSize)
00313 {
00314     _ILI9488_EbiDmaUpdateBuffer(pTxBuffer, wTxSize, 0, 0);
00315     SCB_CleanInvalidateDCache();
00316     if (XDMAD_StartTransfer( ili9488EbiDma.xdmaD, ili9488EbiDma.ili9488DmaTxChannel))
00317         return ILI9488_ERROR_DMA_TRANSFER;
00318     while(!ili9488DmaCtlInEbiMode.txDoneFlag);
00319     ili9488DmaCtlInEbiMode.txDoneFlag = 0;
00320 
00321     return 0;
00322 }
00323 
00324 /**
00325  * \brief Start ILI9488 DMA Rx transfer in SMC mode.
00326  * \param pRxBuffer point to Rx buffer address
00327  * \param wRxSize Rx buffer size in byte
00328  * \returns 0 if the xDMA transfer successfully; otherwise returns 
00329  * ILI9488_DMA_ERROR_XXX.
00330  */
00331 uint8_t ILI9488_EbiDmaRxTransfer(uint32_t *pRxBuffer,uint32_t wRxSize)
00332 {
00333     uint16_t dummyTxBuffer[5];
00334 
00335     _ILI9488_EbiDmaUpdateBuffer(dummyTxBuffer, wRxSize, pRxBuffer, wRxSize);
00336 
00337     SCB_CleanInvalidateDCache();
00338     if (XDMAD_StartTransfer( ili9488EbiDma.xdmaD, ili9488EbiDma.ili9488DmaRxChannel))
00339         return ILI9488_ERROR_DMA_TRANSFER;
00340 
00341     return 0;
00342 }
00343 
00344 /**
00345  * \brief Start ILI9488 DMA Rx transfer .
00346  * \param Instr Instruct 
00347  * \param pTxData point to Tx buffer address
00348  * \param pRxData point to Rx buffer address
00349  * \param ReadWrite Command/Write/Read access
00350  * \param Size buffer size in byte
00351  * \returns 0
00352  */
00353 uint8_t ILI9488_EbiSendCommand(uint16_t Instr, uint16_t *pTxData,
00354         uint32_t *pRxData, AccessIli_t ReadWrite, uint32_t size)
00355 {
00356     if(ReadWrite == AccessInst) {
00357         PIO_Clear(&lcd_ebi_cds_pin);
00358         ili9488DmaCtlInEbiMode.cmdOrDataFlag = 1;
00359         return ILI9488_EbiDmaTxTransfer( &Instr, 1 );
00360     } else if (ReadWrite == AccessWrite) {
00361         PIO_Clear(&lcd_ebi_cds_pin);
00362         ili9488DmaCtlInEbiMode.cmdOrDataFlag = 1;
00363         ILI9488_EbiDmaTxTransfer( &Instr, 1 );
00364         if(size == 0) return 0;
00365         ILI9488_EbiDmaTxTransfer( pTxData, size);
00366         return 0;
00367     } else {
00368         ili9488DmaCtlInEbiMode.rxDoneFlag = 0;
00369         ILI9488_EbiDmaRxTransfer( pRxData, size);
00370         while(!ili9488DmaCtlInEbiMode.rxDoneFlag);
00371     }
00372     return 0;
00373 }
00374 #endif  //BOARD_LCD_ILI9488
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines