[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
很抱歉,必須登入網站才能發佈留言。