工作方式1:
当CPHA=0、CPOL=0时SPI总线工作在方式1。MISO引脚上的数据在第一个SPSCK沿跳变之前已经上线了,而为了保证正确传输,MOSI引脚的MSB位必须与SPSCK的第一个边沿同步,在SPI传输过程中,首先将数据上线,然后在同步时钟信号的上升沿时,SPI的接收方捕捉位信号,在时钟信号的一个周期结束时(下降沿),下一位数据信号上线,再重复上述过程,直到一个字节的8位信号传输结束。
工作方式2:
当CPHA=0、CPOL=1时SPI总线工作在方式2。与前者唯一不同之处只是在同步时钟信号的下降沿时捕捉位信号,上升沿时下一位数据上线。
工作方式3:
当CPHA=1、CPOL=0时SPI总线工作在方式3。MISO引脚和MOSI引脚上的数据的MSB位必须与SPSCK的第一个边沿同步,在SPI传输过程中,在同步时钟信号周期开始时(上升沿)数据上线,然后在同步时钟信号的下降沿时,SPI的接收方捕捉位信号,在时钟信号的一个周期结束时(上升沿),下一位数据信号上线,再重复上述过程,直到一个字节的8位信号传输结束。
工作方式4:
当CPHA=1、CPOL=1时SPI总线工作在方式4。与前者唯一不同之处只是在同步时钟信号的上升沿时捕捉位信号,下降沿时下一位数据上线。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GPIO_PB_8 24
#define GPIO_PH_4 116
#define GPIO_PH_5 117
#define GPIO_PE_11 75
#define GPIO_PE_12 76
#define SCLK GPIO_PH_4
#define MOSI GPIO_PH_5
#define CS GPIO_PE_11
#define Reset GPIO_PE_12
#define LCDPWM GPIO_PB_8
#define OUTP 1 //表示GPIO接口方向为输出
#define INP 0 //表示GPIO接口方向为输入
#define set_gpio_value gpio_set_value
#define get_gpio_value gpio_get_value
//默认为1则一直关比背光灯,默认为0一直打开背光灯
#define LCDdefault 0
//数据循环发送次数
#define sendnum 60000
//先释放一下几个gpio口为了方便以后的占用
static void spi_free_gpio(void)
{
gpio_free(MOSI);
gpio_free(SCLK);
gpio_free(CS);
gpio_free(Reset);
gpio_free(LCDPWM);
}
//申请GPIO口资源
static int spi_request_gpio(void)
{
if (gpio_request(MOSI, "spi_mosi") < 0)
{
printk("fail to request mosi\n");
return -1;
}
if (gpio_request(SCLK, "spi_sclk\n") < 0)
{
printk("fail to request sclk\n");
return -1;
}
if (gpio_request(CS, "spi_cs") < 0)
{
printk("fail to request cs\n");
return -1;
}
if (gpio_request(Reset, "spi_reset") < 0)
{
printk("fail to request reset\n");
return -1;
}
if (gpio_request(LCDPWM, "spi_lcdpwm") < 0)
{
printk("fail to request lcdpwm\n");
return -1;
}
return 0;
}
/* SPI端口初始化 用于每次传递参数 */
static void spi_init(void)
{
// //spi模拟通信初始化
// gpio_direction_output(CS, 1);
// gpio_direction_output(SCLK, 1);
// gpio_direction_output(MOSI, 0);
gpio_set_value(SCLK, 0);
gpio_set_value(MOSI, 0);
}
/*
从设备使能
enable:为1时,使能信号有效,SS低电平
为0时,使能信号无效,SS高电平
*/
//因为不确定cs为高低才是使能,所以先保持原样
void ss_enable(int enable)
{
if (enable)
set_gpio_value(CS, 0); //SS低电平,从设备使能有效
else
set_gpio_value(CS, 1); //SS高电平,从设备使能无效
}
/* SPI字节写 */
void spi_write_cmd(unsigned char b)
{
//变量初始化
int i;
/* SPI端口初始化 */
spi_init();
// udelay(5);
ss_enable(1); //从设备使能有效,通信开始
// udelay(5);
for (i = 8; i >= 0; i--)
{
if (i == 8)
{
set_gpio_value(SCLK, 0);
// udelay(5); //延时
set_gpio_value(MOSI, 0); //如果是写命令则首位先写0
// udelay(5); //延时
set_gpio_value(SCLK, 1); // CPHA=1,在时钟的第一个跳变沿采样
// udelay(5);
}
else
{
set_gpio_value(SCLK, 0);
// udelay(5); //延时
set_gpio_value(MOSI, b & 1 << i); //从高位7到低位0进行串行写入
// udelay(5); //延时
set_gpio_value(SCLK, 1); // CPHA=1,在时钟的第一个跳变沿采样
// udelay(5); //延时
} //延时
}
set_gpio_value(SCLK, 0);
// udelay(5);
//结束单次通信
ss_enable(0);
}
void spi_write_data(unsigned char b)
{
//变量初始化
int i;
/* SPI端口初始化 */
spi_init();
// udelay(5);
ss_enable(1); //从设备使能有效,通信开始
// udelay(5); //延时
for (i = 8; i >= 0; i--)
{
if (i == 8)
{
set_gpio_value(SCLK, 0);
// udelay(5); //延时
set_gpio_value(MOSI, 1); //如果是写数据则首位先写1
// udelay(5); //延时
set_gpio_value(SCLK, 1); // CPHA=1,在时钟的第一个跳变沿采样
// udelay(5);
}
else
{
set_gpio_value(SCLK, 0);
// udelay(5); //延时
set_gpio_value(MOSI, b & 1 << i); //从高位7到低位0进行串行写入
// udelay(5); //延时
set_gpio_value(SCLK, 1); // CPHA=1,在时钟的第一个跳变沿采样
// udelay(5); //延时
}
}
set_gpio_value(SCLK, 0);
// udelay(5);
//结束单次通信
ss_enable(0);
}
//屏幕初始化函数
static void spi_lcd_init(void)
{
//spi模拟通信初始化
gpio_direction_output(CS, 1);
gpio_direction_output(SCLK, 1);
gpio_direction_output(MOSI, 0);
//屏幕初始化
gpio_direction_output(LCDPWM, 1);
gpio_direction_output(Reset, 1);
gpio_set_value(LCDPWM, LCDdefault);
gpio_set_value(Reset, 1);
mdelay(10);
gpio_set_value(Reset, 0);
mdelay(100);
gpio_set_value(Reset, 1);
mdelay(500);
spi_write_cmd(0x11);
mdelay(120);
//--------------------------------ST7789S Frame rate setting----------------------------------//
spi_write_cmd(0xb2);
spi_write_data(0x0c);
spi_write_data(0x0c);
spi_write_data(0x00);
spi_write_data(0x33);
spi_write_data(0x33);
spi_write_cmd(0xb7);
spi_write_data(0x35);
spi_write_cmd(0x3A);
spi_write_data(0x55);
//---------------------------------ST7789S Power setting--------------------------------------//
spi_write_cmd(0xbb);
spi_write_data(0x30);//vcom
spi_write_cmd(0xc3);
spi_write_data(0x1C);
spi_write_cmd(0xc4);
spi_write_data(0x18);
spi_write_cmd(0xc6);
spi_write_data(0x0f);
spi_write_cmd(0xd0);
spi_write_data(0xa4);
spi_write_data(0xa2);
//--------------------------------ST7789S gamma setting---------------------------------------//
spi_write_cmd(0xe0);
spi_write_data(0xf0);
spi_write_data(0x00);
spi_write_data(0x0a);
spi_write_data(0x10);
spi_write_data(0x12);
spi_write_data(0x1b);
spi_write_data(0x39);
spi_write_data(0x44);
spi_write_data(0x47);
spi_write_data(0x28);
spi_write_data(0x12);
spi_write_data(0x10);
spi_write_data(0x16);
spi_write_data(0x1b);
spi_write_cmd(0xe1);
spi_write_data(0xf0);
spi_write_data(0x00);
spi_write_data(0x0a);
spi_write_data(0x10);
spi_write_data(0x11);
spi_write_data(0x1a);
spi_write_data(0x3b);
spi_write_data(0x34);
spi_write_data(0x4e);
spi_write_data(0x3a);
spi_write_data(0x17);
spi_write_data(0x16);
spi_write_data(0x21);
spi_write_data(0x22);
//*********SET RGB Interfae***************
spi_write_cmd(0xB0);
spi_write_data(0x11); //set RGB interface and DE mode.
spi_write_data(0x00);
spi_write_data(0x00);
spi_write_cmd(0xB1);
spi_write_data(0x40); // set DE mode ; SET Hs,Vs,DE,DOTCLK signal polarity
spi_write_data(0x00);
spi_write_data(0x00);
spi_write_cmd(0x3a);
spi_write_data(0x55); //18 RGB ,55-16BIT RGB
//************************
spi_write_cmd(0x11);
mdelay(120); //Delay 120ms
spi_write_cmd(0x29); //display on
spi_write_cmd(0x2c);
printk("finished invitialized.....\n");
}
//设置写入色块的坐标
void addset(unsigned int x,unsigned int y)
{
spi_write_cmd(0x2a); //发出x坐标
spi_write_data(x>>8);
spi_write_data(x&0xff);
spi_write_cmd(0x2b); //发出y坐标
spi_write_data(y>>8);
spi_write_data(y&0xff);
spi_write_cmd(0x2c);
}
//写入色块的函数
void setcolor(void)
{
int ret;
int x, y;
u16 color0 = 0x001f; // RGB565, blue
u16 color1 = 0xf800; // red
u16 color2 = 0x07e0; // green
u16 color3 = 0xffff; // white
u16 color;
//初始化的时候已经把所有需要的口都重新占用了,所以不需要再次申请了
// ret = gpio_request(pdata->reset_io, spi->modalias);
// if (ret < 0)
// goto err0;
// ret = gpio_request(pdata->dc_io, spi->modalias);
// if (ret < 0)
// goto err1;
spi_lcd_init(); //初始化屏
addset(0, 0); //从屏的0,0坐标开始刷
//刷屏, 把整屏分成4块,每块颜色不同
// gpio_direction_output(pdata->dc_io, 1);
for (y = 0; y < 320; y++)
{
for (x = 0; x < 240; x++)
{
if (x < 120)
color = (y < 160) ? color0 : color1;
else
color = (y < 160) ? color2 : color3;
spi_write_data(color >> 8);
spi_write_data(color & 0xff);
}
}
printk("set color finished! ...\n");
}
//入口主函数
static int __init ya15c_spi_init(void)
{
//spi端口先释放,防止之前有人使用
spi_free_gpio();
//占用函数要用的几个IO口
if (spi_request_gpio())
{
printk("ya15c spi initializer failure...\n");
return -1;
}
//发送命令次数
int num = sendnum;
unsigned char datawhite = 0xff;
unsigned char datablack = 0x00;
//屏幕初始化
printk("start to set color! ...\n");
// setcolor();
spi_lcd_init();
//开始循环发送信息
// printk("start send message... \n");
// while (num >= 0)
// {
// spi_write_data(datawhite);
// spi_write_data(datawhite);
// spi_write_data(datawhite);
// // udelay(20);
// num--;
// }
// num = 60000;
// while (num >= 0)
// {
// spi_write_data(datablack);
// spi_write_data(datablack);
// spi_write_data(datablack);
// // udelay(20);
// num--;
// }
return 0;
}
static void __exit ya15c_spi_exit(void)
{
printk("ya15c exit!\n");
}
module_init(ya15c_spi_init);
module_exit(ya15c_spi_exit);
MODULE_LICENSE("GPL");
本文的时序是先拉低然后放数据,上升自动捕获,这个主要还是看对应的spi通信的协议,或者可以自己设置对应的协议,本文是因为已经定了,所以就只能用这种通信方式。
模拟时序的方式就是根据拉高拉低几个io口,具体要用哪几个io口要看电路图
spi_request_gpio之前先free的原因是,已经确认这几个io口就是要给这个驱动使用,所以就可以放心free,不然可能会因为别的程序已经占用而没有办法申请资源
spi_write_cmd和spi_write_data的区别就是一共发送九个bit位,但是第一位是0还是1,这个就要看接受spi数据的手册要求了,不过一般都是一样的。
spi_lcd_init这个是LCD屏幕初始化的函数,这个因为不同的屏幕内容可能会有差异,可以根据自己的屏幕查找(上网搜索)相应的函数数据以及命令内容
setcolor(void) 这个函数包含LCD初始化函数,是用于spi模拟的初始化之后写入色块的,但是由于这样模拟spi写入太过于慢,所以就换了RGB通信也就是现在的LCD初始化参数
原本的spi通信的屏幕参数可以参考这个网页:
https://blog.csdn.net/jklinux/article/details/74411470?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159418532019724811861656%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159418532019724811861656&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-1-74411470.pc_v1_rank_blog_v1&utm_term=spi
循环发送信息,发送的就是纯白和纯黑的颜色,只适用于测试
如果有在做类似项目的人可以作为参考使用,如果有什么问题,可以评论一起交流探讨,一起进步