Lib for FTDI FT800 graphic controller "EVE" The API is changed from the FTDI original names. It use smaller names now. DL() will add something to the display list instead of Ft_App_WrCoCmd_Buffer ... The FTDI programmer Guide is also using this commands.

Dependents:   FT800_RGB_demo FT800_RGB_demo2 FT800_demo_for_habr Temp_&_RH_at_TFT-demo ... more

Fork of FT800 by Peter Drescher

The mbed is talking thru the SPI interface with the graphic engine. We have to set up a list of Commands and send them to the FT800 to get graphics.

Hardware

1. VM800C development modules from FTDI : http://www.ftdichip.com/Products/Modules/VM800C.html

The modules come with different size lcd. 3.5", 4.3" or 5" or without. /media/uploads/dreschpe/ftdi_eve.jpg The picture shows a modified board, because my lcd had a different pinout. The mbed is connected to the pin header on the bottom.

2. EVBEVE-FT800 board from GLYN: http://www.glyn.com/News-Events/Newsletter/Newsletter-2013/October-2013/A-quick-start-for-EVE-Requires-no-basic-knowledge-graphics-sound-and-touch-can-all-be-learned-in-minutes

The module has a 40 pin flex cable connector to connect a display out of the EDT series.

/media/uploads/dreschpe/glyn_eve.jpg

The mbed is connected via the pin header on the left. If you use this board with a EDT display you have to uncomment the #define Inv_Backlite in FT_LCD_Type.h, because the backlight dimming is inverted.

3. ConnectEVE board from MikroElektronika http://www.mikroe.com/add-on-boards/display/connecteve/#headers_10 The board has also a pin header to connect the mbed. - not tested, but it looks like the other boards.

4. ADAM arduino shield http://www.4dsystems.com.au/product/4DLCD_FT843/ Component page : http://mbed.org/components/ADAM/

Works with the NUCLEO boards, but you have to patch three wires.

/media/uploads/dreschpe/adam.jpg

Connection

We need 5 signals to connect to the mbed. SCK, MOSI and MISO are connected to a SPI channel. SS is the chip select signal and PD work as powerdown. The additional INT signal is not used at the moment. It is possible to generate a interrupt signal, but at the moment you have to poll the status register of the FT800 to see if a command is finished.

Software

This lib is based on the demo code from FTDI. If you want to use it, you have to read the programming manual : http://www.ftdichip.com/Support/Documents/ProgramGuides/FT800%20Programmers%20Guide.pdf

See my demo : http://mbed.org/users/dreschpe/code/FT800_RGB_demo/

FT_Gpu_Hal.cpp

Committer:
dreschpe
Date:
2015-02-10
Revision:
6:16e22c789f7d
Parent:
4:363ec27cdfaa

File content as of revision 6:16e22c789f7d:

/* mbed Library for FTDI FT800  Enbedded Video Engine "EVE"
 * based on Original Code Sample from FTDI
 * ported to mbed by Peter Drescher, DC2PD 2014
 * Released under the MIT License: http://mbed.org/license/mit 
 * 19.09.14 changed to shorter function names  
 * FTDI was using very long names. 
 * Ft_App_Flush_Co_Buffer -> Flush_Co_Buffer ...  */

#include "FT_Platform.h"
#include "mbed.h"
#include "FT_LCD_Type.h"

FT800::FT800(PinName mosi,
			PinName miso,
			PinName sck,
			PinName ss,
			PinName intr,
			PinName pd)
	:
	 _spi(mosi, miso, sck),
	 _ss(ss),
	 _pd(pd),
	 _f800_isr(InterruptIn(intr))
	 {
	 	 _spi.format(8,0);                  // 8 bit spi mode 0
    	 _spi.frequency(2000000);          // start with 10 Mhz SPI clock
    	 _ss = 1;                           // cs high
    	 _pd = 1;                           // PD high
		 Bootup();
	 }


ft_bool_t FT800::Bootup(void){
	Open();
	BootupConfig();

	return(1);
	}


