marco valli / TFT_ILI9163C

Dependents:   TFTLCDSCREEN Pong_ILI9163C

Fork of TFT_ILI9163C by _ peu605

TFT_ILI9163C.cpp

Committer:
peu605
Date:
2015-01-27
Revision:
5:836673938ba7
Parent:
3:254e799c24ca
Child:
6:83f3605478ab

File content as of revision 5:836673938ba7:

#include "TFT_ILI9163C.h"
#include "mbed.h"

/**
 * TFT_ILI9163C library for ST Nucleo F411RE
 * 
 * @author Copyright (c) 2014, .S.U.M.O.T.O.Y., coded by Max MC Costa
 * https://github.com/sumotoy/TFT_ILI9163C
 *
 * @author modified by masuda, Masuda Naika
 */

//constructors
TFT_ILI9163C::TFT_ILI9163C(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName dc, PinName reset) 
	: Adafruit_GFX(_TFTWIDTH,_TFTHEIGHT) , SPI(mosi,miso,sclk,NC), _cs(cs), _dc(dc) {
		
		_resetPinName = reset;
		init(cs, dc);
}

TFT_ILI9163C::TFT_ILI9163C(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName dc) 
	: Adafruit_GFX(_TFTWIDTH,_TFTHEIGHT) , SPI(mosi,miso,sclk,NC), _cs(cs), _dc(dc) {
		
		_resetPinName = NC;
		init(cs, dc);
}

//Serial pc(SERIAL_TX, SERIAL_RX);

