数码相框(LCD、I2C)
一:项目介绍
该项目最终实现的功能很简单,手指在触摸屏左滑(下一张图片),右滑(上一张图片)
1.1软硬件资源
硬件:pc机,ARM Cortex-A9开发板
软件:linux 操作系统
1.3项目流程
本项目主要分为三大模块:
一:LCD驱动编写
二:I2C驱动编写
三:使用I2C读取触摸屏上的数据,判断是向左或者向右,再控制lcd进行图片的显示
大体流程图如下所示:
二:项目环境搭建
2.1安装交叉环境编译器 4.5.1,dnw软件
2.2烧写uboot
三:LCD裸板驱动的编写
在编写lcd驱动前先看一下电路图:
可以观察到 LCD1由45根线来控制,主要配置的寄存器是24根RGB以及TOU1 EINT10 以及VDEN VYNC HSYNC VCLK驱动;
在核心板中找到网标,找出相应的寄存器;
编写lcd可大致分为如下几步:
第一步:配置 OUT1 EINT10 以及24根RGB
第二步:看时序图配置相关寄存器
第三步:配置窗口寄存器
3.1 lcd控制器
Exynos4412的LCD控制器可以通过编程支持不同LCD屏的要求,例如行和列像素数,数据总线宽度,接口时序和刷新频率等。
LCD控制器的主要作用,是将定位在系统存储器中的显示缓冲区中的LCD图像数据传送到外部LCD驱动器,并产生必要的控制信号,
例如RGB_VSYNC,RGB_HSYNC, RGB_VCLK等
由上图可知:LCD控制器的构成主要由VSFR,VDMA,VPRCS , VTIME和视频时钟产生器几个模块组成;
(1)VSFR由121个可编程控制器组,一套gammaLUT寄存器组(包括64个寄存器),一套i80命令寄存器组(包括12个寄存器)和5块256*32调色板存储器组成,主要用于对lcd控制器进行配置。
(2)VDMA是LCD专用的DMA传输通道,可以自动从系统总线上获取视频数据传送到VPRCS,无需CPU干涉。
(3)VPRCS收到数据后组成特定的格式(如16bpp或24bpp),然后通过数据接口(RGB_VD, VEN_VD, V656_VD or SYS_VD)传送到外部LCD屏上。
(4)VTIME模块由可编程逻辑组成,负责不同lcd驱动器的接口时序控制需求。VTIME模块产生 RGB_VSYNC, RGB_HSYNC, RGB_VCLK, RGB_VDEN,VEN_VSYNC等信号。
3.2 lcd接口信号
其中主要的RGB接口信号:
(1)LCD_HSYNC:行同步信号,表示一行数据的开始,LCD控制器在整个水平线(整行)数据移入LCD驱动器后,插入一个LCD_HSYNC信号;
(2)LCD_VSYNC: 帧同步信号,表示一帧数据的开始,LCD控制器在一个完整帧显示完成后立即插入一个LCD_VSYNC信号,开始新一帧的显示;VSYNC信号出现的频率表示一秒钟内能显示多少帧图像,称为“显示器的频率”
(3)LCD_VCLK:像素时钟信号,表示正在传输一个像素的数据;
(4)LCD_VDEN:数据使能信号;
(5) LCD_VD[23:0]: LCD像素数据输出端口
3.3、RGB信号的时序
(1)、相关参数说明
VBPD(vertical back porch):表示在一帧图像开始时,垂直同步信号以后的无效的行数。
VFBD(vertical front porch):表示在一帧图像结束后,垂直同步信号以前的无效的行数。
VSPW(vertical sync pulse width):表示垂直同步脉冲的宽度,用行数计算。
HBPD(horizontal back porch):表示从水平同步信号开始到一行的有效数据开始之间的VCLK的个数。
HFPD(horizontal front porth):表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK的个数。
HSPW(horizontal sync pulse width):表示水平同步信号的宽度,用VCLK计算。
(2)、帧的传输过程
VSYNC信号有效时,表示一帧数据的开始,信号宽度为(VSPW +1)个HSYNC信号周期,即(VSPW +1)个无效行;
VSYNC信号脉冲之后,总共还要经过(VBPD+ 1)个HSYNC信号周期,有效的行数据才出现; 所以,在VSYNC信号有效之后,还要经过(VSPW +1 + VBPD + 1)个无效的行;
随即发出(LINEVAL+ 1)行的有效数据;
最后是(VFPD + 1)个无效的行。
(3)、行中像素数据的传输过程
HSYNC信号有效时,表示一行数据的开始,信号宽度为(HSPW+ 1)个VCLK信号周期,即(HSPW +1)个无效像素;
HSYNC信号脉冲之后,还要经过(HBPD +1)个VCLK信号周期,有效的像素数据才出现;
随后发出(HOZVAL+1)个像素的有效数据;
最后是(HFPD +1)个无效的像素。
(4)、将VSYNC、HSYNC、VCLK等信号的时间参数设置好之后,并将帧内存的地址告诉LCD控制器,它即可自动地发起DMA传输从帧内存中得到图像数据,最终在上述信号的控制下RGB数据出现在数据总线VD[23:0]上。用户只需要把要显示的图像数据写入帧内存中。
3.4、lcd相关寄存器设置说明
(1)设置LCD的RGB接口,只需要将其设置为2即可。同时将其IO口设置成为内部上拉,且将其驱动能力设置为最强代码如下:
GPF0CON = 0x22222222;
GPF1CON = 0x22222222;
GPF2CON = 0x22222222;
GPF3CON &= ~(0xffff);
GPF3CON |= 0x2222;
/*max driver strength*/
GPF0DRV = 0xfffffff;
GPF1DRV = 0xfffffff;
GPF2DRV = 0xfffffff;
GPF3DRV &= ~0xff;
GPF3DRV |= 0xff;
(2)设置LCD相关时钟寄存器
这一步主要设置选择LCD时钟输入源为MPLL,且不对其进行分频,同时设置LCDBLK_CFG使其使用FIMD接口,且设置LCDBLK_CFG2使其PWM输出使能;
(4)设置VIDCONx,设置接口类型,时钟分频,极性以及使能LCD控制器等
VIDCON0:这一个寄存器主要设置接口类型和时钟分频,这里仅仅设置了其时钟分频值,由于我们的MPLL为800MHZ,所以这里设置值,根据手册进行计算,要得到33.3MHZ左右的像素时钟;
VIDCON0 = (1 << 17)|(23 <<6)|3;
VIDCON1:主要设置时钟信号,需不需要翻转,以及触发方式;
VIDTCONx:用来设置时序和长宽等参数,这里就主要设置VBPD(vertical back porch)、 VFBD(vertical frontporch)、VSPW(vertical sync pulse width)、HBPD(horizontal backporch)、 HFPD(horizontal sync pulse width)等参数
VIDTCON0取值过程,VIDTCON0设置帧同步时序。
VIDTCON0 = (22 << 16) | (21 << 8) | (0);
VIDTCON1取值过程,VIDTCON1设置像素同步时序。
VIDTCON1 = (35 << 16) | (209 << 8) | (9);
VIDTCON2
VIDTCON2 = (479 << 11) | 799;
(5)设置WINCON0寄存器,即设置数据格式。
Exynos4412的LCD控制器有overlay功能,它支持5个window。这里只使用window0,设置其代码RGB模式为24bit(A888)且使能window0;
WINCON0 = (1 << 22) | (1 << 15) | (11 << 2) | 1;
(6)设置VID0SD0A/B/C,即设置Window0的坐标系
配置VIDW00ADD0B0和VIDW00ADD1B0,设置framebuffer的地址;
(7)配置SHADOWCON和WINCHMAP2、选择使能DMA通道0。由于我们使用的是Window0,所以需要使能DMA通道0;
(8)最后设置VIDCON0低两位使能LCD
VIDCON0 |= 1 | (1 << 1);
下面是Tiny4412 LCD裸板驱动具体代码:
#define LCD_BASE 0x11C00000 #define VIDCON0 (*(volatile unsigned int *)(LCD_BASE + 0x0000))
#define VIDCON1 (*(volatile unsigned int *)(LCD_BASE + 0x0004))
#define VIDCON2 (*(volatile unsigned int *)(LCD_BASE + 0x0008))
#define VIDCON3 (*(volatile unsigned int *)(LCD_BASE + 0x000C))
#define VIDTCON0 (*(volatile unsigned int *)(LCD_BASE + 0x0010))
#define VIDTCON1 (*(volatile unsigned int *)(LCD_BASE + 0x0014))
#define VIDTCON2 (*(volatile unsigned int *)(LCD_BASE + 0x0018))
#define VIDTCON3 (*(volatile unsigned int *)(LCD_BASE + 0x001C))
#define WINCON0 (*(volatile unsigned int *)(LCD_BASE + 0x0020))
#define WINCON1 (*(volatile unsigned int *)(LCD_BASE + 0x0024))
#define WINCON2 (*(volatile unsigned int *)(LCD_BASE + 0x0028))
#define WINCON3 (*(volatile unsigned int *)(LCD_BASE + 0x002C))
#define WINCON4 (*(volatile unsigned int *)(LCD_BASE + 0x0030))
#define SHADOWCON (*(volatile unsigned int *)(LCD_BASE + 0x0034))
#define WINCHMAP2 (*(volatile unsigned int *)(LCD_BASE + 0x003C))
#define VIDOSD0A (*(volatile unsigned int *)(LCD_BASE + 0x0040))
#define VIDOSD0B (*(volatile unsigned int *)(LCD_BASE + 0x0044))
#define VIDOSD0C (*(volatile unsigned int *)(LCD_BASE + 0x0048))
#define VIDOSD1A (*(volatile unsigned int *)(LCD_BASE + 0x0050))
#define VIDOSD1B (*(volatile unsigned int *)(LCD_BASE + 0x0054))
#define VIDOSD1C (*(volatile unsigned int *)(LCD_BASE + 0x0058))
#define VIDOSD1D (*(volatile unsigned int *)(LCD_BASE + 0x005C))
#define VIDOSD2A (*(volatile unsigned int *)(LCD_BASE + 0x0060))
#define VIDOSD2B (*(volatile unsigned int *)(LCD_BASE + 0x0064))
#define VIDOSD2C (*(volatile unsigned int *)(LCD_BASE + 0x0068))
#define VIDOSD2D (*(volatile unsigned int *)(LCD_BASE + 0x006C))
#define VIDOSD3A (*(volatile unsigned int *)(LCD_BASE + 0x0070))
#define VIDOSD3B (*(volatile unsigned int *)(LCD_BASE + 0x0074))
#define VIDOSD3C (*(volatile unsigned int *)(LCD_BASE + 0x0078))
#define VIDOSD4A (*(volatile unsigned int *)(LCD_BASE + 0x0080))
#define VIDOSD4B (*(volatile unsigned int *)(LCD_BASE + 0x0084))
#define VIDOSD4C (*(volatile unsigned int *)(LCD_BASE + 0x0088))
#define VIDW00ADD0B0 (*(volatile unsigned int *)(LCD_BASE + 0x00A0))
#define VIDW00ADD0B1 (*(volatile unsigned int *)(LCD_BASE + 0x00A4))
#define VIDW00ADD0B2 (*(volatile unsigned int *)(LCD_BASE + 0x20A0))
#define VIDW01ADD0B0 (*(volatile unsigned int *)(LCD_BASE + 0x00A8))
#define VIDW01ADD0B1 (*(volatile unsigned int *)(LCD_BASE + 0x00AC))
#define VIDW01ADD0B2 (*(volatile unsigned int *)(LCD_BASE + 0x20A8))
#define VIDW02ADD0B0 (*(volatile unsigned int *)(LCD_BASE + 0x00B0))
#define VIDW02ADD0B1 (*(volatile unsigned int *)(LCD_BASE + 0x00B4))
#define VIDW02ADD0B2 (*(volatile unsigned int *)(LCD_BASE + 0x20B0))
#define VIDW03ADD0B0 (*(volatile unsigned int *)(LCD_BASE + 0x00B8))
#define VIDW03ADD0B1 (*(volatile unsigned int *)(LCD_BASE + 0x00BC))
#define VIDW03ADD0B2 (*(volatile unsigned int *)(LCD_BASE + 0x20B8))
#define VIDW04ADD0B0 (*(volatile unsigned int *)(LCD_BASE + 0x00C0))
#define VIDW04ADD0B1 (*(volatile unsigned int *)(LCD_BASE + 0x00C4))
#define VIDW04ADD0B2 (*(volatile unsigned int *)(LCD_BASE + 0x20C0))
#define VIDW00ADD1B0 (*(volatile unsigned int *)(LCD_BASE + 0x00D0))
#define VIDW00ADD1B1 (*(volatile unsigned int *)(LCD_BASE + 0x00D4))
#define VIDW00ADD1B2 (*(volatile unsigned int *)(LCD_BASE + 0x20D0))
#define VIDW01ADD1B0 (*(volatile unsigned int *)(LCD_BASE + 0x00D8))
#define VIDW01ADD1B1 (*(volatile unsigned int *)(LCD_BASE + 0x00DC))
#define VIDW01ADD1B2 (*(volatile unsigned int *)(LCD_BASE + 0x20D8))
#define VIDW02ADD1B0 (*(volatile unsigned int *)(LCD_BASE + 0x00E0))
#define VIDW02ADD1B1 (*(volatile unsigned int *)(LCD_BASE + 0x00E4))
#define VIDW02ADD1B2 (*(volatile unsigned int *)(LCD_BASE + 0x20E0))
#define VIDW03ADD1B0 (*(volatile unsigned int *)(LCD_BASE + 0x00E8))
#define VIDW03ADD1B1 (*(volatile unsigned int *)(LCD_BASE + 0x00EC))
#define VIDW03ADD1B2 (*(volatile unsigned int *)(LCD_BASE + 0x20E8))
#define VIDW04ADD1B0 (*(volatile unsigned int *)(LCD_BASE + 0x00F0))
#define VIDW04ADD1B1 (*(volatile unsigned int *)(LCD_BASE + 0x00F4))
#define VIDW04ADD1B2 (*(volatile unsigned int *)(LCD_BASE + 0x20F0))
#define VIDW00ADD2 (*(volatile unsigned int *)(LCD_BASE + 0x0100))
#define VIDW01ADD2 (*(volatile unsigned int *)(LCD_BASE + 0x0104))
#define VIDW02ADD2 (*(volatile unsigned int *)(LCD_BASE + 0x0108))
#define VIDW03ADD2 (*(volatile unsigned int *)(LCD_BASE + 0x010C))
#define VIDW04ADD2 (*(volatile unsigned int *)(LCD_BASE + 0x0110))
#define VIDINTCON0 (*(volatile unsigned int *)(LCD_BASE + 0x0130))
#define VIDINTCON1 (*(volatile unsigned int *)(LCD_BASE + 0x0134))
#define W1KEYCON0 (*(volatile unsigned int *)(LCD_BASE + 0x0140))
#define VIDW0ALPHA0 (*(volatile unsigned int *)(LCD_BASE + 0x021C))
#define VIDW0ALPHA1 (*(volatile unsigned int *)(LCD_BASE + 0x0220))
#define VIDW1ALPHA0 (*(volatile unsigned int *)(LCD_BASE + 0x0224))
#define VIDW1ALPHA1 (*(volatile unsigned int *)(LCD_BASE + 0x0228))
#define VIDW2ALPHA0 (*(volatile unsigned int *)(LCD_BASE + 0x022C))
#define VIDW2ALPHA1 (*(volatile unsigned int *)(LCD_BASE + 0x0230))
#define VIDW3ALPHA0 (*(volatile unsigned int *)(LCD_BASE + 0x0234))
#define VIDW3ALPHA1 (*(volatile unsigned int *)(LCD_BASE + 0x0238))
#define VIDW4ALPHA0 (*(volatile unsigned int *)(LCD_BASE + 0x023C))
#define VIDW4ALPHA1 (*(volatile unsigned int *)(LCD_BASE + 0x0240)) #endif
lcd.h
#include "lcd.h"
#define RGB888(r, g, b) (((r) << 16) | ((g) << 8) | (b)) void lcd_init(void);
void clean_screen(unsigned long *fb, int w, int h); int main(void)
{
fb = ADDR0;
lcd_init();
clean_screen(fb, , );
} void clean_screen(unsigned long *fb, int w, int h)
{
int i, j;
for (i = ; i < h; i ++) {
for (j = ; j < w; j ++) {
fb[i * w + j] = RGB888(, , );
}
}
} void lcd_init(void)
{
/*
*<Exyons 4412 datasheet pg138 pg141 pg144 pg147> *
* GPF0CON : [31:0] : 0x2
* GPF1CON : [31:0] : 0x2
* GPF2CON : [31:0] : 0x2
* GPF3CON : [31:0] : 0x2
* */ //定义IO引脚功能为RGB接口
GPF0CON = 0x22222222;
GPF1CON = 0x22222222;
GPF2CON = 0x22222222;
GPF3CON &= ~(0xffff);
GPF3CON |= 0x2222; //max driver strebgh----
GPF0DRV = 0xffffffff;
GPF1DRV = 0xffffffff;
GPF2DRV = 0xffffffff;
GPF3DRV &= ~0xff;
GPF3DRV |= 0xff;
/*
*<Exyons 4412 datasheet pg526>
*CLK_DIV_LCD:
* [3:0]:FIMD0_RATIO 0
* SCLK_FIMD0 = MOUTFIMD0/(FIMD0_RATIO + 1)
* = MOUTFIMD0/1 = 800MHz
* MOUTFIMD0 == SCLKmpll_user_t == 800MHz <Exyons 4412 datasheet pg453> LCD0_BLK
* */ CLK_DIV_LCD &= ~0xf;
/*
*<Exyons 4412 datasheet pg501>
*CLK_SRC_LCD0:
* [3:0]:FIMD0_SEL 0110 ===> SCLKmpll_user_t 选择时钟源为SCLKmpll_user_t
*
* */
CLK_SRC_LCD0 &= ~0xf;
CLK_SRC_LCD0 |= ;
//LCD0_SYS_PWR_REG == 7 Don't use /*<Exyons 4412 datasheet pg1799>
*Using the display controller data, you can select one of the above data paths by setting LCDBLK_CFG Register
*(0x1001_0210). For more information, refer to the "System Others" manual.
*
*
* <Exyons 4412 datasheet pg880>
* LCDBLK_CFG:
* [1] : FIMD of LBLK0 Bypass Selection 1 : FIMD Bypass 使用FIMD接口
*
* LCDBLK_CFG :
* [0]:MIE0_DISPON 1 : PWM outpupt enable
*
*
* */
LCDBLK_CFG |= << ; //set FIMD
LCDBLK_CFG2 |= ; /*
*<Exyons 4412 datasheet pg1869>
*VIDCON0:
* [13:6]: CLKVAL_F //设置lcd时钟分频系数
*
* VCLK == 33.3Mhz <S700-AT070TN92 pg14> DCLK Frequency ===> Type : 33.3Mhz
* VCLK = FIMD * SCLK/(CLKVAL+1)
* VCLK = 800000000 / (CLKVAL + 1)
* 33300000 = 800000000 /(CLKVAL + 1)
* CLKVAL + 1 = 24.02
* CLKVAL = 23
* */ //设置接口类型及时钟分频 33.3MHZ (配置时钟分频系数)
VIDCON0 = ( << ) | ( << ) | ; /*(1 << 17)非常重要 不配制会出现色差*/
//VIDCON0 = (23 << 6) | 3;
/*
*<Exyons 4412 datasheet pg1870 pg1848(时序)> <S700-AT070TN92 pg13(时序)>
*VIDTCON1:
* [5]:IVSYNC ===> 1 : Inverted(反转)
* [6]:IHSYNC ===> 1 : Inverted(反转)
* [7]:IVCLK ===> 1 : Fetches video data at VCLK rising edge (下降沿触发)
* [10:9]:FIXVCLK ====> 01 : VCLK running
* */
/*VIDCON1主要设置像表时钟信号一直存在,且高电平有效,
而IHSYNC=1,极性反转IVSYNC=1,极性反转,这是由于S07的时序图中VSYNC和
HSYNC都是低脉冲有效,而Exynos4412芯片手册时序图,VSYNC 和HSYNC都是高脉冲有效
,所以需要反转*/
VIDCON1 = ( << ) | ( << ) | ( << ) | ( << ); //配置时序相关 /*
*<Exyons 4412 datasheet pg1874 pg1848(时序)> <S700-AT070TN92 pg13(时序)>
*VIDTCON0:
* [23:16]: VBPD + 1 <------> tvpw (1 - 20) 13
* [15:8]: VFPD + 1 <------> tvfp 22
* [7:0]: VSPW + 1 <------> tvb - tvpw = 23 - 13 = 10
* */
/*VIDTCONx用来设置时序和长宽等参数,这里就主要设置VBPD(vertical back porch)、
VFBD(vertical fro ntporch)、VSPW(vertical sync pulse width)、
HBPD(horizontal backporch)、 HFPD(horizontal sync pul se width)等参数*/
VIDTCON0 = ( << ) | ( << ) | (); //配置时序间隔时间 (VIDTCON0 VIDTCON1) /*<Exyons 4412 datasheet pg1874 pg1848(时序)> <S700-AT070TN92 pg13(时序)>
*VIDTCON1:
* [23:16]: HBPD + 1 <------> thpw (1 - 40) 36
* [15:8]: HFPD + 1 <------> thfp 210
* [7:0]: HSPW + 1 <------> thb - thpw = 46 - 36 = 10
*/
VIDTCON1 = ( << ) | ( << ) | (); /*
*<Exyons 4412 datasheet pg1875>
*
*HOZVAL = (Horizontal display size) – 1 and LINEVAL = (Vertical display size) – 1.
* Horizontal(水平) display size : 800
*Vertical(垂直) display size : 480
* */
VIDTCON2 = ( << ) | ; //win0
//#ifdef BPP565
/*
*<Exyons 4412 datasheet pg1877>
*WINCON0:
* [16]:Specifies Half-Word swap control bit. 1 = Enables swap
* [5:2]: Selects Bits Per Pixel (BPP) mode for Window image : 0101 ===> 16BPP
* [1]:Enables/disables video output 1 = Enables
*
* */
// WINCON0 = (1 << 16) | (5 << 2) | 1; /*
*<Exyons 4412 datasheet pg1895>
*VIDOSD0C:Specifies the Window Size (窗口尺寸 单位为word)
*
*
* */
// VIDOSD0C = 480 * 800 >> 1;
//#else
/*
*<Exyons 4412 datasheet pg1877>
*WINCON0:
* [5:2]: Selects Bits Per Pixel (BPP) mode for Window image : 1011 ===> 24BPP
* [1]:Enables/disables video output 1 = Enables
*
* */
/*Exynos4412的LCD控制器有overlay功能,它支持5个window。
这里只使用window0,设置其代码RGB模式为24bit,(A888)且使能window0
*/
WINCON0 = ( << ) | ( << ) | ( << ) | ;//配置窗口0颜色数据格式,使能视频数据输出 /*
*<Exyons 4412 datasheet pg1895>
*VIDOSD0C:Specifies the Window Size (窗口尺寸 单位为word)
*
*
* */
VIDOSD0C = * ; //windows size
//#endif //SHADOWCON &= ~(1 << 5); Don't use /*
*<Exyons 4412 datasheet pg1891 pg1801>
*[0]: Enables Channel 0. 1 = Enables
* */
/*配置SHADOWCON和WINCHMAP2、选择使能DMA通道0,
由于我们使用的是Window0,所以需要使能DMA通道0
*/
SHADOWCON |= ; //选择相应通道 /*
*<Exyons 4412 datasheet pg1894 pg1801>
*[18:16] Selects Channel 0's channel. ===> 001 = Window 0
*[2:0] Selects Window 0's channel. ===> 001 = Channel 0
*
*
* */
WINCHMAP2 &= ~( << );//选择通道与窗口
WINCHMAP2 |= << ;
WINCHMAP2 &= ~;
WINCHMAP2 |= ; /*
*<Exyons 4412 datasheet pg1895>
*VIDOSD0A: LCD左上角坐标
*VIDOSD0B: LCD右下角坐标
*/ VIDOSD0A = ;
VIDOSD0B = ( << ) | ; /*
*<Exyons 4412 datasheet pg1902>
* VIDW00ADD0B0 : window0 frame buffer 起始地址
* VIDW00ADD1B0 : window0 frame buffer 结束地址
* */
VIDW00ADD0B0 = FRAMEBUFFER00;
VIDW00ADD1B0 = FRAMEBUFFER00 + VIDOSD0C * ;
VIDW00ADD2 = ;
/*
* <Exyons 4412 datasheet pg1869>
* Display On: ENVID and ENVID_F are set to "1".
* [0]:ENVID ===> 1 = Enables
* [1]:ENVID_F ===> 1 = Enables
* */
}
页面频率计算公式:
Frame_Rate = /[{(VSPW + ) + (VBPD + ) + (LIINEVAL + ) + (VFPD + )} * {(HSPW + ) + ( HBPD + ) + (HFPD + ) + (HOZVAL + )} * {(CLKVAL + )/(Frequency of Clock source)}] = / [{ + + + } * { + + + } * X / 800M]
= / [ * * X / 800M]
= * * * X / 800M
800M = * * * X
X = 800M / ( * * )
X = 800M /
X = 28.8
四:I2C裸板驱动驱动编写
4.1 I2C总线介绍
I2C总线有两条总线线路,一条是串行数据线(SDA),一条是串行时钟线(SCL)。SDA负责数据传输,SCL负责数据传输的时钟同步。I2C设备通过这两条总线连接到处理器的I2C总线控制器上。I2C总线最主要的特点就是其简单性、有效性以及支持多主控,其中任何能进行发送和接收的的设备都可以成为主控设备。主控设备能控制信号的传输和时钟平率,当然,在同一时间内只能有一个主控设备占用总线;
与其他总线相比,I2C总线有很多重要的特点:
主要特点:
(1)每一个连接到总线的设备都可以通过唯一的设备地址单独访问
(2)串行的8位双向数据传输,位速率在标准模式下可达到100kb/s;快速模式下可以达到400kb/s;告诉模式下可以达到3.4Mb/s
(3)总线长度最长7.6m左右
(4)片上滤波器可以增加抗干扰能力,保证数据的完成传输
(5)连接到一条I2C总线上的设备数量只受到最大电容400pF的限制
(6)它是一个多主机系统,在一条总线上可以同时有多个主机存在,通过冲突检测方式和延时等待防止数据不被破坏。同一时间只能有一个主机占用总线
IIC总线在传输数据的过程中有3种类型的信号:开始信号、结束信号、和应答信号
开始信号(S): 当SCL为高电平时,SDA由高电平向低电平跳变,表示将要开始传输数据
结束信号(P):当SCL为高电平时,SDA由低电平向高电平跳变,表示结束传输数据
响应信号(ACK): 从机接收到8位数据后,在第9个周期,拉低SDA电平,表示已经收到数据。这个信号称为应答信号
如下图:
主机:IIC总线中发送命令的设备,对于ARM处理器来说,主机就是IIC控制器
从机:接受命令的设备
一个典型的I2C通信的数据帧格式如下图所示:
Write:在写入时,I2C主控设备先发起起始位(S),抢占总线,然后,发送7位设备地址和1位0,表示对设备的写入,接着就是向设备传送数据
在读取时,稍微复杂点,因为总线的数据传输方向要改变,其流程总结如下:
(1)I2C主控设备发送起始位(S),抢占总线
(2)发送7位的设备地址和1位0,表示对设备的写入
(3)向设备写入要读取的寄存器地址
(4)再次发送起始位(S)
(5)发送7位设备地址和1位1,表示设备的读取
(6)从设备读取数据
无论要读取还是写入,都必须先写
4.2 I2C总线寄存器介绍
I2C总线控制器的结构如下图:
其中,PCLK是系统的外设时钟,SCL,SDA对应I2C总线的信号,控制器主要包括如下4个寄存器:
(1)I2CCON——I2C总线控制器,可以设置总线控制器的开启,关闭,中断以及总线的分频器;
(2)I2CSTAT——可控制总线的状态,包括发送、接收、主/ 从应答等状态;
(3)I2CADD——I2C总线地址寄存器,一个完整的的I2C总线控制器要求有4种工作模式:主设备发送,主设备接收,从设备发送,从设备接收;
(4)I2CDS——I2C数据接收、发送寄存器;
4.3 I2C总线gpio及寄存器的配置
从电电路图可知:lcd用到的是SDA2、SCL2
找到lcd接到底板的电路,查看SCL2对应的网标
再找到底板连到核心板的网标,找到对应的gpio(gpd1_2 gpd1_3)
下面是I2C具体的寄存器配置
五:利用I2C读取触摸屏数据,控制lcd
由电路图可知,tiny4412开发板的触摸屏是由FT5206GE1这个芯片控制,触摸屏所产生的数据都放在该芯片的寄存器,因此我们只需要读它里面的值就可以了
由电路图我们还可以看出,触摸屏中断为EINT14,因此当我们触碰屏的时候就会发生中断,通过网标我们可以找到触摸屏的中断号:
通过datasheet我们可以找到触摸屏中断号为 62
对应的gpio为:gpx1_6
接下来找到对应的寄存器进行配置:
下面代码就是通过I2C读取触摸屏的数据,从而控制lcd进行显示:
#ifndef _LCD_H
#define _LCD_H
void (*udelay)(int ) = 0xc3e04fec;
void iic_master_read_buff(unsigned char slave_addr, char *data, int len);
void iic_init();
void iic_dest();
void ts_handle();
static int codate[]; void iic_init();
void images_write_to_buff(unsigned int height, unsigned int width, char *, unsigned long addr);
void memcpy(unsigned char *dest, unsigned char *src, unsigned int len);
void init_table(unsigned long *addr);
void irq_init();
void enable_mmu();
void init_images();
void show_next();
void show_pre();
void do_irq(); extern unsigned long vector_start;
unsigned long space;
unsigned char *tmp;
unsigned char *fb;
#endif
lcd.h
#ifndef __REGS_H
#define __REGS_H #define FRAMEBUFFER00 0x5f000000
#define ADDR0 0x5f000000
#define ADDR1 0x60000000
#define ADDR2 0x68000000 #define GPD1CON (*(volatile unsigned long *)0x114000C0)
#define GPD1PUD (*(volatile unsigned long *)0x114000C8)
#define I2CCON1 (*(volatile unsigned long *)0x13870000)
#define I2CADD1 (*(volatile unsigned long *)0x13870008)
#define I2CSTAT1 (*(volatile unsigned long *)0x13870004)
#define I2CDS1 (*(volatile unsigned long *)0x1387000C)
#define I2CLC1 (*(volatile unsigned long *)0x13870010) #define ICCICR_CPU0 (*(volatile unsigned long *)0x10480000)
#define ICCPMR_CPU0 (*(volatile unsigned long *)0x10480004)
#define ICDDCR (*(volatile unsigned long *)0x10490000)
#define ICDIPR15_CPU0 (*(volatile unsigned long *)0x1049043C)
#define ICDIPTR15_CPU0 (*(volatile unsigned long *)0x1049083C)
#define ICDISER1_CPU0 (*(volatile unsigned long *)0x10490104)
#define ICDSGIR (*(volatile unsigned long *)0x10490f00)
#define ICCIAR_CPU0 (*(volatile unsigned long *)0x1048000C)
#define ICCEOIR_CPU0 (*(volatile unsigned long *)0x10480010) #define GPX1CON (*(volatile unsigned long *)0x11000C20) #define EXT_INT41_CON (*(volatile unsigned long *)0x11000E04)
#define EXT_INT41_MASK (*(volatile unsigned long *)0x11000F04)
#define EXT_INT41_PEND (*(volatile unsigned long *)0x11000F44) #define printf(...) (((int (*)(const char *, ...))0xc3e114d8)(__VA_ARGS__)) #define GPX3CON (*(volatile unsigned long *)0x11000c60)
#define GPX3DAT (*(volatile unsigned long *)0x11000c64)
#define GPD0CON (*(volatile unsigned long *)0x110000a0)
#define GPD0DAT (*(volatile unsigned long *)0x110000a4) #define ICCICR_CPU0 (*(volatile unsigned long *)0x10480000)
#define ICCPMR_CPU0 (*(volatile unsigned long *)0x10480004)
#define ICDDCR (*(volatile unsigned long *)0x10490000)
#define ICDIPR16_CPU0 (*(volatile unsigned long *)0x10490440)
#define ICDIPTR16_CPU0 (*(volatile unsigned long *)0x10490840)
#define ICDISER2_CPU0 (*(volatile unsigned long *)0x10490108)
#define ICDSGIR (*(volatile unsigned long *)0x10490f00)
#define ICCIAR_CPU0 (*(volatile unsigned long *)0x1048000C)
#define ICCEOIR_CPU0 (*(volatile unsigned long *)0x10480010) #define EXT_INT43_CON (*(volatile unsigned long *)0x11000E0C)
#define EXT_INT43_MASK (*(volatile unsigned long *)0x11000F0C)
#define EXT_INT43_PEND (*(volatile unsigned long *)0x11000F4C) #define CLK_DIV_LCD (*(volatile unsigned int *)0x1003c534)
#define CLK_SRC_MASK_LCD (*(volatile unsigned int *)0x1003c334)
#define CLK_GATE_IP_LCD (*(volatile unsigned int *)0x1003c934)
#define CLK_SRC_LCD0 (*(volatile unsigned int *)0x1003c234) #define GPF0CON (*(volatile unsigned int *)0x11400180)
#define GPF1CON (*(volatile unsigned int *)0x114001a0)
#define GPF2CON (*(volatile unsigned int *)0x114001c0)
#define GPF3CON (*(volatile unsigned int *)0x114001e0)
#define GPF0DRV (*(volatile unsigned int *)0x1140018c)
#define GPF1DRV (*(volatile unsigned int *)0x114001ac)
#define GPF2DRV (*(volatile unsigned int *)0x114001cc)
#define GPF3DRV (*(volatile unsigned int *)0x114001ec) #define LCDBLK_CFG (*(volatile unsigned int *)0x10010210)
#define LCDBLK_CFG2 (*(volatile unsigned int *)0x10010214) #define LCD_BASE 0x11C00000 #define VIDCON0 (*(volatile unsigned int *)(LCD_BASE + 0x0000))
#define VIDCON1 (*(volatile unsigned int *)(LCD_BASE + 0x0004))
#define VIDCON2 (*(volatile unsigned int *)(LCD_BASE + 0x0008))
#define VIDCON3 (*(volatile unsigned int *)(LCD_BASE + 0x000C))
#define VIDTCON0 (*(volatile unsigned int *)(LCD_BASE + 0x0010))
#define VIDTCON1 (*(volatile unsigned int *)(LCD_BASE + 0x0014))
#define VIDTCON2 (*(volatile unsigned int *)(LCD_BASE + 0x0018))
#define VIDTCON3 (*(volatile unsigned int *)(LCD_BASE + 0x001C))
#define WINCON0 (*(volatile unsigned int *)(LCD_BASE + 0x0020))
#define WINCON1 (*(volatile unsigned int *)(LCD_BASE + 0x0024))
#define WINCON2 (*(volatile unsigned int *)(LCD_BASE + 0x0028))
#define WINCON3 (*(volatile unsigned int *)(LCD_BASE + 0x002C))
#define WINCON4 (*(volatile unsigned int *)(LCD_BASE + 0x0030))
#define SHADOWCON (*(volatile unsigned int *)(LCD_BASE + 0x0034))
#define WINCHMAP2 (*(volatile unsigned int *)(LCD_BASE + 0x003C))
#define VIDOSD0A (*(volatile unsigned int *)(LCD_BASE + 0x0040))
#define VIDOSD0B (*(volatile unsigned int *)(LCD_BASE + 0x0044))
#define VIDOSD0C (*(volatile unsigned int *)(LCD_BASE + 0x0048))
#define VIDOSD1A (*(volatile unsigned int *)(LCD_BASE + 0x0050))
#define VIDOSD1B (*(volatile unsigned int *)(LCD_BASE + 0x0054))
#define VIDOSD1C (*(volatile unsigned int *)(LCD_BASE + 0x0058))
#define VIDOSD1D (*(volatile unsigned int *)(LCD_BASE + 0x005C))
#define VIDOSD2A (*(volatile unsigned int *)(LCD_BASE + 0x0060))
#define VIDOSD2B (*(volatile unsigned int *)(LCD_BASE + 0x0064))
#define VIDOSD2C (*(volatile unsigned int *)(LCD_BASE + 0x0068))
#define VIDOSD2D (*(volatile unsigned int *)(LCD_BASE + 0x006C))
#define VIDOSD3A (*(volatile unsigned int *)(LCD_BASE + 0x0070))
#define VIDOSD3B (*(volatile unsigned int *)(LCD_BASE + 0x0074))
#define VIDOSD3C (*(volatile unsigned int *)(LCD_BASE + 0x0078))
#define VIDOSD4A (*(volatile unsigned int *)(LCD_BASE + 0x0080))
#define VIDOSD4B (*(volatile unsigned int *)(LCD_BASE + 0x0084))
#define VIDOSD4C (*(volatile unsigned int *)(LCD_BASE + 0x0088))
#define VIDW00ADD0B0 (*(volatile unsigned int *)(LCD_BASE + 0x00A0))
#define VIDW00ADD0B1 (*(volatile unsigned int *)(LCD_BASE + 0x00A4))
#define VIDW00ADD0B2 (*(volatile unsigned int *)(LCD_BASE + 0x20A0))
#define VIDW01ADD0B0 (*(volatile unsigned int *)(LCD_BASE + 0x00A8))
#define VIDW01ADD0B1 (*(volatile unsigned int *)(LCD_BASE + 0x00AC))
#define VIDW01ADD0B2 (*(volatile unsigned int *)(LCD_BASE + 0x20A8))
#define VIDW02ADD0B0 (*(volatile unsigned int *)(LCD_BASE + 0x00B0))
#define VIDW02ADD0B1 (*(volatile unsigned int *)(LCD_BASE + 0x00B4))
#define VIDW02ADD0B2 (*(volatile unsigned int *)(LCD_BASE + 0x20B0))
#define VIDW03ADD0B0 (*(volatile unsigned int *)(LCD_BASE + 0x00B8))
#define VIDW03ADD0B1 (*(volatile unsigned int *)(LCD_BASE + 0x00BC))
#define VIDW03ADD0B2 (*(volatile unsigned int *)(LCD_BASE + 0x20B8))
#define VIDW04ADD0B0 (*(volatile unsigned int *)(LCD_BASE + 0x00C0))
#define VIDW04ADD0B1 (*(volatile unsigned int *)(LCD_BASE + 0x00C4))
#define VIDW04ADD0B2 (*(volatile unsigned int *)(LCD_BASE + 0x20C0))
#define VIDW00ADD1B0 (*(volatile unsigned int *)(LCD_BASE + 0x00D0))
#define VIDW00ADD1B1 (*(volatile unsigned int *)(LCD_BASE + 0x00D4))
#define VIDW00ADD1B2 (*(volatile unsigned int *)(LCD_BASE + 0x20D0))
#define VIDW01ADD1B0 (*(volatile unsigned int *)(LCD_BASE + 0x00D8))
#define VIDW01ADD1B1 (*(volatile unsigned int *)(LCD_BASE + 0x00DC))
#define VIDW01ADD1B2 (*(volatile unsigned int *)(LCD_BASE + 0x20D8))
#define VIDW02ADD1B0 (*(volatile unsigned int *)(LCD_BASE + 0x00E0))
#define VIDW02ADD1B1 (*(volatile unsigned int *)(LCD_BASE + 0x00E4))
#define VIDW02ADD1B2 (*(volatile unsigned int *)(LCD_BASE + 0x20E0))
#define VIDW03ADD1B0 (*(volatile unsigned int *)(LCD_BASE + 0x00E8))
#define VIDW03ADD1B1 (*(volatile unsigned int *)(LCD_BASE + 0x00EC))
#define VIDW03ADD1B2 (*(volatile unsigned int *)(LCD_BASE + 0x20E8))
#define VIDW04ADD1B0 (*(volatile unsigned int *)(LCD_BASE + 0x00F0))
#define VIDW04ADD1B1 (*(volatile unsigned int *)(LCD_BASE + 0x00F4))
#define VIDW04ADD1B2 (*(volatile unsigned int *)(LCD_BASE + 0x20F0))
#define VIDW00ADD2 (*(volatile unsigned int *)(LCD_BASE + 0x0100))
#define VIDW01ADD2 (*(volatile unsigned int *)(LCD_BASE + 0x0104))
#define VIDW02ADD2 (*(volatile unsigned int *)(LCD_BASE + 0x0108))
#define VIDW03ADD2 (*(volatile unsigned int *)(LCD_BASE + 0x010C))
#define VIDW04ADD2 (*(volatile unsigned int *)(LCD_BASE + 0x0110))
#define VIDINTCON0 (*(volatile unsigned int *)(LCD_BASE + 0x0130))
#define VIDINTCON1 (*(volatile unsigned int *)(LCD_BASE + 0x0134))
#define W1KEYCON0 (*(volatile unsigned int *)(LCD_BASE + 0x0140))
#define VIDW0ALPHA0 (*(volatile unsigned int *)(LCD_BASE + 0x021C))
#define VIDW0ALPHA1 (*(volatile unsigned int *)(LCD_BASE + 0x0220))
#define VIDW1ALPHA0 (*(volatile unsigned int *)(LCD_BASE + 0x0224))
#define VIDW1ALPHA1 (*(volatile unsigned int *)(LCD_BASE + 0x0228))
#define VIDW2ALPHA0 (*(volatile unsigned int *)(LCD_BASE + 0x022C))
#define VIDW2ALPHA1 (*(volatile unsigned int *)(LCD_BASE + 0x0230))
#define VIDW3ALPHA0 (*(volatile unsigned int *)(LCD_BASE + 0x0234))
#define VIDW3ALPHA1 (*(volatile unsigned int *)(LCD_BASE + 0x0238))
#define VIDW4ALPHA0 (*(volatile unsigned int *)(LCD_BASE + 0x023C))
#define VIDW4ALPHA1 (*(volatile unsigned int *)(LCD_BASE + 0x0240)) #endif
regs.h
#include "lcd.h"
#include "regs.h"
#include "images.h" int main(void)
{
*(unsigned long *)0x47000000 = do_irq;
lcd_init();
irq_init();
init_images();
enable_mmu();
memcpy(0x0, vector_start, 0x1000);
} void images_write_to_buff(unsigned int height, unsigned int width, char *images, unsigned long addr )
{
int i, j;
unsigned char *data;
fb = addr;
data = images;
for(i = ; i < height; i++) {
for(j = ; j < width; j++) {
HEADER_PIXEL(data, (fb + (i * width + j) * )); //以每个像素点读去数据
}
} } /*将图片信息加载进来*/
void init_images()
{
int i;
char *head_data[] = {header_data0, header_data1, header_data2, header_data3,
header_data4, header_data5, header_data6, header_data7,
header_data8, header_data9};
space = 0x1000000;
tmp = ADDR0; for(i = ; i < ; i++) {
images_write_to_buff(, , head_data[i], tmp);
tmp += space;
} tmp = ADDR0;
} void show_next()
{
if(tmp >= ADDR2) //判断是否到达最后一张图片
tmp = ADDR0;
else
tmp += space; VIDW00ADD0B0 = tmp; //framebuff start addr
VIDW00ADD1B0 = tmp + VIDOSD0C * ; //frambuff end addr
VIDW00ADD2 = ;
} void show_pre()
{
if(tmp <= ADDR1) //判断是否到达第一张图片
tmp = ADDR2;
else
tmp -= space; VIDW00ADD0B0 = tmp;
VIDW00ADD1B0 = tmp + VIDOSD0C * ;
VIDW00ADD2 = ;
} void do_irq()
{
#if 1
unsigned long irq = ; if(EXT_INT41_PEND & ( << ))//if interrupt occur
{
EXT_INT41_PEND |= ( << );//clean interrupt ts_handle(); // handle interrupt func
udelay();
}
#else
unsigned long data = ICCIAR_CPU0;
unsigned int irq = data & 0x3ff;
unsigned int cpu = (data >> ) & 0x7;
ICCEOIR_CPU0 = irq | (cpu << ); if( == irq) {
if(EXT_INT43_PEND & (0x1 << )) {
EXT_INT43_PEND |= (0x1 << );
show_next();
printf("next picture\n");
}
if (EXT_INT43_PEND & (0x1 << )) {
EXT_INT43_PEND |= (0x1 << );
show_pre();
printf("pre picture\n");
} }
#endif
} void iic_init()
{
GPD1CON &= ~(0xff << );//Xi2c1SDA/GPD1_2 ; Xi2c1SCL/GPD1_3
GPD1CON |= (0x22 << );//GPD1_2 --> 0x2 = I2C_1_SDA; GPD1_3 --> 0x2 = I2C_1_SCL
GPD1PUD = ;//Disables Pull-up/Pull-down I2CCON1 = 0x2 | ( << ) | ( << );//100000000/512/3==65kb
// I2CADD1 = 0xc0;//slave address
I2CSTAT1 = ( << );//Enables Rx/Tx
I2CLC1 = 0x7;//0111 Enables Filter;15 clocks
} void iic_dest()
{
I2CCON1 = ;
I2CSTAT1 = ;
I2CADD1 = ;
I2CLC1 = ;
} void iic_master_read_buff(unsigned char slave_addr, char *data, int len)
{
iic_dest();
iic_init(); int cnt = ;
while(I2CSTAT1 & ())//if (write) START signal generation
{
I2CSTAT1 = 0X90;
udelay();
printf("i am I2CSTATZZ1 1\n");
} I2CCON1 |= ( << );//I2C-bus acknowledge enable bit
I2CDS1 = slave_addr; //Slave address
I2CSTAT1 = 0Xb0;//1011 Master receive mode ;(Read) Busy (If Read; Enables Rx/Tx while(I2CSTAT1 & )//(Read) Busy If Read
{
printf("i am I2CSTAT1 2\n");
}
udelay(); char tmp = I2CDS1;//第一个数据,为传过去的地址
I2CCON1 &= ~( << );//No interrupt is pending (If Read). Clears pending condition and resumes the operation (If Write).
udelay(); while(cnt < len)
{
if((I2CCON1 & 0x10))
{
data[cnt] = I2CDS1; //read read a byte data of each
I2CCON1 &= ~( << ); //No interrupt is pending (If Read). Clears pending condition and resumes the operation (If Write).
udelay();
cnt++;
}
} I2CSTAT1 = 0X90;//1001 Master receive mode;(Read) Not busy (If Read); enables Rx/Tx; h
} void ts_handle()
{
unsigned short x, y;
unsigned char buf[];
static int m = ; iic_master_read_buff(0x70, buf, ); //0x70为触摸屏地址
x = (buf[] & 0x0f) << | buf[]; if(m < )
codate[m++] = x; /*judge left or right of gesture*/
else {
if(codate[] < codate[]) { //right
printf("move right\n");
show_next();
} else if(codate[] > codate[]) { //left
printf("move left\n");
show_pre();
} /*clean codate */
for(m = ; m < ; m++) {
codate[m] = ;
}
m = ;
udelay();
}
} void irq_init()
{
#if 1
//step 1: enable cpu cpsr
__asm__ __volatile__(
"mrs r0, cpsr\n"
"bic r0, r0, #0x80\n"
"msr cpsr, r0\n"
::: "r0"
); //step 2: GIC NO.62
ICCICR_CPU0 = ;//global enable interrupt (total switch)
ICCPMR_CPU0 = 0xff;//This register provides an interrupt priority filter. Only interrupts with higher priority than the value in this registercan be signaled to the processor ICDDCR = ;//This register enables forwarding of pending interrupts to the CPU interfaces /*一共有1024个中断源,只有160个中断号*/
//id = 62. 一个ICDIPR 控制4个中断,62 / 4 = 15 ...2, so ICDIPR=15
ICDIPR15_CPU0 = ~(0xff << );//the zero is the highest priority
ICDIPTR15_CPU0 = ( << );//0x1 ---> for cpu0
ICDISER1_CPU0 = ( << );// enable interrupt 0 //step 3: set gpio
GPX1CON &= ~(0xf << );
GPX1CON |= (0xf << );//xeint14 <==> gpx1_6 ---->0xF = EXT_INT41[6] //step 4:set ext_int
EXT_INT41_CON &= ~(0x7 << );
EXT_INT41_CON |= (0x3 << );//falling edge; low level
EXT_INT41_MASK &= ~(0x1 << );//enable extint41_6 #else
//step 1: cpu permit interrupt
__asm__ __volatile__(
"mrs r0, cpsr\n"
"bic r0,r0, #0x80\n"
"msr cpsr, r0\n"
:::"r0"
); //step 2: GIC (cgi) enable
ICCICR_CPU0 = ; //总开关
ICCPMR_CPU0 =0xff;//总优先级
ICDDCR = ; //本中断开关 //KEY
ICDIPR16_CPU0 = ( << );//本中断优先级
ICDIPTR16_CPU0 = ( << );//目标cpu
ICDISER2_CPU0 = ( << );//启用本中断 //step 3: Xeint
EXT_INT43_CON = (0x2 << );
EXT_INT43_CON = (0x2 << );
EXT_INT43_MASK = ; //step 4: set gpio
GPX3CON = (0xf << );
GPX3CON = (0xf << ); //step 5: interrupt source
#endif
} void memcpy(unsigned char *dest, unsigned char *src, unsigned int len)
{
int i = ;
for(i = ; i < len; i++) {
dest[i] = src[i];
}
} void init_table(unsigned long *addr)
{
unsigned long va = ;
unsigned long phys = ; //0x40000000-0x80000000 -> 0x40000000-0x80000000
for(va = 0x40000000; va < 0x80000000; va += 0x100000) {
phys = va;
addr[va >> ] = phys | ;
} //0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x10000000; va < 0x14000000; va += 0x100000) {
phys = va;
addr[va >> ] = phys | ;
}
//0x10000000-0x14000000 -> 0x10000000-0x140000000
for(va = 0x0; va < 0x10000000; va += 0x100000) {
phys = va + 0x70000000;
addr[va >> ] = phys | ;
} } void enable_mmu()
{
/*构建表*/
unsigned long addr = 0x50000000;
init_table(addr); /*打开mmu*/
unsigned long mmu = ;
mmu = | ( << ) | ( << ) | ( << );
__asm__ __volatile__ (
"mov r0, #3\n"
"MCR p15, 0, r0, c3, c0, 0\n"//设置为管理员
"MCR p15, 0, %0, c2, c0, 0\n"//设置表的地址
"MCR p15, 0, %1, c1, c0, 0\n"//开启mmu
:
: "r" (addr), "r" (mmu)
:
); } void lcd_init(void)
{
/*
*<Exyons 4412 datasheet pg138 pg141 pg144 pg147> *
* GPF0CON : [31:0] : 0x2
* GPF1CON : [31:0] : 0x2
* GPF2CON : [31:0] : 0x2
* GPF3CON : [31:0] : 0x2
* */ //定义IO引脚功能为RGB接口
GPF0CON = 0x22222222;
GPF1CON = 0x22222222;
GPF2CON = 0x22222222;
GPF3CON &= ~(0xffff);
GPF3CON |= 0x2222; //max driver strebgh----
GPF0DRV = 0xffffffff;
GPF1DRV = 0xffffffff;
GPF2DRV = 0xffffffff;
GPF3DRV &= ~0xff;
GPF3DRV |= 0xff;
/*
*<Exyons 4412 datasheet pg526>
*CLK_DIV_LCD:
* [3:0]:FIMD0_RATIO 0
* SCLK_FIMD0 = MOUTFIMD0/(FIMD0_RATIO + 1)
* = MOUTFIMD0/1 = 800MHz
* MOUTFIMD0 == SCLKmpll_user_t == 800MHz <Exyons 4412 datasheet pg453> LCD0_BLK
* */ CLK_DIV_LCD &= ~0xf;
/*
*<Exyons 4412 datasheet pg501>
*CLK_SRC_LCD0:
* [3:0]:FIMD0_SEL 0110 ===> SCLKmpll_user_t 选择时钟源为SCLKmpll_user_t
*
* */
CLK_SRC_LCD0 &= ~0xf;
CLK_SRC_LCD0 |= ;
//LCD0_SYS_PWR_REG == 7 Don't use /*<Exyons 4412 datasheet pg1799>
*Using the display controller data, you can select one of the above data paths by setting LCDBLK_CFG Register
*(0x1001_0210). For more information, refer to the "System Others" manual.
*
*
* <Exyons 4412 datasheet pg880>
* LCDBLK_CFG:
* [1] : FIMD of LBLK0 Bypass Selection 1 : FIMD Bypass 使用FIMD接口
*
* LCDBLK_CFG :
* [0]:MIE0_DISPON 1 : PWM outpupt enable
*
*
* */
LCDBLK_CFG |= << ; //set FIMD
LCDBLK_CFG2 |= ; /*
*<Exyons 4412 datasheet pg1869>
*VIDCON0:
* [13:6]: CLKVAL_F //设置lcd时钟分频系数
*
* VCLK == 33.3Mhz <S700-AT070TN92 pg14> DCLK Frequency ===> Type : 33.3Mhz
* VCLK = FIMD * SCLK/(CLKVAL+1)
* VCLK = 800000000 / (CLKVAL + 1)
* 33300000 = 800000000 /(CLKVAL + 1)
* CLKVAL + 1 = 24.02
* CLKVAL = 23
* */ //设置接口类型及时钟分频 33.3MHZ (配置时钟分频系数)
VIDCON0 = ( << ) | ( << ) | ; /*(1 << 17)非常重要 不配制会出现色差*/
//VIDCON0 = (23 << 6) | 3;
/*
*<Exyons 4412 datasheet pg1870 pg1848(时序)> <S700-AT070TN92 pg13(时序)>
*VIDTCON1:
* [5]:IVSYNC ===> 1 : Inverted(反转)
* [6]:IHSYNC ===> 1 : Inverted(反转)
* [7]:IVCLK ===> 1 : Fetches video data at VCLK rising edge (下降沿触发)
* [10:9]:FIXVCLK ====> 01 : VCLK running
* */
/*VIDCON1主要设置像表时钟信号一直存在,且高电平有效,
而IHSYNC=1,极性反转IVSYNC=1,极性反转,这是由于S07的时序图中VSYNC和
HSYNC都是低脉冲有效,而Exynos4412芯片手册时序图,VSYNC 和HSYNC都是高脉冲有效
,所以需要反转*/
VIDCON1 = ( << ) | ( << ) | ( << ) | ( << ); //配置时序相关 /*
*<Exyons 4412 datasheet pg1874 pg1848(时序)> <S700-AT070TN92 pg13(时序)>
*VIDTCON0:
* [23:16]: VBPD + 1 <------> tvpw (1 - 20) 13
* [15:8]: VFPD + 1 <------> tvfp 22
* [7:0]: VSPW + 1 <------> tvb - tvpw = 23 - 13 = 10
* */
/*VIDTCONx用来设置时序和长宽等参数,这里就主要设置VBPD(vertical back porch)、
VFBD(vertical fro ntporch)、VSPW(vertical sync pulse width)、
HBPD(horizontal backporch)、 HFPD(horizontal sync pul se width)等参数*/
VIDTCON0 = ( << ) | ( << ) | (); //配置时序间隔时间 (VIDTCON0 VIDTCON1) /*<Exyons 4412 datasheet pg1874 pg1848(时序)> <S700-AT070TN92 pg13(时序)>
*VIDTCON1:
* [23:16]: HBPD + 1 <------> thpw (1 - 40) 36
* [15:8]: HFPD + 1 <------> thfp 210
* [7:0]: HSPW + 1 <------> thb - thpw = 46 - 36 = 10
*/
VIDTCON1 = ( << ) | ( << ) | (); /*
*<Exyons 4412 datasheet pg1875>
*
*HOZVAL = (Horizontal display size) – 1 and LINEVAL = (Vertical display size) – 1.
* Horizontal(水平) display size : 800
*Vertical(垂直) display size : 480
* */
VIDTCON2 = ( << ) | ; //win0
//#ifdef BPP565
/*
*<Exyons 4412 datasheet pg1877>
*WINCON0:
* [16]:Specifies Half-Word swap control bit. 1 = Enables swap
* [5:2]: Selects Bits Per Pixel (BPP) mode for Window image : 0101 ===> 16BPP
* [1]:Enables/disables video output 1 = Enables
*
* */
// WINCON0 = (1 << 16) | (5 << 2) | 1; /*
*<Exyons 4412 datasheet pg1895>
*VIDOSD0C:Specifies the Window Size (窗口尺寸 单位为word)
*
*
* */
// VIDOSD0C = 480 * 800 >> 1;
//#else
/*
*<Exyons 4412 datasheet pg1877>
*WINCON0:
* [5:2]: Selects Bits Per Pixel (BPP) mode for Window image : 1011 ===> 24BPP
* [1]:Enables/disables video output 1 = Enables
*
* */
/*Exynos4412的LCD控制器有overlay功能,它支持5个window。
这里只使用window0,设置其代码RGB模式为24bit,(A888)且使能window0
*/
WINCON0 = ( << ) | ( << ) | ( << ) | ;//配置窗口0颜色数据格式,使能视频数据输出 /*
*<Exyons 4412 datasheet pg1895>
*VIDOSD0C:Specifies the Window Size (窗口尺寸 单位为word)
*
*
* */
VIDOSD0C = * ; //windows size
//#endif //SHADOWCON &= ~(1 << 5); Don't use /*
*<Exyons 4412 datasheet pg1891 pg1801>
*[0]: Enables Channel 0. 1 = Enables
* */
/*配置SHADOWCON和WINCHMAP2、选择使能DMA通道0,
由于我们使用的是Window0,所以需要使能DMA通道0
*/
SHADOWCON |= ; //选择相应通道 /*
*<Exyons 4412 datasheet pg1894 pg1801>
*[18:16] Selects Channel 0's channel. ===> 001 = Window 0
*[2:0] Selects Window 0's channel. ===> 001 = Channel 0
*
*
* */
WINCHMAP2 &= ~( << );//选择通道与窗口
WINCHMAP2 |= << ;
WINCHMAP2 &= ~;
WINCHMAP2 |= ; /*
*<Exyons 4412 datasheet pg1895>
*VIDOSD0A: LCD左上角坐标
*VIDOSD0B: LCD右下角坐标
*/ VIDOSD0A = ;
VIDOSD0B = ( << ) | ; /*
*<Exyons 4412 datasheet pg1902>
* VIDW00ADD0B0 : window0 frame buffer 起始地址
* VIDW00ADD1B0 : window0 frame buffer 结束地址
* */
VIDW00ADD0B0 = FRAMEBUFFER00;
VIDW00ADD1B0 = FRAMEBUFFER00 + VIDOSD0C * ;
VIDW00ADD2 = ;
/*
* <Exyons 4412 datasheet pg1869>
* Display On: ENVID and ENVID_F are set to "1".
* [0]:ENVID ===> 1 = Enables
* [1]:ENVID_F ===> 1 = Enables
* */
} __asm__( /*异常向量表*/
"vector: \n"
" b reset\n"
" b und\n"
" b swi\n"
" b pre_abt\n"
" b data_abt\n"
" .word 0x0\n"
" b irq\n"
" b fiq\n"
"reset:\n"
"und:\n"
" mov sp, #0x47000000\n"
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, =0x47000004\n"
" ldr r2, [r3]\n"
" blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n" "swi:\n"
" mov sp, #0x47000000\n"
" stmdb sp!, {r0-r12, lr}^\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n" "pre_abt:\n" "data_abt:\n"
" mov sp, #0x47000000\n"
" sub lr, lr, #4\n"
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, =0x47000008\n"
" ldr r2, [r3]\n"
" blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n"
"irq:\n" " mov sp, #0x47000000\n"
" sub lr, lr, #4\n"
" stmdb sp!, {r0-r12, lr}\n" " ldr r3, =0x47000000\n" //跳转到c语言
" ldr r2, [r3]\n"
" blx r2\n" " mov sp, #0x47000000\n"
" ldmdb sp, {r0-r12, pc}^ \n" "fiq:\n" ".global vector_start\n"
"vector_start: \n"
".word vector \n " );
数码相框(LCD、I2C)的更多相关文章
- I2C和LCD信号干扰的解决:硬件工程师都硬不起来,让软件工程师硬着头上
DEMO4,LCD的clk干扰I2C,I2C无法通信. 把排针压下,去掉LCD的CLK,恢复正常. 过程: 直接跳线I2C,没问题.两排针插到一起就无法通信. 一个个的排针去除,最终找到LCD ...
- 2.数码相框-编码(ASCII/GB2312/Unicode)介绍,并使LCD显示汉字字符(2)
在上章-学习了数码相框的框架分析(1)了 本章主要内容如下: 1)熟悉ASCII/GB2312/Unicode编码 2)写应用程序,使LCD显示汉字和字符 大家都知道,数据传输的是二进制,而字符和汉字 ...
- 6、修改应用程序数码相框以支持自动关闭LCD
1. 修改数码相框以自动关闭LCD关闭LCD : 在读取触摸屏的函数中判断:如果15S内无数据,执行: echo auto > /sys/devices/platform/mylcd/power ...
- [I2C]I2C架构分析
转自:http://blog.csdn.net/wangpengqi/article/details/17711165 1. I2C 概述 I2C是philips提出的外设总线. I2C只有两条线,一 ...
- linux设备驱动归纳总结(十二):简单的数码相框【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-116926.html linux设备驱动归纳总结(十二):简单的数码相框 xxxxxxxxxxxxxx ...
- linux之I2C裸机驱动解析(转)
1 硬件特性 1.1 概述 I2C总线是由Philips公司开发的两线式串行总线,这两根线为时钟线(SCL)和双向数据线(SDA).由于I2C总线仅需要两根线,因此在电路板上占用的空间更少, ...
- (2)I2c总线SDA\SCL以及开始终止条件
I2C只用两条线(SDA和SCL)在连接到总线上的设备之间传送数据.每一个设备都由唯一的地址来识别(不管是微处理器.LCD驱动器.存储器或者键盘接口),并且可以依照设备的功能作为发送器或者接收器使用. ...
- (1)I2c的简介和特性
I2C我是想全面深入的从嵌入式软件工程师的角度做个理解,刚刚还申请了一个专栏,这个好好写. 学习技术从外文文档看起-- 要全面了解I2C,可以从<I2C-bus specific ...
- 自制单片机之六……串行I2C总线E2PROM AT24CXXX的应用
这一篇介绍I2C存储器的使用.主要是介绍AT24CXX系列器件,它分为两类,主要是通过被存储容量地址来分的,一类是AT24C02-AT24C16,它的存储容量从256字节到2048字节.另一类是AT2 ...
随机推荐
- android 线程那点事
在操作系统中,线程是操作系统调度的最小单元,同时线程又是一种受限的系统资源,即线程不可能无限制的产生,并且线程的创建和销毁都会有相应的开销,当系统中存在大量的线程时,系统会通过时间片轮转的方式调度每个 ...
- gtk+程序在关闭主窗口时的事件流
当鼠标单击gtk+窗口的关闭按钮时,程序首先接收到delete_event,当该事件处理函数返回TRUE表示事件已处理禁止进一步传播,从而取消关闭操作:当返回FALSE时,事件消息进一步向上传播,此时 ...
- linux下64位汇编的系统调用(4)
经过上一篇的铺垫貌似可以很轻松的用汇编写出mmap的代码来,可仔细一看,还是有不少问题需要解决: 1.系统调用mmap如果出错并不直接返回MAP_FAILED(-1),而是一个"类似&quo ...
- Linux内核中断和异常分析(下)
这节,我们继续上,中(以前的日志有)篇目进行分析,结合一个真实的驱动案例来描述linux内核中驱动的中断机制,首先我们先了解一下linux内核中提供的中断接口. 这个接口我们需要包含一个头文件:#in ...
- Android布局优化:include 、merge、ViewStub的详细总结
版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 本篇博客主要是对上篇博客的补充Android性能优化之UI渲染性能优化, 没有什么新东西,觉得应该是都掌握的玩意,写出来也只是自己做个小小的总结. ...
- 点击劫持漏洞之理解 python打造一个挖掘点击劫持漏洞的脚本
前言: 放假了,上个星期刚刚学习完点击劫持漏洞.没来的及写笔记,今天放学总结了一下 并写了一个检测点击劫持的脚本.点击劫持脚本说一下哈.= =原本是打算把网站源码 中的js也爬出来将一些防御的代码匹配 ...
- R实战 第七篇:绘图文本表
文本表是显示数据的重要图形,一个文本表按照区域划分为:列标题,行标题,数据区,美学特征有:前景样式.背景央视.字体.网格线等. 一,使用ggtexttable绘图文本表 载入ggpubr包,可以使用g ...
- MySQL中的行级锁,表级锁,页级锁
在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足. 在数据库的锁机制中介绍过,在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引 ...
- JeeSite
JeeSite是一个 开源的企业信息管理系统 基础框架.主要定位于"企业信息管理"领域,可用作企业信息管理类系统.网站后台管理类系统等.JeeSite是非常强调开发的高效性.健壮性 ...
- javaScript(7)---函数
学习要点: 1.函数声明 2.return返回值 3.arguments对象 函数是定义一次但却可以调用或执行任意多次的一段JS代码.函数有时会有参数,即函数被调用时指定了值的局部变量.函数常常使用这 ...