ft_void_t FT800::BootupConfig(void){
	ft_uint8_t chipid;
	/* Do a power cycle for safer side */
	Powercycle( FT_TRUE);

	/* Access address 0 to wake up the FT800 */
	HostCommand( FT_GPU_ACTIVE_M);
	Sleep(20);

	/* Set the clk to external clock */
	HostCommand( FT_GPU_EXTERNAL_OSC);
	Sleep(10);


	/* Switch PLL output to 48MHz */
	HostCommand( FT_GPU_PLL_48M);
	Sleep(10);

	/* Do a core reset for safer side */
	HostCommand( FT_GPU_CORE_RESET);

	//Read Register ID to check if FT800 is ready.
	chipid = Rd8(  REG_ID);
	while(chipid != 0x7C)
		chipid = Rd8(  REG_ID);


	// Speed up
	_spi.frequency(20000000);           // 20 Mhz SPI clock

	/* Configuration of LCD display */
    DispHCycle = my_DispHCycle;
    Wr16(  REG_HCYCLE, DispHCycle);
    DispHOffset = my_DispHOffset;
    Wr16(  REG_HOFFSET, DispHOffset);
    DispWidth = my_DispWidth;
    Wr16(  REG_HSIZE, DispWidth);
    DispHSync0 = my_DispHSync0;
    Wr16(  REG_HSYNC0, DispHSync0);
    DispHSync1 = my_DispHSync1;
    Wr16(  REG_HSYNC1, DispHSync1);
    DispVCycle = my_DispVCycle;
    Wr16(  REG_VCYCLE, DispVCycle);
    DispVOffset = my_DispVOffset;
    Wr16(  REG_VOFFSET, DispVOffset);
    DispHeight = my_DispHeight;
    Wr16(  REG_VSIZE, DispHeight);
    DispVSync0 = my_DispVSync0;
    Wr16(  REG_VSYNC0, DispVSync0);
    DispVSync1 = my_DispVSync1;
    Wr16(  REG_VSYNC1, DispVSync1);
    DispSwizzle = my_DispSwizzle;
    Wr8(  REG_SWIZZLE, DispSwizzle);
    DispPCLKPol = my_DispPCLKPol;
    Wr8(  REG_PCLK_POL, DispPCLKPol);
    Wr8(  REG_CSPREAD, 1);
    DispPCLK = my_DispPCLK;
    Wr8(  REG_PCLK, DispPCLK);//after this display is visible on the LCD

	Wr16(  REG_PWM_HZ, 1000);

#ifdef Inv_Backlite	              // turn on backlite
	Wr16(  REG_PWM_DUTY, 0);
#else
	Wr16(  REG_PWM_DUTY, 100);
#endif

    Wr8(  REG_GPIO_DIR,0x82);  //| Rd8( REG_GPIO_DIR));
    Wr8(  REG_GPIO,0x080);     //| Rd8( REG_GPIO));

	Wr32(  RAM_DL, CLEAR(1,1,1));
	Wr32(  RAM_DL+4, DISPLAY());
	Wr32(  REG_DLSWAP,1);

	Wr16(  REG_PCLK, DispPCLK);

    /* Touch configuration - configure the resistance value to 1200 - this value is specific to customer requirement and derived by experiment */
    Wr16(  REG_TOUCH_RZTHRESH,1200);

}



/* API to initialize the SPI interface */
ft_bool_t  FT800::Init()
{
	// is done in constructor
	return 1;
}


ft_bool_t  FT800::Open()
{
	cmd_fifo_wp = dl_buff_wp = 0;
	status = OPENED;
	return 1;
}

ft_void_t  FT800::Close( )
{
	status = CLOSED;
}

ft_void_t FT800::DeInit()
{

}

/*The APIs for reading/writing transfer continuously only with small buffer system*/
ft_void_t  FT800::StartTransfer( FT_GPU_TRANSFERDIR_T rw,ft_uint32_t addr)
{
	if (FT_GPU_READ == rw){
		_ss = 0;       // cs low
		_spi.write(addr >> 16);
		_spi.write(addr >> 8);
		_spi.write(addr & 0xff);
		_spi.write(0); //Dummy Read Byte
		status = READING;
	}else{
		_ss = 0;       // cs low
		_spi.write(0x80 | (addr >> 16));
		_spi.write(addr >> 8);
		_spi.write(addr & 0xff);
		status = WRITING;
	}
}


/*The APIs for writing transfer continuously only*/
ft_void_t  FT800::StartCmdTransfer( FT_GPU_TRANSFERDIR_T rw, ft_uint16_t count)
{
	StartTransfer( rw, cmd_fifo_wp + RAM_CMD);
}

ft_uint8_t  FT800::TransferString( const ft_char8_t *string)
{
    ft_uint16_t length = strlen(string);
    while(length --){
       Transfer8( *string);
       string ++;
    }
    //Append one null as ending flag
    Transfer8( 0);
    return(1);
}


ft_uint8_t  FT800::Transfer8( ft_uint8_t value)
{
        return _spi.write(value);
}


ft_uint16_t  FT800::Transfer16( ft_uint16_t value)
{
	ft_uint16_t retVal = 0;

        if (status == WRITING){
		Transfer8( value & 0xFF);//LSB first
		Transfer8( (value >> 8) & 0xFF);
	}else{
		retVal = Transfer8( 0);
		retVal |= (ft_uint16_t)Transfer8( 0) << 8;
	}

	return retVal;
}

