Support for the emWin GUI library from Segger.

Dependents:   lpc4088_displaymodule_emwin

This library contains the porting layer needed to start working with emWin from Segger. Details about emWin can be found both segger.com as well as lpcware.com.

The high performance emWin embedded graphics library developed by SEGGER Microcontroller is now offered by NXP Semiconductors in library form for free commercial use with NXP microcontrollers.

For a better description of what is included and the limitations, see emWin Graphics Library.

Note

The emWin library and PNG support files must be downloaded as the downloaders contains the license info. The steps are described in the readme.h file.

Files at this revision

API Documentation at this revision

Comitter:
alindvall
Date:
Fri Feb 27 11:39:47 2015 +0000
Child:
1:2847cc35a84f
Commit message:
First version

Changed in this revision

EwHAL.cpp Show annotated file Show diff for this revision Revisions of this file
EwHAL.h Show annotated file Show diff for this revision Revisions of this file
GUIConf.h Show annotated file Show diff for this revision Revisions of this file
emwin/emWin_header/dummy.h Show annotated file Show diff for this revision Revisions of this file
png/dummy.h Show annotated file Show diff for this revision Revisions of this file
readme.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EwHAL.cpp	Fri Feb 27 11:39:47 2015 +0000
@@ -0,0 +1,468 @@
+/*
+ *  Copyright 2014 Embedded Artists AB
+ *
+ *  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.
+ */
+#include "EwHAL.h"
+#include "GUI.h"
+#include "GUIDRV_Lin.h"
+#include "rtos.h"
+
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+/* This value is not important but the same value must be used by both the
+   GUI_X_WaitEvent() and the GUI_X_SignalEvent() functions. */
+#define EMWIN_TASK_SIGNAL   (0x2)
+
+/******************************************************************************
+ * Local variables
+ *****************************************************************************/
+
+static EwHAL* _hal = NULL;
+static int _gettimeoffset = 0;
+static Semaphore* _emSem;
+
+static Timer _ewTimer;
+static osThreadId _emTask = 0;
+
+/******************************************************************************
+ * Private Functions
+ *****************************************************************************/
+
+void EwHAL::handleTouchEvent() {
+	GUI_PID_STATE ewCoord = {0};
+
+    if (_touch->read(_coord) == TouchPanel::TouchError_Ok) {
+		ewCoord.x = _coord.x;
+		ewCoord.y = _coord.y;
+		ewCoord.Pressed = (_coord.z == 0) ? 0 : 1;
+		GUI_PID_StoreState(&ewCoord);
+    }
+}
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+EwHAL::EwHAL(int numFB, uint32_t extraMem) {
+
+    RtosLog* log = DMBoard::instance().logger();
+    _display = DMBoard::instance().display();
+    _touch = DMBoard::instance().touchPanel();
+    
+    _width = _display->width();
+    _height = _display->height();
+    _fbSz = _display->fbSize();
+	_numFB = numFB;
+	
+    do {
+		if (numFB < 1) {
+            log->printf("Failed. Must have at least one frame buffer, wanted %d\n", numFB);
+            break;
+		}
+
+        _fb = (uint32_t)_display->allocateFramebuffers(numFB);
+        if (_fb == 0) {
+            log->printf("Failed to allocate memory for %d framebuffer(s)\n", numFB);
+            break;
+        }
+        memset((void*)_fb, 0x0, _fbSz * numFB);
+        
+        _display->setFramebuffer((void*)_fb);
+    
+        _memSz = extraMem;
+        _mem = (uint32_t)malloc(_memSz);
+        if (_mem == 0) {
+            log->printf("Failed to allocate memory block for emwin (wanted %u bytes)\n", _memSz);
+            break;
+        }
+        memset((void*)_mem, 0x0, _memSz);
+        
+        _fp = new FunctionPointer(this, &EwHAL::handleTouchEvent);
+		_touch->setListener(_fp);
+		
+		_hal = this;
+    } while(false);	
+}
+
+EwHAL::~EwHAL() {
+	_hal = NULL;
+	if (_mem != 0) {
+		free((void*)_mem);
+		_mem = NULL;
+	}
+	if (_fb != 0) {
+		free((void*)_fb);
+		_fb = NULL;
+	}
+	if (_fp != NULL) {
+		_touch->setListener(NULL);
+		delete(_fp);
+	}
+}
+
+void EwHAL::showFrameBuffer(int id) {
+    if (id >= 0 && id < getNumFrameBuffers()) {
+        _display->setFramebuffer((void*)(_fb + id * _fbSz));
+    }
+}
+
+/******************************************************************************
+ * emWin HAL functions
+ *****************************************************************************/
+
+/*********************************************************************
+ *
+ *       GUI_X_Config
+ *
+ * Purpose:
+ *   Called during the initialization process in order to set up the
+ *   available memory for the GUI.
+ */
+void GUI_X_Config(void) {
+
+    if (_hal == NULL) return;
+
+    //
+    // Assign memory to emWin
+    //
+
+    GUI_ALLOC_AssignMemory(_hal->getMemoryBlockAddress(), _hal->getMemoryBlockSize());
+    GUI_ALLOC_SetAvBlockSize(0x80);
+    
+    _emTask = Thread::gettid();
+
+    GUI_SetSignalEventFunc(GUI_X_SignalEvent);
+    GUI_SetWaitEventFunc(GUI_X_WaitEvent);
+    GUI_SetWaitEventTimedFunc(GUI_X_WaitEventTimed);
+}
+
+/*********************************************************************
+ *
+ *       LCD_X_Config
+ *
+ * Purpose:
+ *   Called during the initialization process in order to set up the
+ *   display driver configuration.
+ */
+void LCD_X_Config(void) {
+
+    if (_hal == NULL) return;
+    
+    //
+    // Initialize MultiBuffering
+    //
+	if (_hal->getNumFrameBuffers() > 1) {
+		GUI_MULTIBUF_Config(_hal->getNumFrameBuffers());
+	}
+     
+
+    GUI_DEVICE_CreateAndLink(&GUIDRV_Lin_16_API, GUICC_M565, 0, 0);
+
+    //
+    // Display driver configuration, required for Lin-driver
+    //
+    LCD_SetPosEx(0, 0, 0);
+    if (LCD_GetSwapXYEx(0)) {
+        LCD_SetSizeEx  (0, _hal->getDisplayHeight(), _hal->getDisplayWidth());
+        LCD_SetVSizeEx (0, _hal->getDisplayHeight(), _hal->getDisplayWidth());
+    } else {
+        LCD_SetSizeEx  (0, _hal->getDisplayWidth(), _hal->getDisplayHeight());
+        LCD_SetVSizeEx (0, _hal->getDisplayWidth(), _hal->getDisplayHeight());
+    }
+    LCD_SetVRAMAddrEx(0, (void*)0);
+    
+    // TODO: Add Custom callback routine (DMA) for copying the buffers
+    //       Explained in the emWin User Manual rev 5.26 section 21.4.1
+}
+
+/*********************************************************************
+ *
+ *       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) {
+    //	LCD_X_SETORG_INFO * pSetOrg;
+    int r;
+    U32 TouchOrientation;
+
+    if (_hal == NULL) return -1;
+
+    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...
+        //
+        // ...
+
+        //
+        // Set display size and video-RAM address
+        //
+        //		LCD_SetSizeEx (800, 480, 0);
+        //		LCD_SetVSizeEx(800, 480, 0);
+        LCD_SetVRAMAddrEx(0, (void*)_hal->getFrameBufferAddress());
+
+        TouchOrientation = (GUI_MIRROR_X * LCD_GetMirrorXEx(0)) |
+							(GUI_MIRROR_Y * LCD_GetMirrorYEx(0)) |
+							(GUI_SWAP_XY  * LCD_GetSwapXYEx (0)) ;
+        GUI_TOUCH_SetOrientation(TouchOrientation);
+
+        return 0;
+    case LCD_X_SETORG:
+        //
+        // Required for setting the display origin which is passed in the 'xPos' and 'yPos' element of p
+        //
+
+        // pSetOrg = (LCD_X_SETORG_INFO *)pData;
+        //        LPC_LCD->UPBASE = VRAM_ADDR_PHYS +
+        //                (pSetOrg->yPos * YSIZE_PHYS * /*PIXEL_WIDTH*/ 2);  // Needs to be set, before LCDC is enabled
+
+        return 0;
+    case LCD_X_SHOWBUFFER:
+        {
+            LCD_X_SHOWBUFFER_INFO * p = (LCD_X_SHOWBUFFER_INFO *)pData;
+            //
+            // Calculate address of the given buffer
+            //
+            //unsigned long BufferSize = (XSIZE * YSIZE * BITSPERPIXEL) / 8;
+            //unsigned long Addr = _VRamBaseAddr + ewGui->getFrameBufferSize() * pData->Index;
+            //
+            // Make the given buffer visible
+            //
+            _hal->showFrameBuffer(p->Index);
+            //
+            // Send a confirmation that the buffer is visible now
+            //
+            GUI_MULTIBUF_Confirm(p->Index);
+        }
+        return 0;
+    default:
+        r = -1;
+    }
+
+    return r;
+}
+
+
+
+/*********************************************************************
+ *
+ *      Timing:
+ *                 GUI_X_GetTime()
+ *                 GUI_X_Delay(int)
+ *
+ * Some timing dependent routines require a GetTime and delay function. 
+ * Default time unit (tick), normally is 1 ms.
+ */
+
+int GUI_X_GetTime(void) {
+    int t = _ewTimer.read_ms();
+    if (t > 3600000) {
+        // reset once per hour
+        _ewTimer.reset();
+        _gettimeoffset += t;
+        t = 0;
+    }
+    return t + _gettimeoffset;
+}
+
+void GUI_X_Delay(int ms) {
+    Thread::wait(ms);
+}
+
+/*********************************************************************
+ *
+ *       GUI_X_Init()
+ *
+ * Note:
+ *     GUI_X_Init() is called from GUI_Init is a possibility to init
+ *     some hardware which needs to be up and running before the GUI.
+ *     If not required, leave this routine blank.
+ */
+void GUI_X_Init(void) {
+    _ewTimer.start();
+}
+
+
+/*********************************************************************
+ *
+ *       GUI_X_ExecIdle
+ *
+ * Note:
+ *  Called if WM is in idle state
+ */
+
+void GUI_X_ExecIdle(void) {}
+
+/*********************************************************************
+ *
+ *      Multitasking:
+ *
+ *                 GUI_X_InitOS()
+ *                 GUI_X_GetTaskId()
+ *                 GUI_X_Lock()
+ *                 GUI_X_Unlock()
+ *
+ * Note:
+ *   The following routines are required only if emWin is used in a
+ *   true multi task environment, which means you have more than one
+ *   thread using the emWin API.
+ *   In this case the
+ *                       #define GUI_OS 1
+ *  needs to be in GUIConf.h
+ */
+
+   
+static void emTimeout(void const* args) {
+	GUI_X_SignalEvent();
+}
+
+void GUI_X_InitOS(void) {
+	_emSem = new Semaphore(1); 
+}
+
+void GUI_X_Unlock(void) {
+	_emSem->release();
+}
+
+void GUI_X_Lock(void) {
+	_emSem->wait();
+}
+
+U32  GUI_X_GetTaskId(void) {
+	return (U32)Thread::gettid();
+}
+
+void GUI_X_WaitEvent(void) {
+    Thread::signal_wait(EMWIN_TASK_SIGNAL); //wait forever
+}
+
+void GUI_X_SignalEvent(void) {
+	if (_emTask) {
+		osSignalSet(_emTask, EMWIN_TASK_SIGNAL);
+	}
+}
+
+void GUI_X_WaitEventTimed(int Period) {
+    static RtosTimer _emTim(emTimeout, osTimerOnce);
+    if (Period > 0) {
+        
+        //wait no more than Period milliseconds
+        _emTim.start(Period);
+        Thread::signal_wait(EMWIN_TASK_SIGNAL);
+        _emTim.stop();
+    }
+}
+
+/*********************************************************************
+ *
+ *      Logging: OS dependent
+
+Note:
+  Logging is used in higher debug levels only. The typical target
+  build does not use logging and does therefor not require any of
+  the logging routines below. For a release build without logging
+  the routines below may be eliminated to save some space.
+  (If the linker is not function aware and eliminates unreferenced
+  functions automatically)
+
+ */
+
+void GUI_X_Log     (const char *s) { DMBoard::instance().logger()->printf("emWin[Log] %s\n", s); }
+void GUI_X_Warn    (const char *s) { DMBoard::instance().logger()->printf("emWin[Log] %s\n", s); }
+void GUI_X_ErrorOut(const char *s) { DMBoard::instance().logger()->printf("emWin[Log] %s\n", s); }
+
+
+
+/*********************************************************************
+ *
+ *       GUI_TOUCH_X_ActivateX()
+ *
+ * Function decription:
+ *   Called from GUI, if touch support is enabled.
+ *   Switches on voltage on X-axis,
+ *   prepares measurement for Y-axis.
+ *   Voltage on Y-axis is switched off.
+ */
+void GUI_TOUCH_X_ActivateX(void) {
+}
+
+/*********************************************************************
+ *
+ *       GUI_TOUCH_X_ActivateY()
+ *
+ * Function decription:
+ *   Called from GUI, if touch support is enabled.
+ *   Switches on voltage on Y-axis,
+ *   prepares measurement for X-axis.
+ *   Voltage on X-axis is switched off.
+ */
+void GUI_TOUCH_X_ActivateY(void) {
+}
+
+/*********************************************************************
+ *
+ *       GUI_TOUCH_X_MeasureX()
+ *
+ * Function decription:
+ *   Called from GUI, if touch support is enabled.
+ *   Measures voltage of X-axis.
+ */
+int  GUI_TOUCH_X_MeasureX(void) {
+    if (_hal == NULL) return 0;
+
+    return _hal->getTouchX();
+}
+
+/*********************************************************************
+ *
+ *       GUI_TOUCH_X_MeasureY()
+ *
+ * Function decription:
+ *   Called from GUI, if touch support is enabled.
+ *   Measures voltage of Y-axis.
+ */
+int  GUI_TOUCH_X_MeasureY(void) {
+    if (_hal == NULL) return 0;
+
+    return _hal->getTouchY();
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EwHAL.h	Fri Feb 27 11:39:47 2015 +0000
@@ -0,0 +1,102 @@
+
+#ifndef EWHAL_H
+#define EWHAL_H
+
+#include "mbed.h"
+#include "DMBoard.h"
+
+/**
+ * This is the main class to get Segger's emwin library up-and-running
+ * with the mbed online tools.
+ *
+ * This class handles the porting/integration layer in emwin.
+ */
+class EwHAL {
+public:
+
+    EwHAL(int numFB = 1, uint32_t extraMem = 1*1024*1024);
+	~EwHAL();
+
+    /**
+     * Returns the address to a memory block which may be used by emwin
+     * to allocate objects. The memory block returned will be given to emwin
+     * by calling GUI_ALLOC_AssignMemory.
+     */
+    void* getMemoryBlockAddress() { return (void*)_mem; }
+	
+    /**
+     * Returns the size of the memory block returned by
+     * getMemoryBlockAddress().
+     */
+    uint32_t getMemoryBlockSize() { return _memSz; }
+    
+    /**
+     * Returns the width of the display.
+     */
+    uint32_t getDisplayWidth() { return _width; }
+	
+    /**
+     * Returns the height of the display.
+     */
+    uint32_t getDisplayHeight() { return _height; }
+    
+    /**
+     * Returns the address of the framebuffer (video RAM). This address will
+     * be given to emwin by a call to LCD_SetVRAMAddrEx.
+     */
+    void* getFrameBufferAddress() { return (void*)_fb; }
+	
+    /**
+     * Returns the size in bytes of the framebuffer (video RAM). 
+     */
+    uint32_t getFrameBufferSize() { return _fbSz; }
+	
+    /**
+     * Returns the number of frame buffers to use, default is 1 meaning 
+     * that drawing takes place on the same buffer that is being shown.
+     * Double buffering is 2 and Tripple buffering is 3. No other values
+     * should be used.
+     */
+    int getNumFrameBuffers() { return _numFB; }
+	
+    /**
+     * Shows frame buffer number id. If getNumFrameBuffers() returns 1 then
+     * this id will always be 0, if getNumFrameBuffers() returns N then this
+     * function will be called with 0..(N-1). 
+     */
+    void showFrameBuffer(int id);
+    
+    /**
+     * Returns the x coordinate of the latest touch event
+     */
+    int32_t getTouchX() {return _coord.x;}
+
+    /**
+     * Returns the y coordinate of the latest touch event
+     */
+    int32_t getTouchY() {return _coord.y;}
+	
+
+private:
+
+    /**
+     * Called when a new touch event is available. Reads the coordinates and
+	 * forwards them to emWin
+     */
+	void handleTouchEvent();
+
+	int _numFB;
+	FunctionPointer* _fp;
+    uint32_t _width;
+    uint32_t _height;
+    uint32_t _fb;
+    uint32_t _fbSz;
+    uint32_t _mem;
+    uint32_t _memSz;
+    Display*  _display;
+    TouchPanel* _touch;
+	touch_coordinate_t _coord;
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GUIConf.h	Fri Feb 27 11:39:47 2015 +0000
@@ -0,0 +1,71 @@
+/*********************************************************************
+*                SEGGER Microcontroller GmbH & Co. KG                *
+*        Solutions for real time microcontroller applications        *
+**********************************************************************
+*                                                                    *
+*        (c) 1996 - 2014  SEGGER Microcontroller GmbH & Co. KG       *
+*                                                                    *
+*        Internet: www.segger.com    Support:  support@segger.com    *
+*                                                                    *
+**********************************************************************
+
+** emWin V5.24 - Graphical user interface for embedded applications **
+All  Intellectual Property rights  in the Software belongs to  SEGGER.
+emWin is protected by  international copyright laws.  Knowledge of the
+source code may not be used to write a similar product.  This file may
+only be used in accordance with the following terms:
+
+The software has been licensed to  NXP Semiconductors USA, Inc.  whose
+registered  office  is  situated  at 411 E. Plumeria Drive, San  Jose,
+CA 95134, USA  solely for  the  purposes  of  creating  libraries  for
+NXPs M0, M3/M4 and  ARM7/9 processor-based  devices,  sublicensed  and
+distributed under the terms and conditions of the NXP End User License
+Agreement.
+Full source code is available at: www.segger.com
+
+We appreciate your understanding and fairness.
+----------------------------------------------------------------------
+File        : GUIConf.h
+Purpose     : Configures emWins abilities, fonts etc.
+----------------------------------------------------------------------
+*/
+
+#ifndef GUICONF_H
+#define GUICONF_H
+
+/*********************************************************************
+*
+*       Multi layer/display support
+*/
+#define GUI_NUM_LAYERS       16    // Maximum number of available layers
+
+/*********************************************************************
+*
+*       Multi tasking support
+*/
+#define GUI_OS               (1)  // Compile with multitasking support
+
+/*********************************************************************
+*
+*       Configuration of touch support
+*/
+#define GUI_SUPPORT_TOUCH    (1)  // Support a touch screen (req. win-manager)
+
+/*********************************************************************
+*
+*       Default font
+*/
+#define GUI_DEFAULT_FONT     &GUI_Font6x8
+
+/*********************************************************************
+*
+*         Configuration of available packages
+*/
+#define GUI_SUPPORT_MOUSE    1    // Support a mouse
+#define GUI_WINSUPPORT       1    // Use window manager
+#define GUI_SUPPORT_MEMDEV   1    // Memory device package available
+#define GUI_SUPPORT_DEVICES  1    // Enable use of device pointers
+
+#endif  // Avoid multiple inclusion
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emwin/emWin_header/dummy.h	Fri Feb 27 11:39:47 2015 +0000
@@ -0,0 +1,1 @@
+/* Placeholder to get the folder exported by mbed */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/png/dummy.h	Fri Feb 27 11:39:47 2015 +0000
@@ -0,0 +1,1 @@
+/* Placeholder to get the folder exported by mbed */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/readme.h	Fri Feb 27 11:39:47 2015 +0000
@@ -0,0 +1,75 @@
+/* (Had to make this README file .h to get it exportable in mbed)
+
+    emWin Graphical Library
+    -----------------------
+    According to http://www.lpcware.com/content/project/emwin-graphics-library:
+    
+    "The high performance emWin embedded graphics library developed by SEGGER 
+     Microcontroller is now offered by NXP Semiconductors in library form for 
+     free commercial use with NXP microcontrollers."
+    
+    Follow the link above to read more about the graphical library and available
+    features.
+    
+    NOTE: The emWin library cannot be used in the online compiler for legal
+          reasons. You have to export the project and then follow the instructions
+          below to download emWin and then modify your local project.
+    
+    How to get it
+    -------------
+    The library must be downloaded from the page above and at the time this
+    document was written the latest version was emWin 5.24h with the direct
+    link: http://www.lpcware.com/system/files/NXP_emWin524h_libraries.exe
+    
+    Download the executable, run it and have it extract the files to the emwin/
+    folder. After extracting the archive, the emwin/ folder should contain the
+    following:
+    
+        emWin_Config\
+        emWin_header\
+        emWin_library\
+        readme.txt
+        
+    The the 5.24h version (and possibly other later versions as well) is missing
+    PNG support but the manual (available on the linked page above) has instructions
+    on how to add it. Download www.segger.com/link/emwin_png.zip and extract it
+    into the png/ folder. After extracting the folder should contain one or more
+    version folders. This is what the png/ folder may look like:
+    
+        emWin_V5.18/
+        emWin_V5.28/
+        
+    Delete the version that you don't need (probably the oldest one).
+    
+    Updating the project
+    --------------------
+    When this project was exported it did not have the correct paths and files
+    needed by emWin (for lisence reasons). This is what you have to do in your
+    IDE to get it to work:
+    
+        Keil uVision 4:
+        ==============
+        1) Open the project
+        2) Select the Project->Manage menu
+        3) Add a new Group "emLib"
+        4) Add all DMemWin/png/emWin_V5.28/GUI/PNG/*.c files "emLib" group
+        5) Add DMemWinGUI/emwin/emWin_library/Keil/emWin_M4.lib to the "emLib" group
+        6) Close the dialog
+        
+        NXP LPCXpresso IDE:
+        ==================
+        1) Open the workspace
+        2) Import the project from the exported zip file
+        3) Right-click on the DMemWin folder in the Project Explorer and select Refresh...
+        
+        Other IDEs:
+        ==========
+        Do the corresponding actions for your IDE but remember to use the correct
+        library file.
+        
+        If the IDE doesn't get the paths correct by the exporter then you might have
+        to add the following to the include path:
+        
+            DMemWin/emwin/emWin_header/
+
+*/