|
楼主 |
发表于 2016-5-6 08:18:04
|
显示全部楼层
本帖最后由 szhm 于 2016-5-6 08:36 编辑
论坛要修改头像才能发贴,呵呵
因不懂推挽输出,试下用gpio的复用功能,也能驱动LCD.
本程序是本人学习龙芯1C各硬件寄存器的用法,没实际用途
1.源码
// spilcd.c
// 硬件spi 3线
// 同样3线,9位;先用gpio模拟发一位数据/命令,再用硬件SPI发8位;已成功点亮LCD
#include <sys/types.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <memory.h>
/*
SPI0 基址是 0xbfe80000,其最高三位清零得物理地址0x1FE80000
本程序是用户态驱动,mmap()映射物理地址
如是内核程序或无操作系统的裸机程序,应使用0xbfe80000
*/
#define spi_base 0x1FE80000
// 控制寄存器相对于基址的偏移
#define REG_SPCR 0x00 //控制寄存器
#define REG_SPSR 0x01 //状态寄存器
#define REG_SPDR 0x02 //数据传输寄存器
#define REG_SPER 0x03 //外部寄存器
#define REG_SPCS 0x05 //片选
#define RST "46" //ILI9341复位
//SPI0对应了GPIO78、GPIO79、GPIO84,落在GPIO2[95:64]
#define SDA 79
#define SCL 78
#define CS 84
#define gpio_base 0x1FD010C8 //GPIO2--gpio组2
#define GPIO_CFG 0x00
#define GPIO_EN 0x10
#define GPIO_OUT 0x30
void *mapgpio_base;
void gpio_exportout(unsigned int gpio2)
{
*(volatile unsigned int*)(mapgpio_base+GPIO_CFG)|= (1 << (gpio2-64)) ;/*置1,GPIO有效;GPIO2[95:64],要减64*/
*(volatile unsigned int*)(mapgpio_base+GPIO_EN)&=(~(1 << (gpio2-64)));/*置0,方向输出*/
}
void gpio_setvalue(unsigned int gpio2,int value)
{ if (value)
*(volatile unsigned int*)(mapgpio_base+GPIO_OUT)|= (1 << (gpio2-64)) ;//输出1
else
*(volatile unsigned int*)(mapgpio_base+GPIO_OUT)&=(~(1 << (gpio2-64)));//输出0
}
void gpio_unexport(unsigned int gpio2)
{
*(volatile unsigned int*)(mapgpio_base+GPIO_CFG)&=(~(1 << (gpio2-64)));//置0 ,GPIO无效
}
void *mapspi_base;
void s_send(unsigned char X) //硬件spi
{ unsigned char c;
*(volatile unsigned char*)(mapspi_base+REG_SPDR)=X ;//往传输寄存器写入数据
while ( (*(volatile unsigned char*)(mapspi_base+REG_SPSR)) & 0x01);/*直接在此循环判断状态寄存器(没使用中断方式)*/
c=(*(volatile unsigned char*)(mapspi_base+REG_SPDR)) ;//即使从设备没发数据也必须进行读出操作
}
void s_com(unsigned char X) //写命令
{ gpio_exportout(CS);
gpio_exportout(SDA);
gpio_exportout(SCL);
gpio_setvalue(CS,0);
gpio_setvalue(SCL,0);
gpio_setvalue(SDA,0);// 3线,先发一位: 命令 -- 0
gpio_setvalue(SCL,1);
gpio_unexport(SDA);
gpio_unexport(SCL);
gpio_unexport(CS);
s_send(X);
gpio_exportout(CS);
gpio_setvalue(CS,1);
gpio_unexport(CS);
}
void s_data(unsigned char X) //写数据
{ gpio_exportout(CS);
gpio_exportout(SDA);
gpio_exportout(SCL);
gpio_setvalue(CS,0);
gpio_setvalue(SCL,0);
gpio_setvalue(SDA,1);// 3线,先发一位: 数据 -- 1
gpio_setvalue(SCL,1);
gpio_unexport(SDA);
gpio_unexport(SCL);
gpio_unexport(CS);
s_send(X);
gpio_exportout(CS);
gpio_setvalue(CS,1);
gpio_unexport(CS);
}
void coordinate(unsigned int col,unsigned int page)
{
s_com(0x2a); //Column Address Set
s_data(0x00);
s_data(col);
s_data(0x00);
s_data(0xef);
s_com(0x2b); //Row Address Set
s_data((page&0xff00)>>8);
s_data(page&0x00ff);
s_data(0x01);
s_data(0x3f);
s_com(0x2c); //Memory Write
}
int main(int argc ,char *argv[])
{ int fd;
void *map_base;
fd = open("/dev/mem", O_RDWR|O_SYNC);
if(fd == -1)
{ printf("Can't open /dev/mem\n");
return -1;
}
printf("open /dev/mem success\n");
int psize=getpagesize();
int rem=spi_base%psize;
int offset=spi_base-rem;
int length=spi_base+REG_SPCS-offset+1 ; //这里只需+1,spi寄存器只8位一字节
printf("pagesize:%i ; spi0 base:%x ; remainder:%i ; offset:%x ; length:%i\n",psize,spi_base,rem,offset,length);
map_base=(volatile unsigned char*)mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,offset);
if(map_base==NULL || map_base ==MAP_FAILED)
printf("Can't mmap\n");
else
printf("mmap success\n");
mapspi_base=(volatile unsigned char*)(map_base+rem);//同样spi寄存器只8位一字节,所以unsigned char*
*(volatile unsigned char*)(mapspi_base+REG_SPCS)=0xff ;//取消片选CS3
/* SPCR控制寄存器
复位SPI控制寄存器工作, 0x10= 00010000 , spe为0--停止SPI
0 0 0 1 0000
| |
spe mstr
*/
*(volatile unsigned char*)(mapspi_base+REG_SPCR)=0x10 ;
*(volatile unsigned char*)(mapspi_base+REG_SPSR)=0xc0 ;//重置状态寄存器SPSR . 0xc0= 11000000
/* SPER外部寄存器
设置外部寄存器, 0x00= 00000000 , icnt为00--传输完1个字节后发中断, mode为0--采样与发送时机同时
00 000 0 00
| | |
icnt mode spre
*/
*(volatile unsigned char*)(mapspi_base+REG_SPER)=0x00;
/* SPCR控制寄存器
SPCR的spr位和SPER的spre位两者共同设定分频系数,分频系数越小,越快,设分频系数最小,spr(00)+spre(00)=分频系数2 ,很快,点亮整屏约0.5秒内
设置spr为00,即REG_SPCR为0xd0=11010000 ,spie为1--中断使能,spe为1--启动SPI
1 1 0 1 0 0 00
| | | | | \/
spie spe mstr cpol cpha spr
*/
*(volatile unsigned char*)(mapspi_base+REG_SPCR)=0xd0;
*(volatile unsigned char*)(mapspi_base+REG_SPCS)=0x7f ;//设置片选CS3 0x7f= 01111111
//--v-- GPIO
int fd2;
void *map_base2;
fd2 = open("/dev/mem", O_RDWR|O_SYNC);
if(fd2 == -1)
{ printf("Can't open /dev/mem\n");
return -1;
}
printf("open /dev/mem success\n");
rem=gpio_base%psize;
offset=gpio_base-rem;
int length2=gpio_base+GPIO_OUT-offset+4; //这里要+4,GPIO寄存器32位四字节
printf("pagesize:%i ; gpio2 base:%x ; remainder:%i ; offset:%x ; length:%i\n",psize,gpio_base,rem,offset,length2);
map_base2=(volatile unsigned int*)mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd2,offset);
if(map_base==NULL || map_base ==MAP_FAILED)
printf("Can't mmap\n");
else
printf("mmap success\n");
mapgpio_base=(volatile unsigned int*)(map_base2+rem);
//--^--
system("echo "RST" > /sys/class/gpio/export && echo out > /sys/class/gpio/gpio"RST"/direction");
// LCD Reset
system("echo 0 > /sys/class/gpio/gpio"RST"/value");
system("echo 0 > /sys/class/gpio/gpio"RST"/value");
sleep(1);
system("echo 1 > /sys/class/gpio/gpio"RST"/value");
system("echo 1 > /sys/class/gpio/gpio"RST"/value");
sleep(1);
//--v-- ILI9341初始化开始
// 初始化部分是照抄51单片机程序.就是发送命令/数据,具体代表什么意思需参考ILI9341手册
s_com(0xCF);
s_data(0x00);
s_data(0x81);
s_data(0x30);
s_com(0xED);
s_data(0x64);
s_data(0x03);
s_data(0x12);
s_data(0x81);
s_com(0xE8);
s_data(0x85);
s_data(0x10);
s_data(0x78);
s_com(0xCB);
s_data(0x39);
s_data(0x2C);
s_data(0x00);
s_data(0x34);
s_data(0x02);
s_com(0xF7);
s_data(0x20);
s_com(0xEA);
s_data(0x00);
s_data(0x00);
s_com(0xB1);
s_data(0x00);
s_data(0x13);
s_com(0xB6); // Display Function Control
s_data(0x0A);
s_data(0xA2);
s_com(0xC0); //Power control
s_data(0x21); //VRH[5:0]
s_com(0xC1); //Power control
s_data(0x11); //SAP[2:0];BT[3:0]
s_com(0xC5); //VCM control
s_data(0x3F);
s_data(0x3C);
s_com(0xC7); //VCM control2
s_data(0xa4);
s_com(0x36); // Memory Access Control
s_data(0x08);
s_com(0x3A); // Pixel Format Set
s_data(0x55);
s_com(0xF2); // 3Gamma Function Disable
s_data(0x00);
s_com(0x26); //Gamma curve selected
s_data(0x01);
s_com(0xE0); //Set Gamma
s_data(0x0F);
s_data(0x26);
s_data(0x24);
s_data(0x0B);
s_data(0x0E);
s_data(0x09);
s_data(0x54);
s_data(0xA8);
s_data(0x46);
s_data(0x0C);
s_data(0x17);
s_data(0x09);
s_data(0x0F);
s_data(0x07);
s_data(0x00);
s_com(0xE1); //Set Gamma
s_data(0x00);
s_data(0x19);
s_data(0x1B);
s_data(0x04);
s_data(0x10);
s_data(0x07);
s_data(0x2A);
s_data(0x47);
s_data(0x39);
s_data(0x03);
s_data(0x06);
s_data(0x06);
s_data(0x30);
s_data(0x38);
s_data(0x0F);
s_com(0x11); //Exit Sleep
sleep(1);
s_com(0x29); //Display on
s_com(0x22);
s_data(0x00);
sleep(1);
//--^-- ILI9341初始化结束
coordinate(0,0);//窗口坐标
int i,j;
for(j=240;j>0;j--)
{ // 绿 0x07E0
for(i=320;i>0;i--)
{ s_data(0x07);
s_data(0xe0);
}
}
system("echo "RST" > /sys/class/gpio/unexport");
close(fd);
munmap((void*)map_base,length);
close(fd2);
munmap((void*)map_base2,length2);
return 0;
}
2.编译
1)环境
龙芯2F笔记本逸珑8089,debian 9,o32,dietlibc库
2)编译为静态可执行文件
loongson@debian:~$ diet gcc -static -o spilcd spilcd.c
说明:因debian 9的C标准库太新,直接gcc编译,复制到智龙主板运行提示内核太旧.所以使用了精简的C库dietlibc
3.运行
程序复制到智龙根目录下运行
[root@Loongson-gz:/]#./spilcd
很快整屏填充绿色.
|
|