none
Use framebuffer on Windows CE RRS feed

  • General discussion

  • Hi, I need some help from your.

    I have to use the framebuffer for display images on the touchscreen of the embedded platform. I need some informations on how can I do this. The display driver is already develop for my platform (AT91SAM9261). I don't know very well programming in windows CE so I have some difficult.

    For other information, please write below.

    Thanks a lot.
    Monday, October 4, 2010 9:17 AM

All replies

  • Can you brief more on what implementation you are going to do ?

     

    If you want to draw over the screen you can use GDI functions which shall write to the frame buffer for LCD display.

     

    If you want to access it in driver you need to map to the SDRAM-frame buffer and directly write to it.

     

    For video layer drawing you can use Directdraw functions.

     

    Thanks

    Misbah

    Monday, October 4, 2010 9:26 AM
  • Hi,


    I try to explain my problem clearly. I have an external graphical API for paint on the screen. This API want the address of the graphical memory for write in it. I think to pass to it a virtual address where the graphical memory is mapped with mmap style function. So the graphical API can write into this mapped buffer and the LCD memory video is updated.

    It's correct? It possible on Windows CE? Can you help me with this?


    Thanks a lot.
    Thursday, October 7, 2010 8:57 AM
  • Frame buffer physical adddress you can find in your BSP what it is. It shall be in image_cfg.h file or  config.bib file

    You can map this physical address to virtual as :-

    PHYSICAL_ADDRESS pa;

    pa.QuadPart = PHYSICAL_ADD_FBUFF;

    void *ptr;


        if ((ptr= (UCHAR*)MmMapIoSpace(pa, FBUFF_SIZE, FALSE)) == NULL)
        {
                return FALSE;
        }

    ptr shall hold the virtual address of frame buffer

     

    regard

    Misbah

     

    Thursday, October 7, 2010 9:58 AM
  • Thanks for all.

    I have to write a driver for make this code working or I can use this at user space?

    I will test it and report final result.

     

    Thanks again

    Thursday, October 7, 2010 10:28 AM
  • You can close this thread if it has served your purpose.

    Thanks

    Thursday, October 7, 2010 11:17 AM
  • I don't know if this code have to be written in a driver (so I have to develop this) or in user space?
    Thursday, October 7, 2010 11:40 AM
  • This code needs to be written in driver.

     

    from application you always have standard API to draw. see my above answer for your choice/requirement.

     

    Regards

    Misbah

    Thursday, October 7, 2010 12:34 PM
  • The Answer.
    Thursday, October 7, 2010 12:49 PM
  • Can you please mark as answer .
    Thursday, October 7, 2010 1:19 PM
  • I don't have the BUTTON --> Mark as Answer
    Thursday, October 7, 2010 1:40 PM
  • You can find it at the bottom of the text editor along with Reply. It shall be helpful to others if you mark it answer.
    Thursday, October 7, 2010 1:53 PM
  • Thanks, but I see only this:

    Reply   Quote                                        Report As Abuse

     

     

    I have seen that in other post there is this button but not here.

    I don't know the reason.

    Thursday, October 7, 2010 2:05 PM
  • OK, I want to access directly on LCD video memory. I need a driver for map the SDRAM-frame buffer and directly write to it. I need same informations:

    - can I write a stream driver or I have to write a native driver?

    Thanks

    Tuesday, October 12, 2010 8:13 AM
  • You need a stream driver.

    see my last post of Oct 7. The answer is there.

    --Misbah

    Tuesday, October 12, 2010 8:49 AM
  • Hi,

    I have starting to develop the driver. I use a stream driver and on initialization (Init) I make the memory mapper of the frame buffer to a physical address. My problem is that a have to pass this address to my application beacause it use this for write into frame buffer directly.

    I need that the application has direct access to frame buffer, but the address mapped is in kernel space and the application is in user space so I can't return the address obtained by memory map directly.

    How can I give to my application a valid address for write into the frame buffer? I think to use the IOControl for this .. returning the rigth address for application.

    Help me .. thanks. 

    Wednesday, October 13, 2010 6:09 AM
  • You need to map the kernel virtual memory to user space via VirtualCopy and VirtualAlloc() or virtualAlloccopy() APis

    In an ioctl pass this pointer to application and application can directly write to it.

     

    Thanks

    Misbah

    Wednesday, October 13, 2010 8:41 AM
  • Hi to all,

    I have written a simple implementation of the stram driver for my purpose. I'd like to have some suggestions. The code of driver is show below.

    Question:

    - Is this a good starting point or I have some implementation error?

    Header File (.h)

    #ifdef __cplusplus
    extern "C" {
    #endif //__cplusplus
    	
    __declspec(dllexport) DWORD FBR_Init(DWORD dwContext);
    __declspec(dllexport) BOOL FBR_Deinit (DWORD dwContext);
    
    __declspec(dllexport) DWORD FBR_Open(DWORD dwContext, DWORD dwAccess,
    									 DWORD dwShare);
    __declspec(dllexport) BOOL FBR_Close(DWORD dwOpen);
    
    __declspec(dllexport) DWORD FBR_IOControl(DWORD dwOpen, DWORD dwCode,
    										 PBYTE pIn, DWORD dwIn,
    										 PBYTE pOut, DWORD dwOut,
    										 DWORD *pdwBytesWritten);
    #ifdef __cplusplus
    } // extern "C"
    #endif //__cplusplus
    
    #define PHY_ADDRESS_FRAME_BUFFER 0x83F00000
    #define FRAME_BUFFER_SIZE 0x1240
    
    // Suppress warnings by declaring the undeclared.
    //DWORD GetConfigData (DWORD);
    
    #define READ_HWD_ADDR 1
    
    //
    /// Driver instance structure
    //
    typedef struct {
    	void *p_frame_buffer;
    	DWORD dwSize;
    	int nNumOpens;
    } DRVCONTEXT, *PDRVCONTEXT;
    

    Source File (.cpp)

    #include <windows.h>
    #include <ceddk.h> //
    #include "fbr.h"
    
    /* DLL instance handler */
    HINSTANCE hInst;
    
    /* Debug zone support */
    #ifdef DEBUG
    #define DTAG TEXT("FBR: ")
    
    #define ZONE_ERROR		DEBUGZONE(0)
    #define ZONE_WARNING	DEBUGZONE(1)
    #define ZONE_FUNC		DEBUGZONE(2)
    #define ZONE_INIT		DEBUGZONE(3)
    #define ZONE_DRVCALLS	DEBUGZONE(4)
    #define ZONE_EXENTRY	(ZONE_FUNC | ZONE_DRVCALLS)
    
    DBGPARAM dpCurSettings = {
    	TEXT("FBR Driver"), {
    	TEXT("Errors"),		TEXT("Warnings"),	TEXT("Functins"),
    	TEXT("Init"),		TEXT("DriverCall"),	TEXT("Undefined"),
    	TEXT("Undefined"),	TEXT("Undefined"),	TEXT("Undefined"),
    	TEXT("Undefined"),	TEXT("Undefined"),	TEXT("Undefined"),
    	TEXT("Undefined"),	TEXT("Undefined"),	TEXT("Undefined"),
    	TEXT("Undefined") },
    	0x0003
    };
    #endif DEBUG
    
    BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved) {
    	hInst = (HINSTANCE)hinstDLL;
    	switch(dwReason) {
    		case DLL_PROCESS_ATTACH:
    			DEBUGREGISTER(hInst);
    			DisableThreadLibraryCalls(hInst);
    			break;
    		case DLL_PROCESS_DETACH:
    			DEBUGMSG(ZONE_INIT, (DTAG TEXT("DLL_PROCESS_DETACH\r\n")));
    			break;
    	}
    	return TRUE;
    }
    
    DWORD FBR_Init(DWORD dwContext, LPCVOID lpvBusContext)
    {
    	PDRVCONTEXT pDrv;
    	PHYSICAL_ADDRESS pa;
    
    	pa.QuadPart = PHY_ADDRESS_FRAME_BUFFER;
    
    	DEBUGMSG (ZONE_INIT | ZONE_EXENTRY, 
    			 (DTAG TEXT("FBR_Init dwContex:%x\r\n"), dwContext));
    
      // Allocate a device instance structure.
    	pDrv = (PDRVCONTEXT)LocalAlloc (LPTR, sizeof (DRVCONTEXT));
    	if (pDrv) {
    		// Initialize structure.
    		memset ((PBYTE) pDrv, 0, sizeof (DRVCONTEXT));
    		pDrv->dwSize = sizeof (DRVCONTEXT);
    		// Read registry to determine the size of the disk.
    		//GetConfigData (dwContext);
    	} else 
    		DEBUGMSG (ZONE_INIT | ZONE_ERROR, 
    				 (DTAG TEXT("GEN_Init failure. Out of memory\r\n")));
    
    	pDrv->p_frame_buffer = (UCHAR *)MmMapIoSpace(pa, FRAME_BUFFER_SIZE, FALSE);
    	if (pDrv->p_frame_buffer == NULL) {
    		DEBUGMSG (ZONE_INIT | ZONE_ERROR, 
    				 (DTAG TEXT("FBR_Init failure. Unable to map IO Space\r\n")));
    	
    		/* TODO change this */
    		LocalFree ((PBYTE)pDrv);
      }
    	
    	DEBUGMSG (ZONE_FUNC, (DTAG TEXT("FBR_Init-- pDrv: %x\r\n"), pDrv));
    	
    	return (DWORD)pDrv;
    }
    
    BOOL FBR_Deinit (DWORD dwContext)
    {
    	PDRVCONTEXT pDrv = (PDRVCONTEXT) dwContext;
    	
    	DEBUGMSG (ZONE_EXENTRY, 
    			 (DTAG TEXT("FBR_Deinit++ dwContex:%x\r\n"), dwContext));
    
    	/* Unmap the IO Space */	
    	MmUnmapIoSpace(pDrv->p_frame_buffer, FRAME_BUFFER_SIZE);
    
    	if (pDrv && (pDrv->dwSize == sizeof (DRVCONTEXT))) {
    		// Free the driver state buffer.
    		LocalFree ((PBYTE)pDrv);
    	}
    	
    	DEBUGMSG (ZONE_FUNC, (DTAG TEXT("FBR_Deinit--\r\n")));
    	return TRUE;
    }
    
    DWORD GEN_Open (DWORD dwContext, DWORD dwAccess, DWORD dwShare)
    {
    	PDRVCONTEXT pDrv = (PDRVCONTEXT) dwContext;
    
    	DEBUGMSG (ZONE_EXENTRY, 
    			 (DTAG TEXT("FBR_Open++ dwContext: %x\r\n"), dwContext));
    
    	// Verify that the context handle is valid.
    	if (pDrv && (pDrv->dwSize != sizeof (DRVCONTEXT))) {
    		DEBUGMSG (ZONE_ERROR, (DTAG TEXT("FBR_Open failed\r\n")));
    		return 0;
    	}
    	
    	// Count the number of opens.
    	InterlockedIncrement ((long *)&pDrv->nNumOpens);
    	
    	DEBUGMSG (ZONE_FUNC, (DTAG TEXT("FBR_Open--\r\n")));
    	return (DWORD)pDrv;
    }
    
    BOOL GEN_Close (DWORD dwOpen)
    {
    	PDRVCONTEXT pDrv = (PDRVCONTEXT) dwOpen;
    	
    	DEBUGMSG (ZONE_EXENTRY, 
    			 (DTAG TEXT("FBR_Close++ dwOpen: %x\r\n"), dwOpen));
    
    	if (pDrv && (pDrv->dwSize != sizeof (DRVCONTEXT))) {
    		DEBUGMSG (ZONE_FUNC | ZONE_ERROR, 
    				 (DTAG TEXT("FBR_Close failed\r\n")));
    		return 0;
    	}
    
    	if (pDrv->nNumOpens)
    		InterlockedDecrement((long *)&pDrv->nNumOpens);
    
    	DEBUGMSG (ZONE_FUNC, (DTAG TEXT("FBR_Close--\r\n")));
    	return TRUE;
    }
    
    DWORD GEN_IOControl(DWORD dwOpen, DWORD dwCode,
    					PBYTE pIn, DWORD dwIn,
    					PBYTE pOut, DWORD dwOut,
    					DWORD *pdwBytesWritten)
    {
    	PDRVCONTEXT pState;
    	DWORD err = ERROR_INVALID_PARAMETER;
    
    	DEBUGMSG (ZONE_EXENTRY, 
    			 (DTAG TEXT("FBR_IOControl++ dwOpen: %x dwCode: %x\r\n"),
    			 dwOpen, dwCode));
    	
    	pState = (PDRVCONTEXT) dwOpen;
    	switch (dwCode) {
    		case READ_HWD_ADDR:
    		
    			/* TODO Copy pointer value here with VirtualCopy? */
    
    			return TRUE;
    
    		default:
    			DEBUGMSG (ZONE_ERROR, 
    					 (DTAG TEXT("FBR_IOControl: unknown code %x\r\n"), dwCode));
    		return FALSE;
    	}
    	
    	SetLastError (err);
    	DEBUGMSG (ZONE_FUNC, (DTAG TEXT("FBR_IOControl--\r\n")));
    	
    	return TRUE;
    }
    
    
    Thursday, October 14, 2010 6:24 AM
  • It looks ok to me.

     

    In Ioctl call VirtualAllocEx() and map the Vitrual memory of frame buffer to user space.

    if you need the implementation i shall provide but better you try at your end first.

     

    Thanks

    Misbah

    Thursday, October 14, 2010 6:15 PM
  • Hi,

    I can't understand some things.

    1) When I make the MmMapIoSpace the address returned is in kernel space (in my case something like 0xD00XXXXXX).

    2) When I use IOctl I have to return the address mapped with MmMapIoSpace to the processo that call the IOCTL but this address is a kernel space address and not a valid address for the user space.

    How can I resolve this problem? I don't understand how to use the VirtualAllocEx in IOctl for return the address mapped in MmMapIoSpace. 

    Friday, October 15, 2010 8:40 PM
  • I'm going to try to answer your question, and then I'm going to suggest a different approach  altogether to solve your problem to consider.
    To obtain a pointer usable by your application, your driver should use VirtualAllocCopyEx as follows:

    if ((pOut != NULL) && (dwOut >= sizeof(LPVOID)))
    {
     *(LPVOID *)pOut = 
       VirtualAllocCopyEx((HANDLE)GetCurrentProcessId(),
        (HANDLE)GetDirectCallerProcessId(), 
        pDrv->p_frame_buffer, 
        FRAME_BUFFER_SIZE, 
        PAGE_READWRITE|PAGE_NOCACHE);
      *pdwBytesWritten = sizeof(LPVOID);
      return TRUE;
    }
    
    

    If you do this, you'll need to call VirtualFreeEx to release the mapping when you are done using the pointer.

    Now for an alternate approach, which doesn't require this nasty kernel-mode driver to expose the frame buffer pointer to your application.  Surely your AT91SAM9261 display driver supports DirectDraw, right?  In that case, your application can use IDirectDraw::CreateSurface to obtain an IDirectDrawSurface pointer representing the primary surface, and then use the IDirectDrawSurface::Lock method to obtain a pointer to the surface, which your "external graphical API" can paint on.  That code would look something like this:

    LPDIRECTDRAW lpDD;
    LPDIRECTDRAWSURFACE lpPrimary;
    HRESULT hr;
    DDSURFACEDESC ddsd;
    // Initialize DirectDraw
    hr = DirectDrawCreate(NULL, &lpDD, NULL);
    if (SUCCEEDED(hr))
    {
     // hWnd is handle of your top level app window, or you can
     // pass NULL if you specify DDSCL_NORMAL.
     hr = lpDD->SetCooperativeLevel(hWnd, DDSCL_FULLSCREEN);
     if (SUCCEEDED(hr))
     {
     // Create surface
     ddsd.dwSize = sizeof(DDSURFACEDESC);
     ddsd.dwFlags = DDSD_CAPS;
     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
     hr = lpDD->CreateSurface(&ddsd, &lpPrimary, NULL);
     }
    }
    
    

    If the CreateSurface call succeeds, lpPrimary will contain a IDirectDrawSurface pointer to the primary surface, from which you can then obtain a memory surface pointer using Lock().  Then call the IDirectDrawSurface::Unlock method when you're done with the surface memory pointer.

     LPBYTE lpSurfaceMemory;
     DDSURFACEDESC sd;
     sd.dwSize = sizeof(DDSURFACEDESC);
     // Use DDLOCK_WRITEONLY unless your API will also read from the framebuffer
     hr = lpPrimary->Lock(NULL, &sd, DDLOCK_WRITEONLY, NULL);
     if (SUCCEEDED(hr))
     {
     // sd.lpSurface points to primary surface memory (frame buffer)
     // Pass it to your external API for drawing
    
     // Unlock when we're done
     lpPrimary->Unlock(NULL);
     }
    
    
    

    I like this solution a lot better because it avoids the hassle of writing a kernel mode driver and having to add it to the OS.
    A few more things in closing:  First, are you certain this external API you are using will know the format of your display framebuffer - height, width, BPP, stride, etc.  Your API will need to if it is going to properly render graphics directly onto the frame buffer.  Second, are you sure drawing directly to the frame buffer is really for the best, or might you get by with drawing to a secondary surface or bitmap and then blitting that to the primary surface?  Finally, if you use this DirectDraw approach, be sure to review the documentation for IDirectDraw::Lock() and Accessing Surface Memory Directly to avoid any possible problems down the road.
     


    Tom Gensel PTG Systems, LLC
    http://www.ptgsystems.com
    Saturday, October 16, 2010 6:34 AM
  • I'm trying to follow the DirectDraw method but I still have some problems. The function CreateSurface() returns an invalid parameters error and I'm investigating on it.

    Thanks for the suggestion, for now.

    Monday, October 18, 2010 7:29 PM
  • Be sure to set all unused members of the DDSURFACEDESC structure to zero (I didn't do so in the sample code) and be sure to properly set the dwSize member.
    Tom Gensel PTG Systems, LLC
    http://www.ptgsystems.com
    Monday, October 18, 2010 8:01 PM
  • Hi,

    I think that in my board this API are not supported at all, because the Microsoft examples provided with DirectDraw component fails with the same error.

    590974 PID:da002e TID:12f000e OSAXST1: >>> Loading Module 'ddraw.dll' (0x83CA8AD8) at address 0x406B0000-0x406CA000 in Process 'ddex2.exe' (0x83D0B498)
    593732 PID:da002e TID:12f000e DirectDraw Debug Runtime in use.
    593747 PID:400002 TID:12f000e AddToProcessInputLocaleTable: Added process to ProcessInputLocale table, hProcess = 0x00DA002E
    593887 PID:400002 TID:12f000e DDGPEGetPixelFormatFromSurfaceDesc returned DDERR_UNSUPPORTEDFORMAT
    593902 PID:400002 TID:12f000e DDGPECreateSurface ERROR - DDERR_UNSUPPORTEDFORMAT (0x88760218)
    593918 PID:da002e TID:12f000e GWES Hook fails surface creation. IDirectDraw::CreateSurface fails.
    593935 PID:da002e TID:12f000e DDEX2: CreateSurface FAILED 

    I don't understand if the problem is that (unsupported ddraw) or other one. If I can't resolve the problem I will use the "driver solution". I hope that touchscreen and other video functions already works with this solution.

     EDIT:

    From Microsoft Page: "The DirectDraw® API provides support for hardware-accelerated 2-D graphics."

    and for my board I have seen that:

    2D graphic acceleration NOT SUPPORTED (http://www.at91.com/windows4sam/bin/view/Windows4SAM/WindowsEmbeddedCEBSP)

    So I think that this way is not right.

    EDIT:

    Can I use the GDI interface for resolve my problem like with DirectDraw?

    Wednesday, October 20, 2010 6:58 AM