[Netduino Plus 2]_替Netduino Plus 2 接上ILI9341 320*240 SPI TFT 液晶螢幕
本篇主要筆記如何將SPI TFT螢幕,接上NETDUINO
其中TFT Driver是由http://forums.netduino.com/index.php?/topic/11458-ledlcd-tft-screen/
論壇內,作者studlyed所撰寫的,Github位置在https://github.com/veccsolutions/Vecc.Netduino.Drivers.Ili9341
我fork出來,做一些修改跟線路說明,還有一些變動的部分:
https://github.com/thkaw/Vecc.Netduino.Drivers.Ili9341
可以先在看下面文章之前,先把我FORK的版本先抓回來,另外Netduino應該也適用,
但記得要把Vecc.Netduino.Drivers.Ili9341.Sandbox\Progame.cs 在using的部分改成using SecretLabs.NETMF.Hardware.Netduino;,
並且記得去專案裡面includ SecretLabs.NETMF.Hardware.Netduino
I. Wiring
先來講接線好了,這部分我參照alesbedac在官方論壇發的修改的專案,在論壇上可以下載到ILI9341 ND2 Lib.zip
http://forums.netduino.com/index.php?/topic/10785-tft-lcd-ili9341/
另外這個版本是studlyed初期引用的版本,後來studlyed替這個lib增強並整理了許多的功能,我也有用alesbedac的版本簡單改了一下
也可以順利運行在netduino plus 2上頭,
放在Bitbucket上:https://bitbucket.org/thkaw/ili9341-nd2-lib-modify
建議也並抓下來,之後再trace code有些參數在alesbedac的版本會比較好懂。
但這兩個lib相近之處很像,不過studlyed多了一些字形設定還有封裝的比較完整,所以下文都是用studlyed的版本做
不過接線的部分則是參考alesbedac,所以有改一些接口位置的程式碼及微調細節
接線的部分,先來看一下這塊MODULE:
左邊的四根PIN是 FOR SD卡的,我就不講了,也是走SPI介面
右邊才是面板控制等訊號的腳位,由上至下分別為:
- SDO(MISO),不用接,因為沒有資料需要Slave out
- LED,背光源,可以直接接到3.3V或者接到Netduino plus 2的任意DIGITAL腳位,可以用專案內的程式控制LED開啟或關閉,我是直接吃3.3V
- SCK,SPI CLOCK,接到DIGITAL 13
- SDI(MOSI),接到DGITIAL 11
- D/C,就是Data Command的意思,接到ANALOG 2
- RESET,接到ANALOG 1
- CS,CHIP SELECT,接到DIGITAL 10
- GND,隨你接GND…
- VCC,請接3.3V
關於Netduino SPI接腳,可以支援3組SPI裝置,預設我是走第一組,如果要換成別組,請自行更改CS(CHIP SELECT)的接腳
第一組是D10,第二組是D9,第三組是D8。
詳細說明請參考:http://wiki.netduino.com/SPI.ashx
接腳OK之後,打開專案先直接執行看看螢幕有沒有跑出下面的畫面:
如果WORK,可以繼續看下去,如果不WORK,檢查接線…然後還是繼續看下去…
如果遇到螢幕顛倒或者水平垂直相反的問題,也請繼續看下去
II. Code trace/modify
方案打開之後會看到兩個專案Vecc.Netduino.Drivers.Ili9341,Vecc.Netduino.Drivers.Ili9341.Sandbox
主要的Program在Vecc.Netduino.Drivers.Ili9341.Sandbox
而Vecc.Netduino.Drivers.Ili9341下面則是Lib, Driver, Font等Source code
Vecc.Netduino.Drivers.Ili9341.Sandbox\Program.cs的內容非常簡單:
using SecretLabs.NETMF.Hardware.NetduinoPlus; using System.Threading; namespace Vecc.Netduino.Drivers.Ili9341.Sandbox { public class Program { public static void Main() { var tft = new Driver(isLandscape: false, lcdChipSelectPin: Pins.GPIO_PIN_D10, dataCommandPin: Pins.GPIO_PIN_A2, resetPin: Pins.GPIO_PIN_A1); var font = new StandardFixedWidthFont(); tft.ClearScreen(); tft.DrawString(10, 10, "NETDUINO PLUS 2", 0xF800, font); tft.DrawString(10, 50, "ILI9341 TFT TESTING PASS!", 0xF800, font); tft.DrawString(10, 90, " WWW.NTEX.TW", 0xF800, font); tft.DrawLine(20, 170, 210, 170, 0x0F00); tft.DrawRectangle(20, 180, 200, 50, 0x0f00); tft.FillScreen(22, 218, 180, 230, 0xfff0); tft.BacklightOn = true; int i = 0; while (true) { Thread.Sleep(1000); tft.DrawString(10, 90, " WWW.NTEX.TW ", 0xF800, font); Thread.Sleep(1000); tft.DrawString(10, 90, ">>WWW.NTEX.TW<<", 0xF800, font); tft.DrawString(10, 120, i.ToString(), 0x0FF0, font); i++; } } } }
如果你要換接腳接,在new Driver()帶入的建構參數需要跟著一併變動,
lcdChipSelectionPin等於TFT上的CS腳位
dataCommanPin等於D/C腳位
另外如果透過new Driver出來的tft物件,下面的function在Visual Studio裡面會顯示參數名稱,不難猜出他的使用方式
我就不一一細提。
接著讓我們看回Vecc.Netduino.Drivers.Ili9341\Driver.cs的建構子部分:
public Driver(bool isLandscape = false, Cpu.Pin lcdChipSelectPin = Cpu.Pin.GPIO_NONE, Cpu.Pin dataCommandPin = Cpu.Pin.GPIO_NONE, Cpu.Pin resetPin = Cpu.Pin.GPIO_NONE, Cpu.Pin backlightPin = Cpu.Pin.GPIO_NONE, uint spiClockFrequency = 1311, SPI.SPI_module spiModule = SPI.SPI_module.SPI1) { _spi = new SPI(new SPI.Configuration(lcdChipSelectPin, // CS-pin false, // CS-pin active state 0, // The setup time for the SS port 0, // The hold time for the SS port false, // The idle state of the clock true, // The sampling clock edge spiClockFrequency, // The SPI clock rate in KHz spiModule // The used SPI bus (refers to a MOSI MISO and SCLK pin set) )); _dataCommandPort = new OutputPort(dataCommandPin, false); if (resetPin != Cpu.Pin.GPIO_NONE) //Poundy: changed to remove netduino dependencies { _resetPort = new OutputPort(resetPin, false); } else { _resetPort = null; } if (backlightPin != Cpu.Pin.GPIO_NONE) //Poundy: changed to remove netduino dependencies { _backlightPort = new OutputPort(backlightPin, false); } else { _backlightPort = null; } InitializeScreen(); SetOrientation(isLandscape); }
我改了SPI的速度,從原本的20000HZ調整到1311,這個調整是參照alesbedac以及模組資料得到
並且還需要修改一樣是在Driver.cs內,有一個全域變數「lcdPortraitConfig」,否則在垂直顯示的時候,會變成鏡像,由原本的8改為72
const byte lcdPortraitConfig = 72;
如果你的螢幕跟我用同樣晶片但方向不一樣,這個數值可以從alesbedac版本的ILI9341driver.cs找到同名的變數名稱,但在alesbedac的版本,這個數值是透過跟螢幕溝通所取得:
static byte lcdPortraitConfig = lcdBuildMemoryAccessControlConfig( MemoryAccessControlNormalOrder, // rowAddressOrder MemoryAccessControlReverseOrder, // columnAddressOrder MemoryAccessControlNormalOrder, // rowColumnExchange MemoryAccessControlNormalOrder, // verticalRefreshOrder MemoryAccessControlColorOrderRGB, // colorOrder MemoryAccessControlNormalOrder); // horizontalRefreshOrder static byte lcdLandscapeConfig = lcdBuildMemoryAccessControlConfig( MemoryAccessControlNormalOrder, // rowAddressOrder MemoryAccessControlNormalOrder, // columnAddressOrder MemoryAccessControlReverseOrder, // rowColumnExchange MemoryAccessControlReverseOrder, // verticalRefreshOrder MemoryAccessControlColorOrderRGB, // colorOrder MemoryAccessControlReverseOrder); // horizontalRefreshOrder static byte lcdBuildMemoryAccessControlConfig(bool rowAddressOrder, bool columnAddressOrder, bool rowColumnExchange, bool verticalRefreshOrder, bool colorOrder, bool horizontalRefreshOrder) { byte value = 0; if (horizontalRefreshOrder) value |= 0x0004; if (colorOrder) value |= 0x0008; if (verticalRefreshOrder) value |= 0x0010; if (rowColumnExchange) value |= 0x0020; if (columnAddressOrder) value |= 0x0040; if (rowAddressOrder) value |= 0x0080; return value; }
可以下中斷點在lcdBuildMemoryAccessControlConfig()裡的return value,看一下合適的數字是多少,
而studlyed則是直接寫死,所以遇到了我用他的lib運作會有鏡像,需要改一些code修正的問題。
若你在studlyed版本遭遇在建構子明明寫LandScape: false,但她卻還是給你橫向顯示時,可以檢查Driver.cs裡面的SetOrientation()
public void SetOrientation(bool isLandscape) { lock (this) { _isLandscape = isLandscape; SendCommand(Commands.MemoryAccessControl); if (isLandscape) { SendData(lcdLandscapeConfig); Width = 320; Height = 240; } else { SendData(lcdPortraitConfig); Width = 240; Height = 320; } SetWindow(0, Width - 1, 0, Height - 1); } }
把有問題的Width跟Height數值互換,即可解決。
以上,需要更複雜的圖片可能要自己用SETPIXEL去做了,
我也算第一次摸TFT LCD~~發現要顯示圖片沒有想像中的難~~
之後有進階作法再補充了~
以上~
Leave a comment
很抱歉,必須登入網站才能發佈留言。