// F411RE specific
#if defined(TARGET_NUCLEO_F411RE)
void TFT_ILI9163C::init(PinName cs, PinName dc){
	
	SPI_TypeDef *spi_ptr = (SPI_TypeDef*) _spi.spi;
		
    uint32_t cs_port_index = (uint32_t) cs >> 4;
    uint32_t dc_port_index = (uint32_t) dc >> 4;
    
	 //set cs/dc port addresses and masks
    cs_port_reg = (GPIO_TypeDef *) (GPIOA_BASE + (cs_port_index << 10));
    cs_reg_mask = 1 << ((uint32_t) cs & 0xf);
    dc_port_reg = (GPIO_TypeDef *) (GPIOA_BASE + (dc_port_index << 10));
    dc_reg_mask = 1 << ((uint32_t) dc & 0xf);
    
    // set bit band addresses
//  GPIO_TypeDef *cs_port_reg = (GPIO_TypeDef *) (GPIOA_BASE + (cs_port_index << 10));
//  GPIO_TypeDef *dc_port_reg = (GPIO_TypeDef *) (GPIOA_BASE + (dc_port_index << 10));
//  uint8_t cs_port_bit = (uint32_t) cs & 0xf;
//  uint8_t dc_port_bit = (uint32_t) dc & 0xf;
//	bb_cs_port = BITBAND_PERIPH(&cs_port_reg->ODR, cs_port_bit);
//	bb_dc_port = BITBAND_PERIPH(&dc_port_reg->ODR, dc_port_bit);
    
	bb_spi_txe = BITBAND_PERIPH(&spi_ptr->SR, MASK_TO_BITNUM(SPI_SR_TXE));
	bb_spi_bsy = BITBAND_PERIPH(&spi_ptr->SR, MASK_TO_BITNUM(SPI_SR_BSY));
	bb_spi_spe = BITBAND_PERIPH(&spi_ptr->CR1, MASK_TO_BITNUM(SPI_CR1_SPE));
	bb_spi_dff = BITBAND_PERIPH(&spi_ptr->CR1, MASK_TO_BITNUM(SPI_CR1_DFF));
	
#if defined(__F411RE_DMA__)
	// init DMA
	hdma.Init.Direction = DMA_MEMORY_TO_PERIPH;
	hdma.Init.PeriphInc = DMA_PINC_DISABLE;
	hdma.Init.MemInc = DMA_MINC_DISABLE;
	hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
	hdma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
	hdma.Init.Mode = DMA_NORMAL;
	hdma.Init.Priority = DMA_PRIORITY_MEDIUM;
	hdma.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
	hdma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
	hdma.Init.MemBurst = DMA_MBURST_SINGLE;
	hdma.Init.PeriphBurst = DMA_PBURST_SINGLE;
	
    if(_spi.spi == SPI_1){
        hdma.Instance = DMA2_Stream3;		// DMA2_Stream2
		hdma.Init.Channel = DMA_CHANNEL_3;	// DMA_CHANNEL_2
        __DMA2_CLK_ENABLE();
    } else if(_spi.spi == SPI_2){
        hdma.Instance = DMA1_Stream4;
		hdma.Init.Channel = DMA_CHANNEL_0;
        __DMA1_CLK_ENABLE();
    } else if(_spi.spi == SPI_3){
        hdma.Instance = DMA1_Stream5;		// DMA1_Stream7
		hdma.Init.Channel = DMA_CHANNEL_0;	// DMA_CHANNEL0
        __DMA1_CLK_ENABLE();
    } else if(_spi.spi == SPI_4){
        hdma.Instance = DMA2_Stream1;		// DMA2_Stream4
		hdma.Init.Channel = DMA_CHANNEL_4;	// DMA_CHANNEL_5
        __DMA2_CLK_ENABLE();
    } else if(_spi.spi == SPI_5){
        hdma.Instance = DMA2_Stream4;		// DMA2_Stream5, DMA2_Stream6
		hdma.Init.Channel = DMA_CHANNEL_2;	// DMA_CHANNEL5, DMA_CHANNEL7
        __DMA2_CLK_ENABLE();
    }
    
    HAL_DMA_Init(&hdma);

	// set SPI DR ss Peripheral address
	hdma.Instance->PAR = (uint32_t) &spi_ptr->DR;
	
	// set bit band addresses
	bb_spi_txdmaen = BITBAND_PERIPH(&spi_ptr->CR2, MASK_TO_BITNUM(SPI_CR2_TXDMAEN));
	bb_dma_sxcr_en = BITBAND_PERIPH(&hdma.Instance->CR, MASK_TO_BITNUM(DMA_SxCR_EN));
#endif
}
inline void TFT_ILI9163C::selectSlave() {
//	_cs = 0;							// Use DigitalOut
//	*bb_cs_port = 0;					// Use bit band
	cs_port_reg->BSRRH = cs_reg_mask;	// Use BSRR register
}
inline void TFT_ILI9163C::deselectSlave() {
//	_cs = 1;
//	*bb_cs_port = 1;
	cs_port_reg->BSRRL = cs_reg_mask;
}
inline void TFT_ILI9163C::setCommandMode() {
//	_dc = 0;
//	*bb_dc_port = 0;
	dc_port_reg->BSRRH = dc_reg_mask;
}
inline void TFT_ILI9163C::setDataMode() {
//	_dc = 1;
//	*bb_dc_port = 1;
	dc_port_reg->BSRRL = dc_reg_mask;
}
inline void TFT_ILI9163C::waitSpiFree() {
	
//	SPI_TypeDef *spi_ptr = (SPI_TypeDef*) _spi.spi;
//	while ((spi_ptr->SR & SPI_SR_TXE) == 0);
//	while ((spi_ptr->SR & SPI_SR_BSY) != 0);

	while (*bb_spi_txe == 0);
	while (*bb_spi_bsy != 0);
}

inline void TFT_ILI9163C::waitBufferFree() {
	
//	SPI_TypeDef *spi_ptr = (SPI_TypeDef*) _spi.spi;
//	while ((spi_ptr->SR & SPI_SR_TXE) == 0);

	while (*bb_spi_txe == 0);
}

inline void TFT_ILI9163C::set8bitMode() {
	
//	SPI_TypeDef *spi_ptr = (SPI_TypeDef*) _spi.spi;
//	spi_ptr->CR1 &= ~(SPI_CR1_SPE | SPI_CR1_DFF);
//	spi_ptr->CR1 |= SPI_CR1_SPE;
	
	*bb_spi_spe = 0;
	*bb_spi_dff = 0;
	*bb_spi_spe = 1;
}

