嵌入式Linux--驱动ST7789驱动芯片的TFT屏(一)
目录
- 一、步骤
- 二、修改设备树
- 三、编写驱动代码
- 1、引脚连线
- 2、编写Makefile文件
- 3、编写驱动
- 四、编写驱动测试代码
- 五、测试
小屏幕:
- 240x240分辨率
- 1.3inch大
效果图:
一、步骤
- 修改设备树
- 编译出.dtb文件
- 通过网络更新开发板上的设备树文件
- 编写驱动
- 编译出.ko文件
- 编写驱动测试文件
- 编译出驱动测试可执行文件
- 小屏幕正确插线
- 安装驱动模块.ko–小屏幕刷屏
- 测试驱动测试可执行文件
- 完成
二、修改设备树
在imx6ull-alientek-emmc.dts上添加:
//增加引脚控制节点
/{ // 根节点...... // 其他代码ipsRes {#address-cells = <1>;#size-cells = <1>;compatible = "liefyuan-ipsRes";pinctrl-names = "default";pinctrl-0 = <&pinctrl_ipsRes>;res-gpio = <&gpio1 1 GPIO_ACTIVE_HIGH>;status = "okay";};ipsDc {#address-cells = <1>;#size-cells = <1>;compatible = "liefyuan-ipsDc";pinctrl-names = "default";pinctrl-0 = <&pinctrl_ipsDc>;dc-gpio = <&gpio1 4 GPIO_ACTIVE_HIGH>;status = "okay";};...... // 其他代码};
//功能引脚节点
&iomuxc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_hog_1>;......//其他代码pinctrl_ipsRes: ipsRes { //屏幕复位u引脚fsl,pins = <MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0x10B0 /* LED0 */>;}; pinctrl_ipsDc: ipsDc { //屏幕dc(data or command)u引脚fsl,pins = <MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0x10B0 >;};......//其他代码};//节点追加内容
&ecspi3 {fsl,spi-num-chipselects = <1>;cs-gpio = <&gpio1 20 GPIO_ACTIVE_LOW>; /* cant't use cs-gpios! */pinctrl-names = "default";pinctrl-0 = <&pinctrl_ecspi3>;status = "okay";spidev: ipsTft@0 {compatible = "alientek,ipsTft";spi-max-frequency = <1000000000>;reg = <0>;};
};
查看imx6ull.dtsi文件可以看到这个节点:
/ {......//其他代码soc {#address-cells = <1>;#size-cells = <1>;compatible = "simple-bus";interrupt-parent = <&gpc>;ranges;......//其他代码aips1: aips-bus@02000000 {compatible = "fsl,aips-bus", "simple-bus";#address-cells = <1>;#size-cells = <1>;reg = <0x02000000 0x100000>;ranges;spba-bus@02000000 {compatible = "fsl,spba-bus", "simple-bus";#address-cells = <1>;#size-cells = <1>;reg = <0x02000000 0x40000>;ranges;......//其他代码ecspi3: ecspi@02010000 {#address-cells = <1>;#size-cells = <0>;compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";reg = <0x02010000 0x4000>;interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clks IMX6UL_CLK_ECSPI3>,<&clks IMX6UL_CLK_ECSPI3>;clock-names = "ipg", "per";dmas = <&sdma 7 7 1>, <&sdma 8 7 2>;dma-names = "rx", "tx";status = "disabled";};};};};
};
因此要想从开发板上看到这个节点就得:
/sys/firmware/devicetree/base/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02010000 # ls
#address-cells dma-names pinctrl-0
#size-cells dmas pinctrl-names
clock-names fsl,spi-num-chipselects reg
clocks interrupts status
compatible ipsTft@0
cs-gpio name
三、编写驱动代码
1、引脚连线
因此引脚连线:
TFT屏 | Mini板外接IO口 | 描述 |
---|---|---|
GND | GND | |
VCC | 3.3V | |
SCL | 20 | UART2_CTR |
SDA | 18 | UART2_RXD |
RES | 07 | GPIO 1 |
DC | 10 | GPIO 4 |
BLK | NC | NC |
2、编写Makefile文件
Makefile
KERNELDIR := /home/liefyuan/linux/project_drivers/kernelCURRENT_PATH := $(shell pwd)obj-m := tft.obuild : kernel_moduleskernel_modules: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
3、编写驱动
tft.c
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/spi/spi.h> #define ipsTft_CNT 1
#define ipsTft_NAME "ipsTft" #define LCD_W 240
#define LCD_H 240 #define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40
#define BRRED 0XFC07
#define GRAY 0X8430 u8 buf[9] = { RED, GREEN, BLUE, WHITE, BLACK, YELLOW, GRAY, BRRED, CYAN
}; struct ipsTft_dev { dev_t devid; /* 设备号 */ struct cdev cdev; /* cdev */ struct class *class; /* 类 */ struct device *device; /* 设备 */ struct device_node *nd; /* 设备节点 */ int major; /* 主设备号 */ void *private_data; /* 私有数据 */ int dc_gpio; /* 片选所使用的GPIO编号 */ int res_gpio; /* ips屏幕复位引脚 */ int cs_gpio; /* 共用磁力计的cs */
}; static struct ipsTft_dev ipsTftdev; void ipsTft_reginit(struct ipsTft_dev *dev); //1.3寸屏幕
struct spi_lcd_cmd { u8 reg_addr; // command u8 len; //需要从spi_lcd_datas数组里发出数据字节数 int delay_ms; //此命令发送数据完成后,需延时多久
} spi_lcd_cmd_t;struct spi_lcd_cmd_t cmds[] = { {0x36, 1, 30}, {0x3A, 1, 30}, {0xB2, 5, 30}, {0xB7, 1, 30}, {0xBB, 1, 30}, {0xC0, 1, 30}, {0xC2, 1, 30}, {0xC3, 1, 30}, {0xC4, 1, 30}, {0xC6, 1, 30}, {0xD0, 2, 30}, {0xE0, 14, 30}, {0xE1, 14, 30}, {0x21, 0, 30}, {0x11, 0, 120}, {0x29, 0, 30},
}; u8 spi_lcd_datas[] = { 0x00, 0x05, 0x0c,0x0c,0x00,0x33,0x33, 0x35, 0x19, 0x2c, 0x01, 0x12, 0x20, 0x0F, 0xA4,0xA1, 0xD0,0x04,0x0D,0x11,0x13,0x2B,0x3F,0x54,0x4C,0x18,0x0D,0x0B,0x1F,0x23, 0xD0,0x04,0x0C,0x11,0x13,0x2C,0x3F,0x44,0x51,0x2F,0x1F,0x1F,0x20,0x23
};
/* * @description : 向ipsTft多个寄存器写入数据 * @param - dev: ipsTft设备 * @param - reg: 要写入的寄存器首地址 * @param - val: 要写入的数据缓冲区 * @param - len: 要写入的数据长度 * @return : 操作结果 */
static s32 ipsTft_write_regs(struct ipsTft_dev *dev,u8 *buf, u8 len)
{ int ret; struct spi_message m; struct spi_transfer *t; struct spi_device *spi = (struct spi_device *)dev->private_data; t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL); /* 申请内存 */ t->tx_buf = buf; /* 要写入的数据 */ t->len = len; /* 写入的字节数 */ spi_message_init(&m); /* 初始化spi_message */ spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */ ret = spi_sync(spi, &m); /* 同步发送 */ kfree(t); /* 释放内存 */ return ret;
}
/* * @description : 向ipsTft指定寄存器写入指定的值,写一个寄存器 * @param - dev: ipsTft设备 * @param - reg: 要写的寄存器 * @param - data: 要写入的值 * @return : 无 */
static void ipsTft_write_onereg(struct ipsTft_dev *dev, u8 buf)
{ ipsTft_write_regs(dev,&buf, 1); //spi_write(dev,&buf, 1);
}
/* funciton: 写一个命令
*/
void write_command(struct ipsTft_dev *dev, u8 cmd)
{ // dc , command:0 gpio_set_value(dev->dc_gpio, 0); ipsTft_write_onereg(dev,cmd);
}
/* funciton: 写一个数据
*/
void write_data(struct ipsTft_dev *dev, u8 data)
{ gpio_set_value(dev->dc_gpio, 1); ipsTft_write_onereg(dev,data);
}
/* funciton: 写一些数据
*/
static void write_datas(struct ipsTft_dev *dev, int data,int len)
{ gpio_set_value(dev->dc_gpio, 1); ipsTft_write_regs(dev,(u8 *)&data,len);
}
/* * @description : 打开设备 * @param - inode : 传递给驱动的inode * @param - filp : 设备文件,file结构体有个叫做private_data的私有成员变量 * 一般在open的时候将private_data向私有设备结构体赋值。 * @return : 0 成功;其他 失败 */
static int ipsTft_open(struct inode *inode, struct file *filp)
{ filp->private_data = &ipsTftdev; /* 设置私有数据 */ // TODO somethingreturn 0;
}
/* * @description : 关闭/释放设备 * @param - filp : 要关闭的设备文件(文件描述符) * @return : 0 成功;其他 失败 */
static int ipsTft_release(struct inode *inode, struct file *filp)
{ return 0;
}
/* ipsTft操作函数 */
static const struct file_operations ipsTft_ops = { .owner = THIS_MODULE, .open = ipsTft_open, .release = ipsTft_release,
}; void Address_set(struct ipsTft_dev *dev,unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2)
{ write_command(dev,0x2a); write_data(dev,x1>>8); write_data(dev,x1); write_data(dev,x2>>8); write_data(dev,x2); write_command(dev,0x2b); write_data(dev,y1>>8); write_data(dev,y1); write_data(dev,y2>>8); write_data(dev,y2); write_command(dev,0x2C);
}
/* 刷屏函数
*/
void LCD_Clear(struct ipsTft_dev *dev,u16 Color)
{ u16 i,j; Address_set(dev,0,0,LCD_W-1,LCD_H-1); write_command(dev,0x2C); for(i=0;i<LCD_W;i++) { for (j=0;j<LCD_H;j++) { //write_datas(dev,0xF800,2); //全红 write_data(dev,Color>>8); write_data(dev,Color); } }
}
/* * ipsTft内部寄存器初始化函数 * @param : 无 * @return : 无 */
void ipsTft_reginit(struct ipsTft_dev *dev)
{ int i, j, n; gpio_set_value(ipsTftdev.res_gpio, 0); mdelay(20); gpio_set_value(ipsTftdev.res_gpio, 1); mdelay(20); n = 0; // n用于记录数据数组spi_lcd_datas的位置 //发命令,并发出命令所需的数据 for (i = 0; i < ARRAY_SIZE(cmds); i++) //命令 { write_command(dev, cmds[i].reg_addr); for (j = 0; j < cmds[i].len; j++) //发出命令后,需要发出的数据 if(cmds[i].len!=0) write_data(dev, spi_lcd_datas[n++]); if (cmds[i].delay_ms) //如有延时则延时 mdelay(cmds[i].delay_ms); } n=0; LCD_Clear(dev,RED); // 安装驱动模块的时候刷个红色的屏printk("ips init finish!\n");
} /* * @description : spi驱动的probe函数,当驱动与 * 设备匹配以后此函数就会执行 * @param - client : spi设备 * @param - id : spi设备ID * */
static int ipsTft_probe(struct spi_device *spi)
{ int ret = 0; /* 1、构建设备号 */ if (ipsTftdev.major) { ipsTftdev.devid = MKDEV(ipsTftdev.major, 0); register_chrdev_region(ipsTftdev.devid, ipsTft_CNT, ipsTft_NAME); } else { alloc_chrdev_region(&ipsTftdev.devid, 0, ipsTft_CNT, ipsTft_NAME); ipsTftdev.major = MAJOR(ipsTftdev.devid); } /* 2、注册设备 */ cdev_init(&ipsTftdev.cdev, &ipsTft_ops); cdev_add(&ipsTftdev.cdev, ipsTftdev.devid, ipsTft_CNT); /* 3、创建类 */ ipsTftdev.class = class_create(THIS_MODULE, ipsTft_NAME); if (IS_ERR(ipsTftdev.class)) { return PTR_ERR(ipsTftdev.class); } /* 4、创建设备 */ ipsTftdev.device = device_create(ipsTftdev.class, NULL, ipsTftdev.devid, NULL, ipsTft_NAME); if (IS_ERR(ipsTftdev.device)) { return PTR_ERR(ipsTftdev.device); } /* 获取设备树中的spi3外设节点 -- 查询imx6ull.dtsi设备树头文件文件*/ipsTftdev.nd = of_find_node_by_path("/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02010000"); if(ipsTftdev.nd == NULL) { printk("ecspi3 node not find!\r\n"); return -EINVAL; } /* 获取设备树中的gpio属性 */ /* 获取设备树中CS信号节点 */ ipsTftdev.cs_gpio = of_get_named_gpio(ipsTftdev.nd, "cs-gpio", 0); if(ipsTftdev.cs_gpio < 0) { printk("can't get cs-gpio"); return -EINVAL; } /* 获取设备树中RES复位信号节点 */ ipsTftdev.nd = of_find_node_by_path("/ipsRes"); if(ipsTftdev.nd == NULL) { printk("res-gpio node not find!\r\n"); return -EINVAL; } ipsTftdev.res_gpio = of_get_named_gpio(ipsTftdev.nd, "res-gpio", 0); if(ipsTftdev.res_gpio < 0) { printk("can't get res-gpio"); return -EINVAL; } /* 获取设备树中DC数据命令控制信号节点 */ ipsTftdev.nd = of_find_node_by_path("/ipsDc"); if(ipsTftdev.nd == NULL) { printk("ipsDcgpio node not find!\r\n"); return -EINVAL; } ipsTftdev.dc_gpio = of_get_named_gpio(ipsTftdev.nd, "dc-gpio", 0); if(ipsTftdev.dc_gpio < 0) { printk("can't get ipsDc-gpio"); return -EINVAL; } /* 设置GPIO1_IO20为输出,并且输出高电平 */ ret = gpio_direction_output(ipsTftdev.cs_gpio, 1); if(ret < 0) { printk("can't set cs gpio!\r\n"); } ret = gpio_direction_output(ipsTftdev.res_gpio, 1); if(ret < 0) { printk("can't set res gpio!\r\n"); } ret = gpio_direction_output(ipsTftdev.dc_gpio, 1); if(ret < 0) { printk("can't set dc gpio!\r\n"); } /*初始化spi_device */ spi->mode = SPI_MODE_2; /*MODE0,CPOL=0,CPHA=0 */spi_setup(spi); ipsTftdev.private_data = spi; /* 设置私有数据 */ /* 初始化ipsTft内部寄存器 */ ipsTft_reginit(&ipsTftdev); return 0;
}
/* * @description : spi驱动的remove函数,移除spi驱动的时候此函数会执行 * @param - client : spi设备 * @return : 0,成功;其他负值,失败 */
static int ipsTft_remove(struct spi_device *spi)
{ /* 删除设备 */ cdev_del(&ipsTftdev.cdev); unregister_chrdev_region(ipsTftdev.devid, ipsTft_CNT); /* 注销掉类和设备 */ device_destroy(ipsTftdev.class, ipsTftdev.devid); class_destroy(ipsTftdev.class); return 0;
}
/* 传统匹配方式ID列表 */
static const struct spi_device_id ipsTft_id[] = { {"alientek,ipsTft", 0}, {}
};
/* 设备树匹配列表 */
static const struct of_device_id ipsTft_of_match[] = { { .compatible = "alientek,ipsTft" }, { /* Sentinel */ }
};
/* SPI驱动结构体 */
static struct spi_driver ipsTft_driver = { .probe = ipsTft_probe, .remove = ipsTft_remove, .driver = { .owner = THIS_MODULE, .name = "ipsTft", .of_match_table = ipsTft_of_match, }, .id_table = ipsTft_id,
};
/* * @description : 驱动入口函数 * @param : 无 * @return : 无 */
static int __init ipsTft_init(void)
{ return spi_register_driver(&ipsTft_driver);
}
/* * @description : 驱动出口函数 * @param : 无 * @return : 无 */
static void __exit ipsTft_exit(void)
{ spi_unregister_driver(&ipsTft_driver);
}
module_init(ipsTft_init);
module_exit(ipsTft_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("liefyuan");
四、编写驱动测试代码
tftTestApp.c
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
/** @description : main主程序* @param - argc : argv数组元素个数* @param - argv : 具体参数* @return : 0 成功;其他 失败*/
int main(int argc, char *argv[])
{int fd;char *filename;int ret = 0;if (argc != 2) {printf("Error Usage!\r\n");return -1;}filename = argv[1];fd = open(filename, O_RDWR);if(fd < 0) {printf("can't open file %s\r\n", filename);return -1;}else{printf("open the ips!\n");}close(fd); /* 关闭文件 */ return 0;
}
/lib/modules/4.1.15/kernel/drivers/tft # ./tftTestApp /dev/ipsTft
open the ips!
五、测试
安装驱动模块:
- 执行
depmod
- 执行
modprobe tft.ko
- 运行
./tftTestApp /dev/ipsTft
安装前:ls /dev
/ # ls /dev
autofs ram13 tty37
bus ram14 tty38
console ram15 tty39
cpu_dma_latency ram2 tty4
dri ram3 tty40
fb0 ram4 tty41
full ram5 tty42
fuse ram6 tty43
hwrng ram7 tty44
i2c-0 ram8 tty45
i2c-1 ram9 tty46
iio:device0 random tty47
input rfkill tty48
kmsg rtc0 tty49
loop-control snd tty5
loop0 tty tty50
loop1 tty0 tty51
loop2 tty1 tty52
loop3 tty10 tty53
loop4 tty11 tty54
loop5 tty12 tty55
loop6 tty13 tty56
loop7 tty14 tty57
mem tty15 tty58
memory_bandwidth tty16 tty59
mmcblk1 tty17 tty6
mmcblk1boot0 tty18 tty60
mmcblk1boot1 tty19 tty61
mmcblk1p1 tty2 tty62
mmcblk1p2 tty20 tty63
mmcblk1rpmb tty21 tty7
mxc_asrc tty22 tty8
network_latency tty23 tty9
network_throughput tty24 ttymxc0
null tty25 ttymxc2
ppp tty26 ubi_ctrl
pps0 tty27 urandom
pps1 tty28 vcs
ptmx tty29 vcs1
ptp0 tty3 vcsa
ptp1 tty30 vcsa1
pts tty31 video0
ram0 tty32 watchdog
ram1 tty33 watchdog0
ram10 tty34 zero
ram11 tty35 ðA-é
ram12 tty36
安装模块:
/lib/modules/4.1.15/kernel/drivers/tft # depmod
/lib/modules/4.1.15/kernel/drivers/tft # modprobe tft.ko
ips init finish!
如果在线插好的情况下,使用modprobe tft.ko
之后TFT屏就会刷一次屏,刷屏完成以后就打印出ips init finish!
。
安装后:ls /dev
– 多了一个ipsTft
/ # ls /dev
autofs ram12 tty36
bus ram13 tty37
console ram14 tty38
cpu_dma_latency ram15 tty39
dri ram2 tty4
fb0 ram3 tty40
full ram4 tty41
fuse ram5 tty42
hwrng ram6 tty43
i2c-0 ram7 tty44
i2c-1 ram8 tty45
iio:device0 ram9 tty46
input random tty47
ipsTft rfkill tty48
kmsg rtc0 tty49
loop-control snd tty5
loop0 tty tty50
loop1 tty0 tty51
loop2 tty1 tty52
loop3 tty10 tty53
loop4 tty11 tty54
loop5 tty12 tty55
loop6 tty13 tty56
loop7 tty14 tty57
mem tty15 tty58
memory_bandwidth tty16 tty59
mmcblk1 tty17 tty6
mmcblk1boot0 tty18 tty60
mmcblk1boot1 tty19 tty61
mmcblk1p1 tty2 tty62
mmcblk1p2 tty20 tty63
mmcblk1rpmb tty21 tty7
mxc_asrc tty22 tty8
network_latency tty23 tty9
network_throughput tty24 ttymxc0
null tty25 ttymxc2
ppp tty26 ubi_ctrl
pps0 tty27 urandom
pps1 tty28 vcs
ptmx tty29 vcs1
ptp0 tty3 vcsa
ptp1 tty30 vcsa1
pts tty31 video0
ram0 tty32 watchdog
ram1 tty33 watchdog0
ram10 tty34 zero
ram11 tty35 ðA-é
如上,出现了节点了就可以进行驱动测试了:
/lib/modules/4.1.15/kernel/drivers/tft # ./tftTestApp /dev/ipsTft
open the ips!
完成基本测试!
常用操作:
- 将编译出来的.ko文件复制到nfs文件夹下:
cp tft.ko /home/liefyuan/linux/nfs/rootfs/lib/modules/4.1.15/kernel/drivers/tft/
增加了一个小功能,当使用命令./tftTestApp /dev/ipsTft
时屏幕会刷新蓝绿黑白三种颜色。
static int ipsTft_open(struct inode *inode, struct file *filp)
{ filp->private_data = &ipsTftdev; /* 设置私有数据 */ LCD_Clear(&ipsTftdev,BLUE); mdelay(20);LCD_Clear(&ipsTftdev,GREEN);mdelay(20);LCD_Clear(&ipsTftdev,BLACK);mdelay(20);LCD_Clear(&ipsTftdev,WHITE);return 0;
}
嵌入式Linux--驱动ST7789驱动芯片的TFT屏(一)相关推荐
- 嵌入式Linux驱动笔记(二十四)------framebuffer之使用spi-tft屏幕(上)
你好!这里是风筝的博客, 欢迎和我一起交流. 最近入手了一块spi接口的tft彩屏,想着在我的h3板子上使用framebuffer驱动起来. 我们知道: Linux抽象出FrameBuffer这个设备 ...
- 嵌入式Linux驱动大全问世,十年磨一剑,视频!服务!新老客户都有大折扣!
对于学习嵌入式Linux,韦东山老师整理了三条学习路线,适合与不同阶段的学员. 三条嵌入式学习路线 路线一:单片机路线 使用KEL.HAL库来快速的掌握单片机开发 路线二:深入学习单片机/RTOS/U ...
- 华清远见嵌入式Linux驱动开发培训班
课程背景 开放的 Linux 受到广泛的欢迎,得到越来越多公司的支持,但是阻碍 Linux 在各个领域广泛应用的主要因素就是内核/驱动高端人才极度缺乏,Linux源代码中85%是设备驱动,嵌入式系统中 ...
- 嵌入式linux驱动开发之移远4G模块EC800驱动移植指南
回顾下移远4G模块移植过程, 还是蛮简单的.一通百通,无论是其他4G模块都是一样的.这里记录下过程,分享给有需要的人.环境使用正点原子的imax6ul开发板,板子默认支持中兴和移远EC20的驱动,这里 ...
- 嵌入式linux硬件成本,嵌入式Linux驱动和固件有何区别?供应商是如何用固件压缩成本的?...
原标题:嵌入式Linux驱动和固件有何区别?供应商是如何用固件压缩成本的? 作为一个驱动开发者, 你可能发现你面对一个设备必须在它能支持工作前下载固件到它里面. 硬件市场的许多地方的竞争是如此得强烈, ...
- 嵌入式Linux驱动笔记(十八)------浅析V4L2框架之ioctl【转】
转自:https://blog.csdn.net/Guet_Kite/article/details/78574781 权声明:本文为 风筝 博主原创文章,未经博主允许不得转载!!!!!!谢谢合作 h ...
- linux驱动日志格式,( 转)嵌入式Linux驱动Makefile
天气: 晴朗 心情: 高兴 ( 转)嵌入式Linux驱动开发笔记 1.1 模块的编译 Linux驱动一般以模块module的形式来加载,首先需要把驱动编译成模块的形式.简单的例子, Be ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之Pinctrl子系统和GPIO子系统的使用
文章目录 前言 1.Pinctrl子系统 1.1.为什么有Pinctrl子系统 1.2.重要的概念 1.3.代码中怎么引用pinctrl 2.GPIO子系统 2.1.为什么有GPIO子系统 2.2.在 ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之按键驱动框架
文章目录 前言 1.APP怎么读取按键值 1.1.查询方式 1.2.休眠-唤醒方式 1.3.poll方式 1.3.异步通知方式 1.5. 驱动程序提供能力,不提供策略 2.按键驱动程序框架--查询方式 ...
最新文章
- 虚拟化管理的两大棘手之处
- git创建本地版本仓库及注意事项
- OpenLayers学习笔记2——坐标转换问题
- Mysql 索引 总结 —— 概述 || 索引优势劣势|| 索引结构(索引是在MySQL的存储引擎层中实现的)|| BTREE 结构||B+TREE 结构||MySQL中的B+Tree||索引分类
- 【读书笔记】练习的心态
- linux笔记之 rpm常用参数 ,yum安装编译器,httpd服务的开关
- linux cp 时 略过文件,CentOS下执行cp命令式提示略过文件夹
- SRAM,SDRAM,网卡
- 右值引用、移动构造函数和move
- 基于STM32的USB枚举过程学习笔记
- 网络安全实验7 防火墙 Iptables应用
- java项目实战达内代码_2018最新达内学子商城项目静态页面+sql+java代码
- 制作唐诗网页代码_有关于诗词的网页代码
- 学习PLC到底要不要买PLC?
- setex php,python redis setex可以设value为list或者其他数据结构吗?
- multisim变压器反馈式_基于Multisim的电压串联型负反馈电路的仿真与分析
- 安卓自定义View进阶-Canvas之图片文字
- ioc和aop全称是什么
- mysql数据库被勒索删库怎么办
- proguard学习