加载出现段错误,卸载出现正在使用
我自己试出来的解决方法:修改设备树和驱动里的compatible属性(和上一次的不一样),重试加载和卸载正常,但是我加载模块,然后重启开发板,第二次加载模块,问题就又重现了。
我使用韦老师的oled模块一切正常,我是使用ili9341的lcd屏幕,参照改的驱动程序。
请老师帮我看下为啥出现这种问题。谢谢了。
下面是我的 驱动代码和设备树信息。(参考的老师代码是70天驱动直播课中spi驱动oled,使用freambuffer框架)。
#include “linux/delay.h”
#include “linux/kthread.h”
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/spi/spi.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/uaccess.h>
#include <linux/fb.h>
#include <linux/dma-mapping.h>
#define myoled3_SET_XY 99
#define myoled3_SET_XY_WRITE_DATA 100
#define myoled3_SET_XY_WRITE_DATAS 101
#define myoled3_SET_DATAS 102 /* 102为低8位, 高16位用来表示长度 */
#define DARKBLUE 0X01CF //ÉîÀ¶É«
//为0 表示命令,为1表示数据
#define myoled3_CMD 0
#define myoled3_DATA 1
#define myoled3_W 240
#define myoled3_H 320
#define USE_HORIZONTAL 0
typedef struct
{
u16 width;
u16 height;
u16 id;
u8 dir;
u16 wramcmd;
u16 setxcmd;
u16 setycmd;
}_myoled3_dev;
struct fb_info *oled3_fb_info;
struct spi_device *ili9431_oled3_device;
static unsigned int pseudo_palette[16];
static struct gpio_desc *myoled3_dc;
static struct gpio_desc *myoled3_reset;
static struct gpio_desc *myoled3_led;
static struct gpio_desc *myoled3_cs;
static _myoled3_dev myoled3dev;
static struct task_struct *oled3_kthread;
static int myoled3_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
unsigned transp, struct fb_info *info)
{
return 1; /* unkown type */
}
static struct fb_ops myfb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = myoled3_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
/**********************************************************************
* 函数名称: myoled3_write_cmd
* 功能描述: myoled3向特定地址写入数据或者命令
* 输入参数:@uc_data :要写入的数据
@uc_cmd:为1则表示写入数据,为0表示写入命令
* 输出参数:无
* 返 回 值: 无
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/04 V1.0 芯晓 创建
***********************************************************************/
static void myoled3_write_cmd_data(unsigned char uc_data,unsigned char uc_cmd)
{
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
if(uc_cmd==0)
{
//*GPIO4_DR_s &= ~(1<<20);//拉低,表示写入指令
////gpiod_set_value(myoled3_cs,1);
gpiod_set_value(myoled3_dc, 0);
}
else
{
//*GPIO4_DR_s |= (1<<20);//拉高,表示写入数据
////gpiod_set_value(myoled3_cs,1);
gpiod_set_value(myoled3_dc, 1);
}
// spi_writeread(ESCPI1_BASE,uc_data);//写入
spi_write(ili9431_oled3_device, &uc_data, 1);
////gpiod_set_value(myoled3_cs,0);
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}
static void myoled3_write_datas(unsigned char *buf, int len)
{
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
////gpiod_set_value(myoled3_cs,1);
//*GPIO4_DR_s |= (1<<20);//拉高,表示写入数据
gpiod_set_value(myoled3_dc, 1);
// spi_writeread(ESCPI1_BASE,uc_data);//写入
spi_write(ili9431_oled3_device, buf, len);
////gpiod_set_value(myoled3_cs,0);
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}
static void myoled3_RESET(void)
{
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
gpiod_set_value(myoled3_reset,0);
msleep(100);
gpiod_set_value(myoled3_reset,1);
msleep(50);
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}
void myoled3_WriteReg(u8 myoled3_Reg, u16 myoled3_RegValue)
{
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
myoled3_write_cmd_data(myoled3_Reg,myoled3_CMD);
myoled3_write_cmd_data(myoled3_RegValue,myoled3_DATA);
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}
void myoled3_direction(u8 direction)
{
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
myoled3dev.setxcmd=0x2A;
myoled3dev.setycmd=0x2B;
myoled3dev.wramcmd=0x2C;
switch(direction){
case 0:
myoled3dev.width=myoled3_W;
myoled3dev.height=myoled3_H;
myoled3_WriteReg(0x36,(1<<3)|(0<<6)|(0<<7));//BGR==1,MY==0,MX==0,MV==0
break;
case 1:
myoled3dev.width=myoled3_H;
myoled3dev.height=myoled3_W;
myoled3_WriteReg(0x36,(1<<3)|(0<<7)|(1<<6)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
break;
case 2:
myoled3dev.width=myoled3_W;
myoled3dev.height=myoled3_H;
myoled3_WriteReg(0x36,(1<<3)|(1<<6)|(1<<7));//BGR==1,MY==0,MX==0,MV==0
break;
case 3:
myoled3dev.width=myoled3_H;
myoled3dev.height=myoled3_W;
myoled3_WriteReg(0x36,(1<<3)|(1<<7)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
break;
default:break;
}
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}
void myoled3_WriteRAM_Prepare(void)
{
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
myoled3_write_cmd_data(myoled3dev.wramcmd,myoled3_CMD);
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}
void myoled3_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd)
{
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
myoled3_write_cmd_data(myoled3dev.setxcmd,myoled3_CMD);
myoled3_write_cmd_data(xStar>>8,myoled3_DATA);
myoled3_write_cmd_data(0x00FF&xStar,myoled3_DATA);
myoled3_write_cmd_data(xEnd>>8,myoled3_DATA);
myoled3_write_cmd_data(0x00FF&xEnd,myoled3_DATA);
myoled3_write_cmd_data(myoled3dev.setycmd,myoled3_CMD);
myoled3_write_cmd_data(yStar>>8,myoled3_DATA);
myoled3_write_cmd_data(0x00FF&yStar,myoled3_DATA);
myoled3_write_cmd_data(yEnd>>8,myoled3_DATA);
myoled3_write_cmd_data(0x00FF&yEnd,myoled3_DATA);
myoled3_WriteRAM_Prepare(); //
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}
void myoled3_WriteData_16Bit(u16 Data)
{
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
//gpiod_set_value(myoled3_cs,1);
gpiod_set_value(myoled3_dc,1);
spi_write(ili9431_oled3_device,&Data,2);
//gpiod_set_value(myoled3_cs,0);
//printk("%s %s %d\n", FILE, FUNCTION, LINE);
}
void myoled3_Clear(u16 Color)
{
int i=0,m=0;
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
myoled3_SetWindows(0,0,myoled3dev.width-1,myoled3dev.height-1);
//gpiod_set_value(myoled3_cs,1);
gpiod_set_value(myoled3_dc,1);
for(i=0;i<myoled3dev.height;i++)
{
for(m=0;m<myoled3dev.width;m++)
{
myoled3_WriteData_16Bit(Color);
}
printk("%s %s %d\n", __FILE__, __FUNCTION__, i);
}
//gpiod_set_value(myoled3_cs,0);
//printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}
/**********************************************************************
* 函数名称: myoled3_init
* 功能描述: myoled3_init的初始化,包括SPI控制器得初始化
* 输入参数:无
* 输出参数: 初始化的结果
* 返 回 值: 成功则返回0,否则返回-1
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/03/15 V1.0 芯晓 创建
***********************************************************************/
static int myoled3_hardware_init(void)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
myoled3_RESET();
myoled3_write_cmd_data(0xCF,myoled3_CMD);//关闭显示
myoled3_write_cmd_data(0x00,myoled3_DATA);//设置 lower column address
myoled3_write_cmd_data(0xC9,myoled3_DATA);//设置 higher column address
myoled3_write_cmd_data(0X30,myoled3_DATA);//设置 display start line
myoled3_write_cmd_data(0xED,myoled3_CMD);//设置page address
myoled3_write_cmd_data(0x64,myoled3_DATA);// contract control
myoled3_write_cmd_data(0x03,myoled3_DATA);//128
myoled3_write_cmd_data(0X12,myoled3_DATA);//设置 segment remap
myoled3_write_cmd_data(0X81,myoled3_DATA);//normal /reverse
myoled3_write_cmd_data(0xE8,myoled3_CMD);//multiple ratio
myoled3_write_cmd_data(0x85,myoled3_DATA);//duty = 1/64
myoled3_write_cmd_data(0x10,myoled3_DATA);//com scan direction
myoled3_write_cmd_data(0x7A,myoled3_DATA);//set displat offset
myoled3_write_cmd_data(0xCB,myoled3_CMD);//
myoled3_write_cmd_data(0x39,myoled3_DATA);//set osc division
myoled3_write_cmd_data(0x2C,myoled3_DATA);//
myoled3_write_cmd_data(0x00,myoled3_DATA);//ser pre-charge period
myoled3_write_cmd_data(0x34,myoled3_DATA);//
myoled3_write_cmd_data(0x02,myoled3_DATA);//set com pins
myoled3_write_cmd_data(0xF7,myoled3_CMD);//
myoled3_write_cmd_data(0x20,myoled3_DATA);//set vcomh
myoled3_write_cmd_data(0xEA,myoled3_CMD);//
myoled3_write_cmd_data(0x00,myoled3_DATA);//set charge pump disable
myoled3_write_cmd_data(0x00,myoled3_DATA);//
myoled3_write_cmd_data(0xC0,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x1B,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0xC1,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0xC5,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x30,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x30,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0xC7,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0XB7,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x36,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x08,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x3A,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x55,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0xB1,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x1A,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0xB6,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x0A,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0xA2,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0xF2,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x26,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x01,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0xE0,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x0F,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x2A,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x28,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x08,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x0E,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x08,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x54,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0XA9,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x43,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x0A,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x0F,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0XE1,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x15,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x17,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x07,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x11,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x06,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x2B,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x56,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x3C,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x05,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x10,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x0F,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x3F,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x3F,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x0F,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x2B,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x01,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x3f,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x2A,myoled3_CMD);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x00,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0xef,myoled3_DATA);//set dispkay on
myoled3_write_cmd_data(0x11,myoled3_CMD);//set dispkay on
msleep(120);
myoled3_write_cmd_data(0x29,myoled3_CMD);//set dispkay on
myoled3dev.setxcmd=0x2A;
myoled3dev.setycmd=0x2B;
myoled3dev.wramcmd=0x2C;
myoled3dev.width=myoled3_W;
myoled3dev.height=myoled3_H;
myoled3_WriteReg(0x36,(1<<3)|(0<<6)|(0<<7));//BGR==1,MY==0,MX==0,MV==0
myoled3_direction(USE_HORIZONTAL);
gpiod_set_value(myoled3_led,1);
myoled3_Clear(DARKBLUE);
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
static int oled3_thread(void *data)
{
while (1)
{
/* 把Framebuffer的数据刷到oled3上去 */
myoled3_write_datas(oled3_fb_info->screen_base, oled3_fb_info->fix.smem_len);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ);
if (kthread_should_stop()) {
set_current_state(TASK_RUNNING);
break;
}
}
return 0;
}
static int oled3_probe(struct spi_device *spi)
{
dma_addr_t phy_addr;
ili9431_oled3_device = spi;
oled3_fb_info = framebuffer_alloc(0, &spi->dev);
/* 1.2 设置fb_info */
/* a. var : oled3分辨率、颜色格式 */
oled3_fb_info->var.xres_virtual = oled3_fb_info->var.xres = 280;
oled3_fb_info->var.yres_virtual = oled3_fb_info->var.yres = 320;
oled3_fb_info->var.bits_per_pixel = 1; /* rgb565 */
/* b. fix */
strcpy(oled3_fb_info->fix.id, "100ask_myoled3");
oled3_fb_info->fix.smem_len = oled3_fb_info->var.xres * oled3_fb_info->var.yres * oled3_fb_info->var.bits_per_pixel / 8;
/* c. 分配显存 */
oled3_fb_info->screen_base = dma_alloc_wc(NULL, oled3_fb_info->fix.smem_len, &phy_addr,
GFP_KERNEL);
oled3_fb_info->fix.smem_start = phy_addr; /* fb的物理地址 */
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
oled3_fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
oled3_fb_info->fix.visual = FB_VISUAL_MONO10;
oled3_fb_info->fix.line_length = oled3_fb_info->var.xres * oled3_fb_info->var.bits_per_pixel / 8;
/* d. fbops */
oled3_fb_info->fbops = &myfb_ops;
oled3_fb_info->pseudo_palette = pseudo_palette;
register_framebuffer(oled3_fb_info);
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
myoled3_dc = gpiod_get(&spi->dev, "dc", GPIOD_OUT_HIGH);
//myoled3_cs = gpiod_get(&spi->dev, "cs", GPIOD_OUT_LOW);
myoled3_reset = gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
myoled3_led = gpiod_get(&spi->dev, "led", GPIOD_OUT_HIGH);
myoled3_hardware_init();
/* 创建1个内核线程,用来把Framebuffer的数据通过SPI控制器发送给oled3 */
oled3_kthread = kthread_create(oled3_thread, NULL, "100ask_oled3");
wake_up_process(oled3_kthread);
return 0;
}
static int oled3_remove(struct spi_device *spi)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
kthread_stop(oled3_kthread);
/* 反注册 fb_info */
unregister_framebuffer(oled3_fb_info);
//gpiod_put(oled3_dc);
return 0;
}
static const struct of_device_id oled3_of_match[] = {
{.compatible = "100ask,myoled4"},
{}
};
struct spi_driver ili9341_oled3_driver = {
.driver ={
.name = "ili9341_oled3",
.of_match_table = oled3_of_match,
},
.probe = oled3_probe,
.remove = oled3_remove,
};
int ili9341_oled3_init (void)
{
return spi_register_driver(&ili9341_oled3_driver);
}
static void ili9341_oled3_exit(void)
{
spi_unregister_driver(&ili9341_oled3_driver);
}
module_init(ili9341_oled3_init);
module_exit(ili9341_oled3_exit);
MODULE_LICENSE(“GPL v2”);
myoled:myoled {
compatible = "100ask,myoled4";
reg = <0>;
spi-max-frequency = <32000000>;
dc-gpios = <&gpio4 20 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio4 21 GPIO_ACTIVE_HIGH>;
led-gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>;
status = "okay";
};
oled: oled {
compatible = "100ask,oled";
reg = <0>;
spi-max-frequency = <1000000>;
dc-gpios = <&gpio4 20 GPIO_ACTIVE_HIGH>;
};