inline void TFT_ILI9163C::set16bitMode() {
	
//	SPI_TypeDef *spi_ptr = (SPI_TypeDef*) _spi.spi;
//	spi_ptr->CR1 &= ~SPI_CR1_SPE;
//	spi_ptr->CR1 |= (SPI_CR1_SPE | SPI_CR1_DFF);
	
	*bb_spi_spe = 0;
	*bb_spi_dff = 1;
	*bb_spi_spe = 1;
}

void TFT_ILI9163C::writecommand(uint8_t c){
	
	set8bitMode();
	setCommandMode();
	selectSlave();
	
	SPI_TypeDef *spi_ptr = (SPI_TypeDef*) _spi.spi;
	spi_ptr->DR = c;
	
	waitSpiFree();
	deselectSlave();
}


void TFT_ILI9163C::writedata(uint8_t c){
	
	set8bitMode();
	setDataMode();
	selectSlave();
	
	SPI_TypeDef *spi_ptr = (SPI_TypeDef*) _spi.spi;
	spi_ptr->DR = c;
	
	waitSpiFree();
	deselectSlave();
} 


void TFT_ILI9163C::writedata16(uint16_t d){
	
	set16bitMode();
	setDataMode();
	selectSlave();
	
	SPI_TypeDef *spi_ptr = (SPI_TypeDef*) _spi.spi;
	spi_ptr->DR = d;
	
	waitSpiFree();
	deselectSlave();
}


void TFT_ILI9163C::writedata32(uint16_t d1, uint16_t d2){
	
	set16bitMode();
	setDataMode();
	selectSlave();
	
	SPI_TypeDef *spi_ptr = (SPI_TypeDef*) _spi.spi;
	spi_ptr->DR = d1;
	waitBufferFree();
	spi_ptr->DR = d2;
	
	waitSpiFree();
	deselectSlave();
}

#if defined(__F411RE_DMA__)
// use DMA, but polling... :-(
void TFT_ILI9163C::writedata16burst(uint16_t d, int32_t len) {
	
	len = len < 0 ? -len : len;
	
	if (len > 0) {
		set16bitMode();
		setDataMode();
		selectSlave();
	
		// clear DMA flags
//		__HAL_DMA_CLEAR_FLAG(&hdma, __HAL_DMA_GET_TE_FLAG_INDEX(&hdma));
		__HAL_DMA_CLEAR_FLAG(&hdma, __HAL_DMA_GET_TC_FLAG_INDEX(&hdma));
		
		hdma.Instance->M0AR = (uint32_t) &d;
		hdma.Instance->NDTR = len;
		
//		// enable DMA
//		hdma.Instance->CR |= DMA_SxCR_EN;
//		
//		// enable DMA request from SPI
//		SPI_TypeDef *spi_ptr = (SPI_TypeDef*) _spi.spi;
//		spi_ptr->CR2 |= SPI_CR2_TXDMAEN;
//		
//		// wait DMA complete
//		while (hdma.Instance->NDTR);
//		
//		// disable SPI-DMA
//		spi_ptr->CR2 &= ~SPI_CR2_TXDMAEN;
//		
//		// disable DMA
//		hdma.Instance->CR &= ~DMA_SxCR_EN;
//		while (hdma.Instance->CR & DMA_SxCR_EN);
		
		// enable DMA
		*bb_dma_sxcr_en = 1;
		
		// enable DMA request from SPI
		*bb_spi_txdmaen = 1;
		
		// wait DMA complete
		while (hdma.Instance->NDTR);
		
		// disable SPI-DMA
		*bb_spi_txdmaen = 0;
		
		// disable DMA
		*bb_dma_sxcr_en = 0;
		while (*bb_dma_sxcr_en);
		
		waitSpiFree();
		deselectSlave();
	}
}

