SAMV71 Xplained Ultra Software Package 1.5

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