S3C2440 TFT LCD驱动程序编程要点
- 格式:doc
- 大小:24.50 KB
- 文档页数:3
2410_SPI接口与linux驱动以下先从下到上的进行分析:driver/spi下有两个底层相关的spi驱动程序:spi_s3c24xx.c和spi_s3c24xx_gpio.c其中spi_s3c24xx.c是基于s3c24xx下相应的spi接口的驱动程序,spi_s3c24xx_gpio.c允许用户指定3个gpio口接口,模拟标准的spi总线。
s3c2410自带了两个spi接口(spi0和spi1),在此我只研究基于s3c2410下spi接口的驱动程序spi_s3c24xx.c。
首先从spi驱动的检测函数进行分析:static int s3c24xx_spi_probe(struct platform_device *pdev){struct s3c24xx_spi *hw;struct spi_master *master;struct spi_board_info *bi;struct resource *res;int err = 0;int i;master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); if (master == NULL) {dev_err(&pdev->dev, "No memory for spi_master\n");err = -ENOMEM;goto err_nomem;}hw = spi_master_get_devdata(master);memset(hw, 0, sizeof(struct s3c24xx_spi));hw->master = spi_master_get(master);hw->pdata = pdev->dev.platform_data;hw->dev = &pdev->dev;if (hw->pdata == NULL) {dev_err(&pdev->dev, "No platform data supplied\n");err = -ENOENT;goto err_no_pdata;}platform_set_drvdata(pdev, hw);//dev_set_drvdata(&pdev->dev, hw) init_completion(&hw->done);hw->bitbang.master = hw->master;hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;hw->bitbang.chipselect = s3c24xx_spi_chipsel;hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;hw->bitbang.master->setup = s3c24xx_spi_setup;dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (res == NULL) {dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");err = -ENOENT;goto err_no_iores;}hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1, pdev->name);if (hw->ioarea == NULL) {dev_err(&pdev->dev, "Cannot reserve region\n");err = -ENXIO;goto err_no_iores;}hw->regs = ioremap(res->start, (res->end - res->start)+1);if (hw->regs == NULL) {dev_err(&pdev->dev, "Cannot map IO\n");err = -ENXIO;goto err_no_iomap;}hw->irq = platform_get_irq(pdev, 0);if (hw->irq < 0) {dev_err(&pdev->dev, "No IRQ specified\n");err = -ENOENT;goto err_no_irq;}err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);if (err) {dev_err(&pdev->dev, "Cannot claim IRQ\n");goto err_no_irq;}hw->clk = clk_get(&pdev->dev, "spi");if (IS_ERR(hw->clk)) {dev_err(&pdev->dev, "No clock for device\n");err = PTR_ERR(hw->clk);goto err_no_clk;}clk_enable(hw->clk);writeb(0xff, hw->regs + S3C2410_SPPRE);writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);s3c2410_gpio_setpin(S3C2410_GPE13, 0);s3c2410_gpio_setpin(S3C2410_GPE12, 0);s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0); s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0); s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);if (!hw->pdata->set_cs) {s3c2410_gpio_setpin(hw->pdata->pin_cs, 1);s3c2410_gpio_cfgpin(hw->pdata->pin_cs, S3C2410_GPIO_OUTPUT); }err = spi_bitbang_start(&hw->bitbang);if (err) {dev_err(&pdev->dev, "Failed to register SPI master\n");goto err_register;}dev_dbg(hw->dev, "shutdown=%d\n", hw->bitbang.shutdown);bi = &hw->pdata->board_info[0];for (i = 0; i < hw->pdata->board_size; i++, bi++) {dev_info(hw->dev, "registering %s\n", bi->modalias);bi->controller_data = hw;spi_new_device(master, bi);}return 0;err_register:clk_disable(hw->clk);clk_put(hw->clk);err_no_clk:free_irq(hw->irq, hw);err_no_irq:iounmap(hw->regs);err_no_iomap:release_resource(hw->ioarea);kfree(hw->ioarea);err_no_iores:err_no_pdata:spi_master_put(hw->master);;err_nomem:return err;}struct spi_master * __init_or_modulespi_alloc_master(struct device *dev, unsigned size) {struct spi_master *master;if (!dev)return NULL;master = kzalloc(size + sizeof *master, SLAB_KERNEL); if (!master)return NULL;class_device_initialize(&master->cdev);master->cdev.class = &spi_master_class;master->cdev.dev = get_device(dev);spi_master_set_devdata(master, &master[1]);return master;}int spi_bitbang_start(struct spi_bitbang *bitbang){int status;if (!bitbang->master || !bitbang->chipselect)return -EINVAL;INIT_WORK(&bitbang->work, bitbang_work, bitbang);spin_lock_init(&bitbang->lock);spi_new_device INIT_LIST_HEAD(&bitbang->queue);if (!bitbang->master->transfer)bitbang->master->transfer = spi_bitbang_transfer;//spi数据的传输就是通过调用这个方法来实现的if (!bitbang->txrx_bufs) {bitbang->use_dma = 0;bitbang->txrx_bufs = spi_bitbang_bufs;if (!bitbang->master->setup) {if (!bitbang->setup_transfer)bitbang->setup_transfer =spi_bitbang_setup_transfer;bitbang->master->setup = spi_bitbang_setup;bitbang->master->cleanup = spi_bitbang_cleanup;}} else if (!bitbang->master->setup)return -EINVAL;bitbang->busy = 0;bitbang->workqueue = create_singlethread_workqueue(bitbang->master->cdev.dev->bus_id);if (bitbang->workqueue == NULL) {status = -EBUSY;goto err1;}status = spi_register_master(bitbang->master);if (status < 0)goto err2;return status;err2:destroy_workqueue(bitbang->workqueue);err1:return status;}int __init_or_modulespi_register_master(struct spi_master *master){static atomic_t dyn_bus_id = ATOMIC_INIT((1<<16) - 1);struct device *dev = master->cdev.dev;int status = -ENODEV;int dynamic = 0;if (!dev)return -ENODEV;if (master->bus_num < 0) {master->bus_num = atomic_dec_return(&dyn_bus_id); dynamic = 1;}snprintf(master->cdev.class_id, sizeof master->cdev.class_id, "spi%u", master->bus_num);status = class_device_add(&master->cdev);//注册设备if (status < 0)goto done;dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id, dynamic ? " (dynamic)" : "");scan_boardinfo(master);status = 0;done:return status;}static void __init_or_modulescan_boardinfo(struct spi_master *master){struct boardinfo *bi;struct device *dev = master->cdev.dev;down(&board_lock);list_for_each_entry(bi, &board_list, list) {struct spi_board_info *chip = bi->board_info;unsigned n;for (n = bi->n_board_info; n > 0; n--, chip++) {if (chip->bus_num != master->bus_num)continue;if (chip->chip_select >= master->num_chipselect&& master->num_chipselect) {dev_dbg(dev, "cs%d > max %d\n",chip->chip_select,master->num_chipselect);continue;}(void) spi_new_device(master, chip);}}up(&board_lock);}int __initspi_register_board_info(struct spi_board_info const *info, unsigned n)struct boardinfo *bi;bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);if (!bi)return -ENOMEM;bi->n_board_info = n;memcpy(bi->board_info, info, n * sizeof *info);down(&board_lock);list_add_tail(&bi->list, &board_list);up(&board_lock);return 0;}struct spi_device *__init_or_modulespi_new_device(struct spi_master *master, struct spi_board_info *chip){struct spi_device *proxy;//这个结构很重要,以后就是通过这个结构来操作实际的spi设备的struct device *dev = master->cdev.dev;int status;if (!spi_master_get(master))return NULL;proxy = kzalloc(sizeof *proxy, GFP_KERNEL);if (!proxy) {dev_err(dev, "can't alloc dev for cs%d\n",chip->chip_select);goto fail;}proxy->master = master;proxy->chip_select = chip->chip_select;proxy->max_speed_hz = chip->max_speed_hz;proxy->mode = chip->mode;proxy->irq = chip->irq;proxy->modalias = chip->modalias;snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,"%s.%u", master->cdev.class_id,chip->chip_select);proxy->dev.parent = dev;proxy->dev.bus = &spi_bus_type;proxy->dev.platform_data = (void *) chip->platform_data; proxy->controller_data = chip->controller_data;proxy->controller_state = NULL;proxy->dev.release = spidev_release;status = master->setup(proxy);if (status < 0) {dev_dbg(dev, "can't %s %s, status %d\n","setup", proxy->dev.bus_id, status);goto fail;}status = device_register(&proxy->dev);//真正注册原始设备if (status < 0) {dev_dbg(dev, "can't %s %s, status %d\n","add", proxy->dev.bus_id, status);goto fail;}dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id); return proxy;fail:spi_master_put(master);kfree(proxy);return NULL;}static int s3c24xx_spi_setup(struct spi_device *spi){int ret;if (!spi->bits_per_word)spi->bits_per_word = 8;if ((spi->mode & SPI_LSB_FIRST) != 0)return -EINVAL;ret = s3c24xx_spi_setupxfer(spi, NULL);if (ret < 0) {dev_err(&spi->dev, "setupxfer returned %d\n", ret);return ret;}dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",__FUNCTION__, spi->mode, spi->bits_per_word,spi->max_speed_hz);return 0;}static int s3c24xx_spi_setupxfer(struct spi_device *spi,struct spi_transfer *t){struct s3c24xx_spi *hw = to_hw(spi);unsigned int bpw;unsigned int hz;unsigned int div;bpw = t ? t->bits_per_word : spi->bits_per_word;hz = t ? t->speed_hz : spi->max_speed_hz;if (bpw != 8) {dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);return -EINVAL;}div = clk_get_rate(hw->clk) / hz;div = (div / 2) - 1;//求出预分频值if (div < 0)div = 1;if (div > 255)div = 255;dev_dbg(&spi->dev, "setting pre-scaler to %d (hz %d)\n", div, hz);writeb(div, hw->regs + S3C2410_SPPRE);//设置预分频值spin_lock(&hw->bitbang.lock);if (!hw->bitbang.busy) {hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);//修改时钟,先禁用spi}spin_unlock(&hw->bitbang.lock);return 0;}static void s3c24xx_spi_chipsel(struct spi_device *spi, int value){struct s3c24xx_spi *hw = to_hw(spi);unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;unsigned int spcon;switch (value) {case BITBANG_CS_INACTIVE:if (hw->pdata->set_cs)hw->pdata->set_cs(hw->pdata, value, cspol);elses3c2410_gpio_setpin(hw->pdata->pin_cs, cspol ^ 1);break;case BITBANG_CS_ACTIVE:spcon = readb(hw->regs + S3C2410_SPCON);if (spi->mode & SPI_CPHA)spcon |= S3C2410_SPCON_CPHA_FMTB;elsespcon &= ~S3C2410_SPCON_CPHA_FMTB;if (spi->mode & SPI_CPOL)spcon |= S3C2410_SPCON_CPOL_HIGH;elsespcon &= ~S3C2410_SPCON_CPOL_HIGH;spcon |= S3C2410_SPCON_ENSCK;writeb(spcon, hw->regs + S3C2410_SPCON);if (hw->pdata->set_cs)hw->pdata->set_cs(hw->pdata, value, cspol);elses3c2410_gpio_setpin(hw->pdata->pin_cs, cspol);break;}}好了,至此spi主控制器(驱动)和板上spi设备注册完毕,以后要使用spi来传输数据的话,只要先获得spi设备交道了(就好像你要操作一个文件,先要获取文件句柄一样,明白吧^_^)原文地址/luofuchong/archive/2007/09/24/33942.html~~~~~~~~~~~~~~~~~~``任何SPI都有4种模式2008-11-06 22:17void McBSPObj::McBSP0Init(void)//McBSP从设备SPI硬件配置{//PCR设置过程(FSM=0,CLKM=0)McBSP0->SPSA = PCR;McBSP1->SPSD = (0 << PCR_XIOEN) //发送非通用I/O模式位| (0 << PCR_RIOEN) //接收非通用I/O模式位| (0 << PCR_FSXM) //外部发送帧同步脉冲(外部片选)| (0 << PCR_FSRM) //外部接收帧同步脉冲(外部片选)| (0 << PCR_CLKXM) //外部发送时钟(外部时钟源)| (0 << PCR_CLKRM) //外部接收时钟(外部时钟源)#if SPIMODE == 0//SPI设置过程00(0--FS高电平有效,0--CLK上升沿收发数据)| (0 << PCR_FSXP) //发送帧同步脉冲极性(高电平有效)| (0 << PCR_FSRP) //接收帧同步脉冲极性(高电平有效)| (0 << PCR_CLKXP) //发送时钟极性(上升沿发送数据)| (0 << PCR_CLKRP);//接收时钟极性(上升沿接收数据)#endif#if SPIMODE == 1//SPI设置过程01(0--FS高电平有效,1--CLK下降沿收发数据)| (0 << PCR_FSXP) //发送帧同步脉冲极性(高电平有效)| (0 << PCR_FSRP) //接收帧同步脉冲极性(高电平有效)| (1 << PCR_CLKXP) //发送时钟极性(下降沿发送数据)| (1 << PCR_CLKRP);//接收时钟极性(下降沿接收数据)#endif#if SPIMODE == 2//SPI设置过程10(1--FS低电平有效,0--CLK上升沿收发数据)| (1 << PCR_FSXP) //发送帧同步脉冲极性(低电平有效)| (1 << PCR_FSRP) //接收帧同步脉冲极性(低电平有效)| (0 << PCR_CLKXP) //发送时钟极性(上升沿发送数据)| (0 << PCR_CLKRP);//接收时钟极性(上升沿接收数据)#endif#if SPIMODE == 3//SPI设置过程11(1--FS低电平有效,1--CLK下降沿收发数据)| (1 << PCR_FSXP) //发送帧同步脉冲极性(低电平有效)| (1 << PCR_FSRP) //接收帧同步脉冲极性(低电平有效)| (1 << PCR_CLKXP) //发送时钟极性(下降沿发送数据)| (1 << PCR_CLKRP);//接收时钟极性(下降沿接收数据)#endif//MCR1设置过程(RMCM=0)McBSP0->SPSA = MCR1;//McBSP0->SPSD = (0 << MCR1_RMCM) //允许接收多通道选择(0)| (0x00 << MCR1_RPBBLK)| (0x00 << MCR1_RPABLK)| (0x00 << MCR1_RCBLK);//MCR2设置过程(XMCM=0)McBSP0->SPSA = MCR2;//McBSP0->SPSD = (0x00 << MCR2_XMCM) //允许发送多通道选择(00b) | (0x00 << MCR2_XPBBLK)| (0x00 << MCR2_XPABLK)| (0x00 << MCR2_XCBLK);//RCERA设置过程McBSP0->SPSA = RCERA;//McBSP0->SPSD = 0;//RCERB设置过程McBSP0->SPSA = RCERB;//McBSP0->SPSD = 0;//XCERA设置过程McBSP0->SPSA = XCERA;//McBSP0->SPSD = 0;//XCERB设置过程McBSP0->SPSA = XCERB;//McBSP0->SPSD = 0;//XCR1设置过程McBSP0->SPSA = XCR1;//McBSP0->SPSD = (0x00 << XCR1_XFRLEN1) //每帧1个字(每帧中断的次数1!!!) // | (0x02 << XCR1_XWDLEN1);//每字16位长(每次中断的字节数2!!!)| (0x00 << XCR1_XWDLEN1);//每字8位长(每次中断的字节数2!!!)//XCR2设置过程McBSP0->SPSA = XCR2;McBSP0->SPSD = (0 << XCR2_XPHASE) //单相帧(其他设置都为0)| (0x00 << XCR2_XCOMPAND)//发送数据从最高位(MSB)开始| (0x00 << XCR2_XDATDLY);//同步后延迟0位数据//RCR1设置过程McBSP0->SPSA = RCR1;McBSP0->SPSD = (0x00 << RCR1_RFRLEN1) //每帧1个字(每帧中断的次数1!!!) // | (0x02 << RCR1_RWDLEN1);//每字16位长(每次中断的字节数2!!!)| (0x00 << RCR1_RWDLEN1);//每字8位长(每次中断的字节数2!!!)//RCR2设置过程McBSP0->SPSA = RCR2;McBSP0->SPSD = (0 << RCR2_RPHASE) //单相帧(其他设置都为0)| (0x00 << RCR2_RCOMPAND)//接收数据从最高位(MSB)开始| (0x00 << RCR2_RDATDLY);//同步后延迟0位数据//SRGR1设置过程McBSP0->SPSA = SRGR1;McBSP0->SPSD = (0x00 << SRGR1_CLKGDV);//1//SRGR2设置过程McBSP0->SPSA = SRGR2;McBSP0->SPSD = (0 << SRGR2_FSGM)| (1 << SRGR2_CLKSM)//由CPU时钟产生的采样率时钟1| (0 << SRGR2_CLKSP)//0| (1 << SRGR2_GSYNC)//| (0x0f << SRGR2_FPER);//0x0f//SPCR1设置过程(CLKSTP=1Xb,RINTM=00b)McBSP0->SPSA = SPCR1;McBSP0->SPSD = (0x00 << SPCR1_RINTM) //接收中断模式00(每帧接收1次中? | (0 << SPCR1_DLB) //禁止回送| (1 << SPCR1_DXENA) //DX使能| (0x00 << SPCR1_RJUST) //接收符号不扩展| (0x02 << SPCR1_CLKSTP);//SPI模式时钟开始于上升沿(无延迟)//SPCR2设置过程(XINTM=02b)McBSP0->SPSA = SPCR2;McBSP0->SPSD = (0x02 << SPCR2_XINTM)//发送中断模式02| (1 << SPCR2_XEMPTY) //发送移位寄存器空| (1 << SPCR2_XRDY); //发送准备好//SPCR1复位过程McBSP0->SPSA = SPCR1;McBSP0->SPSD|= (1 << SPCR1_RRST);//接收器复位//SPCR2复位过程McBSP0->SPSA = SPCR2;McBSP0->SPSD|= (1 << SPCR2_XRST)//发送器复位| (1 << SPCR2_GRST)//采样率发生器复位| (1 << SPCR2_FRST);//帧同步发生器复位//清除允许BXINT0中断过程// SREG->IFR = (1 << IFR_BXINT0);//清除BXINT0中断标志// SREG->IMR |= (1 << IMR_BXINT0);//允许BXINT0中断//清除允许BRINT0中断过程SREG->IFR = (1 << IFR_BRINT0);//清除BRINT0中断标志SREG->IMR |= (1 << IMR_BRINT0);//允许BRINT0中断}void McBSPObj::McBSP1Init(void)//GPIO配置{McBSP1->SPSA = SPCR1;McBSP1->SPSD = 0;McBSP1->SPSA = SPCR2;McBSP1->SPSD = 0;McBSP1->SPSA = PCR;//设置收发。
VBPD: 垂直同步信号的后肩,单位为1行(Line)的时间。
LINEVAL :垂直显示尺寸-1,即屏行宽-1。
HBPD:水平同步信号的后肩,单位为1VCLK的时间。
HFPD:水平同步信号的前肩,单位为1VCLK的时间。
HSPW:水平同步信号的脉宽,单位为1VCLK的时间。
HOZVAL:水平显示尺寸-1,即屏列宽-1。
由上图可知:扫描一帧所需的时间:=((VSPW+1)+(VBPD+1)+( LINEVAL+1)+(VFPD+1))个行时间。
扫描一行所所需的时间:=((HSPW+1)+(HSPD+1)+(HFPD+1)+ (HOZVAL+1))个VCLK时间。
而一个VCLK时间由LCD寄存器LCDCON1内的CLKVAL决定:=HCLK/[2*(CLKVAL+1)]因此扫描一帧所需的时间:T=[(VSPW+1)+(VBPD+1)+( LINEVAL+1)+(VFPD+1)]*[(HSPW+1)+(HSPD+1)+(HFPD+1)+ (HOZVAL+1)]* HCLK/[2*(CLKVAL+1)]即帧频率为:1/T注意:以上的时序图为一般TFT的时序图。
实际TFT对应的时序图时序可能不一样(比如极性,符号等)。
下文中详述。
图2东华TFT型LCD(WXCAT35)时序图//2440A寄存器参数#define MVAL (13)#define MVAL_USED (0) //0=each frame 1=rate by MVAL#define INVVDEN (1) //0=normal 1=inverted#define BSWP (0) //Byte swap control#define HWSWP (1) //Half word swap control#define PNRMODE (3) // 设置为TFT屏#define BPPMODE (12) // 设置为16bpp模式//东华屏参数#define VBPD (3-1) //12 垂直同步信号的后肩参数见东华pdf #define VFPD (14-1) //4 垂直同步信号的前肩#define VSPW (15-1) //5垂直同步信号的脉宽#define HBPD (38-1) //(22)水平同步信号的后肩#define HFPD (20-1) //(33)水平同步信号的前肩#define HSPW (30-1) //(44)水平同步信号的脉宽#define CLKVAL_TFT (6)//屏大小#define LCD_XSIZE_TFT (240)//屏实际列数#define LCD_YSIZE_TFT (320)// 屏实际行数#define SCR_XSIZE_TFT (240) //虚拟屏列数#define SCR_YSIZE_TFT (320) //虚拟屏行数#define HOZVAL_TFT (LCD_XSIZE_TFT-1)#define LINEVAL_TFT (LCD_YSIZE_TFT-1)以上有关东华屏参数设置,在PDF中如下所示:7. LCDSADDR2寄存器rLCDSADDR2=M5D( ((U32)LCD_BUFFER+(SCR_XSIZE_TFT*LCD_YSIZE_TFT*2))>>1 );//单位为字节一个点16bit=2字节8. LCDSADDR3寄存器rLCDSADDR3=(((SCR_XSIZE_TFT-LCD_XSIZE_TFT)/1)<<11)|(LCD_XSIZE_TFT/1);// 1=*16bit/半字=16/16LCD初始化程序:void Lcd_Init(void){//引脚功能初始化rGPCUP = 0x00000000;rGPCCON = 0xaaaa02a9;rGPDUP = 0x00000000;rGPDCON=0xaaaaaaaa; //Initialize VD[15:8]rLCDCON1=(CLKVAL_TFT<<8)|(MVAL_USED<<7)|(PNRMODE<<5)|(BPPMODE<<1)|0;// TFT LCD panel,16bpp TFT,ENVID=off(Disable the video output and the LCD control signal) rLCDCON2=(VBPD<<24)|(LINEVAL_TFT<<14)|(VFPD<<6)|(VSPW);rLCDCON3=(HBPD<<19)|(HOZVAL_TFT<<8)|(HFPD);rLCDCON4=(MVAL<<8)|(HSPW);rLCDCON5 = (1<<11) | (1<<10) | (1<<9) | (1<<8) | (0<<7) | (0<<6) | (1<<3) |(BSWP<<1) | (HW //5:6:5rLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|M5D((U32)LCD_BUFFER>>1);rLCDSADDR2=M5D( ((U32)LCD_BUFFER+(SCR_XSIZE_TFT*LCD_YSIZE_TFT*2))>>1 );//单位为字节一个rLCDSADDR3=(((SCR_XSIZE_TFT-LCD_XSIZE_TFT)/1)<<11)|(LCD_XSIZE_TFT/1);// 1=*16bit/半字= rLCDINTMSK|=(3); // MASK LCD Sub InterruptrTCONSEL &= (~7) ; // Disable LPC3480rTPAL=0; // Disable Temp Palette}16BPP模式特点:内存数据格式:。
ARM S3C2410驱动TFT-LCD的研究技术分类:嵌入式系统 | 2008-03-07来源:电子开发网 | 作者:张义磊介绍了S3C2410的LCD控制器的数据和控制管脚,并给出了LCD的控制流程和TFT-LCD 的控制器设置规则。
参照TFT-LCD CJM10C0101的逻辑要求和时序要求设计了其驱动电路,设置了各主要LCD寄存器。
开发了CJM10C0101在嵌入式LINUX下的显示驱动程序,并在CJM10C0101上显示了清晰稳定的画面。
实验表明这套装置通用性好,能驱动大部分的TFT-LCD;可移植性强,经过少许修改即可应用在其他嵌入式系统中。
它是S3C2410驱动TFT-LCD的一套较佳的解决方案。
1 引言随着科技的发展,ARM在社会各个方面的应用越来越广。
S3C2410是三星公司生产的基于ARM920T内核的RISC微处理器,主频可达203MHz,适用于信息家电、SmartPhone、Tablet、手持设备、移动终端等领域。
其中,集成的LCD控制器具有通用性,可与大多数的LCD显示模块接口。
CJM10C0101是一种用非晶硅TFT作为开关器件的有源矩阵液晶显示器,该模块包括TFT-LCD显示屏!驱动电路和背光源,其接口为TTL电平。
分辨率为640×480像素,用18bit 数据信号能显示262144色。
6点视角是最佳视角。
在以三星ARM芯片S3C2410为核心,USB、UART、LCD、TOUCHPANEL等作为输入输出设备,FLASH和SDRAM作存储器,加上固化在FLASH里面的嵌入式LINUX组成的嵌入式系统中,我们致力于使此系统用本国生产的TFT-LCD作显示输出,因此研究设计了驱动CJM10C0101型26.4cm(10.4in)TFTLCD的硬件适配电路与嵌入式LINUX下的显示驱动程序。
2 S3C2410 LCD控制器介绍2.1 管脚S3C2410 LCD控制器用于传输视频数据和产生必要的控制信号,像VFRAME、VLINE、VCLK、VM等等。
//===================================================================== ========// File Name : 2440addr.h// Function : S3C2440 Define Address Register// History// 0.0 : Programming start (February 15,2002) -> SOP// Revision : 03.11.2003 ver 0.0 Attatched for 2440//===================================================================== ========#ifndef __2440ADDR_H__#define __2440ADDR_H__#ifdef __cplusplusextern "C" {#endif#include "option.h"// Memory control#define rBWSCON (*(volatile unsigned *)0x48000000) //Bus width & wait status#define rBANKCON0 (*(volatile unsigned *)0x48000004) //Boot ROM control#define rBANKCON1 (*(volatile unsigned *)0x48000008) //BANK1 control#define rBANKCON2 (*(volatile unsigned *)0x4800000c) //BANK2 cControl#define rBANKCON3 (*(volatile unsigned *)0x48000010) //BANK3 control#define rBANKCON4 (*(volatile unsigned *)0x48000014) //BANK4 control#define rBANKCON5 (*(volatile unsigned *)0x48000018) //BANK5 control#define rBANKCON6 (*(volatile unsigned *)0x4800001c) //BANK6 control#define rBANKCON7 (*(volatile unsigned *)0x48000020) //BANK7 control#define rREFRESH (*(volatile unsigned *)0x48000024) //DRAM/SDRAM refresh#define rBANKSIZE (*(volatile unsigned *)0x48000028) //Flexible Bank Size#define rMRSRB6 (*(volatile unsigned *)0x4800002c) //Mode register set for SDRAM#define rMRSRB7 (*(volatile unsigned *)0x48000030) //Mode register set for SDRAM// USB Host// INTERRUPT#define rSRCPND (*(volatile unsigned *)0x4a000000) //Interrupt request status#define rINTMOD (*(volatile unsigned *)0x4a000004) //Interrupt mode control#define rINTMSK (*(volatile unsigned *)0x4a000008) //Interrupt mask control#define rPRIORITY (*(volatile unsigned *)0x4a00000c) //IRQ priority control#define rINTPND (*(volatile unsigned *)0x4a000010) //Interrupt request status#define rINTOFFSET (*(volatile unsigned *)0x4a000014) //Interruot request source offset #define rSUBSRCPND (*(volatile unsigned *)0x4a000018) //Sub source pending#define rINTSUBMSK (*(volatile unsigned *)0x4a00001c) //Interrupt sub mask// DMA#define rDISRC0 (*(volatile unsigned *)0x4b000000) //DMA 0 Initial source#define rDISRCC0 (*(volatile unsigned *)0x4b000004) //DMA 0 Initial source control#define rDIDST0 (*(volatile unsigned *)0x4b000008) //DMA 0 Initial Destination#define rDIDSTC0 (*(volatile unsigned *)0x4b00000c) //DMA 0 Initial Destination control#define rDCON0 (*(volatile unsigned *)0x4b000010) //DMA 0 Control#define rDSTAT0 (*(volatile unsigned *)0x4b000014) //DMA 0 Status#define rDCSRC0 (*(volatile unsigned *)0x4b000018) //DMA 0 Current source#define rDCDST0 (*(volatile unsigned *)0x4b00001c) //DMA 0 Current destination#define rDMASKTRIG0 (*(volatile unsigned *)0x4b000020) //DMA 0 Mask trigger#define rDISRC1 (*(volatile unsigned *)0x4b000040) //DMA 1 Initial source#define rDISRCC1 (*(volatile unsigned *)0x4b000044) //DMA 1 Initial source control#define rDIDST1 (*(volatile unsigned *)0x4b000048) //DMA 1 Initial Destination#define rDIDSTC1 (*(volatile unsigned *)0x4b00004c) //DMA 1 Initial Destination control#define rDCON1 (*(volatile unsigned *)0x4b000050) //DMA 1 Control#define rDSTAT1 (*(volatile unsigned *)0x4b000054) //DMA 1 Status#define rDCSRC1 (*(volatile unsigned *)0x4b000058) //DMA 1 Current source#define rDCDST1 (*(volatile unsigned *)0x4b00005c) //DMA 1 Current destination#define rDMASKTRIG1 (*(volatile unsigned *)0x4b000060) //DMA 1 Mask trigger#define rDISRC2 (*(volatile unsigned *)0x4b000080) //DMA 2 Initial source#define rDISRCC2 (*(volatile unsigned *)0x4b000084) //DMA 2 Initial source control#define rDIDST2 (*(volatile unsigned *)0x4b000088) //DMA 2 Initial Destination#define rDIDSTC2 (*(volatile unsigned *)0x4b00008c) //DMA 2 Initial Destination control#define rDCON2 (*(volatile unsigned *)0x4b000090) //DMA 2 Control#define rDSTAT2 (*(volatile unsigned *)0x4b000094) //DMA 2 Status#define rDCSRC2 (*(volatile unsigned *)0x4b000098) //DMA 2 Current source#define rDCDST2 (*(volatile unsigned *)0x4b00009c) //DMA 2 Current destination#define rDMASKTRIG2 (*(volatile unsigned *)0x4b0000a0) //DMA 2 Mask trigger#define rDISRC3 (*(volatile unsigned *)0x4b0000c0) //DMA 3 Initial source#define rDISRCC3 (*(volatile unsigned *)0x4b0000c4) //DMA 3 Initial source control#define rDIDST3 (*(volatile unsigned *)0x4b0000c8) //DMA 3 Initial Destination#define rDIDSTC3 (*(volatile unsigned *)0x4b0000cc) //DMA 3 Initial Destinationcontrol#define rDCON3 (*(volatile unsigned *)0x4b0000d0) //DMA 3 Control#define rDSTAT3 (*(volatile unsigned *)0x4b0000d4) //DMA 3 Status#define rDCSRC3 (*(volatile unsigned *)0x4b0000d8) //DMA 3 Current source#define rDCDST3 (*(volatile unsigned *)0x4b0000dc) //DMA 3 Current destination#define rDMASKTRIG3 (*(volatile unsigned *)0x4b0000e0) //DMA 3 Mask trigger// CLOCK & POWER MANAGEMENT#define rLOCKTIME (*(volatile unsigned *)0x4c000000) //PLL lock time counter#define rMPLLCON (*(volatile unsigned *)0x4c000004) //MPLL Control#define rUPLLCON (*(volatile unsigned *)0x4c000008) //UPLL Control#define rCLKCON (*(volatile unsigned *)0x4c00000c) //Clock generator control#define rCLKSLOW (*(volatile unsigned *)0x4c000010) //Slow clock control#define rCLKDIVN (*(volatile unsigned *)0x4c000014) //Clock divider control#define rCAMDIVN (*(volatile unsigned *)0x4c000018) //USB, CAM Clock divider control// LCD CONTROLLER#define rLCDCON1 (*(volatile unsigned *)0x4d000000) //LCD control 1#define rLCDCON2 (*(volatile unsigned *)0x4d000004) //LCD control 2#define rLCDCON3 (*(volatile unsigned *)0x4d000008) //LCD control 3#define rLCDCON4 (*(volatile unsigned *)0x4d00000c) //LCD control 4#define rLCDCON5 (*(volatile unsigned *)0x4d000010) //LCD control 5#define rLCDSADDR1 (*(volatile unsigned *)0x4d000014) //STN/TFT Frame buffer start address 1#define rLCDSADDR2 (*(volatile unsigned *)0x4d000018) //STN/TFT Frame buffer start address 2#define rLCDSADDR3 (*(volatile unsigned *)0x4d00001c) //STN/TFT Virtual screen address set#define rREDLUT (*(volatile unsigned *)0x4d000020) //STN Red lookup table#define rGREENLUT (*(volatile unsigned *)0x4d000024) //STN Green lookup table#define rBLUELUT (*(volatile unsigned *)0x4d000028) //STN Blue lookup table#define rDITHMODE (*(volatile unsigned *)0x4d00004c) //STN Dithering mode#define rTPAL (*(volatile unsigned *)0x4d000050) //TFT Temporary palette#define rLCDINTPND (*(volatile unsigned *)0x4d000054) //LCD Interrupt pending#define rLCDSRCPND (*(volatile unsigned *)0x4d000058) //LCD Interrupt source#define rLCDINTMSK (*(volatile unsigned *)0x4d00005c) //LCD Interrupt mask#define rTCONSEL (*(volatile unsigned *)0x4d000060) //LPC3600 Control --- edited by junon#define PALETTE 0x4d000400 //Palette start address//Nand Flash#define rNFCONF (*(volatile unsigned *)0x4E000000) //NAND Flash configuration #define rNFCONT (*(volatile unsigned *)0x4E000004) //NAND Flash control#define rNFCMD (*(volatile unsigned *)0x4E000008) //NAND Flash command#define rNFADDR (*(volatile unsigned *)0x4E00000C) //NAND Flash address#define rNFDATA (*(volatile unsigned *)0x4E000010) //NAND Flash data#define rNFDATA8 (*(volatile unsigned char *)0x4E000010) //NAND Flash data#define NFDATA (0x4E000010) //NAND Flash data address#define rNFMECCD0 (*(volatile unsigned *)0x4E000014) //NAND Flash ECC for Main Area#define rNFMECCD1 (*(volatile unsigned *)0x4E000018)#define rNFSECCD (*(volatile unsigned *)0x4E00001C) //NAND Flash ECC for Spare Area#define rNFSTAT (*(volatile unsigned *)0x4E000020) //NAND Flash operation status#define rNFESTAT0 (*(volatile unsigned *)0x4E000024)#define rNFESTAT1 (*(volatile unsigned *)0x4E000028)#define rNFMECC0 (*(volatile unsigned *)0x4E00002C)#define rNFMECC1 (*(volatile unsigned *)0x4E000030)#define rNFSECC (*(volatile unsigned *)0x4E000034)#define rNFSBLK (*(volatile unsigned *)0x4E000038) //NAND Flash Start block address#define rNFEBLK (*(volatile unsigned *)0x4E00003C) //NAND Flash End block address//Camera Interface. Edited for 2440A#define rCISRCFMT (*(volatile unsigned *)0x4F000000)#define rCIWDOFST (*(volatile unsigned *)0x4F000004)#define rCIGCTRL (*(volatile unsigned *)0x4F000008)#define rCICOYSA1 (*(volatile unsigned *)0x4F000018)#define rCICOYSA2 (*(volatile unsigned *)0x4F00001C)#define rCICOYSA3 (*(volatile unsigned *)0x4F000020)#define rCICOYSA4 (*(volatile unsigned *)0x4F000024)#define rCICOCBSA1 (*(volatile unsigned *)0x4F000028)#define rCICOCBSA2 (*(volatile unsigned *)0x4F00002C)#define rCICOCBSA3 (*(volatile unsigned *)0x4F000030)#define rCICOCBSA4 (*(volatile unsigned *)0x4F000034)#define rCICOCRSA1 (*(volatile unsigned *)0x4F000038)#define rCICOCRSA2 (*(volatile unsigned *)0x4F00003C)#define rCICOCRSA3 (*(volatile unsigned *)0x4F000040)#define rCICOCRSA4 (*(volatile unsigned *)0x4F000044)#define rCICOTRGFMT (*(volatile unsigned *)0x4F000048)#define rCICOCTRL (*(volatile unsigned *)0x4F00004C)#define rCICOSCPRERA TIO (*(volatile unsigned *)0x4F000050)#define rCICOSCPREDST (*(volatile unsigned *)0x4F000054)#define rCICOSCCTRL (*(volatile unsigned *)0x4F000058)#define rCICOTAREA (*(volatile unsigned *)0x4F00005C)#define rCICOSTATUS (*(volatile unsigned *)0x4F000064)#define rCIPRCLRSA1 (*(volatile unsigned *)0x4F00006C)#define rCIPRCLRSA2 (*(volatile unsigned *)0x4F000070)#define rCIPRCLRSA3 (*(volatile unsigned *)0x4F000074)#define rCIPRCLRSA4 (*(volatile unsigned *)0x4F000078)#define rCIPRTRGFMT (*(volatile unsigned *)0x4F00007C)#define rCIPRCTRL (*(volatile unsigned *)0x4F000080)#define rCIPRSCPRERATIO (*(volatile unsigned *)0x4F000084)#define rCIPRSCPREDST (*(volatile unsigned *)0x4F000088)#define rCIPRSCCTRL (*(volatile unsigned *)0x4F00008C)#define rCIPRTAREA (*(volatile unsigned *)0x4F000090)#define rCIPRSTATUS (*(volatile unsigned *)0x4F000098)#define rCIIMGCPT (*(volatile unsigned *)0x4F0000A0)// UART#define rULCON0 (*(volatile unsigned *)0x50000000) //UART 0 Line control#define rUCON0 (*(volatile unsigned *)0x50000004) //UART 0 Control#define rUFCON0 (*(volatile unsigned *)0x50000008) //UART 0 FIFO control#define rUMCON0 (*(volatile unsigned *)0x5000000c) //UART 0 Modem control #define rUTRSTAT0 (*(volatile unsigned *)0x50000010) //UART 0 Tx/Rx status#define rUERSTAT0 (*(volatile unsigned *)0x50000014) //UART 0 Rx error status #define rUFSTAT0 (*(volatile unsigned *)0x50000018) //UART 0 FIFO status#define rUMSTAT0 (*(volatile unsigned *)0x5000001c) //UART 0 Modem status#define rUBRDIV0 (*(volatile unsigned *)0x50000028) //UART 0 Baud rate divisor#define rULCON1 (*(volatile unsigned *)0x50004000) //UART 1 Line control#define rUCON1 (*(volatile unsigned *)0x50004004) //UART 1 Control#define rUFCON1 (*(volatile unsigned *)0x50004008) //UART 1 FIFO control#define rUMCON1 (*(volatile unsigned *)0x5000400c) //UART 1 Modem control #define rUTRSTAT1 (*(volatile unsigned *)0x50004010) //UART 1 Tx/Rx status#define rUERSTAT1 (*(volatile unsigned *)0x50004014) //UART 1 Rx error status #define rUFSTAT1 (*(volatile unsigned *)0x50004018) //UART 1 FIFO status#define rUMSTAT1 (*(volatile unsigned *)0x5000401c) //UART 1 Modem status#define rUBRDIV1 (*(volatile unsigned *)0x50004028) //UART 1 Baud rate divisor #define rULCON2 (*(volatile unsigned *)0x50008000) //UART 2 Line control#define rUCON2 (*(volatile unsigned *)0x50008004) //UART 2 Control#define rUFCON2 (*(volatile unsigned *)0x50008008) //UART 2 FIFO control#define rUMCON2 (*(volatile unsigned *)0x5000800c) //UART 2 Modem control #define rUTRSTAT2 (*(volatile unsigned *)0x50008010) //UART 2 Tx/Rx status#define rUERSTAT2 (*(volatile unsigned *)0x50008014) //UART 2 Rx error status#define rUFSTAT2 (*(volatile unsigned *)0x50008018) //UART 2 FIFO status#define rUMSTAT2 (*(volatile unsigned *)0x5000801c) //UART 2 Modem status#define rUBRDIV2 (*(volatile unsigned *)0x50008028) //UART 2 Baud rate divisor#ifdef __BIG_ENDIAN#define rUTXH0 (*(volatile unsigned char *)0x50000023) //UART 0 Transmission Hold#define rURXH0 (*(volatile unsigned char *)0x50000027) //UART 0 Receive buffer#define rUTXH1 (*(volatile unsigned char *)0x50004023) //UART 1 Transmission Hold#define rURXH1 (*(volatile unsigned char *)0x50004027) //UART 1 Receive buffer#define rUTXH2 (*(volatile unsigned char *)0x50008023) //UART 2 Transmission Hold#define rURXH2 (*(volatile unsigned char *)0x50008027) //UART 2 Receive buffer#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000023)=(unsigned char)(ch)#define RdURXH0() (*(volatile unsigned char *)0x50000027)#define WrUTXH1(ch) (*(volatile unsigned char *)0x50004023)=(unsigned char)(ch)#define RdURXH1() (*(volatile unsigned char *)0x50004027)#define WrUTXH2(ch) (*(volatile unsigned char *)0x50008023)=(unsigned char)(ch)#define RdURXH2() (*(volatile unsigned char *)0x50008027)#define UTXH0 (0x50000020+3) //Byte_access address by DMA#define URXH0 (0x50000024+3)#define UTXH1 (0x50004020+3)#define URXH1 (0x50004024+3)#define UTXH2 (0x50008020+3)#define URXH2 (0x50008024+3)#else //Little Endian#define rUTXH0 (*(volatile unsigned char *)0x50000020) //UART 0 Transmission Hold#define rURXH0 (*(volatile unsigned char *)0x50000024) //UART 0 Receive buffer#define rUTXH1 (*(volatile unsigned char *)0x50004020) //UART 1 Transmission Hold#define rURXH1 (*(volatile unsigned char *)0x50004024) //UART 1 Receive buffer#define rUTXH2 (*(volatile unsigned char *)0x50008020) //UART 2 Transmission Hold#define rURXH2 (*(volatile unsigned char *)0x50008024) //UART 2 Receive buffer#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch)#define RdURXH0() (*(volatile unsigned char *)0x50000024)#define WrUTXH1(ch) (*(volatile unsigned char *)0x50004020)=(unsigned char)(ch)#define RdURXH1() (*(volatile unsigned char *)0x50004024)#define WrUTXH2(ch) (*(volatile unsigned char *)0x50008020)=(unsigned char)(ch)#define RdURXH2() (*(volatile unsigned char *)0x50008024)#define UTXH0 (0x50000020) //Byte_access address by DMA#define URXH0 (0x50000024)#define UTXH1 (0x50004020)#define URXH1 (0x50004024)#define UTXH2 (0x50008020)#define URXH2 (0x50008024)#endif// PWM TIMER#define rTCFG0 (*(volatile unsigned *)0x51000000) //Timer 0 configuration#define rTCFG1 (*(volatile unsigned *)0x51000004) //Timer 1 configuration#define rTCON (*(volatile unsigned *)0x51000008) //Timer control#define rTCNTB0 (*(volatile unsigned *)0x5100000c)//Timer count buffer 0#define rTCMPB0 (*(volatile unsigned *)0x51000010) //Timer compare buffer 0#define rTCNTO0 (*(volatile unsigned *)0x51000014) //Timer count observation 0#define rTCNTB1 (*(volatile unsigned *)0x51000018) //Timer count buffer 1#define rTCMPB1 (*(volatile unsigned *)0x5100001c) //Timer compare buffer 1#define rTCNTO1 (*(volatile unsigned *)0x51000020) //Timer count observation 1#define rTCNTB2 (*(volatile unsigned *)0x51000024) //Timer count buffer 2#define rTCMPB2 (*(volatile unsigned *)0x51000028) //Timer compare buffer 2#define rTCNTO2 (*(volatile unsigned *)0x5100002c) //Timer count observation 2#define rTCNTB3 (*(volatile unsigned *)0x51000030) //Timer count buffer 3#define rTCMPB3 (*(volatile unsigned *)0x51000034) //Timer compare buffer 3#define rTCNTO3 (*(volatile unsigned *)0x51000038) //Timer count observation 3#define rTCNTB4 (*(volatile unsigned *)0x5100003c)//Timer count buffer 4#define rTCNTO4 (*(volatile unsigned *)0x51000040) //Timer count observation 4// USB DEVICE#ifdef __BIG_ENDIAN<ERROR IF BIG_ENDIAN>#define rFUNC_ADDR_REG (*(volatile unsigned char *)0x52000143) //Function address #define rPWR_REG (*(volatile unsigned char *)0x52000147) //Power management#define rEP_INT_REG (*(volatile unsigned char *)0x5200014b) //EP Interrupt pending and clear#define rUSB_INT_REG (*(volatile unsigned char *)0x5200015b) //USB Interrupt pending and clear#define rEP_INT_EN_REG (*(volatile unsigned char *)0x5200015f)//Interrupt enable#define rUSB_INT_EN_REG (*(volatile unsigned char *)0x5200016f)#define rFRAME_NUM1_REG (*(volatile unsigned char *)0x52000173) //Frame number lower byte#define rFRAME_NUM2_REG (*(volatile unsigned char *)0x52000177) //Frame number higher byte#define rINDEX_REG (*(volatile unsigned char *)0x5200017b) //Register index #define rMAXP_REG (*(volatile unsigned char *)0x52000183) //Endpoint max packet#define rEP0_CSR (*(volatile unsigned char *)0x52000187) //Endpoint 0 status#define rIN_CSR1_REG (*(volatile unsigned char *)0x52000187) //In endpoint control status#define rIN_CSR2_REG (*(volatile unsigned char *)0x5200018b)#define rOUT_CSR1_REG (*(volatile unsigned char *)0x52000193) //Out endpoint control status#define rOUT_CSR2_REG (*(volatile unsigned char *)0x52000197)#define rOUT_FIFO_CNT1_REG (*(volatile unsigned char *)0x5200019b) //Endpoint out write count#define rOUT_FIFO_CNT2_REG (*(volatile unsigned char *)0x5200019f)#define rEP0_FIFO (*(volatile unsigned char *)0x520001c3) //Endpoint 0 FIFO#define rEP1_FIFO (*(volatile unsigned char *)0x520001c7) //Endpoint 1 FIFO#define rEP2_FIFO (*(volatile unsigned char *)0x520001cb) //Endpoint 2 FIFO#define rEP3_FIFO (*(volatile unsigned char *)0x520001cf) //Endpoint 3 FIFO#define rEP4_FIFO (*(volatile unsigned char *)0x520001d3) //Endpoint 4 FIFO#define rEP1_DMA_CON (*(volatile unsigned char *)0x52000203) //EP1 DMA interface control#define rEP1_DMA_UNIT (*(volatile unsigned char *)0x52000207) //EP1 DMA Tx unit counter#define rEP1_DMA_FIFO (*(volatile unsigned char *)0x5200020b) //EP1 DMA Tx FIFO counter#define rEP1_DMA_TTC_L (*(volatile unsigned char *)0x5200020f) //EP1 DMA total Tx counter#define rEP1_DMA_TTC_M (*(volatile unsigned char *)0x52000213)#define rEP1_DMA_TTC_H (*(volatile unsigned char *)0x52000217)#define rEP2_DMA_CON (*(volatile unsigned char *)0x5200021b) //EP2 DMA interface control#define rEP2_DMA_UNIT (*(volatile unsigned char *)0x5200021f) //EP2 DMA Tx unit counter#define rEP2_DMA_FIFO (*(volatile unsigned char *)0x52000223) //EP2 DMA Tx FIFO counter#define rEP2_DMA_TTC_L (*(volatile unsigned char *)0x52000227) //EP2 DMA total Tx counter#define rEP2_DMA_TTC_M (*(volatile unsigned char *)0x5200022b)#define rEP2_DMA_TTC_H (*(volatile unsigned char *)0x5200022f)#define rEP3_DMA_CON (*(volatile unsigned char *)0x52000243) //EP3 DMA interface control#define rEP3_DMA_UNIT (*(volatile unsigned char *)0x52000247) //EP3 DMA Tx unit counter#define rEP3_DMA_FIFO (*(volatile unsigned char *)0x5200024b) //EP3 DMA Tx FIFO counter#define rEP3_DMA_TTC_L (*(volatile unsigned char *)0x5200024f) //EP3 DMA total Tx counter#define rEP3_DMA_TTC_M (*(volatile unsigned char *)0x52000253)#define rEP3_DMA_TTC_H (*(volatile unsigned char *)0x52000257)#define rEP4_DMA_CON (*(volatile unsigned char *)0x5200025b) //EP4 DMA interface control#define rEP4_DMA_UNIT (*(volatile unsigned char *)0x5200025f) //EP4 DMA Tx unit counter#define rEP4_DMA_FIFO (*(volatile unsigned char *)0x52000263) //EP4 DMA Tx FIFO counter#define rEP4_DMA_TTC_L (*(volatile unsigned char *)0x52000267) //EP4 DMA total Tx counter#define rEP4_DMA_TTC_M (*(volatile unsigned char *)0x5200026b)#define rEP4_DMA_TTC_H (*(volatile unsigned char *)0x5200026f)#else // Little Endian#define rFUNC_ADDR_REG (*(volatile unsigned char *)0x52000140) //Function address #define rPWR_REG (*(volatile unsigned char *)0x52000144) //Power management#define rEP_INT_REG (*(volatile unsigned char *)0x52000148) //EP Interrupt pending and clear#define rUSB_INT_REG (*(volatile unsigned char *)0x52000158) //USB Interrupt pending and clear#define rEP_INT_EN_REG (*(volatile unsigned char *)0x5200015c) //Interrupt enable #define rUSB_INT_EN_REG (*(volatile unsigned char *)0x5200016c)#define rFRAME_NUM1_REG (*(volatile unsigned char *)0x52000170) //Frame number lower byte#define rFRAME_NUM2_REG (*(volatile unsigned char *)0x52000174) //Frame number higher byte#define rINDEX_REG (*(volatile unsigned char *)0x52000178) //Register index #define rMAXP_REG (*(volatile unsigned char *)0x52000180) //Endpoint max packet#define rEP0_CSR (*(volatile unsigned char *)0x52000184) //Endpoint 0 status#define rIN_CSR1_REG (*(volatile unsigned char *)0x52000184) //In endpoint control status#define rIN_CSR2_REG (*(volatile unsigned char *)0x52000188)#define rOUT_CSR1_REG (*(volatile unsigned char *)0x52000190) //Out endpoint control status#define rOUT_CSR2_REG (*(volatile unsigned char *)0x52000194)#define rOUT_FIFO_CNT1_REG (*(volatile unsigned char *)0x52000198) //Endpoint out write count#define rOUT_FIFO_CNT2_REG (*(volatile unsigned char *)0x5200019c)#define rEP0_FIFO (*(volatile unsigned char *)0x520001c0) //Endpoint 0 FIFO#define rEP1_FIFO (*(volatile unsigned char *)0x520001c4) //Endpoint 1 FIFO#define rEP2_FIFO (*(volatile unsigned char *)0x520001c8) //Endpoint 2 FIFO#define rEP3_FIFO (*(volatile unsigned char *)0x520001cc) //Endpoint 3 FIFO#define rEP4_FIFO (*(volatile unsigned char *)0x520001d0) //Endpoint 4 FIFO#define rEP1_DMA_CON (*(volatile unsigned char *)0x52000200) //EP1 DMA interface control#define rEP1_DMA_UNIT (*(volatile unsigned char *)0x52000204) //EP1 DMA Tx unit counter#define rEP1_DMA_FIFO (*(volatile unsigned char *)0x52000208) //EP1 DMA Tx FIFO counter#define rEP1_DMA_TTC_L (*(volatile unsigned char *)0x5200020c) //EP1 DMA total Tx counter#define rEP1_DMA_TTC_M (*(volatile unsigned char *)0x52000210)#define rEP1_DMA_TTC_H (*(volatile unsigned char *)0x52000214)#define rEP2_DMA_CON (*(volatile unsigned char *)0x52000218) //EP2 DMA interface control#define rEP2_DMA_UNIT (*(volatile unsigned char *)0x5200021c) //EP2 DMA Tx unit counter#define rEP2_DMA_FIFO (*(volatile unsigned char *)0x52000220) //EP2 DMA Tx FIFO counter#define rEP2_DMA_TTC_L (*(volatile unsigned char *)0x52000224) //EP2 DMA total Tx counter#define rEP2_DMA_TTC_M (*(volatile unsigned char *)0x52000228)#define rEP2_DMA_TTC_H (*(volatile unsigned char *)0x5200022c)#define rEP3_DMA_CON (*(volatile unsigned char *)0x52000240) //EP3 DMA interface control#define rEP3_DMA_UNIT (*(volatile unsigned char *)0x52000244) //EP3 DMA Tx unit counter#define rEP3_DMA_FIFO (*(volatile unsigned char *)0x52000248) //EP3 DMA Tx FIFO counter#define rEP3_DMA_TTC_L (*(volatile unsigned char *)0x5200024c) //EP3 DMA total Tx counter#define rEP3_DMA_TTC_M (*(volatile unsigned char *)0x52000250)#define rEP3_DMA_TTC_H (*(volatile unsigned char *)0x52000254)#define rEP4_DMA_CON (*(volatile unsigned char *)0x52000258) //EP4 DMA interface control#define rEP4_DMA_UNIT (*(volatile unsigned char *)0x5200025c) //EP4 DMA Tx unit counter#define rEP4_DMA_FIFO (*(volatile unsigned char *)0x52000260) //EP4 DMA Tx FIFO counter#define rEP4_DMA_TTC_L (*(volatile unsigned char *)0x52000264) //EP4 DMA total Tx counter#define rEP4_DMA_TTC_M (*(volatile unsigned char *)0x52000268)#define rEP4_DMA_TTC_H (*(volatile unsigned char *)0x5200026c)#endif // __BIG_ENDIAN// WATCH DOG TIMER#define rWTCON (*(volatile unsigned *)0x53000000) //Watch-dog timer mode#define rWTDAT (*(volatile unsigned *)0x53000004) //Watch-dog timer data#define rWTCNT (*(volatile unsigned *)0x53000008) //Eatch-dog timer count// IIC#define rIICCON (*(volatile unsigned *)0x54000000) //IIC control#define rIICSTAT (*(volatile unsigned *)0x54000004) //IIC status#define rIICADD (*(volatile unsigned *)0x54000008) //IIC address#define rIICDS (*(volatile unsigned *)0x5400000c) //IIC data shift#define rIICLC (*(volatile unsigned *)0x54000010) //IIC multi-master line control// IIS#define rIISCON (*(volatile unsigned *)0x55000000) //IIS Control#define rIISMOD (*(volatile unsigned *)0x55000004) //IIS Mode#define rIISPSR (*(volatile unsigned *)0x55000008) //IIS Prescaler#define rIISFCON (*(volatile unsigned *)0x5500000c) //IIS FIFO control#ifdef __BIG_ENDIAN#define IISFIFO ((volatile unsigned short *)0x55000012) //IIS FIFO entry#else //Little Endian#define IISFIFO ((volatile unsigned short *)0x55000010) //IIS FIFO entry#endif//AC97, Added for S3C2440A#define rAC_GLBCTRL *(volatile unsigned *)0x5b000000#define rAC_GLBSTAT *(volatile unsigned *)0x5b000004#define rAC_CODEC_CMD *(volatile unsigned *)0x5b000008#define rAC_CODEC_STA T *(volatile unsigned *)0x5b00000C#define rAC_PCMADDR *(volatile unsigned *)0x5b000010#define rAC_MICADDR *(volatile unsigned *)0x5b000014#define rAC_PCMDATA *(volatile unsigned *)0x5b000018#define rAC_MICDA TA *(volatile unsigned *)0x5b00001C#define AC_PCMDATA 0x5b000018#define AC_MICDA TA 0x5b00001C// I/O PORT#define rGPACON (*(volatile unsigned *)0x56000000) //Port A control#define rGPADAT (*(volatile unsigned *)0x56000004) //Port A data#define rGPBCON (*(volatile unsigned *)0x56000010) //Port B control#define rGPBDAT (*(volatile unsigned *)0x56000014) //Port B data#define rGPBUP (*(volatile unsigned *)0x56000018) //Pull-up control B#define rGPCCON (*(volatile unsigned *)0x56000020) //Port C control#define rGPCDAT (*(volatile unsigned *)0x56000024) //Port C data#define rGPCUP (*(volatile unsigned *)0x56000028) //Pull-up control C#define rGPDCON (*(volatile unsigned *)0x56000030) //Port D control#define rGPDDAT (*(volatile unsigned *)0x56000034) //Port D data#define rGPDUP (*(volatile unsigned *)0x56000038) //Pull-up control D#define rGPECON (*(volatile unsigned *)0x56000040) //Port E control#define rGPEDAT (*(volatile unsigned *)0x56000044) //Port E data#define rGPEUP (*(volatile unsigned *)0x56000048) //Pull-up control E#define rGPFCON (*(volatile unsigned *)0x56000050) //Port F control#define rGPFDAT (*(volatile unsigned *)0x56000054) //Port F data#define rGPFUP (*(volatile unsigned *)0x56000058) //Pull-up control F#define rGPGCON (*(volatile unsigned *)0x56000060) //Port G control#define rGPGDAT (*(volatile unsigned *)0x56000064) //Port G data#define rGPGUP (*(volatile unsigned *)0x56000068) //Pull-up control G#define rGPHCON (*(volatile unsigned *)0x56000070) //Port H control#define rGPHDAT (*(volatile unsigned *)0x56000074) //Port H data#define rGPHUP (*(volatile unsigned *)0x56000078) //Pull-up control H#define rGPJCON (*(volatile unsigned *)0x560000d0) //Port J control#define rGPJDAT (*(volatile unsigned *)0x560000d4) //Port J data#define rGPJUP (*(volatile unsigned *)0x560000d8) //Pull-up control J#define rMISCCR (*(volatile unsigned *)0x56000080) //Miscellaneous control#define rDCLKCON (*(volatile unsigned *)0x56000084) //DCLK0/1 control#define rEXTINT0 (*(volatile unsigned *)0x56000088) //External interrupt control register 0 #define rEXTINT1 (*(volatile unsigned *)0x5600008c) //External interrupt control register 1 #define rEXTINT2 (*(volatile unsigned *)0x56000090) //External interrupt control register 2 #define rEINTFLT0 (*(volatile unsigned *)0x56000094) //Reserved#define rEINTFLT1 (*(volatile unsigned *)0x56000098) //Reserved#define rEINTFLT2 (*(volatile unsigned *)0x5600009c) //External interrupt filter control register 2。
2.3.2 实现消息的分派fbmem.c实现了对系统全部FrameBuffer设备的统一管理。
当用户尝试使用一个特定的FrameBuffer时,fbmem.c怎么知道该调用那个特定的设备驱动呢?我们知道,Linux是通过主设备号和次设备号,对设备进行唯一标识。
不同的FrameBuffer 设备向fbmem.c注册时,程序分配给它们的主设备号是一样的,而次设备号是不一样的。
于是我们就可以通过用户指明的次设备号,来觉得具体该调用哪一个FrameBuffer驱动。
下面通过分析fbmem.c的fb_open()函数来说明。
(注:一般我们写FrameBuffer驱动不需要实现open函数,这里只是说明函数流程。
)static int fb_open(struct inode *inode, struct file *file){int fbidx = iminor(inode);struct fb_info *info;int res;/* 得到真正驱动的函数指针*/if (!(info = registered_fb[fbidx])) return -ENODEV;if (info->fbops->fb_open) {res = info->fbops->fb_open(info,1); //调用驱动的open()if (res) module_put(info->fbops->owner);}return res;}当用户打开一个FrameBuffer设备的时,将调用这里的fb_open()函数。
传进来的inode就是欲打开设备的设备号,包括主设备和次设备号。
fb_open函数首先通过iminor()函数取得次设备号,然后查全局数组registered_fb得到设备的fb_info信息,而这里面存放了设备的操作函数集fb_ops。
这样,我们就可以调用具体驱动的fb_open() 函数,实现open的操作。
基于S3C2440的触摸屏驱动程序实现强新建1,田 泽1,2,刘天时1(1.西安石油大学计算机学院,陕西西安710065;2.西北大学信息科学与技术学院,陕西西安710068)摘 要:触摸屏作为人机界面的输入设备被广泛的应用于消费电子、工业控制等诸多领域。
目前流行的嵌入式AR M 处理器S3C2440是一款典型的嵌入式S oC 芯片,它提供了触摸屏控制器接口,方便了嵌入式软、硬件开发。
简要介绍了S3C2440处理器,同时分析了触摸屏的硬件架构、硬件工作原理及与及其工作框图,在此基础上给出了触摸屏与S3C2440的硬件连接电路图。
介绍了S3C2440下触摸屏的W inCE 驱动构架,并指出相关注册表的修改技术。
在S3C2440的嵌入式W inCE 开发平台上,该驱动程序运行良好。
关键词:S3C2440;触摸屏;驱动中图分类号:TP18 文献标识码:A 文章编号:1671Ο654X (2007)04Ο0085Ο03引言触摸屏具有坚固耐用、反应速度快、节省空间、易于交流等许多优点[1],作为一种新的电脑输入设备,是目前最简单方便而且又适用于中国多媒体信息查询国情的输入设备。
利用这种技术,我们只要用手指就能实现对主机操作,使人机交互更为直截了当,极大方便了那些不懂电脑操作的用户。
触摸屏在我国的应用范围非常广阔:公共信息的查询,如电信局、税务局、银行、电力等部门的业务查询;城市街头的信息查询;此外还可广泛应用于领导办公、工业控制、军事指挥、电子游戏、点歌点菜、多媒体教学、房地产预售等[2]。
随着城市向信息化方向发展和电脑网络在日常生活中的渗透,信息查询都会更多以触摸屏形式。
1 硬件架构本文基于S3C2440,实现了W inCE 下触摸屏驱动程序。
除对S3C2440处理器的一些特点做了简单介绍外,从触摸屏的硬件结构、工作机理等进行了全面分析。
1.1 S3C2440处理器简介S3C2440是16 32位精简指令集微处理器,是为应用于小型掌上设备和高性价比,低功耗,高性能的嵌入式系统应用而提供的微控制。
s3c2440触摸屏驱动(针对android版)s3c2440 触摸屏驱动(针对android版)和原来的触摸屏驱动区别不是很⼤,增加了report函数来将事件发送到应⽤层。
驱动结构:很简单的字符设备+平台设备驱动,总的结构来说,主要四个部分构成:proberemoveresumesuspend⼯作机制则是注册设备,然后发⽣ts按下事件后产⽣ts中断以及adc中断,获得按下坐标。
没有读写函数,重点就是在两个中断处理函数上。
1,平台设备架构部分分析:probe函数:流程:ts基址的重映射->获得并启动时钟->ADCCON、ADCDLY、ADCTSC的初始化->初始化input设备完善ts结构体->建⽴ts_filter_chain->申请中断->注册input设备(2.6.27后为event0不再是ts0)。
static int __init s3c2410ts_probe(struct platform_device *pdev){int rc;struct s3c2410_ts_mach_info *info;struct input_dev *input_dev;int ret = 0;dev_info(&pdev->dev,"Starting\n");info =(struct s3c2410_ts_mach_info*)pdev->dev.platform_data;//获得平台设备数据if(!info){dev_err(&pdev->dev,"Hm... too bad: no platform data forts\n");return-EINVAL;}#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUGprintk(DEBUG_LVL "Entering s3c2410ts_init\n");#endifadc_clock = clk_get(NULL,"adc");if(!adc_clock){dev_err(&pdev->dev,"failed to get adc clock source\n");return-ENOENT;}clk_enable(adc_clock);#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUGprintk(DEBUG_LVL "got and enabled clock\n");#endifbase_addr = ioremap(S3C2410_PA_ADC,0x20);//将PA_ADC寄存器重映射到内存上if(base_addr ==NULL){dev_err(&pdev->dev,"Failed to remap register block\n"); ret =-ENOMEM;goto bail0;}/* If we acutally are a S3C2410: Configure GPIOs */if(!strcmp(pdev->name,"s3c2410-ts"))s3c2410_ts_connect();//初始化相关gpio⼝if((info->presc & 0xff)> 0)writel(S3C2410_ADCCON_PRSCEN |S3C2410_ADCCON_PRSCVL(info->presc&0xFF),base_addr + S3C2410_ADCCON);elsewritel(0, base_addr+S3C2410_ADCCON);/* Initialise registers */if((info->delay & 0xffff)> 0)writel(info->delay & 0xffff, base_addr + S3C2410_ADCDLY);writel(WAIT4INT(0), base_addr + S3C2410_ADCTSC);/* Initialise input stuff */memset(&ts, 0,sizeof(struct s3c2410ts));input_dev = input_allocate_device();if(!input_dev){dev_err(&pdev->dev,"Unable to allocate the input device\n");ret =-ENOMEM;}//初始化input设备ts.dev = input_dev;ts.dev->evbit[0]= BIT_MASK(EV_SYN)| BIT_MASK(EV_KEY)|BIT_MASK(EV_ABS);ts.dev->keybit[BIT_WORD(BTN_TOUCH)]= BIT_MASK(BTN_TOUCH);input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);input_set_abs_params(ts.dev, ABS_Y, 0, 0x3FF, 0, 0);input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 1, 0, 0);ts.dev->name = s3c2410ts_name;ts.dev->id.bustype = BUS_RS232;ts.dev->id.vendor = 0xDEAD;ts.dev->id.product = 0xBEEF;ts.dev->id.version = S3C2410TSVERSION;ts.state = TS_STATE_STANDBY;//设置ts状态为就绪ts.event_fifo = kfifo_alloc(TS_EVENT_FIFO_SIZE, GFP_KERNEL, NULL);//为event队列申请内存空间if(IS_ERR(ts.event_fifo)){ret =-EIO;goto bail2;}/* create the filter chain set up for the 2 coordinates we produce */ts.chain = ts_filter_chain_create(pdev, info->filter_config, 2);//针对android的,建⽴filter_chainif(IS_ERR(ts.chain))goto bail2;ts_filter_chain_clear(ts.chain);/* Get irqs */if(request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM,"s3c2410_action", ts.dev)){dev_err(&pdev->dev,"Could not allocate ts IRQ_ADC !\n"); iounmap(base_addr);goto bail3;}if(request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM, "s3c2410_action", ts.dev)){dev_err(&pdev->dev,"Could not allocate ts IRQ_TC !\n"); free_irq(IRQ_ADC, ts.dev);iounmap(base_addr);ret =-EIO;goto bail4;}dev_info(&pdev->dev,"Successfully loaded\n");/* All went ok, so register to the input system */rc = input_register_device(ts.dev);if(rc){ret =-EIO;goto bail5;}return 0;bail5:free_irq(IRQ_TC, ts.dev);free_irq(IRQ_ADC, ts.dev);clk_disable(adc_clock);iounmap(base_addr);disable_irq(IRQ_TC);bail4:disable_irq(IRQ_ADC);bail3:ts_filter_chain_destroy(ts.chain);kfifo_free(ts.event_fifo);bail2:input_unregister_device(ts.dev);bail1:iounmap(base_addr);bail0:return ret;}remove:就是probe的逆运算,static int s3c2410ts_remove(struct platform_device *pdev) {disable_irq(IRQ_ADC);disable_irq(IRQ_TC);free_irq(IRQ_TC,ts.dev);free_irq(IRQ_ADC,ts.dev);if(adc_clock){clk_disable(adc_clock);clk_put(adc_clock);adc_clock =NULL;}input_unregister_device(ts.dev);iounmap(base_addr);ts_filter_chain_destroy(ts.chain);kfifo_free(ts.event_fifo);return 0;}resume与suspend函数可有可⽆,完成触摸屏的激活和挂起,2,中断处理分析:三种模式转换过程:等待down中断模式->x,y连续坐标转换模式->等待up中断模式->等待down中断模式->..两个中断的发⽣:触摸屏按下,发⽣ts中断,开始ad转换,ad转换结束,发⽣adc中断。
24402410LCD显示屏驱动程序u-boot早就支持framebuffer了,不光显示图片,还可以把控制台重定向到lcd上,只是24x0部分缺代码罢了,需要填充一个结构体,可以从openmoko那里copy过来。
不过如果只是为了显示一张图片的话……初始化lcd控制器的代码随便放哪里运行都可以的吧!2440&2410 LCD显示屏驱动程序#include "config.h"// GPB1/TOUT1 for Backlight control(PWM)#define GPB1_TO_OUT() (rGPBUP &= 0xfffd, rGPBCON &= 0xfffffff3, rGPBCON |= 0x00000004)#define GPB1_TO_1() (rGPBDAT |= 0x0002)#define GPB1_TO_0() (rGPBDAT &= 0xfffd)//extern void Uart_Printf(char *f, ...) ;extern unsigned char __CHS[];extern unsigned char __VGA[];//volatile staticunsigned short LCD_BUFFER[SCR_YSIZE_TFT][SCR_XSIZE_TFT];static void Lcd_PowerEnable(int invpwren,int pwren);static void Lcd_Init(void){rGPCUP = 0x00000000;rGPCCON = 0xaaaa02a9;// rGPDUP=0xffffffff; // Disable Pull-up registerrGPDUP = 0x00000000;rGPDCON=0xaaaaaaaa; //Initialize VD[15:8]rLCDCON1=(CLKVAL_TFT << 8)|(MVAL_USED << 7)|(3 <<5 )|(12 << 1)|0;// TFT LCD panel,16bpp TFT,ENVID=offrLCDCON2=(VBPD << 24)|(LINEVAL_TFT << 14)|(VFPD << 6)|(VSPW); rLCDCON3=(HBPD << 19)|(HOZVAL_TFT << 8)|(HFPD);rLCDCON4=(MVAL << 8)|(HSPW);#if(LCD_TYPE == PT035)rLCDCON5 = (1 << 11) | (1 << 10) | (0 << 9) | (0 << 8) | (1 << 7) | (1 << 6)| (1 << 3) |(BSWP << 1) | (HWSWP);#elif(LCD_TYPE == WD_F3224)rLCDCON5 = (1 << 11) | (1 << 10) | (0 << 9) | (0 << 8) | (0 << 7) | (0 << 6)| (1 << 3) |(0 << 1) | (HWSWP);#elif(LCD_TYPE == TX11D)rLCDCON5 = (1 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (0 << 7) | (0<< 6)| (1 << 3) | (1 << 2) | (BSWP << 1) | (HWSWP);#endifrLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|M5D((U32)L CD_BUFFER>>1);rLCDSADDR2=M5D( ((U32)LCD_BUFFER+(SCR_XSIZE_TFT * LCD_YSIZE_TFT * 2)) >> 1 );rLCDSADDR3=(((SCR_XSIZE_TFT - LCD_XSIZE_TFT) / 1) << 11)|(LCD_XSIZE_TFT / 1);rLCDINTMSK|=(3); // MASK LCD Sub InterruptrTCONSEL &= (~7) ; // Disable LPC3480rTPAL=0; // Disable Temp Palette}static void Lcd_EnvidOnOff(int onoff){if(onoff == 1)rLCDCON1 |= 1; // ENVID=ONelserLCDCON1 = rLCDCON1 & 0x3fffe; // ENVID Off}static void Lcd_PowerEnable(int invpwren,int pwren){//GPG4 is setted as LCD_PWRENrGPGUP = rGPGUP & ( ~(1 << 4)) |(1 << 4); // Pull-up disable rGPGCON = rGPGCON & ( ~(3 << 8)) |(3 << 8); //GPG4=LCD_PWREN rGPGDAT = rGPGDAT | (1 << 4) ;// invpwren=pwren;//Enable LCD POWER ENABLE FunctionrLCDCON5 = rLCDCON5 & ( ~(1 << 3)) |(pwren << 3); // PWRENrLCDCON5 = rLCDCON5 & ( ~(1 << 5)) |(invpwren << 5); // INVPWREN}static void Lcd_MoveViewPort(int vx, int vy){U32 addr;SET_IF();#if (LCD_XSIZE_TFT < 32)while((rLCDCON1 >> 18) <= 1); // if x<32#elsewhile((rLCDCON1 >> 18) == 0); // if x>32#endifaddr = (U32)LCD_BUFFER + (vx * 2) + vy * (SCR_XSIZE_TFT * 2);rLCDSADDR1 = ( (addr >> 22) << 21 ) | M5D(addr >> 1);rLCDSADDR2 = M5D(((addr + (SCR_XSIZE_TFT * LCD_YSIZE_TFT * 2)) >> 1)); CLR_IF();}static void MoveViewPort(void){int vx=0,vy=0,vd=1;Uart_Printf("\n*Move the LCD view windos:\n");Uart_Printf(" press 8 is up\n");Uart_Printf(" press 2 is down\n");Uart_Printf(" press 4 is left\n");Uart_Printf(" press 6 is right\n");Uart_Printf(" press Enter to exit!\n");while(1){switch( Uart_GetKey() ){case '8':if(vy>=vd)vy-=vd;Uart_Printf("vx==,vy==\n",vx,vy);Lcd_MoveViewPort(vx,vy);break;case '4':if(vx>=vd)vx-=vd;Uart_Printf("vx==,vy==\n",vx,vy);Lcd_MoveViewPort(vx,vy);break;case '6':if(vx<=(SCR_XSIZE_TFT - LCD_XSIZE_TFT -vd))vx += vd;Uart_Printf("vx==,vy==\n",vx,vy);Lcd_MoveViewPort(vx,vy);break;case '2':if(vy<=(SCR_YSIZE_TFT - LCD_YSIZE_TFT -vd))vy += vd;Uart_Printf("vx==,vy==\n",vx,vy);Lcd_MoveViewPort(vx,vy);break;case '\r':return;default:break;}//Uart_Printf("vx==,vy==\n",vx,vy);//Lcd_MoveViewPort(vx,vy);}}void PutPixel(U32 x,U32 y, U16 c ){if ( (x < SCR_XSIZE_TFT) && (y < SCR_YSIZE_TFT) ) LCD_BUFFER[(y)][(x)] = c;}void GUI_Point(U32 x,U32 y, U16 c ){if ( (x < SCR_XSIZE_TFT) && (y < SCR_YSIZE_TFT) ) LCD_BUFFER[(y)][(x)] = c;}void Lcd_ClearScr( U16 c){unsigned int x,y ;for( y = 0 ; y < SCR_YSIZE_TFT ; y++ ){for( x = 0 ; x < SCR_XSIZE_TFT ; x++ ){LCD_BUFFER[y][x] = c ;}}}void Glib_Line(int x1,int y1,int x2,int y2,int color) { int dx,dy,e;dx = x2 -x1;dy = y2 -y1;if(dx >= 0){if(dy >= 0) // dy>=0{if(dx>=dy) // 1/8 octant{e=dy-dx/2;while(x1<=x2){PutPixel(x1,y1,color); if(e>0){y1+=1;e-=dx;} x1+=1; e+=dy;}}else // 2/8 octant{e=dx-dy/2;while(y1<=y2){PutPixel(x1,y1,color); if(e>0){x1+=1;e-=dy;} y1+=1; e+=dx;}}}else // dy<0{dy=-dy; // dy=abs(dy)if(dx>=dy) // 8/8 octant {e=dy-dx/2;while(x1<=x2){PutPixel(x1,y1,color); if(e>0){y1-=1;e-=dx;} x1+=1; e+=dy;}}else // 7/8 octant{e=dx-dy/2;while(y1>=y2){PutPixel(x1,y1,color); if(e>0){x1+=1;e-=dy;} y1-=1; e+=dx;}}}else //dx<0{dx=-dx; //dx=abs(dx)if(dy >= 0) // dy>=0 {if(dx>=dy) // 4/8 octant {e=dy-dx/2;while(x1>=x2){PutPixel(x1,y1,color); if(e>0){y1+=1;e-=dx;} x1-=1; e+=dy;}}else // 3/8 octant{e=dx-dy/2;while(y1<=y2){PutPixel(x1,y1,color); if(e>0){x1-=1;e-=dy;} y1+=1; e+=dx;}}}else // dy<0{dy=-dy; // dy=abs(dy)if(dx>=dy) // 5/8 octant {e=dy-dx/2;while(x1>=x2){PutPixel(x1,y1,color); if(e>0){y1-=1;e-=dx;} x1-=1; e+=dy;}}else // 6/8 octante=dx-dy/2;while(y1>=y2){PutPixel(x1,y1,color);if(e>0){x1-=1;e-=dy;}y1-=1;e+=dx;}}}}}void Glib_Rectangle(int x1,int y1,int x2,int y2,int color){Glib_Line(x1,y1,x2,y1,color);Glib_Line(x2,y1,x2,y2,color);Glib_Line(x1,y2,x2,y2,color);Glib_Line(x1,y1,x1,y2,color);}void Glib_FilledRectangle(int x1,int y1,int x2,int y2,int color) { int i;for(i=y1;i<=y2;i++)Glib_Line(x1,i,x2,i,color);}void Paint_Bmp(int x0,int y0,int h,int l,unsigned char bmp[]) { int x,y;U32 c;int p = 0;for( y = y0 ; y < l ; y++ ){for( x = x0 ; x < h ; x++ ){c = bmp[p+1] | (bmp[p]<<8) ;if ( ( (x0+x) < SCR_XSIZE_TFT) && ( (y0+y) < SCR_YSIZE_TFT) ) LCD_BUFFER[y0+y][x0+x] = c ;p = p + 2 ;}}#if 1void Lcd_PutASCII(unsigned int x,unsigned int y,unsigned char ch,unsigned int c,unsigned int bk_c,unsigned int st) {unsigned short int i,j;unsigned char *pZK,mask,buf;pZK = &__VGA[ch*16];for( i = 0 ; i < 16 ; i++ ){mask = 0x80;buf = pZK[i];for( j = 0 ; j < 8 ; j++ ){if( buf & mask ){PutPixel(x+j,y+i,c);}else{if( !st ){PutPixel(x+j,y+i,bk_c);}}mask = mask >> 1;}}}void Lcd_PutHZ(unsigned int x,unsigned int y,unsigned short int QW,unsigned int c,unsigned int bk_c,unsigned int st) {unsigned short int i,j;unsigned char *pZK,mask,buf;pZK = &__CHS[ ( ( (QW >> 8) - 1 )*94 + (QW & 0x00FF)- 1 )*32 ]; for( i = 0 ; i < 16 ; i++ ){//左mask = 0x80;buf = pZK[i*2];for( j = 0 ; j < 8 ; j++ ){if( buf & mask ){PutPixel(x+j,y+i,c);}else{if( !st ){PutPixel(x+j,y+i,bk_c);}}mask = mask >> 1;}//右mask = 0x80;buf = pZK[i*2 + 1];for( j = 0 ; j < 8 ; j++ ){if( buf & mask ){PutPixel(x+j + 8,y+i,c);}else{if( !st ){PutPixel(x+j + 8,y+i,bk_c);}}mask = mask >> 1;}}}//----------------------void Lcd_printf(unsigned int x,unsigned int y,unsigned int c,unsigned int bk_c,unsigned int st,char *fmt,...){char __LCD_Printf_Buf[256];va_list ap;unsigned char *pStr = (unsigned char *)__LCD_Printf_Buf;unsigned int i = 0;va_start(ap,fmt);vsprintf(__LCD_Printf_Buf,fmt,ap);va_end(ap);while(*pStr != 0 ){switch(*pStr){case '\n' :{break;}default:{if( *pStr > 0xA0 & *(pStr+1) > 0xA0 ) //中文输出{Lcd_PutHZ( x , y , (*pStr - 0xA0)*0x0100 + *(pStr+1) - 0xA0 , c , bk_c , st);pStr++;i++;x += 16;}else //英文输出{Lcd_PutASCII( x , y , *pStr , c , bk_c , st );x += 8;}break;}}pStr++;i++;if( i > 256 ) break;}}#endifvoid Lcd_Display(void){Lcd_Init();Lcd_PowerEnable(0, 1);Lcd_EnvidOnOff(1);Lcd_ClearScr( (0x00<<11) | (0x00<<5) | (0x00) ); #if((LCD_TYPE == PT035)||(LCD_TYPE == WD_F3224)) Paint_Bmp(0, 0, 320, 240, phone);#elif(LCD_TYPE == TX11D)Paint_Bmp(0, 0, 480, 272, LCD43_ucos);#endif}。
1、引言2、汇编基础2.1、伪操作GET 伪操作类似于C 语言里面的include,是将一个源文件包含到当前源文件中,并将被包含的文件在其当前位置进行汇编处理。
IMPORT伪操作相当于C 语言中的extern 声明,它告诉编译器当前的符号不再本源文件中定义,而是在其他源文件中定义,在本源文件中可能引用该符号。
AERA 伪操作用于定义一个代码或者数据段。
ASSERT在汇编编译器对汇编程序的扫描中,如果ASSERT 中条件不成立,ASSERT 伪操作将报告错误信息。
2.2、汇编指令LDR伪指令将一个32 位的常数或者一个地址值读取到寄存器中。
BL跳转指令,L 决定是否保存返回地址。
MRS用于将状态寄存器的内容传送到通用寄存器中。
MSR用于将通用寄存器的内容或一个立即数传送到状态寄存器中。
LDM和STM分别为批量Load/Store内存访问指令。
FD为满递减数据栈。
3、启动代码功能模块分解启动代码主要是在主程序运行之前初始化系统硬件及软件的运行环境,它的主要功能包括以下的几个方面:* 建立中断向量表* 初始化系统堆栈* 应用程序执行环境初始化* 跳转至主函数3.1、系统堆栈初始化ARM有7种模式:* 用户模式* 快速中断模式* 中断模式* 管理模式* 中止模式* 未定义模式* 系统模式系统堆栈的初始化主要是给各个处理器模式分配堆栈空间。
堆栈是为中断或程序跳转服务的,当发生中断或程序跳转时,需要将当前处理器的状态及一些参数保持在堆栈中,当中断处理完毕以后或程序执行完后返回时,再将堆栈保存的现场数据进行恢复,以保证原来的程序正确运行。
USERMODE EQU 0x10 ;用户模式FIQMODE EQU 0x11 ;快速中断模式IRQMODE EQU 0x12 ;中断模式SVCMODE EQU 0x13 ;监管模式ABORTMODE EQU 0x17 ;异常中断模式UNDEFMODE EQU 0x1b ;未定义模式MODEMASK EQU 0x1f ;模式掩码NOINT EQU 0xc0 ;取消中断;设置工作模式的堆栈的起始地址;在option.inc 中定义了_STACK_BASEADDRESS EQU 0x33ff8000 UserStack EQU (_STACK_BASEADDRESS-0x3800) ;堆栈空间0x33ff4800 SVCStack EQU (_STACK_BASEADDRESS-0x2800) ;堆栈空间0x33ff5800 UndefStack EQU (_STACK_BASEADDRESS-0x2400) ;堆栈空间0x33ff5c00AbortStack EQU (_STACK_BASEADDRESS-0x2000) ;堆栈空间0x33ff6000IRQStack EQU (_STACK_BASEADDRESS-0x1000) ;堆栈空间0x33ff7000 FIQStack EQU (_STACK_BASEADDRESS-0x0) ;堆栈空间0x33ff8000堆栈初始化的顺序决定系统最后运行在哪种处理器模式,最后初始化哪种模式的堆栈,系统就运行在哪种模式。
22科技资讯 SC I EN C E & TE C HN O LO G Y I NF O R MA T IO N 信 息 技 术随着各种控制系统监控界面要求的提高,触摸屏和彩色LC D屏的应用越来越受到用户的欢迎。
本文以配有3.5寸触摸屏和彩色LCD屏的32位计算机S3C2440为硬件平台,以“风帆旋转角度控制系统”的具体案例开发为背景,详细介绍在S3C2440裸机上开发LC D及触摸屏应用的方法和具体过程,经实践证明按本方法可快速开发L C D 及触摸屏监控界面且可靠性好。
1 LCD 显示函数库开发一般S3C2440开发板配套开发资料包含PutPixel(U32x,U32y,U32c)单象素显示函数,可在此基础上开发LC D显示函数库graph.h,以便用显示接口函数开发各种应用程序。
L CD 显示函数库如表1所示,各L C D 显示接口函数在本文案例应用的方法作如下简介。
以画直线、画矩形、画填充矩形和画填充圆函数为基础,编写风帆绘制风帆状态绘制函数和实时曲线绘制,利用Glib_Sail ( )在LCD屏上显示风帆当前状态图,利用Act_Curve( )绘制风帆角度实时曲线;把0~9数码和小数点制作成12×16的位图,并用BM P图片转换软件转化成数据,建立数码库sm_1216.h,以便数值显示函数显示数值;由于建立文字库工作量大,且要显示的中文字符较少,所以把连在一起要显示的文字和按钮都做成位图,并转化建立文字图片库zf_6522.h和按钮图片库anniu_7034.h,以便图片显示函数显示文字和触摸按钮。
2 触摸屏应用函数库开发一般S3C2440开发板配套开发资料中包含触摸屏触摸中断服务函数,该函数获取当前触摸点的坐标(xdata,ydata),可在此基础上开发触摸屏应用函数库Touchpanel.h,以方便开发各种应用程序。
本文应用触摸屏需完成任务有:通过触摸完成控制系统参数设定(风帆设定角度),还需通过触摸启动或停止按钮完成控制系统的启停状态的转换。
S3C2440A驱动RGB TFT液晶屏设计方案探讨编辑:D z3w文章来源:网络我们无意侵犯您的权益,如有侵犯请[联系我们]S3C2440A驱动RG B TF T液晶屏设计方案探讨1引言随着科技的进步,T F T L C D作为显示器件在各种嵌入式系统中得到越来越广泛的应用。
带触摸屏的T F T L C D模组在系统应用中不仅能为人机界面提供高质量的画面显示,而且能提供更直观、方便的交互性输入。
T M T035D N A F W U1是深圳天马微电子股份有限公司生产的8.89c m(3.5i n)T F T L C D模组,该模组内置了L C D驱动器,集成了四线电阻式触摸屏和背光电路。
S3C2440A是三星公司设计的一款基于A R M920T内核的32位嵌入式R I S C(r e d u c e d i n s t r u c t i o n s s e t c o m p u t e r)微处理器,它的最高工作频率可达533 M H z,内部集成了通用的L C D控制器、8通道10位A D C和触摸屏接口,且具备高性能、低功耗的优点,适用于智能手机、便携式媒体播放器、手持导航仪等领域。
本文基于S3C2440A嵌入式系统,以T M T035D N A F W U1为显示设备,设计了T F T L C D驱动电路,并完成L i n u x下驱动显示效果的调试。
2T F T L C D接口时序T M T035D N A F W U1的显示分辨率为320×240,采用24位数字R G B接口,可以显示16.7M颜色。
R G B接口是为T F T L C D模组提供高品质显示而设计的接口,该接口可以高速、低功耗地完成动画显示,其中包含4个重要的控制信号V S Y N C、H S Y N C、D C L K和V D E N,分别用于帧、行、像素的数据传输。
图1为T M T035D N A F W U1模组R G B接口时序示意图。
S3C2440uboot2010.06LCD驱动移植手册十四、添加LCD驱动和LOGO制作1、在drivers/video目录中新增s3c2440_fb.c,代码如下:#include#if defined(CONFIG_VIDEO_S3C2440)#include#include "videomodes.h"#include#include/** Export Graphic Device*/GraphicDevice smi;#define VIDEO_MEM_SIZE 0x200000#define MVAL (0)#define MVAL_USED (0) //0=each frame 1=rate by MVAL#define INVVDEN (1) //0=normal 1=inverted#define BSWP (0) //Byte swap control#define HWSWP (1) //Half word swap control#define VBPD (12)#define VFPD (4)#define VSPW (10)#define HBPD (43)#define HFPD (8)#define HSPW (1)#define CLKVAL_TFT (4)void lcd_enable(void){struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();struct s3c24x0_lcd * const lcd = s3c24x0_get_base_lcd();gpio->GPGUP = gpio->GPGUP & ((~(1 << 4)) | (1 << 4));gpio->GPGCON = gpio->GPGCON & ((~( 3 << 8)) | ( 3 << 8));gpio->GPGDAT = gpio->GPGDAT | (1 << 4 );lcd->LCDCON5 = lcd->LCDCON5 & ((~( 1 << 3)) | (1 << 3)); // PWREN lcd->LCDCON5 = lcd->LCDCON5 & ((~( 1 << 5)) | (0 << 5)); // INVPWREN lcd->LCDCON1 |= 1;gpio->GPBUP = gpio->GPBUP & ((~(1 << 1)) | (1 << 1));gpio->GPBCON = gpio->GPBCON & ((~( 3 << 2)) | ( 3 << 2));gpio->GPBDAT = gpio->GPBDAT | (1 << 1 );/************************************************************** ******************* Init video chip with common Linux graphic modes (lilo)*/void *video_hw_init (void){struct s3c24x0_lcd * const lcd = s3c24x0_get_base_lcd();GraphicDevice *pGD = (GraphicDevice *)&smiint videomode;int bppmode;unsigned long t1, hsynch, vsynch;char *penv;int tmp, i, bits_per_pixel;struct ctfb_res_modes *res_mode;struct ctfb_res_modes var_mode;tmp = 0;videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE;/* get video mode via environment */if ((penv = getenv ("videomode")) != NULL) {/* deceide if it is a string */if (penv[0] <= '9') {videomode = (int) simple_strtoul (penv, NULL, 16);tmp = 1;}}else{tmp = 1;}if (tmp) {/* parameter are vesa modes *//* search params */for (i = 0; i < VESA_MODES_COUNT; i++) {if (vesa_modes[i].vesanr == videomode)break;}if (i == VESA_MODES_COUNT) {printf ("no VESA Mode found, switching to mode 0x%x ", CONFIG_SYS_DEFAULT_VIDEO_MODE);i = 0;res_mode = (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].resindex];bits_per_pixel = vesa_modes[i].bits_per_pixel;}else{res_mode = (struct ctfb_res_modes *) &var_mode;bits_per_pixel = video_get_params (res_mode, penv);}/* calculate hsynch and vsynch freq (info only) */t1 = (res_mode->left_margin + res_mode->xres + res_mode->right_margin + res_mode->hsync_le n) / 8;t1 *= 8;t1 *= res_mode->pixclock;t1 /= 1000;hsynch = 1000000000L / t1;t1 *= (res_mode->upper_margin + res_mode->yres + res_mode->lower_margin + res_mode->vsy nc_len);t1 /= 1000;vsynch = 1000000000L / t1;/* fill in Graphic device struct */sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres, res_mode->yres, bits_pe r_pixel, (hsynch / 1000), (vsynch / 1000));pGD->winSizeX = res_mode->xres;pGD->winSizeY = res_mode->yres;pGD->plnSizeX = res_mode->xres;pGD->plnSizeY = res_mode->yres;switch (bits_per_pixel){case 8:pGD->gdfBytesPP = 1;pGD->gdfIndex = GDF__8BIT_INDEX;bppmode = 11;break;case 16:pGD->gdfBytesPP = 2;pGD->gdfIndex = GDF_16BIT_565RGB;bppmode = 12;break;case 24:pGD->gdfBytesPP = 3;pGD->gdfIndex = GDF_24BIT_888RGB;bppmode = 13;break;}pGD->frameAdrs = LCD_VIDEO_ADDR;pGD->memSize = VIDEO_MEM_SIZE;lcd->LCDCON1 = (CLKVAL_TFT << 8) | (MVAL_USED << 7) | (3 << 5) | (bppmode << 1) | 0;lcd->LCDCON2 = (VBPD << 24) | (pGD->winSizeY-1 << 14) | (VFPD << 6) | (VSPW);lcd->LCDCON3 = (HBPD << 19) | (pGD->winSizeX-1 << 8) | (HFPD);lcd->LCDCON4 = (MVAL << 8) | (HSPW);lcd->LCDCON5 = (1 << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 7) | (0 << 6) | (1 << 3) | (BSWP < < 1) | (HWSWP);lcd->LCDINTMSK |= (3);lcd->LPCSEL &= (~7);lcd->TPAL = 0x0;writel((pGD->frameAdrs >> 1), &lcd->LCDSADDR1);/* This marks the end of the frame buffer. */writel((((readl(&lcd->LCDSADDR1))&0x1fffff) + (pGD->winSizeX+0) *pGD->winSizeY), &lcd->LCDSA DDR2);writel((pGD->winSizeX & 0x7ff), &lcd->LCDSADDR3);/* Clear video memory */memset((void *)pGD->frameAdrs, 0, pGD->memSize);lcd_enable();return ((void*)&smi);}void video_set_lut (unsigned int index,/* color number */unsigned char r, /* red */unsigned char g, /* green */unsigned char b /* blue */){}#endif /* CONFIG_VIDEO_S3C2440 */修改video目录下Makefile文件COBJS-$(CONFIG_VIDEO_VCXK) += bus_vcxk.oCOBJS-$(CONFIG_VIDEO_S3C24X0) += s3c24x0_fb.o videomodes.o cfb_console.o COBJS := $(COBJS-y)2、修改include/configs/SMDK2440.h,添加下面的宏定义/* LCD settings */#define CONFIG_VIDEO#define CONFIG_VIDEO_S3C2440#define CONFIG_VIDEO_LOGO#define CONFIG_VIDEO_BMP_LOGO#define VIDEO_FB_16BPP_WORD_SWAP#define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE (800*480+1024+100)#define LCD_VIDEO_ADDR 0x33d00000#define CONFIG_CMD_BMP#define CONFIG_CFB_CONSOLE#define CONFIG_SYS_CONSOLE_INFO_QUIET/* for PC-keyboard */#define VIDEO_KBD_INIT_FCT 0#define VIDEO_TSTC_FCT serial_tstc#define VIDEO_GETC_FCT serial_getc3、修改drivers/video/videomodes.c{0x31A, RES_MODE_1280x1024, 16},{0x31B, RES_MODE_1280x1024, 24},{0x213, RES_MODE_800x480, 16},};RES_MODE_800x480前的数据0x213与前面的不同即可。
基于S3C2440A终端LCD驱动电路的设计与实现
引言
现在大部分的便携式手持终端产品,如移动电话、导航系统等,都拥有
一个小型LCD 显示屏,这使LCD 驱动电路的设计成为手持终端设计的重要组
成部分。
本文以应用于特殊行业的手持终端为例,叙述LCD 驱动电路的设计实
现方法。
硬件电路设计
硬件电路结构
本设计中手持终端CPU 采用三星公司ARM920T 内核处理器
S3C2440A,其LCD 控制器支持STN LCD 和TFT LCD,实际使用的LCD 为LTS350Q1-PE1_PI,属于TFT LCD。
电路框图如图1 所示。
驱动电路主要包括三部分:第一部分是LCD 驱动,采用MAX1779 芯片;第二部分是LED 背光驱动,采用MP1521 芯片;第三部分是VCOM 信号驱动,采
用LM8261 芯片。
这里主要叙述LCD 驱动和背光电路的实现。
LCD 驱动电路
由于LCD 内集成有数字电路和模拟电路,需要外部提供数字电压
DVDD 和模拟电压AVDD。
另外,为了完成数据扫描,需要TFT 轮流开启/关闭。
当TFT 开启时,数据通过源极驱动器加载到显示电极,显示电极和公共电
极间的电压差再作用于液晶实现显示,因此需要控制TFT 的开启电压VGH、
关闭电压VGL,以及加到公共电极上的电压VCOM。
S3C2440上LCD驱动(FrameBuffer)实例开发讲解一、开发环境·主机:VMWare--Fedora 9·开发板:Mini2440--64MB Nand, Kernel:2.6.30.4·编译器:arm-linux-gcc-4.3.2二、背景知识1. LCD工作的硬件需求:要使一块LCD正常的显示文字或图像,不仅需要LCD驱动器,而且还需要相应的LCD控制器。
在通常情况下,生产厂商把LCD驱动器会以COF/COG 的形式与LCD玻璃基板制作在一起,而LCD控制器则是由外部的电路来实现,现在很多的MCU内部都集成了LCD控制器,如S3C2410/2440等。
通过LCD 控制器就可以产生LCD驱动器所需要的控制信号来控制STN/TFT屏了。
2. S3C2440内部LCD控制器结构图:我们根据数据手册来描述一下这个集成在S3C2440内部的LCD控制器:a:LCD控制器由REGBANK、LCDCDMA、TIMEGEN、VIDPRCS寄存器组成;b:REGBANK由17个可编程的寄存器组和一块256*16的调色板内存组成,它们用来配置LCD控制器的;c:LCDCDMA是一个专用的DMA,它能自动地把在侦内存中的视频数据传送到LCD驱动器,通过使用这个DMA通道,视频数据在不需要CPU的干预的情况下显示在LCD屏上;d:VIDPRCS接收来自LCDCDMA的数据,将数据转换为合适的数据格式,比如说4/8位单扫,4位双扫显示模式,然后通过数据端口VD[23:0]传送视频数据到LCD驱动器;e:TIMEGEN由可编程的逻辑组成,他生成LCD驱动器需要的控制信号,比如VSYNC、HSYNC、VCLK和LEND等等,而这些控制信号又与REGBANK寄存器组中的LCDCON1/2/3/4/5的配置密切相关,通过不同的配置,TIMEGEN 就能产生这些信号的不同形态,从而支持不同的LCD驱动器(即不同的STN/TFT屏)。
S3C2440 TFT LCD驱动程序编程要点
1、打开LCD背光
将LCD背光对应的GPIO设置为禁止上拉(GPxUP相应位写入1),选择output类型(GPxCON相应位写入01),输出为高电平(GPxDAT相应位写入1)。
2、打开LCD电源
可以将GPG4选择为LCD_PWREN(GPGCON:9-8写入11),这时候LCD电源的打开/关闭可以通过LCDCON5:3来控制。
也可以自定义其他GPIO用作LCD电源开关,只需将此GPIO设置为禁止上拉(GPxUP相应位写入1),选择output类型(GPxCON相应位写入01),输出为高电平(GPxDAT相应位写入1)打开LCD电源。
3、设置其他信号线
其他信号线包括VD0-VD23和VFRAME、VLINE、VCLK等,分别在GPCCON,GPDCON 中选择相应功能。
4、设置LCD的频率(VCLK)
LCD的Datasheet上一般会写有一个推荐的频率,比如我使用的屏幕推荐频率为6.4M,我需要通过一些计算选择一个合适的CLKVAL以产生这个频率:
对于TFT LCD,S3C2440提供的VCLK的计算公式为:
VCLK = HCLK / ((CLKVAL+1)*2)
可以得出:
CLKVAL = HCLK / (VCLK * 2) - 1
我的HCLK是100Mhz(CPU运行在400Mhz, CLKDIV_VAL设置为5,Fclk:Hclk:Pclk = 1:4:8),VCLK使用屏幕推荐的6.4M,得到:
CLKVAL = 100000000 / (6400000 * 2) - 1 = 6.8
选择最接近的整数值7,写入LCDCON1:17-8。
(VCLK其实就是根据每秒帧数*帧行数*行像素计算出来的,帧行数和行像素需要包含空白数和同步数)
5、设置其他相关参数
LCD相关的参数主要还有这几个:
LINEVAL: LCD水平像素-1,如320-1 = 319
HOZVAL: LCD垂直像素-1,如240-1 = 239
HFPD: 行开始前的VCLK时钟数(LCD屏幕的Datasheet一般有推荐值)
HBPD: 行结束后的VCLK时钟数(LCD屏幕的Datasheet一般有推荐值)
HSPW: 行之间水平同步的无效VCLK时钟数(LCD屏幕的Datasheet一般有推荐值) VFPD: 帧数据开始前的空白行数(LCD屏幕的Datasheet一般有推荐值)
VBPD: 帧数据结束后的空白行数(LCD屏幕的Datasheet一般有推荐值)
VSPW: 帧之间垂直同步的无效行数(LCD屏幕的Datasheet一般有推荐值)
(相关寄存器LCDCON2, LCDCON3, LCDCON4)
6、设置视频缓冲区的地址
2440支持虚拟屏幕,可以通过改变LCD寄存器实现屏幕快速移动
PAGEWIDTH:虚拟屏幕一行的字节数,如果不使用虚拟屏幕,设置为实际屏幕的行字节数,如16位宽320像素,设为320 * 2
OFFSIZE:虚拟屏幕左侧偏移的字节数,如果不使用虚拟屏幕,设置为0
LCDBANK: 视频帧缓冲区内存地址30-22位
LCDBASEU: 视频帧缓冲区的开始地址21-1位
LCDBASEL: 视频帧缓冲区的结束地址21-1位
(相关寄存器LCDSADDR1,LCDSADDR2,LCDSADDR3)
7、确定信号的极性
2440的LCD控制器允许设置VCLK、VLINE、VFRAME等信号的极性(上升沿有效还是下降沿有效),需要对照LCD的Datasheet一一确认。
(相关寄存器LCDCON5)
8、禁止LPC3600/LCC3600模式!
如果不是使用三星LPC3600/LCC3600 LCD,必须禁止LPC3600/LCC3600模式(写入0到TCONSEL)!
9、打开视频输出
ENVID设为1 (LCDCON1:0写入1)。