#else
// use software loop, fast enough :-)
void TFT_ILI9163C::writedata16burst(uint16_t d, int32_t len) {
	
	len = len < 0 ? -len : len;
	
	if (len > 0) {
		set16bitMode();
		setDataMode();
		selectSlave();
		
		SPI_TypeDef *spi_ptr = (SPI_TypeDef*) _spi.spi;
		while (len--) {
			waitBufferFree();
			spi_ptr->DR = d;
		}
		
		waitSpiFree();
		deselectSlave();
	}
}
#endif

// mbed general
#else
void TFT_ILI9163C::init(PinName cs, PinName dc){
	// nothing here
}

void TFT_ILI9163C::writecommand(uint8_t c){
	
	_dc = 0;
	_cs = 0;
	
	SPI::write(c);

	_cs = 1;
}


void TFT_ILI9163C::writedata(uint8_t c){
	
	_dc = 1;
	_cs = 0;
	
	SPI::write(c);
	
	_cs = 1;
} 


void TFT_ILI9163C::writedata16(uint16_t d){
	
	_dc = 1;
	_cs = 0;
	
	SPI::write(d >> 8);
	SPI::write(d & 0xff);
	
	_cs = 1;
}


void TFT_ILI9163C::writedata32(uint16_t d1, uint16_t d2){
	
	_dc = 1;
	_cs = 0;
	
	SPI::write(d1 >> 8);
	SPI::write(d1 & 0xff);
	SPI::write(d2 >> 8);
	SPI::write(d2 & 0xff);

	_cs = 1;
}


void TFT_ILI9163C::writedata16burst(uint16_t d, int32_t len) {
	
	len = len < 0 ? -len : len;
	
	if (len > 0) {
	
		_dc = 1;
		_cs = 0;
		
		while (len--) {
			SPI::write(d >> 8);
			SPI::write(d & 0xff);
		}
	
		_cs = 1;
	}
}
#endif


void TFT_ILI9163C::setBitrate(uint32_t n){
	SPI::frequency(n);
}


void TFT_ILI9163C::begin(void) {
	
	SPI::format(8,0);			// 8 bit spi mode 0
	SPI::frequency(5000000L);	// 5MHz
	
	if (_resetPinName != NC) {
		DigitalOut _reset(_resetPinName);
		_reset = 1;
	    wait_ms(1);
	    _reset = 0;
	    wait_ms(2);
	    _reset = 1;
	    wait_ms(120);
    }

/*
7) MY:  1(bottom to top), 0(top to bottom) 	Row Address Order
6) MX:  1(R to L),        0(L to R)        	Column Address Order
5) MV:  1(Exchanged),     0(normal)        	Row/Column exchange
4) ML:  1(bottom to top), 0(top to bottom) 	Vertical Refresh Order
3) RGB: 1(BGR), 		   0(RGB)           	Color Space
2) MH:  1(R to L),        0(L to R)        	Horizontal Refresh Order
1)
0)

     MY, MX, MV, ML,RGB, MH, D1, D0
	 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0	//normal
	 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0	//Y-Mirror
	 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0	//X-Mirror
	 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0	//X-Y-Mirror
	 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0	//X-Y Exchange
	 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0	//X-Y Exchange, Y-Mirror
	 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0	//XY exchange
	 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0
*/
	_Mactrl_Data = 0;	// 0b00000000;
	_colorspaceData = __COLORSPC;//start with default data;
	chipInit();
}


