嵌入式Linux应用开发-第十五章具体单板的按键驱动程序
嵌入式Linux应用开发-第十五章具体单板的按键驱动程序
- 第十五章 具体单板的按键驱动程序(查询方式)
- 15.1 GPIO操作回顾
- 15.2 AM335X的按键驱动程序(查询方式)
- 15.2.1 先看原理图确定引脚及操作方法
- 15.2.2 再看芯片手册确定寄存器及操作方法
- 15.2.3 编程
- 15.2.3.1 程序框架
- 15.2.3.2 硬件相关的代码
- 15.2.3.3 测试
- 15.2.4 课后作业
- 15.3 RK3288的按键驱动程序(查询方式)
- 15.3.1 先看原理图确定引脚及操作方法
- 15.3.2 再看芯片手册确定寄存器及操作方法
- 15.3.3 编程
- 15.3.1.1 程序框架
- 15.3.4 测试
- 15.4 RK3399的按键驱动程序(查询方式)
- 15.4.1 先看原理图确定引脚及操作方法
- 15.4.2 再看芯片手册确定寄存器及操作方法
- 15.4.3 编程
- 15.4.3.1 程序框架
- 15.4.3.2 硬件相关的代码
- 15.4.4 测试
- 15.4.5 课后作业
- 15.5 IMX6ULL-QEMU的按键驱动程序(查询方式)
- 15.5.1 先看原理图确定引脚及操作方法
- 15.5.2 再看芯片手册确定寄存器及操作方法
- 15.5.3 编程
- 15.5.3.1 程序框架
- 15.5.3.2 硬件相关的代码
- 15.5.4 测试
- 15.5.5 课后作业
第十五章 具体单板的按键驱动程序(查询方式)
15.1 GPIO操作回顾
参考《第四章 普适的 GPIO引脚操作方法》、《第五章 具体单板的 GPIO操作方法》。
15.2 AM335X的按键驱动程序(查询方式)
15.2.1 先看原理图确定引脚及操作方法
AM335X是底板+核心板的结构,打开底板原理图 xxxxxx_am335x_v12_原理图.pdf,它有 4个按键,本视频只操作一个按键,原理图如下:
平时按键电平为高,按下按键后电平为低。 按键引脚为 GPIO1_25。
15.2.2 再看芯片手册确定寄存器及操作方法
步骤 1:
使能 GPIO1模块
设置CM_PER_GPIO1_CLKCTRL寄存器的bit[18]为1,bit[1:0]为0x2,该寄存器地址为0x44E00000+0xAC。
步骤 2:
把 GPIO1_25对应的引脚设置为 GPIO模式
要用哪一个寄存器来把 GPIO1_25对应的引脚设置为 GPIO模式?
① 在核心板原理图 ET-som335X原理图.pdf里搜“GPIO1_25”,可以看到下图,确定 pin number为 U16:
② 在芯片手册 AM335x Sitara™ Processors.pdf里搜“U16”,可得下图,引脚名为 GPMC_A9,用作 GPIO时要设置为 mode 7:
③ 在芯片手册 AM335x_datasheet_spruh73p.pdf中搜 gpmc_a9,
所以,要把GPIO1_25对应的引脚设置为 GPIO模式,要设置 conf_gpmc_a9寄存器的bit[5]为1,bit[2:0]为 7,这个寄存器的地址是 0x44E10000+0x864。
步骤 3:
设置 GPIO1内部寄存器,把 GPIO1_25设置为输入引脚,读数据寄存器 GPIO_OE寄存器:地址为 0x4804C000+0x134,bit[25]设置为 1。
GPIO_DATAIN寄存器:地址为 0x4804C000+0x138,读其 bit[25]。
15.2.3 编程
15.2.3.1 程序框架
使用 GIT下载所有源码后,本节源码位于如下目录:
01_all_series_quickstart\
05_嵌入式 Linux驱动开发基础知识\source\
04_button_drv\02_button_drv_for_boards\01_button_drv_for_am335x
15.2.3.2 硬件相关的代码
主要看 board_am335x.c,先看它的入口函数,代码如下。
第 84行向上层驱动注册一个 button_operations结构体,该结构体在第 76~80行定义。
76 static struct button_operations my_buttons_ops = {
77 .count = 1,
78 .init = board_am335x_button_init,
79 .read = board_am335x_button_read,
80 };
81
82 int board_am335x_button_drv_init(void)
83 {
84 register_button_operations(&my_buttons_ops);
85 return 0;
86 }
87
button_operations结构体中有 init函数指针,它指向 board_am335x_button_init函数,在里面将会初始化 LED引脚:使能、设置为 GPIO模式、设置为输出引脚。代码如下。
值得关注的是第 32~35行,对于寄存器要先使用 ioremap得到它的虚拟地址,以后使用虚拟地址访问寄存器。
21 static volatile unsigned int *CM_PER_GPIO1_CLKCTRL;
22 static volatile unsigned int *conf_gpmc_a9;
23 static volatile unsigned int *GPIO1_OE;
24 static volatile unsigned int *GPIO1_DATAIN;
25
26 static void board_am335x_button_init (int which) /* 初始化 button, which-哪个 button */
27 {
28 if (which == 0)
29 {
30 if (!CM_PER_GPIO1_CLKCTRL)
31 {
32 CM_PER_GPIO1_CLKCTRL = ioremap(0x44E00000 + 0xAC, 4);
33 conf_gpmc_a9 = ioremap(0x44E10000 + 0x864, 4);
34 GPIO1_OE = ioremap(0x4804C000 + 0x134, 4);
35 GPIO1_DATAIN = ioremap(0x4804C000 + 0x138, 4);
36 }
37
38 //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);
39 /* a. 使能 GPIO1
40 * set PRCM to enalbe GPIO1
41 * set CM_PER_GPIO1_CLKCTRL (0x44E00000 + 0xAC)
42 * val: (1<<18) | 0x2
43 */
44 *CM_PER_GPIO1_CLKCTRL = (1<<18) | 0x2;
45
46 /* b. 设置 GPIO1_25的功能,让它工作于 GPIO模式
47 * set Control Module to set GPIO1_25 (U16) used as GPIO
48 * conf_gpmc_a9 as mode 7
49 * addr : 0x44E10000 + 0x864
50 * bit[5] : 1, Input enable value for the PAD
51 * bit[2:0] : mode 7
52 */
53 *conf_gpmc_a9 = (1<<5) | 7;
54
55 /* c. 设置 GPIO1_25的方向,让它作为输入引脚
56 * set GPIO1's registers , to set 设置 GPIO1_25的方向'S dir (input)
57 * GPIO_OE
58 * addr : 0x4804C000 + 0x134
59 * set bit 25
60 */
61
62 *GPIO1_OE |= (1<<25); 63 }
64
65 }
66
button_operations结构体中还有有 read函数指针,它指向 board_am335x_button_read函数,在里面将会读取并返回按键引脚的电平。代码如下。
67 static int board_am335x_button_read (int which) /* 读 button, which-哪个 */
68 {
69 printk("%s %s line %d, button %d, 0x%x\n", __FILE__, __FUNCTION__, __LINE__, which, *GPIO1_DATAIN);
70 if (which == 0)
71 return (*GPIO1_DATAIN & (1<<25)) ? 1 : 0;
72 else
73 return 0;
74 }
75
15.2.3.3 测试
安装驱动程序之后执行测试程序,观察它的返回值(执行测试程序的同时操作按键):
# insmod button_drv.ko
# insmod board_am335x.ko
# ./button_test /dev/xxxxxx_button0
15.2.4 课后作业
① 修改 board_am335x.c,增加更多按键
② 修改 button_test.c,使用按键来点灯
15.3 RK3288的按键驱动程序(查询方式)
15.3.1 先看原理图确定引脚及操作方法
Firefly的 RK3288开发板上没有按键,我们为它制作的扩展板上有 1个按键。在扩展板原理图rk3288_extend_v12_0715.pdf中可以看到按键,如下:
平时按键电平为高,按下按键后电平为低。 按键引脚为 GPIO7_B1。
15.3.2 再看芯片手册确定寄存器及操作方法
芯片手册为 Rockchip_RK3288_TRM_V1.2_Part1-20170321.pdf,不过我们总结如下。
步骤 1:
使能 GPIO7模块
设置 CRU_CLKGATE14_CON寄存器的 bit[7]为 0。 要设置 bit7,必须同时设置 bit23为 1。
该寄存器地址为 0xFF760000+0x198。
步骤 2:
把 GPIO7_B1对应的引脚设置为 GPIO模式
设置 GRF_GPIO7B_IOMUX寄存器的 bit[3:2]为 0b00。 要设置 bit[3:2],必须同时设置 bit[19:18]为 0b11。 该寄存器地址为 0xFF770000+0x0070。
步骤 3:
设置 GPIO7内部寄存器,把 GPIO7_B1设置为输入引脚,读数据寄存器
GPIO_SWPORTA_DDR方向寄存器:地址为 0xFF7E0000+ 0x0004,bit[9]设置为 0。 GPIO_EXT_PORTA外部端口寄存器:地址为 0xFF7E0000+ 0x0050,读其 bit[9]。
注意:
GPIO_A0~A7 对应 bit0bit7;GPIO_B0B7 对应 bit8~bit15;
GPIO_C0~C7 对应 bit16bit23;GPIO_D0D7 对应 bit24~bit31
15.3.3 编程
15.3.1.1 程序框架
使用 GIT下载所有源码后,本节源码位于如下目录:
01_all_series_quickstart\
05_嵌入式 Linux驱动开发基础知识\source\
04_button_drv\02_button_drv_for_boards\02_button_drv_for_rk3288
15.3.1.2 硬件相关的代码
主要看 board_rk3288.c,先看它的入口函数,代码如下。
第 81行向上层驱动注册一个 button_operations结构体,该结构体在第 73~77行定义。 73 static struct button_operations
my_buttons_ops = {
74 .count = 1,
75 .init = board_rk3288_button_init,
76 .read = board_rk3288_button_read,
77 };
78
79 int board_rk3288_button_drv_init(void)
80 {
81 register_button_operations(&my_buttons_ops);
82 return 0;
83 }
button_operations结构体中有 init函数指针,它指向 board_rk3288_button_init函数,在里面将会初始化 LED引脚:使能、设置为 GPIO模式、设置为输出引脚。代码如下。
值得关注的是第 32~35行,对于寄存器要先使用 ioremap得到它的虚拟地址,以后使用虚拟地址访问寄存器。
21 static volatile unsigned int *CRU_CLKGATE14_CON;
22 static volatile unsigned int *GRF_GPIO7B_IOMUX ;
23 static volatile unsigned int *GPIO7_SWPORTA_DDR;
24 static volatile unsigned int *GPIO7_EXT_PORTA ;
25
26 static void board_rk3288_button_init (int which) /* 初始化 button, which-哪个 button */
27 {
28 if (which == 0)
29 {
30 if (!CRU_CLKGATE14_CON)
31 {
32 CRU_CLKGATE14_CON = ioremap(0xFF760000 + 0x0198, 4);
33 GRF_GPIO7B_IOMUX = ioremap(0xFF770000 + 0x0070, 4);
34 GPIO7_SWPORTA_DDR = ioremap(0xFF7E0000 + 0x0004, 4);
35 GPIO7_EXT_PORTA = ioremap(0xFF7E0000 + 0x0050, 4);
36 }
37
38 /* rk3288 GPIO7_B1 */
39 /* a. 使能 GPIO7
40 * set CRU to enable GPIO7
41 * CRU_CLKGATE14_CON 0xFF760000 + 0x198
42 * (1<<(7+16)) | (0<<7)
43 */
44 *CRU_CLKGATE14_CON = (1<<(7+16)) | (0<<7);
45
46 /* b. 设置 GPIO7_B1用于 GPIO
47 * set PMU/GRF to configure GPIO7_B1 as GPIO
48 * GRF_GPIO7B_IOMUX 0xFF770000 + 0x0070
49 * bit[3:2] = 0b00
50 * (3<<(2+16)) | (0<<2)
51 */
52 *GRF_GPIO7B_IOMUX =(3<<(2+16)) | (0<<2);
53
54 /* c. 设置 GPIO7_B1作为 input引脚
55 * set GPIO_SWPORTA_DDR to configure GPIO7_B1 as input 56 * GPIO_SWPORTA_DDR 0xFF7E0000 + 0x0004
57 * bit[9] = 0b0
58 */
59 *GPIO7_SWPORTA_DDR &= ~(1<<9);
60 }
61
62 }
button_operations结构体中还有有 read函数指针,它指向 board_rk3288_button_read函数,在里面将会读取并返回按键引脚的电平。代码如下。
64 static int board_rk3288_button_read (int which) /* 读 button, which-哪个 */
65 {
66 //printk("%s %s line %d, button %d, 0x%x\n", __FILE__, __FUNCTION__, __LINE__, which, *GPIO1_DATAIN);
67 if (which == 0)
68 return (*GPIO7_EXT_PORTA & (1<<9)) ? 1 : 0;
69 else
70 return 0;
71 }
15.3.4 测试
安装驱动程序之后执行测试程序,观察它的返回值(执行测试程序的同时操作按键):
# insmod button_drv.ko
# insmod board_rk3288.ko
# ./button_test /dev/xxxxxx_button0
15.3.5 课后作业
① 修改 button_test.c,使用按键来点灯
15.4 RK3399的按键驱动程序(查询方式)
15.4.1 先看原理图确定引脚及操作方法
Firefly的 RK3399开发板上没有按键,我们为它制作的扩展板上有 3个按键。在扩展板原理图rk3399_extend_v12_0709final.pdf中可以看到按键,如下:
平时按键电平为高,按下按键后电平为低。
按键引脚为 GPIO0_B1、GPIO0_B2、GPIO0_B4。 本视频中,只操作一个按键:GPIO0_B1。
15.4.2 再看芯片手册确定寄存器及操作方法
芯片手册为 Rockchip RK3399TRM V1.3 Part1.pdf和 Rockchip RK3399TRM V1.3 Part2.pdf,不过我们总结如下。
步骤 1:
使能 GPIO0模块
设置 PMUCRU_CLKGATE_CON1寄存器的 bit[3]为 0。
要设置 bit3,必须同时设置 bit19为 1。 该寄存器地址为 0xFF760000+ 0x0104。
步骤 2:
把 GPIO0_B1对应的引脚设置为 GPIO模式
设置 PMUGRF_GPIO0B_IOMUX寄存器的 bit[3:2]为 0b00。 要设置 bit[3:2],必须同时设置 bit[19:18]为 0b11。 该寄存器地址为 0xFF310000+0x0004。
步骤 3:
设置 GPIO0内部寄存器,把 GPIO0_B1设置为输入引脚,读数据寄存器 这些寄存器的介绍在芯片手册 Rockchip RK3399TRM V1.3 Part2.pdf中。
GPIO_SWPORTA_DDR方向寄存器:地址为 0xFF720000+ 0x0004,bit[9]设置为 0。 GPIO_EXT_PORTA外部端口寄存器:地址为 0xFF720000+ 0x0050,读其 bit[9]。
注意:
GPIO_A0~A7 对应 bit0bit7;GPIO_B0B7 对应 bit8~bit15;
GPIO_C0~C7 对应 bit16bit23;GPIO_D0D7 对应 bit24~bit31
15.4.3 编程
15.4.3.1 程序框架
使用 GIT下载所有源码后,本节源码位于如下目录:
01_all_series_quickstart\
05_嵌入式 Linux驱动开发基础知识\source\
04_button_drv\02_button_drv_for_boards\03_button_drv_for_rk3399
15.4.3.2 硬件相关的代码
主要看 board_rk3399.c,先看它的入口函数,代码如下。
第 81行向上层驱动注册一个 button_operations结构体,该结构体在第 73~77行定义。
73 static struct button_operations my_buttons_ops = {
74 .count = 1,
75 .init = board_rk3399_button_init,
76 .read = board_rk3399_button_read,
77 };
78
79 int board_rk3399_button_drv_init(void)
80 {
81 register_button_operations(&my_buttons_ops); 82 return 0;
83 }
button_operations结构体中有 init函数指针,它指向 board_rk3399_button_init函数,在里面将会初始化 LED引脚:使能、设置为 GPIO模式、设置为输出引脚。代码如下。
值得关注的是第 32~35行,对于寄存器要先使用 ioremap得到它的虚拟地址,以后使用虚拟地址访问寄存器。
21 static volatile unsigned int *PMUCRU_CLKGATE_CON1;
22 static volatile unsigned int *GRF_GPIO0B_IOMUX ;
23 static volatile unsigned int *GPIO0_SWPORTA_DDR;
24 static volatile unsigned int *GPIO0_EXT_PORTA ;
25
26 static void board_rk3399_button_init (int which) /* 初始化 button, which-哪个 button */
27 {
28 if (which == 0)
29 {
30 if (!PMUCRU_CLKGATE_CON1)
31 {
32 PMUCRU_CLKGATE_CON1 = ioremap(0xFF760000+ 0x0104, 4);
33 GRF_GPIO0B_IOMUX = ioremap(0xFF310000+0x0004, 4);
34 GPIO0_SWPORTA_DDR = ioremap(0xFF720000 + 0x0004, 4);
35 GPIO0_EXT_PORTA = ioremap(0xFF720000 + 0x0050, 4);
36 }
37
38 /* rk3399 GPIO0_B1 */
39 /* a. 使能 GPIO0
40 * set CRU to enable GPIO0
41 * PMUCRU_CLKGATE_CON1 0xFF760000+ 0x0104
42 * (1<<(3+16)) | (0<<3)
43 */
44 *PMUCRU_CLKGATE_CON1 = (1<<(3+16)) | (0<<3);
45
46 /* b. 设置 GPIO0_B1用于 GPIO
47 * set PMU/GRF to configure GPIO0_B1 as GPIO
48 * GRF_GPIO0B_IOMUX 0xFF310000+0x0004
49 * bit[3:2] = 0b00
50 * (3<<(2+16)) | (0<<2)
51 */
52 *GRF_GPIO0B_IOMUX =(3<<(2+16)) | (0<<2);
53
54 /* c. 设置 GPIO0_B1作为 input引脚
55 * set GPIO_SWPORTA_DDR to configure GPIO0_B1 as input 56 * GPIO_SWPORTA_DDR 0xFF720000 + 0x0004
57 * bit[9] = 0b0
58 */
59 *GPIO0_SWPORTA_DDR &= ~(1<<9);
60 }
61
62 }
button_operations结构体中还有有 read函数指针,它指向 board_rk3399_button_read函数,在里面将会读取并返回按键引脚的电平。代码如下。
64 static int board_rk3399_button_read (int which) /* 读 button, which-哪个 */
65 {
66 //printk("%s %s line %d, button %d, 0x%x\n", __FILE__, __FUNCTION__, __LINE__, which, *GPIO1_DATAIN);
67 if (which == 0)
68 return (*GPIO0_EXT_PORTA & (1<<9)) ? 1 : 0;
69 else
70 return 0;
71 }
15.4.4 测试
安装驱动程序之后执行测试程序,观察它的返回值(执行测试程序的同时操作按键):
# insmod button_drv.ko
# insmod board_rk3399.ko
# ./button_test /dev/xxxxxx_button0
15.4.5 课后作业
① 修改 board_rk3399.c,增加更多按键
② 修改 button_test.c,使用按键来点灯
15.5 IMX6ULL-QEMU的按键驱动程序(查询方式)
使用 QEMU模拟的硬件,它的硬件资源可以随意扩展。
在 IMX6ULL QEMU 虚拟开发板上,我们为它设计了 2个 按键。在 QEMU的 GUI上有 4个按键,右边的 2个留待以后用于电源管理。
15.5.1 先看原理图确定引脚及操作方法
平时按键电平为低,按下按键后电平为高。 按键引脚为 GPIO5_IO01、GPIO1_IO18。
15.5.2 再看芯片手册确定寄存器及操作方法
步骤 1:
使能 GPIO1、GPIO5
设置 b[31:30]、b[27:26]就可以使能 GPIO5、GPIO1,设置为什么值呢?
注意:在 imx6ullrm.pdf中,CCM_CCGR1的 b[31:30]是保留位;我以前写程序时错用了 imx6ul(不是imx6ull)的手册,导致程序中额外操作了这些保留位。不去设置 b[31:30],GPIO5也是默认使能的。
看下图,设置为 0b11:
① 00:该 GPIO模块全程被关闭
② 01:该 GPIO模块在 CPU run mode情况下是使能的;在 WAIT或 STOP模式下,关闭 ③ 10:保留
④ 11:该 GPIO模块全程使能
步骤 2:
设置 GPIO5_IO01、GPIO1_IO18为 GPIO模式
① 对于 GPIO5_IO01,设置如下寄存器:
② 对于 GPIO1_IO18,设置如下寄存器:
步骤 3:
设置 GPIO5_IO01、GPIO1_IO18为输入引脚,读取引脚电平 寄存器地址为:
设置方向寄存器,把引脚设置为输出引脚:
读取引脚状态寄存器,得到引脚电平:
15.5.3 编程
15.5.3.1 程序框架
使用 GIT下载所有源码后,本节源码位于如下目录:
01_all_series_quickstart\
05_嵌入式 Linux驱动开发基础知识\source\
04_button_drv\02_button_drv_for_boards\04_button_drv_for_xxxxxx_imx6ull-qemu
15.5.3.2 硬件相关的代码
主要看 board_xxxxxx_imx6ull-qemu.c。
涉及的寄存器挺多,一个一个去执行 ioremap效率太低。
先定义结构体,然后对结构体指针进行 ioremap。
对于 IOMUXC,可以如下定义:
struct iomux { volatile unsigned int unnames[23]; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO01; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO02; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO05; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO06; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO07; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO08; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO09; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA; volatile unsigned int IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B;
};
struct iomux *iomux = ioremap(0x20e0000, sizeof(struct iomux));
对于 GPIO,可以如下定义:
struct imx6ull_gpio { volatile unsigned int dr; volatile unsigned int gdir; volatile unsigned int psr; volatile unsigned int icr1; volatile unsigned int icr2; volatile unsigned int imr; volatile unsigned int isr; volatile unsigned int edge_sel;
};
struct imx6ull_gpio *gpio1 = ioremap(0x209C000, sizeof(struct imx6ull_gpio)); struct imx6ull_gpio *gpio5 = ioremap(0x20AC000, sizeof(struct imx6ull_gpio));
看一个驱动程序,先看它的入口函数,代码如下。
第 127行向上层驱动注册一个 button_operations结构体,该结构体在第 119~123行定义。 119 static struct button_operations
my_buttons_ops = {
120 .count = 2,
121 .init = board_imx6ull_button_init,
122 .read = board_imx6ull_button_read,
123 };
124
125 int board_imx6ull_button_drv_init(void)
126 {
127 register_button_operations(&my_buttons_ops);
128 return 0;
129 }
button_operations结构体中有 init函数指针,它指向 board_imx6ull_button_init函数,在里面将会初始化 LED引脚:使能、设置为 GPIO模式、设置为输出引脚。代码如下。
值得关注的是第 65~70行,对于寄存器要先使用 ioremap得到它的虚拟地址,以后使用虚拟地址访问寄存器。
50 /* enable GPIO1,GPIO5 */
51 static volatile unsigned int *CCM_CCGR1;
52
53 /* set GPIO5_IO03 as GPIO */
54 static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1;
55
56 static struct iomux *iomux;
57
58 static struct imx6ull_gpio *gpio1;
59 static struct imx6ull_gpio *gpio5;
60
61 static void board_imx6ull_button_init (int which) /* 初始化 button, which-哪个 button */
62 {
63 if (!CCM_CCGR1)
64 {
65 CCM_CCGR1 = ioremap(0x20C406C, 4);
66 IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1 = ioremap(0x229000C, 4); 67
68 iomux = ioremap(0x20e0000, sizeof(struct iomux));
69 gpio1 = ioremap(0x209C000, sizeof(struct imx6ull_gpio));
70 gpio5 = ioremap(0x20AC000, sizeof(struct imx6ull_gpio));
71 }
72
73 if (which == 0)
74 {
75 /* 1. enable GPIO5
76 * CG15, b[31:30] = 0b11
77 */
78 *CCM_CCGR1 |= (3<<30);
79
80 /* 2. set GPIO5_IO01 as GPIO
81 * MUX_MODE, b[3:0] = 0b101
82 */
83 *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER1 = 5;
84
85 /* 3. set GPIO5_IO01 as input
86 * GPIO5 GDIR, b[1] = 0b0
87 */
88 gpio5->gdir &= ~(1<<1);
89 }
90 else if(which == 1)
91 {
92 /* 1. enable GPIO1
93 * CG13, b[27:26] = 0b11
94 */
95 *CCM_CCGR1 |= (3<<26);
96
97 /* 2. set GPIO1_IO18 as GPIO
98 * MUX_MODE, b[3:0] = 0b101
99 */
100 iomux->IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B = 5;
101
102 /* 3. set GPIO1_IO18 as input
103 * GPIO1 GDIR, b[18] = 0b0
104 */
105 gpio1->gdir &= ~(1<<18);
106 } 107
108 }
button_operations结构体中还有有 read函数指针,它指向 board_imx6ull_button_read函数,在里面将会读取并返回按键引脚的电平。代码如下。
110 static int board_imx6ull_button_read (int which) /* 读 button, which-哪个 */
111 {
112 //printk("%s %s line %d, button %d, 0x%x\n", __FILE__, __FUNCTION__, __LINE__, which, *GPIO1_DATAIN);
113 if (which == 0)
114 return (gpio5->psr & (1<<1)) ? 1 : 0;
115 else
116 return (gpio1->psr & (1<<18)) ? 1 : 0;
117 }
15.5.4 测试
先启动 IMX6ULL QEMU模拟器,挂载 NFS文件系统。
运行 QEMU时,
QEMU内部为主机虚拟出一个网卡, IP为 10.0.2.2,
IMX6ULL有一个网卡, IP为 10.0.2.15,
它连接到主机的虚拟网卡。
这样 IMX6ULL就可以通过 10.0.2.2去访问 Ubuntu了。
安装驱动程序之后执行测试程序,观察它的返回值(执行测试程序的同时操作按键):
# insmod button_drv.ko
# insmod board_drv.ko
# insmod board_xxxxxx_imx6ull-qemu.ko
# ./button_test /dev/xxxxxx_button0
# ./button_test /dev/xxxxxx_button1
15.5.5 课后作业
① 修改 button_test.c,使用按键来点灯
相关文章:
嵌入式Linux应用开发-第十五章具体单板的按键驱动程序
嵌入式Linux应用开发-第十五章具体单板的按键驱动程序 第十五章 具体单板的按键驱动程序(查询方式)15.1 GPIO操作回顾15.2 AM335X的按键驱动程序(查询方式)15.2.1 先看原理图确定引脚及操作方法15.2.2 再看芯片手册确定寄存器及操作方法15.2.3 编程15.2.3.1 程序框架15.2.3.2 硬…...
MySQL体系结构和四层架构介绍
MySQL体系结构图如下: 四层介绍 1. 连接层: 它的主要功能是处理客户端与MySQL服务器之间的连接(比如Java应用程序通过JDBC连接MySQL)。当客户端应用程序连接到MySQL服务器时,连接层对用户进行身份验证、建立安全连接并管理会话状态。它还处理…...
【产品运营】如何做好B端产品规划
产品规划是基于当下掌握的多维度信息,为追求特定目的,而制定的产品资源投入计划。 产品规划是基于当下掌握的多维度信息(客户需求、市场趋势、竞争对手、竞争策略等),为追求特定目的(商业增长、客户满意等&…...
ruoyi-启动
1 springboot 版本 git 地址 ruoyi-vue-pro: 🔥 官方推荐 🔥 RuoYi-Vue 全新 Pro 版本,优化重构所有功能。基于 Spring Boot MyBatis Plus Vue & Element 实现的后台管理系统 微信小程序,支持 RBAC 动态权限、数据权限…...
select完成服务器并发
服务器 #include <myhead.h>#define PORT 4399 //端口号 #define IP "192.168.0.191"//IP地址//键盘输入事件 int keybord_events(fd_set readfds); //客户端交互事件 int cliRcvSnd_events(int , struct sockaddr_in*, fd_set *, int *); //客户端连接事件 …...
初级篇—第四章聚合函数
文章目录 聚合函数介绍聚合函数介绍COUNT函数AVG和SUM函数MIN和MAX函数 GROUP BY语法基本使用使用多个列分组WITH ROLLUP HAVING基本使用WHERE和HAVING的对比开发中的选择 SELECT的执行过程查询的结构SQL 的执行原理 练习流程函数 聚合函数介绍 聚合函数作用于一组数据&#x…...
计算机图像处理-中值滤波
非线性滤波 非线性滤波是利用原始图像跟模版之间的一种逻辑关系得到结果,常用的非线性滤波方法有中值滤波和高斯双边滤波,分别对应cv2.medianBlur(src, ksize)方法和cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]])方法。 …...
Golang中的包和模块设计
Go,也被称为Golang,是一种静态类型、编译型语言,因其简洁性和对并发编程的强大支持而受到开发者们的喜爱。Go编程的一个关键方面是其包和模块系统,它允许创建可重用、可维护和高效的代码。本博客文章将深入探讨在Go中设计包和模块…...
web:[极客大挑战 2019]Upload
题目 页面显示为一个上传,猜测上传一句话木马文件 先查看源代码看一下有没有有用的信息,说明要先上传图片,先尝试上传含有一句话木马的图片 构造payload <?php eval($_POST[123]);?> 上传后页面显示为,不能包含<&…...
ICMP差错包
ICMP报文分类 Type Code 描述 查询/差错 0-Echo响应 0 Echo响应报文 查询 3-目的不可达 0 目标网络不可达报文 差错 1 目标主机不可达报文 差错 2 目标协议不可达报文 差错 3 目标端口不可达报文 差错 4 要求分段并设置DF flag标志报文 差错 5 源路由…...
算法基础课第二部分
算法基础课 第四讲 数学知识AcWing1381. 阶乘(同余,因式分解) 质数AcWing 866. 质数的判定---试除法AcWing 868. 质数的判定---埃氏筛AcWing867. 分解质因数---试除法AcWing 197. 阶乘---分解质因数---埃式筛 约数AcWing 869. 求约数---试除法AcWing 870. 约数个数-…...
【数据结构】外部排序、多路平衡归并与败者树、置换-选择排序(生成初始归并段)、最佳归并树算法
目录 1、外部排序 1.1 基本概念 1.2 方法 2、多路平衡归并与败者树 2.1 K路平衡归并 2.2 败者树 3、置换-选择排序(生成初始归并段)编辑 4、最佳归并树 4.1 理论基础编辑 4.2 构造方法 编辑 5、各种排序算法的性质 1、外部排序 1.1 基本概…...
抽象工厂模式 创建性模式之五
在看这篇文章之前,请先看看“简单工厂模式”和“工厂方法模式”这两篇博文,会更有助于理解。我们现在已经知道,简单工厂模式就是用一个简单工厂去创建多个产品,工厂方法模式是每一个具体的工厂只生产一个具体的产品,然…...
servlet如何获取PUT和DELETE请求的参数
1. servlet为何不能获取PUT和DELETE请求的参数 Servlet的规范是POST的数据需要转给request.getParameter*()方法,没有规定PUT和DELETE请求也这么做 The Servlet spec requires form data to be available for HTTP POST but not for HTTP PUT or PATCH requests. T…...
【Vue.js】使用Element中的Mock.js搭建首页导航左侧菜单---【超高级教学】
一,Mock.js 1.1 认识Mock.js Mock.js是一个用于前端开发中生成随机数据、模拟接口响应的 JavaScript 库。模拟数据的生成器,用来帮助前端调试开发、进行前后端的原型分离以及用来提高自动化测试效率 总结来说,Element中的Mock.js是一个用于…...
从技术创新到应用实践,百度智能云发起大模型平台应用开发挑战赛!
大模型已经成为未来技术发展方向的重大变革,热度之下更需去虚向实,让技术走进产业场景。在这样的背景下,百度智能云于近期发起了“百度智能云千帆大模型平台应用开发挑战赛”。 挖掘大模型落地应用 千帆大模型平台应用开发挑战赛启动 在不久前…...
简单三步 用GPT-4和Gamma自动生成PPT PDF
1. 用GPT-4 生产PPT内容 我想把下面的文章做成PPT,请你给出详细的大纲和内容 用于谋生的知识,学生主要工作是学习,成年人的工作是养家糊口,这是基本的要求,在这之上,才能有更高的追求。 不要短期期望过高…...
QT设置弹窗显示屏幕中央
Qt设置每次运行弹窗显示屏幕中央 要确保Qt应用程序中的弹出窗口每次都显示在屏幕的中央,您可以使用以下方法: 使用QMessageBox的move方法手动设置窗口位置: #include <QApplication> #include <QMessageBox> #include <QDesk…...
正点原子嵌入式linux驱动开发——STM32MP1启动详解
STM32单片机是直接将程序下载到内部 Flash中,上电以后直接运行内部 Flash中的程序。 STM32MP157内部没有供用户使用的 Flash,系统都是存放在外部 Flash里面的,比如 EMMC、NAND等,因此 STM32MP157上电以后需要从外部 Flash加载程序…...
FPGA的数字钟带校时闹钟报时功能VHDL
名称:基于FPGA的数字钟具有校时闹钟报时功能 软件:Quartus 语言:VHDL 要求: 1、计时功能:这是数字钟设计的基本功能,每秒钟更新一次,并且能在显示屏上显示当前的时间。 2、闹钟功能:如果当前的时间与闹钟设置的时…...
分析各种表达式求值过程
目录 算术运算与赋值 编译器常用的两种优化方案 常量传播 常量折叠 加法 Debug编译选项组下编译后的汇编代码分析 Release开启02执行效率优先 减法 Release版下优化和加法一致,不再赘述 乘法 除法 算术结果溢出 自增和自减 关系运算与逻辑运算 JCC指…...
企业风险管理策略终极指南
企业风险管理不一定是可怕的。企业风险管理是一个模糊且难以定义的主题领域。它涵盖了企业的多种风险和程序,与传统的风险管理有很大不同。 那么,企业风险管理到底是什么?在本文中,我们将确定它是什么,提出两种常见的…...
OpenCV之分水岭算法(watershed)
Opencv 中 watershed函数原型: void watershed( InputArray image, InputOutputArray markers ); 第一个参数 image,必须是一个8bit 3通道彩色图像矩阵序列,第一个参数没什么要说的。关键是第二个参数 markers,Opencv官方文档的说…...
npm 命令
目录 初始化 搜索 安装 删除 更新 换源 查看 其他 补充 1.初始化 npm init #初始化一个package.json文件 npm init -y | npm init --yes 2.搜索 npm s jquery | npm search jquery 3.安装 npm install npm -g #更新到最新版本 npm i uniq | npm ins…...
【bug 记录】yolov5_C_demo 部署在 rv1126
问题1:opencv find 不到 在 CMakeLists 中将正确的 OpenCV库 路径添加到 CMAKE_PREFIX_PATH 变量中 set(CMAKE_PREFIX_PATH “/mnt/usr/local” ${CMAKE_PREFIX_PATH}) 问题2: rknn_api.h 找不到 将该文件从别处复制到项目 include 文件夹 问题3&…...
[vue-admin-template实战笔记]
1.克隆项目 git clone gitgitee.com:panjiachen/vue-admin-template.git 2.安装依赖 npm install 3.运行项目就会自动打开网页,并且热部署插件 npm run dev 4.查看代码 //将vue-admin-template拖入到idea中即可查看代码 1)并且发现,常用的东西已经集…...
unity 限制 相机移动 区域(无需碰撞检测)
限制功能原著地址:unity限制相机可移动区域(box collider)_unity限制相机移动区域_manson-liao的博客-CSDN博客 一、创建限制区域 创建一个Cube,Scale大小1,添加组件:BoxCollder,调整BoxColld…...
Hudi第二章:集成Spark
系列文章目录 Hudi第一章:编译安装 Hudi第二章:集成Spark 文章目录 系列文章目录前言一、安装Spark1、安装Spark2.安装hive 二、spark-shell1.启动命令2.插入数据3.查询数据1.转换DF2.查询 3.更新4.时间旅行5.增量查询6.指定时间点查询7.删除数据1.获取…...
springboot和vue:八、vue快速入门
vue快速入门 新建一个html文件 导入 vue.js 的 script 脚本文件 <script src"https://unpkg.com/vuenext"></script>在页面中声明一个将要被 vue 所控制的 DOM 区域,既MVVM中的View <div id"app">{{ message }} </div…...
docker-compose内网本地安装
1:通过包管理器安装 Docker Compose,请按照以下步骤进行操作: 首先,确保你的系统上已经安装了 Docker。如果尚未安装 Docker,请根据你的操作系统使用适当的包管理器进行安装打开终端,并运行以下命令下载 D…...
网站建设制作网站/企业培训视频
点击上方蓝色字体,选择“标星公众号”优质文章,第一时间送达关注公众号后台回复pay或mall获取实战项目资料视频作者:我是小茗同学来源:https://www.cnblogs.com/liuxianan1. 前言个人网站最近增加了评论功能,为了方便用…...
哈尔滨疫情最新消息今天新增/seo搜索引擎优化业务
策略模式 class Context { public:Strategy strategy;Context (Strategy& strategy){this.strategy strategy;}void ContextInterface(){strategy.AlgorithmInterface();} }装饰模式 把类中的装饰功能从类中搬移去除,这样可以简化原有的类。把每个要装饰的功能…...
许昌建设局网站/优化网站的意思
这远非无关紧要- 几乎唯一的办法是知道分号( 或者,代码在语法上是正确的) 是否像编译前的第一个阶段那样解析它。 在什么地方或者什么时候应该使用分号绝对没有什么严格的规则。 一些示例:class foo{foo();// <foo(int x) {.. . }//No semicolon, fun…...
b2b网站发布信息平台/什么网站做推广比较好
上一节我们准备好了 macvlan 的实验环境,今天在 host1 和 host2 中创建 macvlan 网络 mac_net1: 注意:在 host2 中也要执行相同的命令。 ① -d macvlan 指定 driver 为 macvlan。 ② macvlan 网络是 local 网络,为了保证跨主机能…...
免费下载网站软件/百度官网下载
分类: LINUX2016-11-07 14:58:49/////第一条线 mmc子系统核心初始化drivers/mmc/core/core.c//子系统初始化 subsys_initcall(mmc_init);第二条线mmc控制器平台驱动注册module_init(sdhci_drv_init);第三条线 磁盘设备驱动注册drivers/mmc/card/block.cmodule_ini…...
服饰类网站模板/怎么可以在百度发布信息
function have_chinies(str){ var reg /[\u4E00-\u9FA5]/g; if(reg.test(str)) { alert("含有汉字"); return true; } return false;}转载于:https://www.cnblogs.com/shichangyi/archive/2012/12/07/ecshop1.html...