ft_uint32_t  FT800::Transfer32( ft_uint32_t value)
{
	ft_uint32_t retVal = 0;
	if (status == WRITING){
		Transfer16( value & 0xFFFF);//LSB first
		Transfer16( (value >> 16) & 0xFFFF);
	}else{
		retVal = Transfer16( 0);
		retVal |= (ft_uint32_t)Transfer16( 0) << 16;
	}
	return retVal;
}

ft_void_t   FT800::EndTransfer( )
{
	_ss = 1;
	status = OPENED;
}


ft_uint8_t  FT800::Rd8( ft_uint32_t addr)
{
	ft_uint8_t value;
	StartTransfer( FT_GPU_READ,addr);
	value = Transfer8( 0);
	EndTransfer( );
	return value;
}
ft_uint16_t FT800::Rd16( ft_uint32_t addr)
{
	ft_uint16_t value;
	StartTransfer( FT_GPU_READ,addr);
	value = Transfer16( 0);
	EndTransfer( );
	return value;
}
ft_uint32_t FT800::Rd32( ft_uint32_t addr)
{
	ft_uint32_t value;
	StartTransfer( FT_GPU_READ,addr);
	value = Transfer32( 0);
	EndTransfer( );
	return value;
}

ft_void_t FT800::Wr8( ft_uint32_t addr, ft_uint8_t v)
{
	StartTransfer( FT_GPU_WRITE,addr);
	Transfer8( v);
	EndTransfer( );
}
ft_void_t FT800::Wr16( ft_uint32_t addr, ft_uint16_t v)
{
	StartTransfer( FT_GPU_WRITE,addr);
	Transfer16( v);
	EndTransfer( );
}
ft_void_t FT800::Wr32( ft_uint32_t addr, ft_uint32_t v)
{
	StartTransfer( FT_GPU_WRITE,addr);
	Transfer32( v);
	EndTransfer( );
}

ft_void_t FT800::HostCommand( ft_uint8_t cmd)
{
  _ss = 0;
  _spi.write(cmd);
  _spi.write(0);
  _spi.write(0);
  _ss = 1;
}

ft_void_t FT800::ClockSelect( FT_GPU_PLL_SOURCE_T pllsource)
{
   HostCommand( pllsource);
}

ft_void_t FT800::PLL_FreqSelect( FT_GPU_PLL_FREQ_T freq)
{
   HostCommand( freq);
}

ft_void_t FT800::PowerModeSwitch( FT_GPU_POWER_MODE_T pwrmode)
{
   HostCommand( pwrmode);
}

ft_void_t FT800::CoreReset( )
{
   HostCommand( 0x68);
}


ft_void_t FT800::Updatecmdfifo( ft_uint16_t count)
{
	 cmd_fifo_wp  = ( cmd_fifo_wp + count) & 4095;
	//4 byte alignment
	 cmd_fifo_wp = ( cmd_fifo_wp + 3) & 0xffc;
	Wr16( REG_CMD_WRITE, cmd_fifo_wp);
}


ft_uint16_t FT800::fifo_Freespace( )
{
	ft_uint16_t fullness,retval;

	fullness = ( cmd_fifo_wp - Rd16( REG_CMD_READ)) & 4095;
	retval = (FT_CMD_FIFO_SIZE - 4) - fullness;
	return (retval);
}

ft_void_t FT800::WrCmdBuf( ft_uint8_t *buffer,ft_uint16_t count)
{
	ft_uint32_t length =0, SizeTransfered = 0;

#define MAX_CMD_FIFO_TRANSFER   fifo_Freespace( )
	do {
		length = count;
		if (length > MAX_CMD_FIFO_TRANSFER){
		    length = MAX_CMD_FIFO_TRANSFER;
		}
      	        CheckCmdBuffer( length);

                StartCmdTransfer( FT_GPU_WRITE,length);

                SizeTransfered = 0;
		while (length--) {
                    Transfer8( *buffer);
		    		buffer++;
                    SizeTransfered ++;
		}
                length = SizeTransfered;

		EndTransfer( );
		Updatecmdfifo( length);

		WaitCmdfifo_empty( );

		count -= length;
	}while (count > 0);
}


ft_void_t FT800::WrCmdBufFromFlash( FT_PROGMEM ft_prog_uchar8_t *buffer,ft_uint16_t count)
{
	ft_uint32_t length =0, SizeTransfered = 0;

#define MAX_CMD_FIFO_TRANSFER   fifo_Freespace( )
	do {
		length = count;
		if (length > MAX_CMD_FIFO_TRANSFER){
		    length = MAX_CMD_FIFO_TRANSFER;
		}
      	        CheckCmdBuffer( length);

                StartCmdTransfer( FT_GPU_WRITE,length);


                SizeTransfered = 0;
		while (length--) {
                    Transfer8( ft_pgm_read_byte_near(buffer));
		    buffer++;
                    SizeTransfered ++;
		}
                length = SizeTransfered;

    	        EndTransfer( );
		Updatecmdfifo( length);

		WaitCmdfifo_empty( );

		count -= length;
	}while (count > 0);
}


