/***************************************************************************//** * @brief * Configure and initialize TFT Direct Drive * * @param[in] ebiTFTInit * TFT Initialization structure ******************************************************************************/ void EBI_TFTInit(const EBI_TFTInit_TypeDef *ebiTFTInit) { uint32_t ctrl; /* Configure base address for frame buffer offset to EBI bank */ EBI_TFTFrameBaseSet(ebiTFTInit->addressOffset); /* Configure display size and porch areas */ EBI_TFTSizeSet(ebiTFTInit->hsize, ebiTFTInit->vsize); EBI_TFTHPorchSet(ebiTFTInit->hPorchFront, ebiTFTInit->hPorchBack, ebiTFTInit->hPulseWidth); EBI_TFTVPorchSet(ebiTFTInit->vPorchFront, ebiTFTInit->vPorchBack, ebiTFTInit->vPulseWidth); /* Configure timing settings */ EBI_TFTTimingSet(ebiTFTInit->dclkPeriod, ebiTFTInit->startPosition, ebiTFTInit->setupCycles, ebiTFTInit->holdCycles); /* Configure line polarity settings */ EBI_PolaritySet(ebiLineTFTCS, ebiTFTInit->csPolarity); EBI_PolaritySet(ebiLineTFTDClk, ebiTFTInit->dclkPolarity); EBI_PolaritySet(ebiLineTFTDataEn, ebiTFTInit->dataenPolarity); EBI_PolaritySet(ebiLineTFTVSync, ebiTFTInit->vsyncPolarity); EBI_PolaritySet(ebiLineTFTHSync, ebiTFTInit->hsyncPolarity); /* Main control, EBI bank select, mask and blending configuration */ ctrl = (uint32_t)(ebiTFTInit->bank) | (uint32_t)(ebiTFTInit->width) | (uint32_t)(ebiTFTInit->colSrc) | (uint32_t)(ebiTFTInit->interleave) | (uint32_t)(ebiTFTInit->fbTrigger) | (uint32_t)(ebiTFTInit->shiftDClk == true ? (1 << _EBI_TFTCTRL_SHIFTDCLKEN_SHIFT) : 0) | (uint32_t)(ebiTFTInit->maskBlend) | (uint32_t)(ebiTFTInit->driveMode); EBI->TFTCTRL = ctrl; /* Enable TFT pins */ if (ebiTFTInit->driveMode != ebiTFTDDModeDisabled) { EBI->ROUTE |= (EBI_ROUTE_TFTPEN); } }
/**************************************************************************//** * @brief EBI interrupt routine, configures new frame buffer offset *****************************************************************************/ void EBI_IRQHandler(void) { uint32_t flags; /* Get cause of interrupt */ flags = EBI_IntGet(); /* Clear interrupt */ EBI_IntClear(flags); /* Process VSYNC interrupt */ if (flags & EBI_IF_VFPORCH) { /* Swap buffers if new frame is ready */ if (nextOffset != -1) { EBI_TFTFrameBaseSet(nextOffset); nextOffset = -1; } } }
/* VSYNC interrupt handler. This performs the actual flipping * of the buffers. */ void EBI_IRQHandler(void) { uint32_t flags; flags = EBI_IntGet(); EBI_IntClear(flags); if ( flags & EBI_IF_VSYNC ) { if ( pendingFrameIndex >= 0 ) { /* Set Direct Drive frame buffer address to the new frame */ EBI_TFTFrameBaseSet(FRAME_BUFFER_SIZE * pendingFrameIndex); /* Send a confirmation to emWin that the old back buffer is visible now */ GUI_MULTIBUF_Confirm(pendingFrameIndex); /* Reset the pending flag */ pendingFrameIndex = -1; } } }
/**************************************************************************//** * @brief EBI interrupt routine, configures new frame buffer offset *****************************************************************************/ void EBI_IRQHandler(void) { uint32_t flags; uint32_t lineNumber; uint32_t prevMaskBlend; /* Get source for interrupt */ flags = EBI_IntGet(); /* Clear interrupt */ EBI_IntClear(flags); /* Process vertical sync interrupt */ if (flags & EBI_IF_VFPORCH) { /* Keep tracke of number of frames drawn */ frameCtr++; /* Increase this increment to 2/4/8 to increase scroll speed */ hzOffset += 1; /* Wrap around when a full screen has been displayed */ if (hzOffset == (D_WIDTH + font16x28.c_width)) { hzOffset = 0; } /* We only redraw when we need to */ if (hzOffset != hPos) { hPos = hzOffset; /* We only redraw when we need a new character */ if ((hPos % 16) == 0) { /* Update frame buffer - we do this in the interrupt routine to */ /* ensure a smooth scroller no matter what else is being done. */ /* However, drawing these fonts with low optimization will take */ /* more than one scan line, so this _can_ result in tearing at the */ /* top of the screen for this example. */ prevMaskBlend = EBI->TFTCTRL & _EBI_TFTCTRL_MASKBLEND_MASK; EBI_TFTMaskBlendMode(ebiTFTMBDisabled); TFT_DrawFont(D_WIDTH + hPos, D_HEIGHT - font16x28.height, *scrollptr); if (hPos > 0) { TFT_DrawFont(hPos - font16x28.c_width, D_HEIGHT - font16x28.height, *scrollptr); } EBI->TFTCTRL |= prevMaskBlend; /* Update pointer into text, reset if at last character */ scrollptr++; if (*scrollptr == '\0') { scrollptr = scrolltext; } } } } /* Process horizontal sync interrupt */ if (flags & EBI_IF_HSYNC) { lineNumber = EBI_TFTVCount(); /* Adjust for porch size */ if (lineNumber >= 3) lineNumber -= 3; if (lineNumber < (D_HEIGHT - font16x28.c_height)) { EBI_TFTFrameBaseSet(lineNumber * V_WIDTH * 2); } else { EBI_TFTFrameBaseSet(lineNumber * V_WIDTH * 2 + hzOffset * 2); } } }
/********************************************************************* * * LCD_X_DisplayDriver * * Purpose: * This function is called by the display driver for several purposes. * To support the according task the routine needs to be adapted to * the display controller. Please note that the commands marked with * 'optional' are not cogently required and should only be adapted if * the display controller supports these features. * * Parameter: * LayerIndex - Index of layer to be configured * Cmd - Please refer to the details in the switch statement below * pData - Pointer to a LCD_X_DATA structure * * Return Value: * < -1 - Error * -1 - Command not handled * 0 - Ok */ int LCD_X_DisplayDriver(unsigned LayerIndex, unsigned Cmd, void * pData) { int r; (void)LayerIndex; /* Unused parameter */ switch (Cmd) { // // Required // case LCD_X_INITCONTROLLER: { // // Called during the initialization process in order to set up the // display controller and put it into operation. If the display // controller is not initialized by any external routine this needs // to be adapted by the customer... // _InitController(); EnableVsyncInterrupt(); return 0; } case LCD_X_SETVRAMADDR: { // // Required for setting the address of the video RAM for drivers // with memory mapped video RAM which is passed in the 'pVRAM' element of p // LCD_X_SETVRAMADDR_INFO * p; p = (LCD_X_SETVRAMADDR_INFO *)pData; _SetVRAMAddr(p->pVRAM); return 0; } case LCD_X_SETORG: { // // Required for setting the display origin which is passed in the 'xPos' and 'yPos' element of p // LCD_X_SETORG_INFO * p; p = (LCD_X_SETORG_INFO *)pData; _SetOrg(p->xPos, p->yPos); return 0; } case LCD_X_SETLUTENTRY: { // // Required for setting a lookup table entry which is passed in the 'Pos' and 'Color' element of p // LCD_X_SETLUTENTRY_INFO * p; p = (LCD_X_SETLUTENTRY_INFO *)pData; _SetLUTEntry(p->Color, p->Pos); return 0; } case LCD_X_ON: { // // Required if the display controller should support switching on and off // return 0; } case LCD_X_OFF: { // // Required if the display controller should support switching on and off // // ... return 0; } /* This command is received every time the GUI is done drawing a frame */ case LCD_X_SHOWBUFFER: { /* Get the data object */ LCD_X_SHOWBUFFER_INFO * p; p = (LCD_X_SHOWBUFFER_INFO *)pData; /* Set frame buffer to the new frame, will be automatically reloaded on VSYNC */ EBI_TFTFrameBaseSet(FRAME_BUFFER_SIZE * p->Index); /* Save the pending buffer index. ISR will send confirmation on next VSYNC. */ pendingFrameIndex = p->Index; return 0; } default: r = -1; } return r; }
/********************************************************************* * * _SetOrg * * Purpose: * Should set the origin of the display typically by modifying the * frame buffer base address register */ static void _SetOrg(int xPos, int yPos) { orgx = xPos; orgy = yPos; EBI_TFTFrameBaseSet(VRAM_pointer+2*( (XSIZE_PHYS*yPos) + xPos ) ); }
/********************************************************************* * * _SetVRAMAddr * * Purpose: * Should set the frame buffer base address */ static void _SetVRAMAddr(void * pVRAM) { VRAM_pointer = (uint32_t)pVRAM - EBI_BankAddress(EBI_BANK2); EBI_TFTFrameBaseSet(VRAM_pointer); }