Basically i glued Peter Drescher and Simon Ford libs in a GraphicsDisplay class, then derived TFT or LCD class (which inherits Protocols class), then the most derived ones (Inits), which are per-display and are the only part needed to be adapted to diff hw.
Dependents: testUniGraphic_150217 maze_TFT_MMA8451Q TFT_test_frdm-kl25z TFT_test_NUCLEO-F411RE ... more
Revision 20:14daa48ffd4c, committed 2015-03-23
- Comitter:
- Geremia
- Date:
- Mon Mar 23 14:08:04 2015 +0000
- Parent:
- 19:1bdfb971b2c1
- Child:
- 21:ae0a4eedfc90
- Commit message:
- Add ILI 9320/9325/9328 custom TFT932x class, parallel/spi 8/16bit, with orientation, scroll, pixelread, fastwindow.; Par8 and 16 tested, SPI not at all, needs checking if the CS toggle is necessary (see SPI8.cpp SPI16.cpp).
Changed in this revision
--- a/Display/LCD.cpp Mon Mar 02 10:52:26 2015 +0000 +++ b/Display/LCD.cpp Mon Mar 23 14:08:04 2015 +0000 @@ -243,15 +243,17 @@ // first check parameter if((x >= screensize_X) || (y >= screensize_Y)) return; -// if(draw_mode == NORMAL) -// { - if(color) buffer[(x + ((y>>3)*screensize_X))^1] &= ~(1 << (y&7)); // erase pixel - else buffer[(x + ((y>>3)*screensize_X))^1] |= (1 << (y&7)); //Black=0000, set pixel -// } -// else -// { // XOR mode -// if(color == 1) buffer[x + ((y>>3) * screensize_X)] ^= (1 << (y&7)); // xor pixel -// } + if(color) buffer[(x + ((y>>3)*screensize_X))^1] &= ~(1 << (y&7)); // erase pixel + else buffer[(x + ((y>>3)*screensize_X))^1] |= (1 << (y&7)); //Black=0000, set pixel +} +unsigned short LCD::pixelread(int x, int y) +{ + if(!(orientation&1)) SWAP(x,y); + // first check parameter + if((x >= screensize_X) || (y >= screensize_Y)) return 0; + + if((buffer[(x + ((y>>3)*screensize_X))^1] & (1 << (y&7)))==0) return 0xFFFF ; // pixel not set, White + else return 0; // pixel set, Black } void LCD::copy_to_lcd(void) {
--- a/Display/LCD.h Mon Mar 02 10:52:26 2015 +0000 +++ b/Display/LCD.h Mon Mar 23 14:08:04 2015 +0000 @@ -68,7 +68,12 @@ */ virtual void window(int x, int y, int w, int h); - + /** Read pixel color at location + * @param x is the horizontal offset to this pixel. + * @param y is the vertical offset to this pixel. + * @returns 16bit color, 0000=Black(pixel set), FFFF=White(pixel clear). + */ + virtual unsigned short pixelread(int x, int y); /** Push a single pixel into the window and increment position. * You must first call window() then push pixels in loop. @@ -139,15 +144,15 @@ */ int sizeX(); - /** get display X size in pixels (native, orientation independent) - * @returns screen height in pixels. + /** get display Y size in pixels (native, orientation independent) + * @returns Y size in pixels */ int sizeY(); //////////////////////////////////////////////////////////////////////////////// // not implemented yet ////////////////////////////////////////////////////////////////// - virtual unsigned short pixelread(int x, int y){return 0;}; + // virtual unsigned short pixelread(int x, int y){return 0;}; virtual void window4read(int x, int y, int w, int h){}; void setscrollarea (int startY, int areasize){}; void scroll (int lines){};
--- a/Display/TFT.cpp Mon Mar 02 10:52:26 2015 +0000 +++ b/Display/TFT.cpp Mon Mar 23 14:08:04 2015 +0000 @@ -123,6 +123,7 @@ void TFT::hw_reset() { proto->hw_reset(); + BusEnable(true); } void TFT::BusEnable(bool enable) { @@ -291,7 +292,7 @@ { if(BGR2RGB(rback)==px) isBGR=true; } - // else debug("\r\nfail to identify gram read color format,\r\nsent %.4X read16 %.4X read18 %.4X", px, rback, rback18); + // debug("\r\nIdentify gram read color format,\r\nsent %.4X read16 %.4X(bgr%.4X) read18 %.4X(bgr%.4X)", px, rback, BGR2RGB(rback), rback18, BGR2RGB(rback18)); } // try to identify display controller void TFT::identify()
--- a/Display/TFT.h Mon Mar 02 10:52:26 2015 +0000 +++ b/Display/TFT.h Mon Mar 23 14:08:04 2015 +0000 @@ -146,8 +146,8 @@ */ int sizeX(); - /** get display X size in pixels (native, orientation independent) - * @returns screen height in pixels. + /** get display Y size in pixels (native, orientation independent) + * @returns Y size in pixels */ int sizeY();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Display/TFT932x.cpp Mon Mar 23 14:08:04 2015 +0000 @@ -0,0 +1,309 @@ + /* mbed UniGraphic library - custom TFT driver class, ILI932x specific + * Copyright (c) 2015 Giuliano Dianda + * Released under the MIT License: http://mbed.org/license/mit + */ + +#include "TFT932x.h" + +//#include "mbed_debug.h" + +#define SWAP(a, b) { a ^= b; b ^= a; a ^= b; } + +TFT932x::TFT932x(proto_t displayproto, PortName port, PinName CS, PinName reset, PinName DC, PinName WR, PinName RD, const int lcdsize_x, const int lcdsize_y, const char *name) + : GraphicsDisplay(name), screensize_X(lcdsize_x), screensize_Y(lcdsize_y) +{ + if(displayproto==PAR_8) + { + proto = new PAR8(port, CS, reset, DC, WR, RD); + dummycycles=1; + } + else if(displayproto==PAR_16) + { + proto = new PAR16(port, CS, reset, DC, WR, RD); + dummycycles=0; + } + // set_orientation(0); + foreground(White); + background(Black); + set_auto_up(false); //we don't have framebuffer + usefastwindow=false; + fastwindowready=false; + is18bit=false; + isBGR=false; + // cls(); + // locate(0,0); +} +TFT932x::TFT932x(proto_t displayproto, int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, const int lcdsize_x, const int lcdsize_y, const char *name) + : GraphicsDisplay(name), screensize_X(lcdsize_x), screensize_Y(lcdsize_y) +{ + if(displayproto==SPI_8) + { + proto = new SPI8(Hz, mosi, miso, sclk, CS, reset); + dummycycles=4; + } + else if(displayproto==SPI_16) + { + proto = new SPI16(Hz, mosi, miso, sclk, CS, reset); + dummycycles=2; + } + // set_orientation(0); + foreground(White); + background(Black); + set_auto_up(false); + usefastwindow=false; + fastwindowready=false; + is18bit=false; + isBGR=false; + // locate(0,0); +} +// dummy read needed before read gram +// read gram protocol function does 1 dymmy read as for MIPI standard, but ILI932x needs more and protocol specific number of cycles +// for example in spi mode, 5 dummy byte read needed, so for SPI16 2x16bit clocks done here and the 5th dummy will be handled by read gram function +void TFT932x::dummyread() + { + for(unsigned int i=0; i<dummycycles; i++) proto->dummyread(); + } +void TFT932x::reg_select(unsigned char reg, bool forread) + { + proto->reg_select(reg, forread); + } +void TFT932x::reg_write(unsigned char reg, unsigned short data) + { + proto->reg_write(reg, data); + } +unsigned short TFT932x::reg_read(unsigned char reg) + { + return proto->reg_read(reg); + } +void TFT932x::wr_gram(unsigned short data) + { + proto->wr_gram(data); + } +void TFT932x::wr_gram(unsigned short data, unsigned int count) + { + proto->wr_gram(data, count); + } +void TFT932x::wr_grambuf(unsigned short* data, unsigned int lenght) + { + proto->wr_grambuf(data, lenght); + } +unsigned short TFT932x::rd_gram() + { + return proto->rd_gram(is18bit); // protocol will handle 18to16 bit conversion + + } +//for TFT, just send data, position counters are in hw +void TFT932x::window_pushpixel(unsigned short color) +{ + proto->wr_gram(color); +} +void TFT932x::window_pushpixel(unsigned short color, unsigned int count) +{ + proto->wr_gram(color, count); +} +void TFT932x::window_pushpixelbuf(unsigned short* color, unsigned int lenght) + { + proto->wr_grambuf(color, lenght); + } +void TFT932x::hw_reset() + { + proto->hw_reset(); + BusEnable(true); + } +void TFT932x::BusEnable(bool enable) + { + proto->BusEnable(enable); + } +// ILI932x can't rotate in hw (swap raw<->columns) for landscape views, +// but can change the way address counter is auto incremented/decremented +void TFT932x::set_orientation(int o) +{ + // if(orientation == o) return; + orientation = o; + switch (orientation) + // BGR bit set for all modes, seems most TFT are like that, in case override set_orientation() in init + // ORG bit set for all modes + { + case 0:// default, portrait view 0° + reg_write(0x0001,0x0100); // S720 to S1 + reg_write(0x0060,0xA700); // G320 to G1 + reg_write(0x03, 0x10B0); + set_width(screensize_X); + set_height(screensize_Y); + break; + case 1:// landscape view +90° + reg_write(0x0001,0x0000); // S1 to S720 + reg_write(0x0060,0xA700); // G320 to G1 + reg_write(0x03, 0x10B8); // AM=1 increase addr ctr first vertically then horizontally + set_width(screensize_Y); + set_height(screensize_X); + break; + case 2:// portrait view +180° + reg_write(0x0001,0x0000); // S1 to S720 + reg_write(0x0060,0x2700); // G1 to G320 + reg_write(0x03, 0x10B0); + set_width(screensize_X); + set_height(screensize_Y); + break; + case 3:// landscape view -90° + reg_write(0x0001,0x0100); // S720 to S1 + reg_write(0x0060,0x2700); // G1 to G320 + reg_write(0x03, 0x10B8); // AM=1 increase addr ctr first vertically then horizontally + set_width(screensize_Y); + set_height(screensize_X); + break; + } +} +void TFT932x::invert(unsigned char o) +{ + unsigned short oldreg = reg_read(0x61); + if(o == 0) reg_write(0x61, oldreg|1); // seems most TFT have REV bit enabled for normal display + else reg_write(0x61, oldreg&0xFFFE); +} +void TFT932x::FastWindow(bool enable) + { + usefastwindow=enable; + } +// TFT have both column and raw autoincrement inside a window, with internal counters +void TFT932x::window(int x, int y, int w, int h) +{ + if(orientation==1 || orientation==3) + { + SWAP(x,y); + SWAP(w,h); + } + fastwindowready=false; // end raw/column going to be set to lower value than bottom-right corner + reg_write(0x50, x);//start column + reg_write(0x51, x+w-1);//end column + reg_write(0x52, y);//start page + reg_write(0x53, y+h-1);//end page + + reg_write(0x20, 0); // since ORG bit is set, address is windows relative, so should be set always to 0000 + reg_write(0x21, 0); + + reg_select(0x22, false); //write mem, just write gram next +} +void TFT932x::window4read(int x, int y, int w, int h) +{ + if(orientation==1 || orientation==3) + { + SWAP(x,y); + SWAP(w,h); + } + fastwindowready=false; // end raw/column going to be set to lower value than bottom-right corner + reg_write(0x50, x);//start column + reg_write(0x51, x+w-1);//end column + reg_write(0x52, y);//start page + reg_write(0x53, y+h-1);//end page + + reg_write(0x20, 0); // since ORG bit is set, address is windows relative, so should be set always to 0000 + reg_write(0x21, 0); + + reg_select(0x22, true); //read mem, just read gram next + dummyread(); +} +void TFT932x::pixel(int x, int y, unsigned short color) +{ + if(usefastwindow) + { + if(fastwindowready) //setting only start column/page does speedup, but needs end raw/column previously set to bottom-right corner + { + if(orientation==1 || orientation==3) SWAP(x,y); + reg_write(0x50, x);//start column only + reg_write(0x52, y);//start page only + reg_write(0x20, 0); // since ORG bit is set, address is window relative, so should be set always to 0000 + reg_write(0x21, 0); + reg_select(0x22, false); //write mem, just write gram next + } + else + { + window(x,y,width()-x,height()-y); // set also end raw/column to bottom-right corner + fastwindowready=true; + } + } + else window(x,y,1,1); + wr_gram(color); +} +unsigned short TFT932x::pixelread(int x, int y) +{ + /* if(usefastwindow) // for ILI9325 fastwindows for reading works only in PAR16 + { + if(fastwindowready) //setting only start column/page does speedup, but needs end raw/column previously set to bottom-right corner + { + if(orientation==1 || orientation==3) SWAP(x,y); + reg_write(0x50, x);//start column only + reg_write(0x52, y);//start page only + reg_write(0x20, 0); // since ORG bit is set, address is window relative, so should be set always to 0000 + reg_write(0x21, 0); + reg_select(0x22, true); //read mem, just read gram next + } + else + { + window4read(x,y,width()-x,height()-y); // set also end raw/column to bottom-right corner + fastwindowready=true; + } + } + else*/ + window4read(x,y,1,1); + + unsigned short color; + color = rd_gram(); + if(isBGR) color = BGR2RGB(color); // in case, convert BGR to RGB + return color; +} +void TFT932x::setscrollarea (int startY, int areasize) // ie 0,480 for whole screen +{ + // ILI932x allows only ful lscreen scrolling + unsigned short oldreg = reg_read(0x61); + reg_write(0x61, oldreg|2); // enable scroll +} +void TFT932x::scroll (int lines) // ie 1= scrollup 1, 479= scrolldown 1 +{ + reg_write(0x6A, lines%screensize_Y); // select the (absolute)line which will be displayed as first line +} +void TFT932x::scrollreset() +{ + unsigned short oldreg = reg_read(0x61); + // reg_write(0x61, oldreg&0xFFFD); // disable scroll + reg_write(0x6A, 0); +} +void TFT932x::cls (void) +{ + WindowMax(); + wr_gram(_background,screensize_X*screensize_Y); +} +// try to get read gram pixel format, could be 16bit or 18bit, RGB or BGR +void TFT932x::auto_gram_read_format() +{ + unsigned short px=0xCDB1; + unsigned short rback, rback18; + pixel(0,0,px); + window4read(0,0,1,1); + rback=proto->rd_gram(0); // try 16bit + window4read(0,0,1,1); + rback18=proto->rd_gram(1); // try 18bit converted to 16 + if((rback18==px) || (BGR2RGB(rback18)==px)) + { + is18bit=true; + if(BGR2RGB(rback18)==px) isBGR=true; + } + else if((rback==px) || (BGR2RGB(rback)==px)) + { + if(BGR2RGB(rback)==px) isBGR=true; + } + // debug("\r\nIdentify gram read color format,\r\nsent %.4X read16 %.4X(bgr%.4X) read18 %.4X(bgr%.4X)", px, rback, BGR2RGB(rback), rback18, BGR2RGB(rback18)); +} +// try to identify display controller +void TFT932x::identify() +{ + tftID = reg_read(0x00); + hw_reset(); // in case wrong cmd messed up important settings +} +int TFT932x::sizeX() +{ + return screensize_X; +} +int TFT932x::sizeY() +{ + return screensize_Y; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Display/TFT932x.h Mon Mar 23 14:08:04 2015 +0000 @@ -0,0 +1,266 @@ +#ifndef MBED_TFT932x_H +#define MBED_TFT932x_H + +#include "GraphicsDisplay.h" +#include "PAR8.h" +#include "PAR16.h" +#include "SPI8.h" +#include "SPI16.h" +#include "Protocols.h" + + +/** A custom base class for ILI932x color TFT Display (except ILI9327 which is MIPI standard) +*/ +class TFT932x : public GraphicsDisplay +{ + +public: + + /** Create a monochrome LCD Parallel interface + * @param name The name used by the parent class to access the interface + */ + TFT932x(proto_t displayproto,PortName port, PinName CS, PinName reset, PinName DC, PinName WR, PinName RD, const int lcdsize_x, const int lcdsize_y, const char* name); + + /** Create a monochrome LCD SPI interface + * @note ILI9325D has different SPI protocol, not supported here + * @param name The name used by the parent class to access the interface + */ + TFT932x(proto_t displayproto, int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, const int lcdsize_x, const int lcdsize_y, const char* name); + + /////// functions that come for free, but can be overwritten/////////////////////////////////////////////////// +/////// ----------------------------------------------------/////////////////////////////////////////////////// + + /** Draw a pixel in the specified color. + * @param x is the horizontal offset to this pixel. + * @param y is the vertical offset to this pixel. + * @param color defines the color for the pixel. + */ + virtual void pixel(int x, int y, unsigned short color); + + /** Set the window, which controls where items are written to the screen. + * When something hits the window width, it wraps back to the left side + * and down a row. If the initial write is outside the window, it will + * be captured into the window when it crosses a boundary. + * @param x is the left edge in pixels. + * @param y is the top edge in pixels. + * @param w is the window width in pixels. + * @param h is the window height in pixels. + */ + virtual void window(int x, int y, int w, int h); + + /** Read pixel color at location + * @param x is the horizontal offset to this pixel. + * @param y is the vertical offset to this pixel. + * @returns 16bit color. + */ + virtual unsigned short pixelread(int x, int y); + + /** Set the window from which gram is read from. Autoincrements row/column + * @param x is the left edge in pixels. + * @param y is the top edge in pixels. + * @param w is the window width in pixels. + * @param h is the window height in pixels. + */ + virtual void window4read(int x, int y, int w, int h); + + /** Push a single pixel into the window and increment position. + * You must first call window() then push pixels. + * @param color is the pixel color. + */ + virtual void window_pushpixel(unsigned short color); + + /** Push some pixels of the same color into the window and increment position. + * You must first call window() then push pixels. + * @param color is the pixel color. + * @param count: how many + */ + virtual void window_pushpixel(unsigned short color, unsigned int count); + + /** Push array of pixel colors into the window and increment position. + * You must first call window() then push pixels. + * @param color is the pixel color. + */ + virtual void window_pushpixelbuf(unsigned short* color, unsigned int lenght); + + /** Framebuffer is not used for TFT + */ + virtual void copy_to_lcd(){ }; + + /** display inverted colors + * + * @param o = 0 normal, 1 invert + */ + void invert(unsigned char o); + + /** clear the entire screen + * The inherited one sets windomax then fill with background color + * We override it to speedup + */ + virtual void cls(); + + /** Set the orientation of the screen + * x,y: 0,0 is always top left + * + * @param o direction to use the screen (0-3) + * 0 = default 0° portrait view + * 1 = +90° landscape view + * 2 = +180° portrait view + * 3 = -90° landscape view + * + */ + virtual void set_orientation(int o); + + /** Set ChipSelect high or low + * @param enable true/false + */ + virtual void BusEnable(bool enable); + + /** Enable fast window (default disabled) + * used to speedup functions that plots single pixels, like circle, oblique lines or just sparse pixels + * @param enable true/false + * @note most but not all controllers support this, even if datasheet tells they should + */ + void FastWindow(bool enable); + + /** Enable scroll + * scroll is done in hw but only on the native vertical axis + * TFTs are mainly native protrait view, so horizontal scroll if rotated in landscape view + * @note ILI932x does not allow partial screen scrolling, only full screen is selectable + * @param startY unused, always 0 for ILI932x + * @param areasize unused, always screensize_Y for ILI932x + */ + void setscrollarea (int startY=0, int areasize=0); + + /** Scroll up(or left) the scrollarea + * + * @param lines number of lines to scroll, 1= scrollup 1, areasize-1= scrolldown 1 + */ + void scroll (int lines); + + /** Disable scroll and display un-scrolled screen + * + */ + void scrollreset(); + + /** get display X size in pixels (native, orientation independent) + * @returns X size in pixels + */ + int sizeX(); + + /** get display Y size in pixels (native, orientation independent) + * @returns Y size in pixels + */ + int sizeY(); + + unsigned int tftID; + + + + +protected: + + +////// functions needed by parent class /////////////////////////////////////// +////// -------------------------------- /////////////////////////////////////// + + /** ILI932x specific, does a dummy read cycle, number of bits is protocol dependent + * for PAR protocols: a signle RD bit toggle + * for SPI8: 8clocks + * for SPI16: 16 clocks + */ + virtual void dummyread (); + + /** ILI932x specific, select register for a successive write or read + * + * @param reg register to be selected + * @param forread false = a write next (default), true = a read next + * @note forread only used by SPI protocols + */ + virtual void reg_select(unsigned char reg, bool forread =false); + + /** ILI932x specific, write register with data + * + * @param reg register to write + * @param data 16bit data + */ + virtual void reg_write(unsigned char reg, unsigned short data); + + /** ILI932x specific, read register + * + * @param reg register to be read + * @returns 16bit register value + */ + virtual unsigned short reg_read(unsigned char reg); + + /** Send 16bit pixeldata to display controller + * + * @param data: halfword to send + * + */ + virtual void wr_gram(unsigned short data); + + /** Send same 16bit pixeldata to display controller multiple times + * + * @param data: halfword to send + * @param count: how many + * + */ + virtual void wr_gram(unsigned short data, unsigned int count); + + /** Send array of pixeldata shorts to display controller + * + * @param data: unsigned short pixeldata array + * @param lenght: lenght (in shorts) + * + */ + virtual void wr_grambuf(unsigned short* data, unsigned int lenght); + + /** Read 16bit pixeldata from display controller (with dummy cycle) + * + * @note autoconverts 18to16bit based on display identify info + * @returns 16bit color + */ + virtual unsigned short rd_gram(); + + /** HW reset sequence (without display init commands) + */ + void hw_reset(); + + /** Try to get read gram pixel format, could be 16bit or 18bit, RGB or BGR + * autoset internal flags so pixelread() will always return correct value. + */ + virtual void auto_gram_read_format(); + + /** Try to identify display ID + * @note support ILI9341,94xx, MIPI standard. May be be overridden in Init class for other specific IC + */ + virtual void identify(); + + unsigned int scrollbugfix; + + + +private: + + Protocols* proto; + const int screensize_X; + const int screensize_Y; + // pixel location + int cur_x; + int cur_y; + // window location + int win_x1; + int win_x2; + int win_y1; + int win_y2; + int orientation; + bool dummycycles; + bool usefastwindow; + bool fastwindowready; + bool fastwindowready4read; + bool is18bit; + bool isBGR; + +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Inits/ILI932x.cpp Mon Mar 23 14:08:04 2015 +0000 @@ -0,0 +1,113 @@ + /* mbed UniGraphic library - Device specific class + * Copyright (c) 2015 Giuliano Dianda + * Released under the MIT License: http://mbed.org/license/mit + */ + +#include "Protocols.h" +#include "ILI932x.h" + +////////////////////////////////////////////////////////////////////////////////// +// display settings /////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + + +ILI932x::ILI932x(proto_t displayproto, PortName port, PinName CS, PinName reset, PinName DC, PinName WR, PinName RD, const char *name , unsigned int LCDSIZE_X, unsigned int LCDSIZE_Y) + : TFT932x(displayproto, port, CS, reset, DC, WR, RD, LCDSIZE_X, LCDSIZE_Y, name) +{ + hw_reset(); + BusEnable(true); //set CS low, will stay low untill manually set high with BusEnable(false); + identify(); // will collect tftID + if(tftID==0x9325) init9325(); + auto_gram_read_format();// try to get read gram pixel format, could be 16bit or 18bit, RGB or BGR. Will set flags accordingly + set_orientation(0); + FastWindow(true); // most but not all controllers support this, even if datasheet tells they should. + cls(); + locate(0,0); +} +ILI932x::ILI932x(proto_t displayproto, int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, const char *name, unsigned int LCDSIZE_X, unsigned int LCDSIZE_Y) + : TFT932x(displayproto, Hz, mosi, miso, sclk, CS, reset, LCDSIZE_X, LCDSIZE_Y, name) +{ + hw_reset(); //TFT class forwards to Protocol class + BusEnable(true); //set CS low, TFT932x class will toggle CS every transfer + identify(); // will collect tftID + if(tftID==0x9325) init9325(); + auto_gram_read_format();// try to get read gram pixel format, could be 16bit or 18bit, RGB or BGR. Will set flags accordingly + set_orientation(0); + FastWindow(true); // most but not all controllers support this, even if datasheet tells they should. + cls(); + locate(0,0); +} +// reset and init the lcd controller + +void ILI932x::init9325() +{ + /* Example for ILI9325 ----------------------------------------------------*/ + + reg_write(0x0001,0x0100); + reg_write(0x0002,0x0700); + reg_write(0x0003,0x1030); + reg_write(0x0004,0x0000); + reg_write(0x0008,0x0207); + reg_write(0x0009,0x0000); + reg_write(0x000A,0x0000); + reg_write(0x000C,0x0000); + reg_write(0x000D,0x0000); + reg_write(0x000F,0x0000); +//power on sequence VGHVGL + reg_write(0x0010,0x0000); + reg_write(0x0011,0x0007); + reg_write(0x0012,0x0000); + reg_write(0x0013,0x0000); + reg_write(0x0007,0x0001); +wait_ms(200); +//vgh + reg_write(0x0010,0x1290); + reg_write(0x0011,0x0227); +wait_ms(50); + //vregiout + reg_write(0x0012,0x001d); //0x001b + wait_ms(50); + //vom amplitude + reg_write(0x0013,0x1500); + wait_ms(50); + //vom H + reg_write(0x0029,0x0018); + reg_write(0x002B,0x000D); +wait_ms(50); +//gamma + reg_write(0x0030,0x0004); + reg_write(0x0031,0x0307); + reg_write(0x0032,0x0002);// 0006 + reg_write(0x0035,0x0206); + reg_write(0x0036,0x0408); + reg_write(0x0037,0x0507); + reg_write(0x0038,0x0204);//0200 + reg_write(0x0039,0x0707); + reg_write(0x003C,0x0405);// 0504 + reg_write(0x003D,0x0F02); + //ram + reg_write(0x0050,0x0000); + reg_write(0x0051,0x00EF); + reg_write(0x0052,0x0000); + reg_write(0x0053,0x013F); + reg_write(0x0060,0xA700); + reg_write(0x0061,0x0001); + reg_write(0x006A,0x0000); + // + reg_write(0x0080,0x0000); + reg_write(0x0081,0x0000); + reg_write(0x0082,0x0000); + reg_write(0x0083,0x0000); + reg_write(0x0084,0x0000); + reg_write(0x0085,0x0000); + // + reg_write(0x0090,0x0010); + reg_write(0x0092,0x0600); + reg_write(0x0093,0x0003); + reg_write(0x0095,0x0110); + reg_write(0x0097,0x0000); + reg_write(0x0098,0x0000); + + reg_write(0x0007,0x0133); // display on + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Inits/ILI932x.h Mon Mar 23 14:08:04 2015 +0000 @@ -0,0 +1,57 @@ +#ifndef MBED_ILI932x_H +#define MBED_ILI932x_H + + + +#include "mbed.h" +#include "TFT932x.h" + +/** Class for ILI932x tft display controller +* to be copypasted and adapted for other controllers +*/ +class ILI932x : public TFT932x +{ + + public: + + /** Create a PAR display interface + * @param displayproto PAR_8 or PAR_16 + * @param port GPIO port name to use + * @param CS pin connected to CS of display + * @param reset pin connected to RESET of display + * @param DC pin connected to data/command of display + * @param WR pin connected to SDI of display + * @param RD pin connected to RS of display + * @param name The name used by the parent class to access the interface + * @param LCDSIZE_X x size in pixel - optional + * @param LCDSIZE_Y y size in pixel - optional + */ + ILI932x(proto_t displayproto, PortName port, PinName CS, PinName reset, PinName DC, PinName WR, PinName RD, const char* name, unsigned int LCDSIZE_X = 240, unsigned int LCDSIZE_Y = 320); + + /** Create an SPI display interface + * @param displayproto SPI_8 or SPI_16 + * @param Hz SPI speed in Hz + * @param mosi SPI pin + * @param miso SPI pin + * @param sclk SPI pin + * @param CS pin connected to CS of display + * @param reset pin connected to RESET of display + * @param name The name used by the parent class to access the interface + * @param LCDSIZE_X x size in pixel - optional + * @param LCDSIZE_Y y size in pixel - optional + */ + ILI932x(proto_t displayproto, int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, const char* name, unsigned int LCDSIZE_X = 240, unsigned int LCDSIZE_Y= 320); + + + +protected: + + + /** Init command sequence + */ + void init9325(); + + + +}; +#endif \ No newline at end of file
--- a/Protocols/PAR16.cpp Mon Mar 02 10:52:26 2015 +0000 +++ b/Protocols/PAR16.cpp Mon Mar 23 14:08:04 2015 +0000 @@ -25,56 +25,27 @@ _WR=1; _RD=1; _CS=1; -#ifdef STMPORTDEBUG - findport(port); //on return, GPIO get disabled -#endif _port.mode(PullNone); _port.output(); // will re-enable our GPIO port hw_reset(); } -#ifdef STMPORTDEBUG -// create a port obj with STM HAL drivers, just to collect memorymapped regs -void PAR16::findport(PortName port) -{ - port_t tempport; - port_init(&tempport, port, 0xFF, PIN_INPUT); - outreg = tempport.reg_out; - inreg = tempport.reg_in; - // debug("out 0x%.8X in 0x%.8X\r\n", outreg, inreg); -} -#endif void PAR16::wr_cmd8(unsigned char cmd) -{ -#ifdef USE_CS - _CS = 0; -#endif +{ _DC = 0; // 0=cmd _port.write(cmd); // write 8bit _WR=0; _WR=1; -#ifdef USE_CS - _CS = 1; -#endif + _DC = 1; // 1=data next } void PAR16::wr_data8(unsigned char data) { -#ifdef USE_CS - _CS = 0; -#endif - _DC = 1; // 1=data _port.write(data); // write 8bit _WR=0; _WR=1; -#ifdef USE_CS - _CS = 1; -#endif } void PAR16::wr_cmd16(unsigned short cmd) -{ -#ifdef USE_CS - _CS = 0; -#endif +{ _DC = 0; // 0=cmd _port.write(cmd>>8); // write 8bit _WR=0; @@ -82,62 +53,35 @@ _port.write(cmd&0xFF); // write 8bit _WR=0; _WR=1; -#ifdef USE_CS - _CS = 1; -#endif + _DC = 1; // 1=data next } void PAR16::wr_data16(unsigned short data) { -#ifdef USE_CS - _CS = 0; -#endif - _DC = 1; // 1=data _port.write(data>>8); // write 8bit _WR=0; _WR=1; _port.write(data&0xFF); // write 8bit _WR=0; _WR=1; -#ifdef USE_CS - _CS = 1; -#endif } void PAR16::wr_gram(unsigned short data) { -#ifdef USE_CS - _CS = 0; -#endif - _DC = 1; // 1=data _port.write(data); // write 16bit _WR=0; _WR=1; -#ifdef USE_CS - _CS = 1; -#endif } void PAR16::wr_gram(unsigned short data, unsigned int count) { -#ifdef USE_CS - _CS = 0; -#endif - _DC = 1; // 1=data while(count) { - _port.write(data); // write 16bit + _port.write(data); // rewrite even if same data, otherwise too much fast _WR=0; _WR=1; count--; } -#ifdef USE_CS - _CS = 1; -#endif } void PAR16::wr_grambuf(unsigned short* data, unsigned int lenght) { -#ifdef USE_CS - _CS = 0; -#endif - _DC = 1; // 1=data while(lenght) { _port.write(*data); // write 16bit @@ -146,17 +90,10 @@ data++; lenght--; } -#ifdef USE_CS - _CS = 1; -#endif } unsigned short PAR16::rd_gram(bool convert) { -#ifdef USE_CS - _CS = 0; -#endif unsigned int r=0; - _DC = 1; // 1=data _port.input(); _RD = 0; @@ -164,7 +101,7 @@ _RD = 1; _RD = 0; -// _RD = 0; // add wait + // _RD = 0; // add wait r |= _port.read(); _RD = 1; if(convert) @@ -178,20 +115,14 @@ // during reading, you read the raw 18bit gram r = RGB24to16((r&0xFF0000)>>16, (r&0xFF00)>>8, r&0xFF);// 18bit pixel padded to 24bits, rrrrrr00_gggggg00_bbbbbb00, converted to 16bit } -#ifdef USE_CS - _CS = 1; -#endif _port.output(); return (unsigned short)r; } unsigned int PAR16::rd_reg_data32(unsigned char reg) { -#ifdef USE_CS - _CS = 0; -#endif wr_cmd8(reg); unsigned int r=0; - _DC = 1; // 1=data + // _DC = 1; // 1=data _port.input(); _RD = 0; @@ -221,10 +152,9 @@ r |= (_port.read()&0xFF); _RD = 1; - _CS = 1; // force CS HIG to interupt the cmd in case was not supported -#ifndef USE_CS //if CS is not used, force fixed LOW again + _CS = 1; // toggle CS to interupt the cmd in case was not supported _CS = 0; -#endif + _port.output(); return r; } @@ -233,6 +163,52 @@ { return rd_reg_data32(reg); } +// ILI932x specific +void PAR16::dummyread() +{ + _port.input(); + _RD = 0; + _port.read(); // dummy read + _RD=1; + // _port.output(); +} +// ILI932x specific +void PAR16::reg_select(unsigned char reg, bool forread) +{ + _DC = 0; + _port.write(reg); // write 16bit + _WR=0; + _WR=1; + _DC = 1; // 1=data next +} +// ILI932x specific +void PAR16::reg_write(unsigned char reg, unsigned short data) +{ + _DC = 0; + _port.write(reg); // write 16bit + _WR=0; + _WR=1; + _DC = 1; + _port.write(data); // write 16bit + _WR=0; + _WR=1; +} +// ILI932x specific +unsigned short PAR16::reg_read(unsigned char reg) +{ + unsigned short r=0; + _DC = 0; + _port.write(reg); // write 16bit + _WR=0; + _WR=1; + _DC = 1; + _port.input(); + _RD=0; + r |= _port.read(); // read 16bit + _RD=1; + _port.output(); + return r; +} void PAR16::hw_reset() { wait_ms(15); @@ -241,12 +217,9 @@ _WR = 1; _RD = 1; _reset = 0; // display reset - wait_us(50); + wait_ms(2); _reset = 1; // end reset - wait_ms(15); -#ifndef USE_CS - _CS=0; // put CS low now and forever -#endif + wait_ms(100); } void PAR16::BusEnable(bool enable) {
--- a/Protocols/PAR16.h Mon Mar 02 10:52:26 2015 +0000 +++ b/Protocols/PAR16.h Mon Mar 23 14:08:04 2015 +0000 @@ -96,6 +96,35 @@ */ virtual unsigned int rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd); + /** ILI932x specific, does a dummy read cycle, number of bits is protocol dependent + * for PAR protocols: a signle RD bit toggle + * for SPI8: 8clocks + * for SPI16: 16 clocks + */ + virtual void dummyread (); + + /** ILI932x specific, select register for a successive write or read + * + * @param reg register to be selected + * @param forread false = a write next (default), true = a read next + * @note forread only used by SPI protocols + */ + virtual void reg_select(unsigned char reg, bool forread =false); + + /** ILI932x specific, write register with data + * + * @param reg register to write + * @param data 16bit data + */ + virtual void reg_write(unsigned char reg, unsigned short data); + + /** ILI932x specific, read register + * + * @param reg register to be read + * @returns 16bit register value + */ + virtual unsigned short reg_read(unsigned char reg); + /** HW reset sequence (without display init commands) */ virtual void hw_reset();
--- a/Protocols/PAR8.cpp Mon Mar 02 10:52:26 2015 +0000 +++ b/Protocols/PAR8.cpp Mon Mar 23 14:08:04 2015 +0000 @@ -26,111 +26,63 @@ _WR=1; _RD=1; _CS=1; -#ifdef STMPORTDEBUG - findport(port); //on return, GPIO get disabled -#endif _port.mode(PullNone); _port.output(); // will re-enable our GPIO port hw_reset(); } -#ifdef STMPORTDEBUG -// create a port obj with STM HAL drivers, just to collect memorymapped regs -void PAR8::findport(PortName port) -{ - port_t tempport; - port_init(&tempport, port, 0xFF, PIN_INPUT); - outreg = tempport.reg_out; - inreg = tempport.reg_in; - // debug("out 0x%.8X in 0x%.8X\r\n", outreg, inreg); -} -#endif void PAR8::wr_cmd8(unsigned char cmd) -{ -#ifdef USE_CS - _CS = 0; -#endif +{ _DC = 0; // 0=cmd + _port.write(cmd); // write 8bit _WR=0; - _port.write(cmd); // write 8bit _WR=1; -#ifdef USE_CS - _CS = 1; -#endif + _DC = 1; // 1=data next } void PAR8::wr_data8(unsigned char data) { -#ifdef USE_CS - _CS = 0; -#endif - _DC = 1; // 1=data + _port.write(data); // write 8bit _WR=0; - _port.write(data); // write 8bit _WR=1; -#ifdef USE_CS - _CS = 1; -#endif } void PAR8::wr_cmd16(unsigned short cmd) -{ -#ifdef USE_CS - _CS = 0; -#endif +{ _DC = 0; // 0=cmd - _WR=0; _port.write(cmd>>8); // write 8bit - _WR=1; _WR=0; - _port.write(cmd&0xFF); // write 8bit _WR=1; -#ifdef USE_CS - _CS = 1; -#endif + _port.write(cmd&0xFF); // write 8bit + _WR=0; + _WR=1; + _DC = 1; // 1=data next } void PAR8::wr_data16(unsigned short data) { -#ifdef USE_CS - _CS = 0; -#endif - _DC = 1; // 1=data + _port.write(data>>8); // write 8bit _WR=0; - _port.write(data>>8); // write 8bit _WR=1; + _port.write(data&0xFF); // write 8bit _WR=0; - _port.write(data&0xFF); // write 8bit _WR=1; -#ifdef USE_CS - _CS = 1; -#endif } void PAR8::wr_gram(unsigned short data) { -#ifdef USE_CS - _CS = 0; -#endif - _DC = 1; // 1=data + _port.write(data>>8); // write 8bit _WR=0; - _port.write(data>>8); // write 8bit _WR=1; + _port.write(data&0xFF); // write 8bit _WR=0; - _port.write(data&0xFF); // write 8bit _WR=1; -#ifdef USE_CS - _CS = 1; -#endif } void PAR8::wr_gram(unsigned short data, unsigned int count) { -#ifdef USE_CS - _CS = 0; -#endif - _DC = 1; // 1=data if((data>>8)==(data&0xFF)) { count<<=1; - _port.write(data); // write 8bit + // _port.write(data); // write 8bit while(count) { + _port.write(data); // rewrite even if same data, otherwise too much fast _WR=0; _WR=1; count--; @@ -140,62 +92,49 @@ { while(count) { + _port.write(data>>8); // write 8bit _WR=0; - _port.write(data>>8); // write 8bit _WR=1; + _port.write(data&0xFF); // write 8bit _WR=0; - _port.write(data&0xFF); // write 8bit _WR=1; count--; } } -#ifdef USE_CS - _CS = 1; -#endif } void PAR8::wr_grambuf(unsigned short* data, unsigned int lenght) { -#ifdef USE_CS - _CS = 0; -#endif - _DC = 1; // 1=data while(lenght) { + _port.write((*data)>>8); // write 8bit _WR=0; - _port.write((*data)>>8); // write 8bit _WR=1; + _port.write((*data)&0xFF); // write 8bit _WR=0; - _port.write((*data)&0xFF); // write 8bit _WR=1; data++; lenght--; } -#ifdef USE_CS - _CS = 1; -#endif } unsigned short PAR8::rd_gram(bool convert) { -#ifdef USE_CS - _CS = 0; -#endif unsigned int r=0; - _DC = 1; // 1=data _port.input(); _RD = 0; + _RD = 0; // add wait _port.read(); //dummy read _RD = 1; _RD = 0; -// _RD = 0; // add wait - r |= (_port.read()&0xFF); + _RD = 0; // add wait + r |= _port.read(); + _RD = 1; r <<= 8; - _RD = 1; _RD = 0; -// _RD = 0; // add wait - r |= (_port.read()&0xFF); + _RD = 0; // add wait + r |= _port.read(); _RD = 1; if(convert) { @@ -208,20 +147,13 @@ // during reading, you read the raw 18bit gram r = RGB24to16((r&0xFF0000)>>16, (r&0xFF00)>>8, r&0xFF);// 18bit pixel padded to 24bits, rrrrrr00_gggggg00_bbbbbb00, converted to 16bit } -#ifdef USE_CS - _CS = 1; -#endif _port.output(); return (unsigned short)r; } unsigned int PAR8::rd_reg_data32(unsigned char reg) { -#ifdef USE_CS - _CS = 0; -#endif wr_cmd8(reg); unsigned int r=0; - _DC = 1; // 1=data _port.input(); _RD = 0; @@ -252,9 +184,7 @@ _RD = 1; _CS = 1; // force CS HIG to interupt the cmd in case was not supported -#ifndef USE_CS //if CS is not used, force fixed LOW again _CS = 0; -#endif _port.output(); return r; } @@ -263,6 +193,70 @@ { return rd_reg_data32(reg); } +// ILI932x specific +void PAR8::dummyread() +{ + _port.input(); + _RD=0; + _RD=0; // add wait + _port.read(); // dummy read + _RD=1; + // _port.output(); +} +// ILI932x specific +void PAR8::reg_select(unsigned char reg, bool forread) +{ + _DC = 0; + _port.write(0); // write MSB + _WR=0; + _WR=1; + _port.write(reg); // write LSB + _WR=0; + _WR=1; + _DC = 1; // 1=data next +} +// ILI932x specific +void PAR8::reg_write(unsigned char reg, unsigned short data) +{ + _DC = 0; + _port.write(0); // write MSB + _WR=0; + _WR=1; + _port.write(reg); // write MSB + _WR=0; + _WR=1; + _DC = 1; + _port.write(data>>8); + _WR=0; + _WR=1; + _port.write(data&0xFF); + _WR=0; + _WR=1; +} +// ILI932x specific +unsigned short PAR8::reg_read(unsigned char reg) +{ + unsigned short r=0; + _DC = 0; + _port.write(0); + _WR=0; + _WR=1; + _port.write(reg); + _WR=0; + _WR=1; + _DC = 1; + _port.input(); + _RD=0; + r |= _port.read(); // read 8bit + _RD=1; + r <<= 8; + _RD=0; + r |= _port.read(); // read 8bit + _RD=1; + _port.output(); + + return r; +} void PAR8::hw_reset() { wait_ms(15); @@ -271,12 +265,9 @@ _WR = 1; _RD = 1; _reset = 0; // display reset - wait_us(50); + wait_ms(2); _reset = 1; // end reset - wait_ms(15); -#ifndef USE_CS - _CS=0; // put CS low now and forever -#endif + wait_ms(100); } void PAR8::BusEnable(bool enable) {
--- a/Protocols/PAR8.h Mon Mar 02 10:52:26 2015 +0000 +++ b/Protocols/PAR8.h Mon Mar 23 14:08:04 2015 +0000 @@ -96,6 +96,35 @@ */ virtual unsigned int rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd); + /** ILI932x specific, does a dummy read cycle, number of bits is protocol dependent + * for PAR protocols: a signle RD bit toggle + * for SPI8: 8clocks + * for SPI16: 16 clocks + */ + virtual void dummyread (); + + /** ILI932x specific, select register for a successive write or read + * + * @param reg register to be selected + * @param forread false = a write next (default), true = a read next + * @note forread only used by SPI protocols + */ + virtual void reg_select(unsigned char reg, bool forread =false); + + /** ILI932x specific, write register with data + * + * @param reg register to write + * @param data 16bit data + */ + virtual void reg_write(unsigned char reg, unsigned short data); + + /** ILI932x specific, read register + * + * @param reg register to be read + * @returns 16bit register value + */ + virtual unsigned short reg_read(unsigned char reg); + /** HW reset sequence (without display init commands) */ virtual void hw_reset();
--- a/Protocols/Protocols.h Mon Mar 02 10:52:26 2015 +0000 +++ b/Protocols/Protocols.h Mon Mar 23 14:08:04 2015 +0000 @@ -104,6 +104,35 @@ */ virtual unsigned int rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd) = 0; + /** ILI932x specific, does a dummy read cycle, number of bits is protocol dependent + * for PAR protocols: a signle RD bit toggle + * for SPI8: 8clocks + * for SPI16: 16 clocks + */ + virtual void dummyread () = 0; + + /** ILI932x specific, select register for a successive write or read + * + * @param reg register to be selected + * @param forread false = a write next (default), true = a read next + * @note forread only used by SPI protocols + */ + virtual void reg_select(unsigned char reg, bool forread =false) = 0; + + /** ILI932x specific, write register with data + * + * @param reg register to write + * @param data 16bit data + */ + virtual void reg_write(unsigned char reg, unsigned short data) = 0; + + /** ILI932x specific, read register + * + * @param reg register to be read + * @returns 16bit register value + */ + virtual unsigned short reg_read(unsigned char reg) = 0; + /** HW reset sequence (without display init commands) */ virtual void hw_reset() = 0;
--- a/Protocols/SPI16.cpp Mon Mar 02 10:52:26 2015 +0000 +++ b/Protocols/SPI16.cpp Mon Mar 23 14:08:04 2015 +0000 @@ -17,7 +17,6 @@ */ #include "SPI16.h" -//#define USE_CS SPI16::SPI16(int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, PinName DC) : _CS(CS), _spi(mosi, miso, sclk), _reset(reset), _DC(DC) @@ -33,101 +32,52 @@ void SPI16::wr_cmd8(unsigned char cmd) { -#ifdef USE_CS - _CS = 0; -#endif _spi.format(8,0); // it takes time, better use wr_cmd16 with NOP cmd _DC.write(0); // 0=cmd _spi.write(cmd); // write 8bit _spi.format(16,0); -#ifdef USE_CS - _CS = 1; -#endif + _DC.write(1); // 1=data next } void SPI16::wr_data8(unsigned char data) { -#ifdef USE_CS - _CS = 0; -#endif _spi.format(8,0); // it takes time, check prev cmd parameter, in case use wr_data16 with repeated byte - _DC.write(1); // 1=data _spi.write(data); // write 8bit _spi.format(16,0); -#ifdef USE_CS - _CS = 1; -#endif } void SPI16::wr_cmd16(unsigned short cmd) -{ -#ifdef USE_CS - _CS = 0; -#endif +{ _DC.write(0); // 0=cmd _spi.write(cmd); // write 16bit -#ifdef USE_CS - _CS = 1; -#endif + _DC.write(1); // 1=data next } void SPI16::wr_data16(unsigned short data) { -#ifdef USE_CS - _CS = 0; -#endif - _DC.write(1); // 1=data _spi.write(data); // write 16bit -#ifdef USE_CS - _CS = 1; -#endif } void SPI16::wr_gram(unsigned short data) { -#ifdef USE_CS - _CS = 0; -#endif - _DC.write(1); // 1=data _spi.write(data); // write 16bit -#ifdef USE_CS - _CS = 1; -#endif } void SPI16::wr_gram(unsigned short data, unsigned int count) { -#ifdef USE_CS - _CS = 0; -#endif - _DC.write(1); // 1=data while(count) { _spi.write(data); count--; } -#ifdef USE_CS - _CS = 1; -#endif } void SPI16::wr_grambuf(unsigned short* data, unsigned int lenght) { -#ifdef USE_CS - _CS = 0; -#endif - _DC.write(1); // 1=data while(lenght) { _spi.write(*data); data++; lenght--; } -#ifdef USE_CS - _CS = 1; -#endif } unsigned short SPI16::rd_gram(bool convert) { -#ifdef USE_CS - _CS = 0; -#endif unsigned int r=0; - _DC.write(1); // 1=data r |= _spi.write(0); // 16bit, whole first byte is dummy, second is red r <<= 16; r |= _spi.write(0); @@ -138,20 +88,15 @@ r = RGB24to16((r&0xFF0000)>>16, (r&0xFF00)>>8, r&0xFF);// 18bit pixel padded to 24bits, rrrrrr00_gggggg00_bbbbbb00, converted to 16bit } else r >>= 8; -_CS = 1; // force CS HIG to interupt the "read state" -#ifndef USE_CS //if CS is not used, force fixed LOW again + _CS = 1; // force CS HIG to interupt the "read state" _CS = 0; -#endif + return (unsigned short)r; } unsigned int SPI16::rd_reg_data32(unsigned char reg) { -#ifdef USE_CS - _CS = 0; -#endif wr_cmd8(reg); unsigned int r=0; - _DC.write(1);; // 1=data r |= _spi.write(0); // we get only 15bit valid, first bit was the dummy cycle r <<= 16; @@ -160,9 +105,7 @@ r |= (_spi.write(0) >> 15); // we clocked 15 more bit so ILI waiting for 16th, we need to reset spi bus _CS = 1; // force CS HIG to interupt the cmd -#ifndef USE_CS //if CS is not used, force fixed LOW again _CS = 0; -#endif return r; } unsigned int SPI16::rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd) @@ -173,29 +116,71 @@ wr_cmd8(SPIreadenablecmd); // spi-in enable cmd, 0xD9 (ili9341) or 0xFB (ili9488) or don't know wr_data8(0xF0|regparam); // in low nibble specify which reg parameter we want wr_cmd8(reg); // now send cmd (select register we want to read) - _DC.write(1); // 1=data r <<= 8; r |= (_spi.write(0) >> 8); } -_CS = 1; // force CS HIG to interupt the cmd -#ifndef USE_CS //if CS is not used, force fixed LOW again + _CS = 1; // force CS HIG to interupt the cmd _CS = 0; -#endif + return r; } +// ILI932x specific +void SPI16::dummyread() +{ + _spi.write(0); // dummy read +} +// ILI932x specific +void SPI16::reg_select(unsigned char reg, bool forread) +{ + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + _spi.write(0x70); // write 0070 + _spi.write(reg); // write 16bit + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + if(forread) _spi.write(0x73); + else _spi.write(0x72); +} +// ILI932x specific +void SPI16::reg_write(unsigned char reg, unsigned short data) +{ + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + _spi.write(0x70); // write 0070 + _spi.write(reg); // write 16bit + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + _spi.write(0x72); // write 0072 + _spi.write(data); // write 16bit +} +// ILI932x specific +unsigned short SPI16::reg_read(unsigned char reg) +{ + unsigned int r=0; + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + _spi.write(0x70); // write 0070 + _spi.write(reg); // write 16bit + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + _spi.write(0x73); // write 0073 + r |= _spi.write(0); // read 16bit, 8bit dummy + 8bit valid + r <<= 16; + r |= _spi.write(0); // read 16bit + + _CS = 1; //fixme: to resync, maybe really needed + _CS = 0; //fixme: to resync, maybe really needed + return (r>>8); +} void SPI16::hw_reset() { wait_ms(15); _DC = 1; - // _CS = 1; - _CS = 0; + _CS = 1; _reset = 0; // display reset - wait_us(50); + wait_ms(2); _reset = 1; // end reset - wait_ms(15); -#ifndef USE_CS - _CS=0; // put CS low now and forever -#endif + wait_ms(100); } void SPI16::BusEnable(bool enable) {
--- a/Protocols/SPI16.h Mon Mar 02 10:52:26 2015 +0000 +++ b/Protocols/SPI16.h Mon Mar 23 14:08:04 2015 +0000 @@ -20,7 +20,7 @@ * @param reset pin connected to RESET of display * @param DC pin connected to data/command of display */ - SPI16(int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, PinName DC); + SPI16(int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, PinName DC=NC); protected: @@ -99,6 +99,35 @@ */ virtual unsigned int rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd); + /** ILI932x specific, does a dummy read cycle, number of bits is protocol dependent + * for PAR protocols: a signle RD bit toggle + * for SPI8: 8clocks + * for SPI16: 16 clocks + */ + virtual void dummyread (); + + /** ILI932x specific, select register for a successive write or read + * + * @param reg register to be selected + * @param forread false = a write next (default), true = a read next + * @note forread only used by SPI protocols + */ + virtual void reg_select(unsigned char reg, bool forread =false); + + /** ILI932x specific, write register with data + * + * @param reg register to write + * @param data 16bit data + */ + virtual void reg_write(unsigned char reg, unsigned short data); + + /** ILI932x specific, read register + * + * @param reg register to be read + * @returns 16bit register value + */ + virtual unsigned short reg_read(unsigned char reg); + /** HW reset sequence (without display init commands) */ virtual void hw_reset();
--- a/Protocols/SPI8.cpp Mon Mar 02 10:52:26 2015 +0000 +++ b/Protocols/SPI8.cpp Mon Mar 23 14:08:04 2015 +0000 @@ -18,7 +18,6 @@ #include "SPI8.h" -//#define USE_CS SPI8::SPI8(int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, PinName DC) : _CS(CS), _spi(mosi, miso, sclk), _reset(reset), _DC(DC) @@ -27,75 +26,39 @@ _DC=1; _CS=1; _spi.format(8,0); // 8 bit spi mode 0 - // _spi.frequency(12000000); // 10 Mhz SPI clock, 12mhz for F411 _spi.frequency(Hz); hw_reset(); } void SPI8::wr_cmd8(unsigned char cmd) -{ -#ifdef USE_CS - _CS = 0; -#endif +{ _DC.write(0); // 0=cmd _spi.write(cmd); // write 8bit -#ifdef USE_CS - _CS = 1; -#endif + _DC.write(1); // 1=data next } void SPI8::wr_data8(unsigned char data) { -#ifdef USE_CS - _CS = 0; -#endif - _DC.write(1); // 1=data _spi.write(data); // write 8bit -#ifdef USE_CS - _CS = 1; -#endif } void SPI8::wr_cmd16(unsigned short cmd) -{ -#ifdef USE_CS - _CS = 0; -#endif +{ _DC.write(0); // 0=cmd _spi.write(cmd>>8); // write 8bit _spi.write(cmd&0xFF); // write 8bit -#ifdef USE_CS - _CS = 1; -#endif + _DC.write(1); // 1=data next } void SPI8::wr_data16(unsigned short data) { -#ifdef USE_CS - _CS = 0; -#endif - _DC.write(1); // 1=data _spi.write(data>>8); // write 8bit _spi.write(data&0xFF); // write 8bit -#ifdef USE_CS - _CS = 1; -#endif } void SPI8::wr_gram(unsigned short data) { -#ifdef USE_CS - _CS = 0; -#endif - _DC.write(1); // 1=data _spi.write(data>>8); // write 8bit _spi.write(data&0xFF); // write 8bit -#ifdef USE_CS - _CS = 1; -#endif } void SPI8::wr_gram(unsigned short data, unsigned int count) { -#ifdef USE_CS - _CS = 0; -#endif - _DC.write(1); // 1=data if((data>>8)==(data&0xFF)) { count<<=1; @@ -114,16 +77,9 @@ count--; } } -#ifdef USE_CS - _CS = 1; -#endif } void SPI8::wr_grambuf(unsigned short* data, unsigned int lenght) { -#ifdef USE_CS - _CS = 0; -#endif - _DC.write(1); // 1=data while(lenght) { _spi.write((*data)>>8); // write 8bit @@ -131,17 +87,10 @@ data++; lenght--; } -#ifdef USE_CS - _CS = 1; -#endif } unsigned short SPI8::rd_gram(bool convert) { -#ifdef USE_CS - _CS = 0; -#endif unsigned int r=0; - _DC.write(1); // 1=data _spi.write(0); // whole first byte is dummy r |= _spi.write(0); r <<= 8; @@ -155,19 +104,13 @@ r = RGB24to16((r&0xFF0000)>>16, (r&0xFF00)>>8, r&0xFF);// 18bit pixel padded to 24bits, rrrrrr00_gggggg00_bbbbbb00, converted to 16bit } _CS = 1; // force CS HIG to interupt the "read state" -#ifndef USE_CS //if CS is not used, force fixed LOW again _CS = 0; -#endif return (unsigned short)r; } unsigned int SPI8::rd_reg_data32(unsigned char reg) { -#ifdef USE_CS - _CS = 0; -#endif wr_cmd8(reg); unsigned int r=0; - _DC.write(1); // 1=data r |= _spi.write(0); // we get only 7bit valid, first bit was the dummy cycle r <<= 8; @@ -180,9 +123,7 @@ r |= (_spi.write(0) >> 7); // we clocked 7 more bit so ILI waiting for 8th, we need to reset spi bus _CS = 1; // force CS HIG to interupt the cmd -#ifndef USE_CS //if CS is not used, force fixed LOW again _CS = 0; -#endif return r; } unsigned int SPI8::rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd) @@ -193,30 +134,73 @@ wr_cmd8(SPIreadenablecmd); // spi-in enable cmd, 0xD9 (ili9341) or 0xFB (ili9488) or don't know wr_data8(0xF0|regparam); // in low nibble specify which reg parameter we want wr_cmd8(reg); // now send cmd (select register we want to read) - _DC.write(1); // 1=data r <<= 8; r |= _spi.write(0); // r = _spi.write(0) >> 8; for 16bit } -_CS = 1; // force CS HIG to interupt the cmd -#ifndef USE_CS //if CS is not used, force fixed LOW again + _CS = 1; // force CS HIG to interupt the cmd _CS = 0; -#endif + return r; +} +// ILI932x specific +void SPI8::dummyread() +{ + _spi.write(0); // dummy read +} +// ILI932x specific +void SPI8::reg_select(unsigned char reg, bool forread) +{ + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + _spi.write(0x70); + _spi.write(0); // write MSB + _spi.write(reg); // write LSB + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + if(forread) _spi.write(0x73); + else _spi.write(0x72); +} +// ILI932x specific +void SPI8::reg_write(unsigned char reg, unsigned short data) +{ + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + _spi.write(0x70); + _spi.write(0); // write MSB + _spi.write(reg); // write LSB + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + _spi.write(0x72); + _spi.write(data>>8); + _spi.write(data&0xFF); +} +// ILI932x specific +unsigned short SPI8::reg_read(unsigned char reg) +{ + unsigned short r=0; + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + _spi.write(0x70); + _spi.write(0); // write MSB + _spi.write(reg); // write LSB + _CS = 1; //fixme: really needed? + _CS = 0; //fixme: really needed? + _spi.write(0x73); + _spi.write(0); // dummy read + r = _spi.write(0); // read 8bit + r <<= 8; + r |= _spi.write(0); // read 8bit return r; } void SPI8::hw_reset() { wait_ms(15); _DC = 1; - // _CS = 1; - _CS = 0; + _CS = 1; _reset = 0; // display reset - wait_us(50); + wait_ms(2); _reset = 1; // end reset - wait_ms(15); -#ifndef USE_CS - _CS=0; // put CS low now and forever -#endif + wait_ms(100); } void SPI8::BusEnable(bool enable) {
--- a/Protocols/SPI8.h Mon Mar 02 10:52:26 2015 +0000 +++ b/Protocols/SPI8.h Mon Mar 23 14:08:04 2015 +0000 @@ -20,7 +20,7 @@ * @param reset pin connected to RESET of display * @param DC pin connected to data/command of display */ - SPI8(int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, PinName DC); + SPI8(int Hz, PinName mosi, PinName miso, PinName sclk, PinName CS, PinName reset, PinName DC=NC); protected: @@ -96,6 +96,35 @@ */ virtual unsigned int rd_extcreg_data32(unsigned char reg, unsigned char SPIreadenablecmd); + /** ILI932x specific, does a dummy read cycle, number of bits is protocol dependent + * for PAR protocols: a signle RD bit toggle + * for SPI8: 8clocks + * for SPI16: 16 clocks + */ + virtual void dummyread (); + + /** ILI932x specific, select register for a successive write or read + * + * @param reg register to be selected + * @param forread false = a write next (default), true = a read next + * @note forread only used by SPI protocols + */ + virtual void reg_select(unsigned char reg, bool forread =false); + + /** ILI932x specific, write register with data + * + * @param reg register to write + * @param data 16bit data + */ + virtual void reg_write(unsigned char reg, unsigned short data); + + /** ILI932x specific, read register + * + * @param reg register to be read + * @returns 16bit register value + */ + virtual unsigned short reg_read(unsigned char reg); + /** HW reset sequence (without display init commands) */ virtual void hw_reset();