LCD驱动其实对TinyCLR并无必要,特别是在EM-STM3210E开发板上,因为该开发板上的内存太小了,片内64K,片外扩展了128K,加起来也不过172K,而我们知道针对320*240的显示大小,16bit的位图所占的大小就是150K,很显然.Net Micro Framework所提供的图形库如不加修改是很难正常运行的,不过对我们来说在LCD屏幕上显示文字信息也是值得期待的,如果修改一下图形库,在LCD上画个线、画个圆和显示个位图也绝不成问题。
和我们以前开发的驱动相比,LCD的驱动开发还是比较繁琐一些的,因为LCD的驱动代码分散在三个目录中(题外话,我觉得针对.Net Micro Framework来说,最难的驱动是网卡驱动(特别是wifi驱动)、其次是USB驱动,和它们相比,LCD驱动就是小菜了)。
和其它驱动类似,在具体写LCD驱动之前,我们先在CortexM3.h头文件里,写一个和LCD寄存器相关的结构体,以便以于操作LCD寄存器,这种做法其实也是.Net Micro Framework驱动代码的一种风格。
struct CortexM3_LCD
{
//LCD /CS is CE4 - Bank 4 of NOR/SRAM Bank 1~4
static const UINT32 c_Base = 0x6C000000;
/****/ volatile UINT16 REG;
/****/ volatile UINT16 RAM;
void WriteReg(UINT8 Reg,UINT16 Value)
{
REG = Reg;
RAM = Value;
}
UINT16 ReadReg(UINT8 Reg)
{
REG = Reg;
return RAM;
}
void SetCursor(UINT16 x,UINT16 y)
{
WriteReg(32,x);
WriteReg(33,y);
}
void SetPixel(UINT16 x,UINT16 y,UINT16 c)
{
WriteReg(32,x);
WriteReg(33,y);
WriteReg(34,c);
}
void WriteRAM_Prepare()
{
REG = 34;
}
};
首先我们在\DeviceCode\Targets\Native\CortexM3\DeviceCode目录创建LCD子目录,该驱动文件其实实现的功能很简单,归结起来就如下四个函数。
LCD_Controller_Initialize LCD初始化
LCD_Controller_Uninitialize
LCD_Controller_Enable LCD使能
LCD_GetFrameBuffer 获得LCD显示缓冲区首地址
但是对我们的ILI9320 LCD来说,LCD_Controller_Enable和LCD_GetFrameBuffer都不是必要的,从我们开发板附送的LCD示例上看,LCD显示缓冲区首地址的概念似乎是不存在的,我们直接写RAM即可,至于写入坐标是通过代码 WriteReg(32,x)和WriteReg(33,y)来控制(其实LCD驱动并不像我想象的那么简单,有很多功能需要仔细研究技术手册才能发现,不过为了简单起见,我们先按示例提供的方式来显示)。
在LCD_Controller_Initialize初始化代码中需要几个延时(我在写SysTick驱动的文章中提到了这一点),如下代码所示:
CortexM3_LCD &LCD = CortexM3::LCD();
HAL_Time_Sleep_MicroSeconds_InterruptEnabled(50000);
LCD.WriteReg(227, 0x3008); // Set internal timing
LCD.WriteReg(231, 0x0012); // Set internal timing
LCD.WriteReg(239, 0x1231); // Set internal timing
LCD.WriteReg(1 , 0x0100); // set SS=1:0x0100 and SM=0:0x0400 bit
LCD.WriteReg(2 , 0x0700); // set 1 line inversion
LCD.WriteReg(3 , 0x1030); // set GRAM write direction and BGR=1.
//放缩 0x0000 无 0x0001 1/2 0x0003 1/4
LCD.WriteReg(4 , 0x0000); // Resize register
LCD.WriteReg(8 , 0x0207); // set the back porch and front porch
LCD.WriteReg(9 , 0x0000); // set non-display area refresh cycle ISC[3:0]
LCD.WriteReg(10 , 0x0000); // FMARK function
//0x0000 18bit RGB接口 0x0001 16bit RGB接口 0x0002 6bit RGB接口
LCD.WriteReg(12 , 0x0000); // RGB interface setting
LCD.WriteReg(13 , 0x0000); // Frame marker Position
LCD.WriteReg(15 , 0x0000); // RGB interface polarity
/**************Power On sequence ****************/
LCD.WriteReg(16 , 0x0000); // SAP, BT[3:0], AP, DSTB, SLP, STB
LCD.WriteReg(17 , 0x0007); // DC1[2:0], DC0[2:0], VC[2:0]
LCD.WriteReg(18 , 0x0000); // VREG1OUT voltage
LCD.WriteReg(19 , 0x0000); // VDV[4:0] for VCOM amplitude
HAL_Time_Sleep_MicroSeconds_InterruptEnabled(200000); // Delay 200 MS , Dis-charge capacitor power voltage
LCD.WriteReg(16 , 0x1690); // SAP, BT[3:0], AP, DSTB, SLP, STB
LCD.WriteReg(17 , 0x0227); // R11H=0x0221 at VCI=3.3V, DC1[2:0], DC0[2:0], VC[2:0]
HAL_Time_Sleep_MicroSeconds_InterruptEnabled(50000); // Delay 50ms
LCD.WriteReg(18 , 0x001D); // External reference voltage= Vci;
HAL_Time_Sleep_MicroSeconds_InterruptEnabled(50000); // Delay 50ms
LCD.WriteReg(19 , 0x0800); // R13H=1D00 when R12H=009D;VDV[4:0] for VCOM amplitude
LCD.WriteReg(41 , 0x0014); // R29H=0013 when R12H=009D;VCM[5:0] for VCOMH
LCD.WriteReg(43 , 0x000B); // Frame Rate = 96Hz
HAL_Time_Sleep_MicroSeconds_InterruptEnabled(50000); // Delay 50ms
LCD.WriteReg(32 , 0x0000); // GRAM horizontal Address
LCD.WriteReg(33 , 0x0000); // GRAM Vertical Address
对NativeSample项目来说,在debug版本直接使用HAL_Time_Sleep_MicroSeconds_InterruptEnabled是没有问题的,但是在Release版本上面的函数前面要加一句GLOBAL_LOCK(irq)代码,也就是循环期间要关闭中断,才能正常运行。不过无论加不加这句代码,在TinyCLR项目中,Release版本也是无法正常运行的,甚至是直接用for循环也不行,不知道MDK的编译优化到底改变了些什么,有时间需要深入研究一下(当然上班之后,我也可以在RVDS上调试看看,有时候就是这样,同样的代码用MDK调试通不过,但是用RVDS就没有问题)。
接下来我们要在\DeviceCode\Drivers\Display目录下新建ILI9320子目录,在该目录的代码中我们实现文字显示(当然指西文字符,要显示汉字,在如此小的内存中我们得需要特别的技巧)。
详细的代码这里我就不贴了,不过要特别说明的是,EM-STM3210E的开发板有些问题,LCD其实是倒着装的,按开发板的测试示例来移植我们的代码,最终的显示是倒的,如下图所示:
所以我们一是要重设LCD相应的寄存器,把显存翻转过来,代码如下:
/* 数据颜色序(BGR): 0x1000 BGR 0x0000 RGB */
/* 扫描方向(AM): 0x0008 从右到左 0x0000 从上到下 */
/* 数据填充方向(I/D):0x0000 0x0010 0x0020 0x0030 */
LCD.WriteReg(3 , 0x1000 | 0x0000 ); //0x0030 正常模式
其次是修改WriteChar函数里的代码,让它适应这个变化,修改后的代码如下,注意要用LCD的宽度和高度值减去x,y的坐标。
const UINT8* font = Font_GetGlyph( c );
CortexM3_LCD &LCD = CortexM3::LCD();
int cx=0,ry=0;
for(int y = 0; y < Font_Height(); y++)
{
for(int x = 0; x < Font_Width(); x+=2)
{
cx=g_ILI9320_Config.ControllerConfig.Width-(col+x)-1;
ry=g_ILI9320_Config.ControllerConfig.Height-(row+y)-1;
// the font data is mirrored
if(ILI9320_GETBIT(Font_Width() - x ,y,font,1)) LCD.SetPixel(cx, ry,0x07e0);
else LCD.SetPixel(cx, ry,0);
if(ILI9320_GETBIT(Font_Width() - (x+1),y,font,1)) LCD.SetPixel(cx-1, ry,0x07e0);
else LCD.SetPixel(cx-1, ry,0);
}
}
修改代码后,我们的显示就已经翻转了,如下图所示:
最后我们还要在\Solutions\STM3210E\DeviceCode目录下新建子目录Display,在该目录下新建ILI9320_config.cpp文件,该文件主要完成LCD的一些参数配置,主要配置如下:
#define ILI9320_SCREEN_WIDTH 240
#define ILI9320_SCREEN_HEIGHT 320
#define ILI9320_ENABLE_TFT TRUE
#define ILI9320_ENABLE_COLOR TRUE
#define ILI9320_PIXEL_POLARITY FALSE
#define ILI9320_FIRST_LINE_POLARITY FALSE
#define ILI9320_LINE_PULSE_POLARITY FALSE
#define ILI9320_SHIFT_CLK_POLARITY FALSE
#define ILI9320_OUTPUT_ENABLE_POLARITY FALSE
#define ILI9320_CLK_IDLE_ENABLE TRUE
#define ILI9320_CLK_SELECT_ENABLE TRUE
#define ILI9320_PIXELCLOCKDIVIDER 9
#define ILI9320_BUS_WIDTH 16
#define ILI9320_BITS_PER_PIXEL 16
#define ILI9320_ORIENTATION 0
这时候也许有人会问,何必这么麻烦,把一个LCD驱动分解到三个目录中,都放在一个目录行不行? 当然这是可以的,这样做的目的就是,针对不同开发板,有些代码可以方便地复用。
开发完LCD驱动,如果仅仅显示文字,不显示一个位图,总觉得缺少点什么。说干就干,我显示一个320*240的位图。
但说起来容易做起来难,一个16bit的320*240的位图要150k,先不说如何去显示它,光说它放在什么地方,就是一个头疼的地方,如果把它编写到代码中,我们的片内Flash才512k,很显然放不下,放到NandFlash中,我们没有实现文件系统,在说也没有实现UsbMassStorage功能,我们也无法把图片拷贝到NandFlash中。
幸好在开发wifi驱动过程中我实现了一个MFDeploy的插件,通过该插件可以把位图下载到NandFlash中(因为Ti提供的wifi开发板,wifi初始化时需要加载三个文件,原先是放在文件系统中的,单这样做代价高了点,不仅要实现文件系统,还要实现UsbMassStorage功能,否则文件也是没法放到NandFlash上的,所以才开发了这个插件)。至于这个插件是如何实现的,我在以后准备要写的【玩转.Net MF】系列文章中我会详细介绍的。
在下载位图之前,我们先做一张320*240的位图,保存时要做如下选择,如下图:
要选择R5G6B5,此外要勾选翻转行序(也可以不勾选,不过代码要做些调整,否则图形是倒的)。
我们的实现思路是,从NandFlash中先读一部分数据,然后再显示一部分图形,最终完成一幅图的显示,这样就避开了内容小的问题。
LCD驱动中位图显示函数LCD_BitBltEx中的代码如下:
UINT16 * StartOfLine_src = (UINT16 *)&data[0];
CortexM3_LCD &LCD = CortexM3::LCD();
if(x==0 && y==0) LCD.SetCursor(g_ILI9320_Config.ControllerConfig.Width-1,g_ILI9320_Config.ControllerConfig.Height-1);
LCD.WriteRAM_Prepare();
for(int i=0;i<width*height;i++)
{
LCD.RAM = *StartOfLine_src++;
}
NativeSample.cpp中的测试代码如下:
BYTE bytReadData[15360];
UINT32 index=0x00520046;
BlockStorageDevice *device= BlockStorageList::GetFirstDevice();
for(int y=0;y<320;y+=32)
{
device->Read(index,15360,bytReadData);
LCD_BitBltEx(0,y,240,32,(UINT32 *)bytReadData);
index+=15360;
}
最终的效果图如下:
分享到:
相关推荐
It begins with the basics of accessing hardware and networking before delving deep into the less well–known areas such as cryptography and globalization, and how to use technologies such as wireless ...
《玩转.NET Micro Framework移植-基于STM32F10x处理器》源程序
.NET Micro Framework 电子书
.net micro framework关于文件操作的例子,非常详细。还包括了点击等东西
expert .net micro frameworkexpert .net micro frameworkexpert .net micro framework
.NET Micro Framework自动化测试工具,需.NET Micro Framework3.0和.NET Micro Framework Test Kit支持...
Microsoft .NET Micro Framework 2.5 SDK。 这个我暂时没用,权当放在这里存放,需要的,自己动手。
micro framework 4.0 SDK,最新开发工具包
近来有些刚入门的用户,不太了解.NET Micro Framework开发板的使用,所以写了这篇文档,以期缩短用户对开发板的熟悉时间。
这是我自己改造的.Net Micro Framework模拟器,比windows自带的漂亮多了。 覆盖该目录下的同名文件(路径以实际开发包安装位置为准)即可。 C:\Program Files\Microsoft .NET Micro Framework\v2.0.3036\Tools 支持...
.NET Micro Framework for Windows 7(X64) USB驱动安装说明,包含相应的驱动程序
.NET Micro Framework 电子书
http://item.taobao.com/item.htm?id=7117999726 .NET Micro Framework开发板的Key文件的部署说明。
.NET Micro Framework开发板原理图(红牛开发板)
.NET Micro Framework开发板使用手册(红牛开发板)
如何顺利编译.Net Micro Framework Porting Kit 4.1 安装路径不能有空格
注:比上一个模拟器多了支持方向键控制 这是我自己改造的.Net Micro Framework模拟器,比windows自带的漂亮多了。 覆盖该目录下的同名文件(路径以实际开发包安装位置为准)即可。 C:\Program Files\...
《玩转.NET Micro Framework 移植-基于STM32F10x处理器》一书所有的源代码。其它更多的资源可以访问我的blog:http://blog.csdn.net/norains 谢谢!
GHI .NET Micro Framework培训教材