void TFT_ILI9163C::chipInit() {
	writecommand(CMD_SWRESET);//software reset
	wait_ms(120);
	writecommand(CMD_SLPOUT);//exit sleep
	wait_ms(5);
	writecommand(CMD_PIXFMT);//Set Color Format 16bit   
	writedata(0x05);
	wait_ms(5);
	writecommand(CMD_GAMMASET);//default gamma curve 3
	writedata(0x04);//0x04
	wait_ms(1);
	writecommand(CMD_GAMRSEL);//Enable Gamma adj    
	writedata(0x01); 
	wait_ms(1);
	writecommand(CMD_NORML);
	
	writecommand(CMD_DFUNCTR);
	writedata(0xff);	// writedata(0b11111111);//
	writedata(0x06);	// writedata(0b00000110);//

	writecommand(CMD_PGAMMAC);//Positive Gamma Correction Setting
	#if defined(__GAMMASET1)
		writedata(0x36);//p1
		writedata(0x29);//p2
		writedata(0x12);//p3
		writedata(0x22);//p4
		writedata(0x1C);//p5
		writedata(0x15);//p6
		writedata(0x42);//p7
		writedata(0xB7);//p8
		writedata(0x2F);//p9
		writedata(0x13);//p10
		writedata(0x12);//p11
		writedata(0x0A);//p12
		writedata(0x11);//p13
		writedata(0x0B);//p14
		writedata(0x06);//p15
	#else
		writedata(0x3F);//p1
		writedata(0x25);//p2
		writedata(0x1C);//p3
		writedata(0x1E);//p4
		writedata(0x20);//p5
		writedata(0x12);//p6
		writedata(0x2A);//p7
		writedata(0x90);//p8
		writedata(0x24);//p9
		writedata(0x11);//p10
		writedata(0x00);//p11
		writedata(0x00);//p12
		writedata(0x00);//p13
		writedata(0x00);//p14
		writedata(0x00);//p15
	#endif

	writecommand(CMD_NGAMMAC);//Negative Gamma Correction Setting
	#if defined(__GAMMASET1)
		writedata(0x09);//p1
		writedata(0x16);//p2
		writedata(0x2D);//p3
		writedata(0x0D);//p4
		writedata(0x13);//p5
		writedata(0x15);//p6
		writedata(0x40);//p7
		writedata(0x48);//p8
		writedata(0x53);//p9
		writedata(0x0C);//p10
		writedata(0x1D);//p11
		writedata(0x25);//p12
		writedata(0x2E);//p13
		writedata(0x34);//p14
		writedata(0x39);//p15
	#else
		writedata(0x20);//p1
		writedata(0x20);//p2
		writedata(0x20);//p3
		writedata(0x20);//p4
		writedata(0x05);//p5
		writedata(0x15);//p6
		writedata(0x00);//p7
		writedata(0xA7);//p8
		writedata(0x3D);//p9
		writedata(0x18);//p10
		writedata(0x25);//p11
		writedata(0x2A);//p12
		writedata(0x2B);//p13
		writedata(0x2B);//p14
		writedata(0x3A);//p15
	#endif

	writecommand(CMD_FRMCTR1);//Frame Rate Control (In normal mode/Full colors)
	writedata(0x08);//0x0C//0x08
	writedata(0x02);//0x14//0x08
	wait_ms(1);
	writecommand(CMD_DINVCTR);//display inversion 
	writedata(0x07);
    wait_ms(1);
	writecommand(CMD_PWCTR1);//Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD   
	writedata(0x0A);//4.30 - 0x0A
	writedata(0x02);//0x05
	wait_ms(1);
	writecommand(CMD_PWCTR2);//Set BT[2:0] for AVDD & VCL & VGH & VGL   
	writedata(0x02);
	wait_ms(1);
	writecommand(CMD_VCOMCTR1);//Set VMH[6:0] & VML[6:0] for VOMH & VCOML   
	writedata(0x50);//0x50
	writedata(99);//0x5b
	wait_ms(1);
	writecommand(CMD_VCOMOFFS);
	writedata(0);//0x40
	wait_ms(1);
  
	colorSpace(_colorspaceData);
	setRotation(0);
	wait_ms(1);

	fillScreen(BLACK);
	writecommand(CMD_DISPON);//display ON 
}

/*
Colorspace selection:
0: RGB
1: GBR
*/
void TFT_ILI9163C::colorSpace(uint8_t cspace) {
	if (cspace < 1){
		_Mactrl_Data &= ~(1 << 3);	// bitClear(_Mactrl_Data,3);
	} else {
		_Mactrl_Data |= 1 << 3;		// bitSet(_Mactrl_Data,3);
	}
}


