zoukankan      html  css  js  c++  java
  • 实验九--裸机LCD

    一。环境

      系统:ubuntu12.04

      开发板:jz2440

      编译器:gcc

    二。说明

        有空补上

    三。代码

     Makefile:

     1 CC      = arm-linux-gcc
     2 LD      = arm-linux-ld
     3 AR      = arm-linux-ar
     4 OBJCOPY = arm-linux-objcopy
     5 OBJDUMP = arm-linux-objdump
     6 
     7 CFLAGS         := -Wall -O2
     8 
     9 
    10 export     CC LD AR OBJCOPY OBJDUMP CFLAGS
    11 
    12 objs := head.o init.o nand.o lcddrv.o framebuffer.o main.o
    13 
    14 lcd.bin: $(objs)
    15     ${LD} -Tlcd.lds -o lcd_elf $^
    16     ${OBJCOPY} -O binary -S lcd_elf $@
    17     ${OBJDUMP} -D -m arm lcd_elf > lcd.dis
    18 
    19 
    20 %.o:%.c
    21     ${CC} $(CFLAGS) -c -o $@ $<
    22 
    23 %.o:%.S
    24     ${CC} $(CFLAGS) -c -o $@ $<
    25 
    26 clean:
    27     rm -f lcd.bin lcd_elf lcd.dis *.o
    28     

    head.S:

     1 @******************************************************************************
     2 @ File: head.S
     3 @ 功能: 设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
     4 @******************************************************************************       
     5    
     6 .extern     main
     7 .text 
     8 .global _start 
     9 _start:
    10 @******************************************************************************       
    11 @ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用
    12 @******************************************************************************       
    13     b   Reset
    14 
    15 @ 0x04: 未定义指令中止模式的向量地址
    16 HandleUndef:
    17     b   HandleUndef 
    18  
    19 @ 0x08: 管理模式的向量地址,通过SWI指令进入此模式
    20 HandleSWI:
    21     b   HandleSWI
    22 
    23 @ 0x0c: 指令预取终止导致的异常的向量地址
    24 HandlePrefetchAbort:
    25     b   HandlePrefetchAbort
    26 
    27 @ 0x10: 数据访问终止导致的异常的向量地址
    28 HandleDataAbort:
    29     b   HandleDataAbort
    30 
    31 @ 0x14: 保留
    32 HandleNotUsed:
    33     b   HandleNotUsed
    34 
    35 @ 0x18: 中断模式的向量地址
    36 HandleIRQ:
    37     b   HandleIRQ
    38 
    39 @ 0x1c: 快中断模式的向量地址
    40 HandleFIQ:
    41     b   HandleFIQ
    42 
    43 Reset:                  
    44     ldr sp, =4096           @ 设置栈指针,以下都是C函数,调用前需要设好栈
    45     bl  disable_watch_dog   @ 关闭WATCHDOG,否则CPU会不断重启
    46     bl  clock_init          @ 设置MPLL,改变FCLK、HCLK、PCLK
    47     bl  memsetup            @ 设置存储控制器以使用SDRAM
    48     bl  nand_init           @ 初始化NAND Flash
    49     
    50                             @ 复制代码到SDRAM中
    51     ldr r0, =0x30000000     @ 1. 目标地址 = 0x30000000,这是SDRAM的起始地址
    52     mov r1, #4096           @ 2. 源地址   = 4096,运行地址在SDRAM中的代码保存在NAND Flash 4096地址开始处
    53     mov r2, #16*1024        @ 3. 复制长度 = 16K,对于本实验,这是足够了
    54     bl  CopyCode2SDRAM      @ 调用C函数CopyCode2SDRAM
    55     
    56     bl  clean_bss           @ 清除bss段,未初始化或初值为0的全局/静态变量保存在bss段
    57 
    58 
    59 
    60     msr cpsr_c, #0xdf       @ 进入系统模式
    61     ldr sp, =0x34000000     @ 设置系统模式栈指针,
    62 
    63 
    64 
    65     ldr lr, =halt_loop      @ 设置返回地址
    66     ldr pc, =main           @ 调用main函数
    67 halt_loop:
    68     b   halt_loop

    上面的sdram,时钟,nand flash等同前面的,不贴出来了

    现在与lcd有关的函数:

    main.c:

     1 #include "lcddrv.h"
     2 #include "framebuffer.h"
     3 #include "s3c24xx.h"
     4 
     5 void delay()
     6 
     7 {
     8 
     9 unsigned long cnt;
    10 
    11 for(cnt=0;cnt<100000;cnt++);
    12 
    13 }
    14 
    15 int main()
    16 {
    17     Lcd_Port_Init();                     // 设置LCD引脚
    18     Tft_Lcd_Init(); // 初始化LCD控制器
    19     Lcd_PowerEnable(0, 1);               // 设置LCD_PWREN有效,它用于打开LCD的电源
    20     Lcd_EnvidOnOff(1);                   // 使能LCD控制器输出信号
    21 
    22     ClearScr(0x0);  // 清屏,黑色
    23     while (1)
    24     {           
    25            
    26         Mire();  
    27     delay(); 
    28         //Lcd_EnvidOnOff(0);
    29  
    30     }
    31     
    32     return 0;
    33 }

    由main函数可以看出,本程序只是驱动lcd来画同心圆,参考代码是韦东山先生的,此处作了较大的删改:

    framebuffer.c:

     1 /*
     2  * FILE: framebuffer.c
     3  * 实现在framebuffer上画点、画线、画同心圆、清屏的函数
     4  */
     5 
     6 #include "framebuffer.h"
     7 
     8 extern unsigned int fb_base_addr;
     9 extern unsigned int bpp;
    10 extern unsigned int xsize;
    11 extern unsigned int ysize;
    12 
    13 /* 
    14  * 画点
    15  * 输入参数:
    16  *     x、y : 象素坐标
    17  *     color: 颜色值
    18  *         对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),
    19  *     需要转换为5:6:5格式
    20  *         对于8BPP: color为调色板中的索引值,
    21  *     其颜色取决于调色板中的数值
    22  */
    23 void PutPixel(unsigned int x, unsigned int y, unsigned int color)
    24 {
    25     unsigned char red,green,blue;
    26 
    27     switch (bpp){
    28         case 16:
    29         {
    30             unsigned short *addr = (unsigned short *)fb_base_addr + (y * xsize + x);
    31             red   = (color >> 19) & 0x1f;
    32             green = (color >> 10) & 0x3f;
    33             blue  = (color >>  3) & 0x1f;
    34             color = (red << 11) | (green << 5) | blue; // 格式5:6:5
    35             *addr = (unsigned short) color;
    36             break;
    37         }
    38  
    39 
    40         default:
    41             break;
    42     }
    43 }
    44 
    45 /* 
    46  * 绘制同心圆
    47  */
    48 void Mire(void)
    49 {
    50     unsigned int x,y;
    51     unsigned int color;
    52     unsigned char red,green,blue,alpha;
    53 
    54     for (y = 0; y < ysize; y++)
    55         for (x = 0; x < xsize; x++){
    56             color = ((x-xsize/2)*(x-xsize/2) + (y-ysize/2)*(y-ysize/2))/64;
    57             red   = (color/8) % 256;
    58             green = (color/4) % 256;
    59             blue  = (color/2) % 256;
    60             alpha = (color*2) % 256;
    61 
    62             color |= ((unsigned int)alpha << 24);
    63             color |= ((unsigned int)red   << 16);
    64             color |= ((unsigned int)green << 8 );
    65             color |= ((unsigned int)blue       );
    66 
    67             PutPixel(x,y,color);
    68         }
    69 }
    70 
    71 /* 
    72  * 将屏幕清成单色
    73  * 输入参数:
    74  *     color: 颜色值
    75  *         对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),
    76  *     需要转换为5:6:5格式
    77  *         对于8BPP: color为调色板中的索引值,
    78  *     其颜色取决于调色板中的数值
    79  */
    80 void ClearScr(unsigned int color)
    81 {   
    82     unsigned int x,y;
    83     
    84     for (y = 0; y < ysize; y++)
    85         for (x = 0; x < xsize; x++)
    86             PutPixel(x, y, color);
    87 }

    lcddrv.c:

      1 /*
      2  * FILE: lcddrv.c
      3  * 提供操作LCD控制器、调色板等的底层函数
      4  */
      5 
      6 #include "s3c24xx.h"
      7 #include "lcddrv.h"
      8 
      9 #define GPB0_tout0  (2<<(0*2))
     10 #define GPB0_out    (1<<(0*2))
     11 #define GPB1_out    (1<<(1*2))
     12 
     13 #define GPB0_MSK    (3<<(0*2))
     14 #define GPB1_MSK    (3<<(1*2))
     15 
     16 
     17 unsigned int fb_base_addr;
     18 unsigned int bpp;
     19 unsigned int xsize;
     20 unsigned int ysize;
     21 
     22 
     23 /*
     24  * 初始化用于LCD的引脚
     25  */
     26 void Lcd_Port_Init(void)
     27 {
     28     GPCUP   = 0xffffffff;   // 禁止内部上拉
     29     GPCCON  = 0xaaaaaaaa;   // GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND 
     30     GPDUP   = 0xffffffff;   // 禁止内部上拉
     31     GPDCON  = 0xaaaaaaaa;   // GPIO管脚用于VD[23:8]
     32       GPBCON &= ~(GPB0_MSK);  // Power enable pin
     33     GPBCON |= GPB0_out;
     34     GPBDAT &= ~(1<<0);            // Power off
     35    
     36 }
     37 
     38 /*
     39  * 初始化LCD控制器
     40  * 输入参数:
     41  * type: 显示模式
     42  *      MODE_TFT_8BIT_240320  : 240*320 8bpp的TFT LCD
     43  *      MODE_TFT_16BIT_240320 : 240*320 16bpp的TFT LCD
     44  *      MODE_TFT_8BIT_640480  : 640*480 8bpp的TFT LCD
     45  *      MODE_TFT_16BIT_640480 : 640*480 16bpp的TFT LCD
     46  */
     47 void Tft_Lcd_Init()
     48 {
     49    
     50         /* 
     51          * 设置LCD控制器的控制寄存器LCDCON1~5
     52          * 1. LCDCON1:
     53          *    设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2]
     54          *    选择LCD类型: TFT LCD   
     55          *    设置显示模式: 16BPP
     56          *    先禁止LCD信号输出
     57          * 2. LCDCON2/3/4:
     58          *    设置控制信号的时间参数
     59          *    设置分辨率,即行数及列数
     60          * 现在,可以根据公式计算出显示器的频率:
     61          * 当HCLK=100MHz时,
     62          * Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LIINEVAL+1)+(VFPD+1)}x
     63          *              {(HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1)}x
     64          *              {2x(CLKVAL+1)/(HCLK)}]
     65          *            = 60Hz
     66          * 3. LCDCON5:
     67          *    设置显示模式为16BPP时的数据格式: 5:6:5
     68          *    设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转
     69          *    半字(2字节)交换使能
     70          */
     71         LCDCON1 = (4<<8) | (LCDTYPE_TFT<<5) | 
     72                   (BPPMODE_16BPP<<1) | (ENVID_DISABLE<<0);
     73         LCDCON2 = (1<<24) | (271<<14) | 
     74                   (1<<6) | (9);
     75         LCDCON3 = (1<<19) | (479<<8) | (1);
     76         LCDCON4 = 40;
     77         LCDCON5 = (FORMAT8BPP_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | 
     78                   (HWSWP<<1);
     79 
     80         /*
     81          * 设置LCD控制器的地址寄存器LCDSADDR1~3
     82          * 帧内存与视口(view point)完全吻合,
     83          * 图像数据格式如下:
     84          *         |----PAGEWIDTH----|
     85          *    y/x  0   1   2       239
     86          *     0   rgb rgb rgb ... rgb
     87          *     1   rgb rgb rgb ... rgb
     88          * 1. LCDSADDR1:
     89          *    设置LCDBANK、LCDBASEU
     90          * 2. LCDSADDR2:
     91          *    设置LCDBASEL: 帧缓冲区的结束地址A[21:1]
     92          * 3. LCDSADDR3:
     93          *    OFFSIZE等于0,PAGEWIDTH等于(240*2/2)
     94          */
     95         LCDSADDR1 = ((LCDFRAMEBUFFER>>22)<<21) | LOWER21BITS(LCDFRAMEBUFFER>>1);
     96         LCDSADDR2 = LOWER21BITS((LCDFRAMEBUFFER+ 
     97                     (480)*(272)*2)>>1);
     98         LCDSADDR3 = (0<<11) | (480*2/2);
     99 
    100         /* 禁止临时调色板寄存器 */
    101         TPAL = 0;
    102 
    103         fb_base_addr = LCDFRAMEBUFFER;
    104         bpp = 16;
    105         xsize = 480;
    106         ysize = 272;
    107 
    108       
    109 }
    110 
    111 
    112 /*
    113  * 设置是否输出LCD电源开关信号LCD_PWREN
    114  * 输入参数:
    115  *     invpwren: 0 - LCD_PWREN有效时为正常极性
    116  *               1 - LCD_PWREN有效时为反转极性
    117  *     pwren:    0 - LCD_PWREN输出有效
    118  *               1 - LCD_PWREN输出无效
    119  */
    120 void Lcd_PowerEnable(int invpwren, int pwren)
    121 {
    122     GPGCON = (GPGCON & (~(3<<8))) | (3<<8);   // GPG4用作LCD_PWREN
    123     GPGUP  = (GPGUP & (~(1<<4))) | (1<<4);    // 禁止内部上拉    
    124         
    125     LCDCON5 = (LCDCON5 & (~(1<<5))) | (invpwren<<5);  // 设置LCD_PWREN的极性: 正常/反转
    126     LCDCON5 = (LCDCON5 & (~(1<<3))) | (pwren<<3);     // 设置是否输出LCD_PWREN
    127 }    
    128 
    129 /*
    130  * 设置LCD控制器是否输出信号
    131  * 输入参数:
    132  * onoff: 
    133  *      0 : 关闭
    134  *      1 : 打开
    135  */
    136 void Lcd_EnvidOnOff(int onoff)
    137 {
    138     if (onoff == 1)
    139     {
    140         LCDCON1 |= 1;         // ENVID ON
    141         GPBDAT |= (1<<0);            // Power on
    142     }
    143     else
    144     {
    145         LCDCON1 &= 0x3fffe;  // ENVID Off
    146         GPBDAT &= ~(1<<0);     // Power off
    147     }
    148 }    

    现在贴出重要的头文件做为理解用:

    lcddrv.h:

     1 /*
     2  * FILE: lcddrv.h
     3  * 操作LCD控制器、调色板等的底层函数接口
     4  */
     5 
     6 #ifndef __LCDDRV_H__
     7 #define __LCDDRV_H__
     8 
     9 
    10 #define LOWER21BITS(n)  ((n) & 0x1fffff)
    11 
    12 #define BPPMODE_16BPP   0xC
    13 
    14 
    15 #define LCDTYPE_TFT     0x3
    16 
    17 #define ENVID_DISABLE   0
    18 #define ENVID_ENABLE    1
    19 
    20 #define FORMAT8BPP_5551 0
    21 #define FORMAT8BPP_565  1
    22 
    23 #define HSYNC_NORM      0
    24 #define HSYNC_INV       1
    25 
    26 #define VSYNC_NORM      0
    27 #define VSYNC_INV       1
    28 
    29 #define VDEN_NORM        0
    30 #define VDEN_INV        1
    31 
    32 #define BSWP            1
    33 #define HWSWP           1
    34 
    35 #define LCDFRAMEBUFFER 0x30400000
    36 
    37 /*
    38  * 初始化用于LCD的引脚
    39  */
    40 void Lcd_Port_Init(void);
    41 
    42 /*
    43  * 初始化LCD控制器
    44  * 输入参数:
    45  * type: 显示模式
    46  *      MODE_TFT_8BIT_640480  : 640*640 8bpp的TFT LCD
    47  *      MODE_TFT_16BIT_640480 : 640*640 16bpp的TFT LCD
    48  */
    49 void Tft_Lcd_Init();
    50 
    51 void Lcd_EnvidOnOff(int onoff);
    52 
    53 /*
    54  * 设置是否输出LCD电源开关信号LCD_PWREN
    55  * 输入参数:
    56  *     invpwren: 0 - LCD_PWREN有效时为正常极性
    57  *               1 - LCD_PWREN有效时为反转极性
    58  *     pwren:    0 - LCD_PWREN输出有效
    59  *               1 - LCD_PWREN输出无效
    60  */
    61 void Lcd_PowerEnable(int invpwren, int pwren);
    62 
    63 
    64 #endif /*__LCDDRV_H__*/

    自然不难看出,仍然有不少冗余项,这里先不做深究。

    上面代码经过烧写验证,没有问题。

    代码删减了串口,中断,以及print函数的硬件重定向等内容,以便更直观理解lcd驱动。

    关于代码中重要函数,有时间补上。

         

  • 相关阅读:
    深度学习时代的图模型,清华发文综述图网络
    深入解析CNN pooling 池化层原理及其作用
    如何理解线性回归中的“回归”,回归到哪里?
    线性回归中“回归”的含义
    深度学习基础——Epoch、Iteration、Batchsize
    手动清空微信PC客户端数据
    Mini-batch 和batch的区别
    Python中绘制场景热力图
    HSV颜色识别-HSV基本颜色分量范围
    Android拨打接听电话自动免提
  • 原文地址:https://www.cnblogs.com/hulig7/p/4138582.html
Copyright © 2011-2022 走看看