ft_void_t FT800::CheckCmdBuffer( ft_uint16_t count)
{
   ft_uint16_t getfreespace;
   do{
        getfreespace = fifo_Freespace( );
   }while(getfreespace < count);
}

ft_void_t FT800::WaitCmdfifo_empty( )
{
   while(Rd16( REG_CMD_READ) != Rd16( REG_CMD_WRITE));

    cmd_fifo_wp = Rd16( REG_CMD_WRITE);
}

ft_void_t FT800::WaitLogo_Finish( )
{
    ft_int16_t cmdrdptr,cmdwrptr;

    do{
         cmdrdptr = Rd16( REG_CMD_READ);
         cmdwrptr = Rd16( REG_CMD_WRITE);
    }while ((cmdwrptr != cmdrdptr) || (cmdrdptr != 0));
     cmd_fifo_wp = 0;
}


ft_void_t FT800::ResetCmdFifo( )
{
    cmd_fifo_wp = 0;
}


ft_void_t FT800::WrCmd32( ft_uint32_t cmd)
{
         CheckCmdBuffer( sizeof(cmd));

         Wr32( RAM_CMD +  cmd_fifo_wp,cmd);

         Updatecmdfifo( sizeof(cmd));
}


ft_void_t FT800::ResetDLBuffer( )
{
            dl_buff_wp = 0;
}

/* Toggle PD_N pin of FT800 board for a power cycle*/
ft_void_t FT800::Powercycle(  ft_bool_t up)
{
	if (up)
	{
             //Toggle PD_N from low to high for power up switch
            _pd = 0;
            Sleep(20);

            _pd = 1;
            Sleep(20);
	}else
	{
             //Toggle PD_N from high to low for power down switch
            _pd = 1;
            Sleep(20);

            _pd = 0;
            Sleep(20);
	}
}

ft_void_t FT800::WrMemFromFlash( ft_uint32_t addr,const ft_prog_uchar8_t *buffer, ft_uint32_t length)
{
	//ft_uint32_t SizeTransfered = 0;

	StartTransfer( FT_GPU_WRITE,addr);

	while (length--) {
            Transfer8( ft_pgm_read_byte_near(buffer));
	    buffer++;
	}

	EndTransfer( );
}

ft_void_t FT800::WrMem( ft_uint32_t addr,const ft_uint8_t *buffer, ft_uint32_t length)
{
	//ft_uint32_t SizeTransfered = 0;

	StartTransfer( FT_GPU_WRITE,addr);

	while (length--) {
            Transfer8( *buffer);
	    buffer++;
	}

	EndTransfer( );
}


ft_void_t FT800::RdMem( ft_uint32_t addr, ft_uint8_t *buffer, ft_uint32_t length)
{
	//ft_uint32_t SizeTransfered = 0;

	StartTransfer( FT_GPU_READ,addr);

	while (length--) {
	   *buffer = Transfer8( 0);
	   buffer++;
	}

	EndTransfer( );
}

ft_int32_t FT800::Dec2Ascii(ft_char8_t *pSrc,ft_int32_t value)
{
	ft_int16_t Length;
	ft_char8_t *pdst,charval;
	ft_int32_t CurrVal = value,tmpval,i;
	ft_char8_t tmparray[16],idx = 0;

	Length = strlen(pSrc);
	pdst = pSrc + Length;

	if(0 == value)
	{
		*pdst++ = '0';
		*pdst++ = '\0';
		return 0;
	}

	if(CurrVal < 0)
	{
		*pdst++ = '-';
		CurrVal = - CurrVal;
	}
	/* insert the value */
	while(CurrVal > 0){
		tmpval = CurrVal;
		CurrVal /= 10;
		tmpval = tmpval - CurrVal*10;
		charval = '0' + tmpval;
		tmparray[idx++] = charval;
	}

	for(i=0;i<idx;i++)
	{
		*pdst++ = tmparray[idx - i - 1];
	}
	*pdst++ = '\0';

	return 0;
}


ft_void_t FT800::Sleep(ft_uint16_t ms)
{
	wait_ms(ms);
}

ft_void_t FT800::Sound_ON(){
	 Wr8(  REG_GPIO, 0x02 | Rd8( REG_GPIO));
}

ft_void_t FT800::Sound_OFF(){
	 Wr8(  REG_GPIO, 0xFD & Rd8( REG_GPIO));
}