北京新站優(yōu)化國內(nèi)永久免費建站
1.實驗?zāi)康?/h1>
????????編寫LED燈的驅(qū)動,在應(yīng)用程序中編寫控制LED燈亮滅的代碼邏輯實現(xiàn)LED燈功能的控制;
2.LED燈相關(guān)寄存器分析
LED1->PE10 LED1亮滅:
RCC寄存器[4]->1 0X50000A28
GPIOE_MODER[21:20]->01 (輸出) 0X50006000
GPIOE_ODR[10]->1(輸出高電平) 0(輸出低電平)0X50006014
LED2->PF10 LED2亮滅:
RCC寄存器[5]->1 0X50000A28
GPIOE_MODER[21:20]->01 (輸出) 0X50006000
GPIOE_ODR[10]->1(輸出高電平) 0(輸出低電平)0X50006014
LED3->PE8 LED3亮滅:
RCC寄存器[4]->1 0X50000A28
GPIOE_MODER[17:16]->01 (輸出) 0X50006000
GPIOE_ODR[8]->1(輸出高電平) 0(輸出低電平)0X50006014
GPIOE_OTYPER默認為00
GPIOE_PUPDR默認為0
GPIOE_OSPEEDR默認為00
3.編寫代碼
---Makefile---工程管理文件
modname?=demo
arch?=arm
ifeq ($(arch),arm)
KERNELDIR:= /home/ubuntu/FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61 #編譯生成ARM架構(gòu)
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build #編譯生成X86架構(gòu)
endifPWD:=$(shell pwd) #模塊化編譯文件路徑
all:make -C $(KERNELDIR) M=$(PWD) modules
clean:make -C $(KERNELDIR) M=$(PWD) cleanobj-m:=$(modname).o
---head.h---頭文件
#ifndef __HEAD_H__
#define __HEAD_H__typedef struct
{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR;
}gpio_t;//LED1和LED3寄存器地址
#define LED1_ADDR 0x50006000
#define LED2_ADDR 0x50007000
#define LED3_ADDR 0x50006000
#define RCC_ADDR 0x50000A28#endif
---mychrdev.c---驅(qū)動程序
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "head.h"
#include<linux/device.h>char kbuf[128] = {0};
unsigned int major;
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;struct class *cls;
struct device *dev;//封裝操作方法
int mycdev_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{int ret;if(size > sizeof(kbuf)){size = sizeof(kbuf);}ret = copy_to_user(ubuf,kbuf,size);if(ret){printk("copy_to_user err\n");return -EIO;}return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{unsigned long ret;if(size > sizeof(kbuf)){size = sizeof(kbuf);}ret = copy_from_user(kbuf,ubuf,size);if(ret){printk("copy_from_user err\n"); return -EIO; }switch(kbuf[0]){case '1':if(kbuf[1] == '1') //開燈vir_led1->ODR |= (0x1 << 10);else if(kbuf[1] == '0') //關(guān)燈vir_led1->ODR &= (~(0x1 << 10));break;case '2':if(kbuf[1] == '1') //開燈vir_led2->ODR |= (0x1 << 10);else if(kbuf[1] == '0') //關(guān)燈vir_led2->ODR &= (~(0x1 << 10));break;case '3':if(kbuf[1] == '1') //開燈vir_led3->ODR |= (0x1 << 8);else if(kbuf[1] == '0') //關(guān)燈vir_led3->ODR &= (~(0x1 << 8));break;default:printk("輸入錯誤\n"); }return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}struct file_operations fops={.open=mycdev_open,.read=mycdev_read,.write=mycdev_write,.release=mycdev_close,
};//相關(guān)寄存器地址映射及初始化
int all_led_init(void)
{//相關(guān)寄存器的內(nèi)存映射vir_led1=ioremap(LED1_ADDR,sizeof(gpio_t));if(vir_led1 == NULL){printk("物理內(nèi)存映射失敗%d\n",__LINE__);return -ENOMEM;}vir_led2=ioremap(LED2_ADDR,sizeof(gpio_t));if(vir_led2 == NULL){printk("物理內(nèi)存映射失敗%d\n",__LINE__);return -ENOMEM;}vir_led3 = vir_led1;vir_rcc=ioremap(RCC_ADDR,4);if(vir_rcc == NULL){printk("物理內(nèi)存映射失敗%d\n",__LINE__);return -ENOMEM;}printk("寄存器內(nèi)存映射成功\n");//硬件寄存器的初始化(*vir_rcc) |= (0x3 << 4);//LED1vir_led1->MODER &= (~(0x3 << 20));vir_led1->MODER |= (0x1 << 20);vir_led1->ODR &= (~(0x1 << 10));//LED2vir_led2->MODER &= (~(0x3 << 20));vir_led2->MODER |= (0x1 << 20);vir_led2->ODR &= (~(0x1 << 10));//LED3vir_led3->MODER &= (~(0x3 << 16));vir_led3->MODER |= (0x1 << 16);vir_led3->ODR &= (~(0x1 << 8));printk("寄存器初始化成功\n");return 0;
}//入口函數(shù)
static int __init mycdev_init(void)
{major = register_chrdev(0,"mychrdev",&fops);if(major < 0){printk("字符設(shè)備驅(qū)動注冊失敗\n");return major;}printk("字符設(shè)備驅(qū)動注冊成功:major=%d\n",major);//寄存器映射及初始化all_led_init();//向上提交目錄cls = class_create(THIS_MODULE,"mychrdev");if(IS_ERR(cls)){printk("向上提交目錄失敗\n");return -PTR_ERR(cls);}printk("向上提交目錄成功\n");//向上提交設(shè)備節(jié)點信息int i;for(i=0; i<3; i++){dev = device_create(cls,NULL,MKDEV(major,i),NULL,"mychrdev%d",i);if(IS_ERR(dev)){printk("向上提交設(shè)備節(jié)點信息失敗\n");return -PTR_ERR(dev);}}printk("向上提交設(shè)備節(jié)點信息成功\n");return 0;
}//出口函數(shù)
static void __exit mycdev_exit(void)
{//銷毀設(shè)備節(jié)點信息int i;for(i=0; i<3; i++){device_destroy(cls,MKDEV(major,i));}//銷毀目錄信息class_destroy(cls);//取消物理內(nèi)存的映射iounmap(vir_led1);iounmap(vir_led2);iounmap(vir_rcc);//字符設(shè)備驅(qū)動注銷unregister_chrdev(major,"mychrdev");
}//聲明
//入口函數(shù)地址
module_init(mycdev_init);
//出口函數(shù)地址
module_exit(mycdev_exit);
//遵循的GPL協(xié)議
MODULE_LICENSE("GPL");
---test.c---應(yīng)用程序測試程序
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>int main(int argc,char const *argv[])
{char buf[128]={0};int fd = open("/dev/mychrdev0",O_RDWR);if(fd < 0){printf("設(shè)備文件打開失敗\n");exit(-1);}while(1){printf("第一個字符:1(LED1) 2(LED2) 3(LED3)\n");printf("第二個字符1(開燈)0(關(guān)燈)\n");printf("輸入控制燈的兩個字符>>> ");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] = '\0';//像設(shè)備文件中寫write(fd,buf,sizeof(buf));}close(fd);return 0;
}