This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM3352: LCDC DMA not working

Part Number: AM3352

Hi,

I'm running the Sitara LCD interface under TiRTOS, in LIDD mode, to an ILI9341 based display, and everything is working fine except that I can't get the LCDC DMA unit to work at all.

The display gets initialized, and addresses written etc., using normal non-DMA writes.  And up until now I have been downloading the display image byte-by-byte in a tight little loop. But for a faster transfer of the entire display image I wanted to switch to DMA mode, send the data, then switch back when the transfer has completed.

Below is a dump of the LCDC registers immediately prior to setting the lidd_dma_en bit to launch the transfer.  I can't show a dump with this bit set, as -- and this is the first bit of weirdness -- reading the registers while in LIDD DMA mode causes a hard crash, with the CPU completely off in the weeds.  The documentation does indicate that the reads and writes to the LIDD_CSx_DATA registers are not permitted in LIDD DMA mode, but a hard crash is an unusual response.

The other bit of weirdness that I see is that when I enable the DMA clock, along with the core and LIDD clocks, via the CLKC_ENABLE register during normal post power up initialization, the DMA clock enable doesn't stick.  When I go to start the first DMA transfer it has been cleared.  This is easily overcome by enabling the clock prior to the transfer, but it does seem odd.

I don't have any of the interrupts enabled, intending simply to poll the done bit in IRQSTATUS_RAW.  But we never get there.  In fact, looking at the LCD CSX output on the scope shows no activity whatsoever when DMA is launched.

If anyone can see the problem here I would be more than happy to be shown the error of my ways!