void TFT_ILI9163C::clearScreen(uint16_t color) {
	homeAddress();
	writedata16burst(color, _GRAMSIZE);
}

void TFT_ILI9163C::homeAddress() {
	setAddrWindow(0x00,0x00,_GRAMWIDTH-1,_GRAMHEIGH-1);
}


void TFT_ILI9163C::setCursor(int16_t x, int16_t y) {
	if (boundaryCheck(x,y)) return;
	setAddrWindow(0x00,0x00,x,y);
	cursor_x = x;
	cursor_y = y;
}


void TFT_ILI9163C::pushColor(uint16_t color) {
	 writedata16(color);
}


void TFT_ILI9163C::drawPixel(int16_t x, int16_t y, uint16_t color) {
	if (boundaryCheck(x,y)) return;
	if ((x < 0) || (y < 0)) return;
	setAddrWindow(x,y,x+1,y+1);
	writedata16(color);
}


void TFT_ILI9163C::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
	// Rudimentary clipping
	if (boundaryCheck(x,y)) return;
	if (((y + h) - 1) >= _height) h = _height-y;
	
	setAddrWindow(x,y,x,(y+h)-1);
	writedata16burst(color, h);
}

inline bool TFT_ILI9163C::boundaryCheck(int16_t x,int16_t y){
	if ((x >= _width) || (y >= _height)) return true;
	return false;
}

void TFT_ILI9163C::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
	// Rudimentary clipping
	if (boundaryCheck(x,y)) return;
	if (((x+w) - 1) >= _width)  w = _width-x;
	
	setAddrWindow(x,y,(x+w)-1,y);
	writedata16burst(color, w);
}

void TFT_ILI9163C::fillScreen(uint16_t color) {
	clearScreen(color);
}

// fill a rectangle
void TFT_ILI9163C::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
	
	if (boundaryCheck(x,y)) return;
	if (((x + w) - 1) >= _width)  w = _width  - x;
	if (((y + h) - 1) >= _height) h = _height - y;
	
	setAddrWindow(x,y,(x+w)-1,(y+h)-1);
	writedata16burst(color, w * h);
}


// Pass 8-bit (each) R,G,B, get back 16-bit packed color

uint16_t TFT_ILI9163C::Color565(uint8_t r, uint8_t g, uint8_t b) {
	return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}


void TFT_ILI9163C::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
	
	writecommand(CMD_CLMADRS); // Column
	
	if (rotation == 1) {
		writedata32(x0 + __OFFSET, x1 + __OFFSET);
	} else {
		writedata32(x0, x1);
	}

	writecommand(CMD_PGEADRS); // Page
	if (rotation == 0){
		writedata32(y0 + __OFFSET, y1 + __OFFSET);
	} else {
		writedata32(y0, y1);
	}

	writecommand(CMD_RAMWR); //Into RAM
}


void TFT_ILI9163C::setRotation(uint8_t m) {
	rotation = m &3; // can't be higher than 3
	switch (rotation) {
	case 0:
		_Mactrl_Data = 0x08;	// 0b00001000;
		_width  = _TFTWIDTH;
		_height = _TFTHEIGHT;//-__OFFSET;
		break;
	case 1:
		_Mactrl_Data = 0x68;	// 0b01101000;
		_width  = _TFTHEIGHT;//-__OFFSET;
		_height = _TFTWIDTH;
		break;
	case 2:
		_Mactrl_Data = 0xC8;	// 0b11001000;
		_width  = _TFTWIDTH;
		_height = _TFTHEIGHT;//-__OFFSET;
		break;
	case 3:
		_Mactrl_Data = 0xA8;	// 0b10101000;
		_width  = _TFTWIDTH;
		_height = _TFTHEIGHT;//-__OFFSET;
		break;
	}
	colorSpace(_colorspaceData);
	writecommand(CMD_MADCTL);
	writedata(_Mactrl_Data);
}


void TFT_ILI9163C::invertDisplay(bool i) {
	writecommand(i ? CMD_DINVON : CMD_DINVOF);
}