Thanks,
GerryL

  • The RTOS team have been notified. They will respond here.
  • Hi,

    Can you clarify what Processor SDK RTOS release and test example you used for this?

    Regards, Eric
  • Hi Eric,

    The SDK is pdk_am335x_1_0_3.  I'm not using any particular test example or driver, but going direct to hardware via calls at the HW_WR_REG32 level.

    Everything else is working fine -- it's just the DMA that won't budge.

    Thanks,
    Gerry

  • Hi Gerry,

    Thanks! Do you have the code portion for enable DMA clock, setup DMA and starts transfer? Do you refer to any existing code in pdk_am335x_1_0_x for that?

    Regards, Eric
  • Hi Eric,

    File attached below.  I've copied in a number external functions at the end of the file, so it should be pretty much self-contained.

    There are some references to "gDisplay" and "gdisp" etc. which are part of the uGFX graphics package that I am using.  They don't impact the transfer function itself.  When the package interfaces with the display it is through the functions write_index() and/or write_data(), which are shown.

    The main transfer function is board_ILI9341_DXD16_CopyAll(), at line 236.

    Thanks,
    GerryL

    /* NAME
     *    board_ILI9341_DXD16.c
     *
     * COPYRIGHT AND LICENSE
     *    Copyright 2018 Session Control LLC
     *
     *    Licensed under the Apache License, Version 2.0 (the "License");
     *    you may not use this file except in compliance with the License.
     *    You may obtain a copy of the License at
     *
     *        http://www.apache.org/licenses/LICENSE-2.0
     *
     *    Unless required by applicable law or agreed to in writing, software
     *    distributed under the License is distributed on an "AS IS" BASIS,
     *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     *    See the License for the specific language governing permissions and
     *    limitations under the License.
     *
     * DESCRIPTION
     *    Interface to display for uGFX
     *
     * REVISION HISTORY
     *    180610   Initial version
     */
    
    
    /* -----------------------------------------------------------------------
       Steering flags . .
       ----------------------------------------------------------------------- */
    
    #define  USE_DMA
    
    
    /* -----------------------------------------------------------------------
       Includes . .
       ----------------------------------------------------------------------- */
    
    #include "gfx.h"
    #include "src\gdisp\gdisp.h"
    #include "src\gdisp\gdisp_driver.h"
    
    // #include "board_ILI9341_DXD16.h" <<< relevant portions copied into this file
    
    #include "sc1Types.h"
    // #include "sc1Cpu_TiAM335x.h"
    // #include <stdint.h>
    
    #include "ti\starterware\include\lcdc.h"           /* mostly raster mode & interrupt controls -- might use some func's */
    #include "ti\starterware\include\hw\hw_lcdc.h"     /* register addresses and masks */
    #include "ti\starterware\include\hw\hw_types.h"    /* TI hw access macros */
    #include "ti\starterware\include\hw\soc_am335x.h"  /* for base address SOC_LCDC_0_REGS */
    
    
    /* -----------------------------------------------------------------------
       Definitions . .
       ----------------------------------------------------------------------- */
    
       ////////////////////////////////////
       // Clock setup . .
       // - DPLL output = LCD_CLK
       // - "memclk" = MCLK = LCD_CLK / AM335X_LCDC_CLKDIV
       ////////////////////////////////////
    
    #define  AM335X_LCDC_DPLL_FREQ_MHZ  100
    #define  AM335X_LCDC_CLKDIV         1     /* retain 100MHz */
    
    
       ////////////////////////////////////
       // Read/write am335x LCD controller register . .
       // [see ti\starterware\include\hw\hw_types.h]
       ////////////////////////////////////
    
    #define  AM335X_LCDC_RD( regOfst )           (HW_RD_REG32( SOC_LCDC_0_REGS + regOfst ))
    #define  AM335X_LCDC_WR( regOfst , wrData )  (HW_WR_REG32((SOC_LCDC_0_REGS + regOfst ), wrData ))
    
    
       ////////////////////////////////////
       // Setup & hold durations in ns for ILI9341 . .
       // - based on AM335x LCD controller timing configuration (reg LIDD_CS0_CONF)
       ////////////////////////////////////
    
    #define  ILI9341_NS_WR_SETUP        0
    #define  ILI9341_NS_WR_STROBE       15
    #define  ILI9341_NS_WR_HOLD         51    /* total >= 66 */
    
    #define  ILI9341_NS_RD_SETUP        0
    #define  ILI9341_NS_RD_STROBE       355
    #define  ILI9341_NS_RD_HOLD         95    /* total >= 450 */
    
    
       ////////////////////////////////////
       // DMA priority . .
       ////////////////////////////////////
    
    #define  DMA_BUS_MASTER_PRIO        0  /* 0~7, 0=highest (dflt) */
    // #define  DMA_BUS_MASTER_PRIO        4  /* 0~7 */
    
    
    /* -----------------------------------------------------------------------
       typedefs, enums, structs . .
       ----------------------------------------------------------------------- */
    
    /* -----------------------------------------------------------------------
       Local variables . .
       ----------------------------------------------------------------------- */
    
    static const float   sMemClkPeriodF = 1000.0F / ((float)AM335X_LCDC_DPLL_FREQ_MHZ);
    
    
    /* -----------------------------------------------------------------------
       Local (static) prototypes . .
       ----------------------------------------------------------------------- */
    
    static UINT32 calcMemclkPerNsec(UINT32 nsec);
    static void   clkcReset        (UINT32 resetMask);
    
    
    /* -----------------------------------------------------------------------
       Public functions . .
       ----------------------------------------------------------------------- */
    
    
    /* -----------------------------------------------------------------------
       Initialization . .
       ----------------------------------------------------------------------- */
    
    void init_board(GDisplay *g)
    {
       UINT32   wrData;
    
       ////////////////////////////////////
       // Specific resets . .
       ////////////////////////////////////
    
       clkcReset( LCDC_CLKC_RESET_CORE_MASK
                | LCDC_CLKC_RESET_LIDD_MASK
                | LCDC_CLKC_RESET_DMA_MASK
                | LCDC_CLKC_RESET_MAIN_MASK );   // UINT32 resetMask)
    
    
       ////////////////////////////////////
       // Setup the LCD DPLL and local clock divider . .
       // - DPLL output = LCD_CLK = 100MHz
       // - "memclk" = MCLK = LCD_CLK / AM335X_LCDC_CLKDIV = 100MHz   [AM335X_LCDC_CLKDIV = 1]
       // (ignore errors)
       ////////////////////////////////////
    
       // DPLL freq . .
       sc1Cpu_TiAM335x_SetDpllFreqMHz(eDpll_Disp, AM335X_LCDC_DPLL_FREQ_MHZ);  // sc1Cpu_TiAM335x_DpllType dpllType, UINT32 freqMHz)
    
       // Use the DPLL output . .
       sc1Cpu_TiAM335x_SetLcdClkSource(eLcdClkSrc_DPLL_LCD); // sc1Cpu_TiAM335x_LcdClkSrc clkSrc)
    
       // CTRL register -- divide DPLL output by N (N=1) . .
       wrData = ((AM335X_LCDC_CLKDIV << LCDC_LCD_CTRL_CLKDIV_SHIFT) & LCDC_LCD_CTRL_CLKDIV_MASK);   // [divide by 1]
              // the rest zero
              // LCDC_LCD_CTRL_AUTO_UFLOW_RESTART_MANUAL
              // LCDC_LCD_CTRL_MODESEL_LIDD;
       AM335X_LCDC_WR( LCDC_LCD_CTRL , wrData );
    
    
       ////////////////////////////////////
       // Setup AM335x LCD controller registers . .
       // - values from hw_lcd.h
       // - other macros from hw_types.h
       // - raster mode, DMA, and IRQ settings left in default state (n/u)
       ////////////////////////////////////
    
       // Clock enables . .
       wrData = 0;
       HW_SET_FIELD(wrData, LCDC_CLKC_ENABLE_CORE, LCDC_CLKC_ENABLE_CORE_ENABLE);
    #ifdef USE_DMA
       HW_SET_FIELD(wrData, LCDC_CLKC_ENABLE_DMA , LCDC_CLKC_ENABLE_DMA_ENABLE);
    #else
       HW_SET_FIELD(wrData, LCDC_CLKC_ENABLE_DMA , LCDC_CLKC_ENABLE_DMA_DISABLE);
    #endif
       HW_SET_FIELD(wrData, LCDC_CLKC_ENABLE_LIDD, LCDC_CLKC_ENABLE_LIDD_ENABLE);
       AM335X_LCDC_WR( LCDC_CLKC_ENABLE , wrData );
    
       // Clock resets (not necessary)
    
       // LIDD_CTRL register . .
       wrData = LCDC_LIDD_CTRL_LIDD_MODE_SEL_SYNC_MPU80;  // no shift
              // the rest zero (ALE=D/CK, RDX, WRX, CSX all active low) . .
              // LCDC_LIDD_CTRL_ALEPOL_NOINVERT           for D/CX
              // LCDC_LIDD_CTRL_RS_EN_POL_NOINVERT
              // LCDC_LIDD_CTRL_WS_DIR_POL_NOINVERT
              // LCDC_LIDD_CTRL_CS0_E0_POL_NOINVERT
              // LCDC_LIDD_CTRL_CS1_E1_POL_NOINVERT
              // LCDC_LIDD_CTRL_LIDD_DMA_EN_DEACTIVATE
              // LCDC_LIDD_CTRL_DMA_CS0_CS1_DMACS0
       AM335X_LCDC_WR( LCDC_LIDD_CTRL , wrData );
    
    
       // LIDD_CS0_CONF = bus timing . .
       // - the timing parameters are defined by the LIDD_CS0_CONF and LIDD_CS1_CONF registers.
       // - the timing configuration is based on an internal reference clock, MCLK. The MCLK is generated
       //    out of LCD_CLK, which is determined by the CLKDIV bit in the LCD_CTRL register.
       //
       //       MCLK = LCD_CLK when CLKDIV = 0
       //
       //              LCD_CLK
       //       MCLK = ------- when CLKDIV != 0
       //              CLKDIV
       //
       // - note that HW_SET_FIELD takes partial register name
       //    #define HW_SET_FIELD(regVal, REG_FIELD, fieldVal)
       //        ((regVal) = ((regVal) & (uint32_t) (~(uint32_t) REG_FIELD##_MASK)) |
       //                        ((((uint32_t) fieldVal) << (uint32_t) REG_FIELD##_SHIFT) &
       //                        (uint32_t) REG_FIELD##_MASK))
       wrData = 0;
       HW_SET_FIELD(wrData, LCDC_LIDD_CS0_CONF_TA      , 0);
       HW_SET_FIELD(wrData, LCDC_LIDD_CS0_CONF_R_HOLD  , calcMemclkPerNsec(ILI9341_NS_RD_HOLD  ));
       HW_SET_FIELD(wrData, LCDC_LIDD_CS0_CONF_R_STROBE, calcMemclkPerNsec(ILI9341_NS_RD_STROBE));
       HW_SET_FIELD(wrData, LCDC_LIDD_CS0_CONF_R_SU    , calcMemclkPerNsec(ILI9341_NS_RD_SETUP ));
       HW_SET_FIELD(wrData, LCDC_LIDD_CS0_CONF_W_HOLD  , calcMemclkPerNsec(ILI9341_NS_WR_HOLD  ));
       HW_SET_FIELD(wrData, LCDC_LIDD_CS0_CONF_W_STROBE, calcMemclkPerNsec(ILI9341_NS_WR_STROBE));
       HW_SET_FIELD(wrData, LCDC_LIDD_CS0_CONF_W_SU    , calcMemclkPerNsec(ILI9341_NS_WR_SETUP ));
       AM335X_LCDC_WR( LCDC_LIDD_CS0_CONF , wrData );
    
    
       // System configuration . .
       wrData = 0;
       HW_SET_FIELD(wrData, LCDC_SYSCONFIG_IDLEMODE,    LCDC_SYSCONFIG_IDLEMODE_SMART   ); // or LCDC_SYSCONFIG_IDLEMODE_NOIDLE       (debug?)
       HW_SET_FIELD(wrData, LCDC_SYSCONFIG_STANDBYMODE, LCDC_SYSCONFIG_STANDBYMODE_SMART); //    LCDC_SYSCONFIG_STANDBYMODE_NOSTANDBY (debug?)
       AM335X_LCDC_WR( LCDC_SYSCONFIG , wrData );
    }
    
    
    /* ------------------------------------
       Clock calc . .
       ------------------------------------ */
    
    static UINT32 calcMemclkPerNsec(UINT32 nsec)
    {
       float cycles = ((float)nsec) / sMemClkPeriodF;
       return ((UINT32)(cycles + 0.9999F));
    }
    
    
    /* -----------------------------------------------------------------------
       Copy full display buffer to display . .
       - re-create gdispGBlitArea() full screen special case
       ----------------------------------------------------------------------- */
    
    void board_ILI9341_DXD16_CopyAll(GDisplay*      g,
                                     const pixel_t* surfaceP,
                                     coord_t        hWidth,
                                     coord_t        vHeight)
    {
       UINT32 h, v;
    
       gfxMutexEnter(&(g)->mutex);
       gdisp_lld_write_start(g);
    
    #ifdef USE_DMA
       // ================================================
    
    // +++___>>> added this reset later, but it didn't help
       clkcReset(LCDC_CLKC_RESET_LIDD_MASK | LCDC_CLKC_RESET_DMA_MASK);  // UINT32 resetMask)
    // <<<+++___
    
       // All clocks enabled . .
       // (apparently doing this during init doesn't hold)
       AM335X_LCDC_WR( LCDC_CLKC_ENABLE , 0x07 );
    
       // DMA control . .
       UINT32 dmaCtrl = 0;
       HW_SET_FIELD(dmaCtrl, LCDC_LCDDMA_CTRL_DMA_MASTER_PRIO , DMA_BUS_MASTER_PRIO);
       HW_SET_FIELD(dmaCtrl, LCDC_LCDDMA_CTRL_TH_FIFO_READY   , LCDC_LCDDMA_CTRL_TH_FIFO_READY_EIGHT);
       HW_SET_FIELD(dmaCtrl, LCDC_LCDDMA_CTRL_BURST_SIZE      , LCDC_LCDDMA_CTRL_BURST_SIZE_ONE);
       HW_SET_FIELD(dmaCtrl, LCDC_LCDDMA_CTRL_BYTE_SWAP       , 1);                                 // BYTE SWAP <<<<<<<
       HW_SET_FIELD(dmaCtrl, LCDC_LCDDMA_CTRL_BIGENDIAN       , LCDC_LCDDMA_CTRL_BIGENDIAN_OFF);    // NOT BIGENDIAN
       HW_SET_FIELD(dmaCtrl, LCDC_LCDDMA_CTRL_EOF_INTEN       , 0);                                 // no int enable (this bit doesn't show up in datasheet)
       HW_SET_FIELD(dmaCtrl, LCDC_LCDDMA_CTRL_FRAME_MODE      , LCDC_LCDDMA_CTRL_FRAME_MODE_ONE);   // single frame (no ping-pong)
       AM335X_LCDC_WR( LCDC_LCDDMA_CTRL , dmaCtrl );
    
       // Address base & ceiling reg's . .
       UINT32 imageBase =  ((UINT32)surfaceP)                           & LCDC_LCDDMA_FB0_BASE_FB0_BASE_MASK;
       UINT32 imageCeil = (((UINT32)surfaceP) + (hWidth * vHeight * 2)) & LCDC_LCDDMA_FB0_BASE_FB0_BASE_MASK;
       AM335X_LCDC_WR( LCDC_LCDDMA_FB0_BASE    , imageBase );
       AM335X_LCDC_WR( LCDC_LCDDMA_FB0_CEILING , imageCeil );
    
       // Now adjust the LIDD_CTRL register to enable the DMA . .
       // - dma_cs0_cs1 = 0
       // - lidd_dma_en = 1 <<< last (then dma begins)
       UINT32 liddCtrl = AM335X_LCDC_RD( LCDC_LIDD_CTRL );
       HW_SET_FIELD(liddCtrl, LCDC_LIDD_CTRL_DMA_CS0_CS1 , LCDC_LIDD_CTRL_DMA_CS0_CS1_DMACS0);
       HW_SET_FIELD(liddCtrl, LCDC_LIDD_CTRL_LIDD_DMA_EN , LCDC_LIDD_CTRL_LIDD_DMA_EN_ACTIVATE);
       AM335X_LCDC_WR( LCDC_LIDD_CTRL , liddCtrl );
    
       // Spin until DMA done . .
       while (TRUE) {
          UINT32 irqStatRaw = AM335X_LCDC_RD( LCDC_IRQSTATUS_RAW );
          if ((irqStatRaw & LCDC_IRQSTATUS_RAW_DONE_MASK) != 0) {
             break;
          }
       }
    
       // Adjust LIDD_CTRL register again to disable DMA . .
       liddCtrl = AM335X_LCDC_RD( LCDC_LIDD_CTRL );
       HW_SET_FIELD(liddCtrl, LCDC_LIDD_CTRL_LIDD_DMA_EN , LCDC_LIDD_CTRL_LIDD_DMA_EN_DEACTIVATE);
       AM335X_LCDC_WR( LCDC_LIDD_CTRL , liddCtrl );
    
    
       // [LCDC_IRQSTATUS_RAW:done should go away?] <<<<<<<<<<<<<<
    
       // Test reset required for DMA operation . .
       // - Errata: Advisory 1.0.27
       clkcReset(LCDC_CLKC_RESET_LIDD_MASK | LCDC_CLKC_RESET_DMA_MASK);  // UINT32 resetMask)
    
    
       // ================================================
    #else    // USE_DMA
       // ================================================
    
       // Non-DMA version works!
       volatile UINT32* cs0DataP = (volatile UINT32*)(SOC_LCDC_0_REGS + LCDC_LIDD_CS0_DATA);
    
       for (v=0; v<vHeight; v++) {
          for (h=0; h<hWidth; h++) {
             pixel_t p = *surfaceP++;
             *cs0DataP = p >> 8 ;
             *cs0DataP = (BYTE)p;
          }
       }
    #ifndef MEM_BARRIER_DISABLE
       asm("    dsb");   // instead of doing it after every write
    #endif
    
       // ================================================
    #endif   // USE_DMA
    
       gdisp_lld_write_stop(g);
       gfxMutexExit(&(g)->mutex);
    }
    
    
    /* ------------------------------------
       Resets . .
       ------------------------------------ */
    
    #define  CLKC_RESET_COUNTS          100
    #define  CLKC_RESET_RECOVERY        20
    
    volatile UINT32 vClkcResetDelay = 0;
    
    static void clkcReset(UINT32 resetMask)
    {
       AM335X_LCDC_WR( LCDC_CLKC_RESET , resetMask );
       for (vClkcResetDelay=0; vClkcResetDelay<CLKC_RESET_COUNTS; vClkcResetDelay++) {}
    
       AM335X_LCDC_WR( LCDC_CLKC_RESET , 0 );
       for (vClkcResetDelay=0; vClkcResetDelay<CLKC_RESET_RECOVERY; vClkcResetDelay++) {}
    }
    
    
    // ===========================================================================================================================
    // ===========================================================================================================================
    // External functions copied in:
    // ===========================================================================================================================
    // ===========================================================================================================================
    
    void gdisp_lld_write_start(GDisplay *g) {
    
       acquire_bus(g);
    
       set_viewport(g);
    
       write_index(g, 0x2C);
    }
    
    
    void gdisp_lld_write_stop(GDisplay *g) {
       release_bus(g);
    }
    
    
    static void acquire_bus(GDisplay *g)
    {
       // Bus always available
    }
    
    
    static void release_bus(GDisplay *g)
    {
       // Bus always available
    }
    
    
    static void set_viewport(GDisplay *g) {
       write_index(g, 0x2A);
       write_data(g, (g->p.x >> 8));
       write_data(g, (uint8_t) g->p.x);
       write_data(g, (g->p.x + g->p.cx - 1) >> 8);
       write_data(g, (uint8_t) (g->p.x + g->p.cx - 1));
    
       write_index(g, 0x2B);
       write_data(g, (g->p.y >> 8));
       write_data(g, (uint8_t) g->p.y);
       write_data(g, (g->p.y + g->p.cy - 1) >> 8);
       write_data(g, (uint8_t) (g->p.y + g->p.cy - 1));
    }
    
    
    static void write_index(GDisplay *g, uint16_t index)
    {
       AM335X_LCDC_WR( LCDC_LIDD_CS0_ADDR , index );   // causes bus transaction to ILI9341
    }
    
    
    static void write_data(GDisplay *g, uint16_t data)
    {
       AM335X_LCDC_WR( LCDC_LIDD_CS0_DATA , data );    // causes bus transaction to ILI9341
    }
    
    
    /* ------------------------------------
       DPLL Controls & Status . .
       ------------------------------------ */
    
    typedef enum sc1Cpu_TiAM335x_DpllTypeT
    {
       eDpll_Core,    // not supported for adjustment
       eDpll_MPU,
       eDpll_DDR,
       eDpll_Disp,
       eDpll_Periph,  // not supported for adjustment
       eDpll_Max
    
    } sc1Cpu_TiAM335x_DpllType;
    
    
    sc1Err sc1Cpu_TiAM335x_SetDpllFreqMHz(sc1Cpu_TiAM335x_DpllType dpllType, UINT32 freqMHz)
    {
       sc1Err err = eErr_None;
    
       switch (dpllType) {
          case eDpll_MPU:
          case eDpll_DDR:
          case eDpll_Disp:
             break;
          // case eDpll_Core:
          // case eDpll_Periph:
          default:
             err = eErr_FeatureUnsupported;
             break;
       }
    
       if (err == eErr_None) {
          // For now go with highest workable DCO freq . .
          UINT32 dpllPostDivM2 = (ADPLLS_DCO_MHZ_MAX / 2) / freqMHz;
          if ( (dpllPostDivM2 < 1                                                                                               )
          ||   (dpllPostDivM2 > (CM_WKUP_CM_DIV_M2_DPLL_MPU_DPLL_CLKOUT_DIV >> CM_WKUP_CM_DIV_M2_DPLL_MPU_DPLL_CLKOUT_DIV_SHIFT)) ) { // > 31
             err = eErr_DataOutOfRange;
          }
          else {
             UINT32 dpllMult;
             UINT32 dpllDiv;
    
             dpllMult = freqMHz * dpllPostDivM2;                // there's an additional div by 2 in the mult feedback path
             dpllDiv  = sc1Cpu_TiAM335x_GetXtalFreqMHz() - 1;   // ref always 1MHz
    
             sc1Os_assert((dpllMult <= ADPLLS_DCO_MHZ_MAX) && (dpllMult >= ADPLLS_DCO_MHZ_MIN)); // won't
    
             switch (dpllType) {
                case eDpll_MPU:
                   DpllSetMulDiv_MPU(dpllMult, dpllDiv, dpllPostDivM2);
                   break;
                case eDpll_DDR:
                   DpllSetMulDiv_DDR(dpllMult, dpllDiv, dpllPostDivM2);
                   break;
                case eDpll_Disp:
                   DpllSetMulDiv_Disp(dpllMult, dpllDiv, dpllPostDivM2);
                   break;
                // case eDpll_Core:
                // case eDpll_Periph:
                default:
                   break;
             }
          }
       }
       return err;
    }
    
    
    static void DpllSetMulDiv_Disp(UINT32 dpllMult,
                                   UINT32 dpllDiv,
                                   UINT32 dpllPostDivM2)
    {
        /* Put the PLL in bypass mode */
    
        HW_WR_FIELD32_RAW(SOC_CM_WKUP_REGS + CM_WKUP_CM_CLKMODE_DPLL_DISP,
            CM_WKUP_CM_CLKMODE_DPLL_DISP_DPLL_EN,
            CM_WKUP_CM_CLKMODE_DPLL_DISP_DPLL_EN_SHIFT,
            CM_WKUP_CM_CLKMODE_DPLL_DISP_DPLL_EN_DPLL_MN_BYP_MODE);
    
         /* Wait for DPLL to go in to bypass mode */
    
        while(0U == HW_RD_FIELD32_RAW(SOC_CM_WKUP_REGS + CM_WKUP_CM_IDLEST_DPLL_DISP,
            CM_WKUP_CM_IDLEST_DPLL_DISP_ST_MN_BYPASS,
            CM_WKUP_CM_IDLEST_DPLL_DISP_ST_MN_BYPASS_SHIFT));
    
        /* Set the multipler and divider values for the PLL */
    
        HW_WR_FIELD32_RAW(SOC_CM_WKUP_REGS + CM_WKUP_CM_CLKSEL_DPLL_DISP,
            CM_WKUP_CM_CLKSEL_DPLL_DISP_DPLL_MULT,
            CM_WKUP_CM_CLKSEL_DPLL_DISP_DPLL_MULT_SHIFT,
            dpllMult);
        HW_WR_FIELD32_RAW(SOC_CM_WKUP_REGS + CM_WKUP_CM_CLKSEL_DPLL_DISP,
            CM_WKUP_CM_CLKSEL_DPLL_DISP_DPLL_DIV,
            CM_WKUP_CM_CLKSEL_DPLL_DISP_DPLL_DIV_SHIFT,
            dpllDiv);
    
        /* Set the CLKOUT2 divider */
    
        HW_WR_FIELD32_RAW(SOC_CM_WKUP_REGS + CM_WKUP_CM_DIV_M2_DPLL_DISP,
            CM_WKUP_CM_DIV_M2_DPLL_DISP_DPLL_CLKOUT_DIV,
            CM_WKUP_CM_DIV_M2_DPLL_DISP_DPLL_CLKOUT_DIV_SHIFT,
            dpllPostDivM2);
    
        /* Now LOCK the PLL by enabling it */
    
        HW_WR_FIELD32_RAW(SOC_CM_WKUP_REGS + CM_WKUP_CM_CLKMODE_DPLL_DISP,
            CM_WKUP_CM_CLKMODE_DPLL_DISP_DPLL_EN,
            CM_WKUP_CM_CLKMODE_DPLL_DISP_DPLL_EN_SHIFT,
            CM_WKUP_CM_CLKMODE_DPLL_DISP_DPLL_EN);
    
        while(0U == HW_RD_FIELD32_RAW(SOC_CM_WKUP_REGS + CM_WKUP_CM_IDLEST_DPLL_DISP,
            CM_WKUP_CM_IDLEST_DPLL_DISP_ST_DPLL_CLK,
            CM_WKUP_CM_IDLEST_DPLL_DISP_ST_DPLL_CLK_SHIFT));
    }
    
    
    /* ------------------------------------
       LCDC clock source . .
       - CLKSEL_LCDC_PIXEL_CLK, TRM p1299
       ------------------------------------ */
    
    typedef enum sc1Cpu_TiAM335x_LcdClkSrcT
    {
       eLcdClkSrc_DPLL_LCD = 0,
       eLcdClkSrc_CORE_M5  = 1,
       eLcdClkSrc_PER_M2   = 2
    
    } sc1Cpu_TiAM335x_LcdClkSrc;
    
    
    sc1Err sc1Cpu_TiAM335x_SetLcdClkSource(sc1Cpu_TiAM335x_LcdClkSrc clkSrc)
    {
       switch (clkSrc) {
          case eLcdClkSrc_DPLL_LCD:
          case eLcdClkSrc_CORE_M5:
          case eLcdClkSrc_PER_M2:
             HW_WR_REG32(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_LCDC_PIXEL_CLK,                                                           // uint32_t addr,
                         (((UINT32)clkSrc) << CM_DPLL_CLKSEL_LCDC_PIXEL_CLK_CLKSEL_SHIFT) & CM_DPLL_CLKSEL_LCDC_PIXEL_CLK_CLKSEL);   // uint32_t value)
             break;
          default:
             return eErr_DataOutOfRange;
       }
       return eErr_None;
    }
    
    
    /* EOF */
    

  • GerryL,

    Please take a look at this old e2e thread e2e.ti.com/.../2063795 where someone was trying to access the LCDC registers. The customer never came back to confirm what JDD suggested in the final post, but please digest this thread to see if there is something of value to your question.

    Lali
  • Hi Lali,

    Thanks for the link.  The clocks mentioned in that post have all been enabled . .

    "-enable the LCDC functional clock 0x44e00018=0x2" -- this is register CM_PER_LCDC_CLKCTRL, and for my application this is done just after power up in a call to am335x_prcm.c/PRCMModuleEnable(), moduleId=CHIPDB_MOD_ID_LCDC.

    "-Add *0x4830E06C in the expressions window and set *0x4830E06C=0x7, that will enable the clocks to the submodules." -- this is the LCDC register CLKC_ENABLE, and in my sample code it is set to value 0x07, which enables the Core, LIDD and DMA clocks.

    At this point I have to ask whether or not there are any issues with the LCDC DMA implementation in the AM3352?  If anyone on this forum has seen it working then please speak up, as I am beginning to have my doubts.

    Thanks,
    GerryL

  • GerryL,

    I should have caught this earlier, but there is a LCDC DMA example in the pdk_am335x_1_0_10!! located at C:\ti\pdk_am335x_1_0_10\packages\MyExampleProjects\LCDC_RasterExample_evmAM335x_armTestProject

    It's part of the latest Processor SDK RTOS package from here http://software-dl.ti.com/processor-sdk-rtos/esd/AM335X/latest/index_FDS.html

    Did you want to give this a whirl and see if it works?

    Lali