基於樹莓派Raspberry: 字元裝置核心驅動程式框架編寫
之前寫了一篇移植2.4寸TFT驅動到樹莓派的文章,那篇博文中的驅動程式碼是國外大牛寫的,看了一下,還是有很多地方沒理解,是得好好再學習一下核心驅動的編寫,這裡就從字元裝置驅動開始,採用最簡單的LED驅動來建立核心驅動移植的驅動框架.
個人原創,轉載請註明原文出處:
參考文章:
核心驅動與普通微控制器模組驅動的差別就是在於,寫核心驅動的時候,要提供核心呼叫的介面,使核心能找到相應的驅動入口,使用者通過告訴核心要幹嘛,核心再去呼叫那個驅動,驅動的最底層和微控制器模組是一樣的,同樣是對GPIO的操作,配置輸入輸出,以及某些特殊的暫存器. LED的點亮就是對GPIO的操作 .
對於ARM的GPIO呼叫需要通過IO對映的方法,要操作記憶體上對應的地址.
對於bcm2708上的io對應關係,可以檢視bcm2835的手冊,和stm32基本上是一樣的,因為同為ARM體系:
我參考的那部落格講這個比較清楚,可以參考下,由於樹莓派的核心以及很好的提供了GPIO呼叫的介面,即把記憶體操作封裝了很好,這裡就不像那篇部落格那樣再自己寫函式通過記憶體操作來進行GPIO操作,覺得有點麻煩,但是對於學好底層很有用.
一 首先上個驅動程式
這裡直接把該程式新增到核心的原始碼目錄裡面,也可在自己的目錄下,但是要寫Makefile.
在/drivers/char/新建rasp_led.c,核心中的kconfig檔案和makefile檔案,參照前一篇文章
led.c:
/********************************************************************/ /***************Rasp led 驅動程式************************************/ /***************作者: Embbnux Ji*************************************/ /***************部落格: http://blog.csdn.net/embbnux/ *****************/ /********************************************************************/ #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> #include <mach/platform.h> #include <linux/platform_device.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/delay.h> #include <linux/uaccess.h> #include <linux/init.h> #include <linux/gpio.h> #define DEVICE_NAME "Pi_Led" #define DRIVER_NAME "pi_led" //class宣告核心模組驅動資訊,是UDEV能夠自動生成/dev下相應檔案 static dev_t pi_led_devno; //裝置號 static struct class *pi_led_class; static struct cdev pi_led_class_dev; struct gpio_chip *gpiochip; #define led_pin 4 //gpio 4 //這部分函式為核心呼叫後open的裝置IO操作,和裸板程式一樣 int open_flag=0; static int pi_led_open(struct inode *inode, struct file *filp) { printk("Open led ing!\n"); if(open_flag ==0){ open_flag =1; printk("Open led success!\n"); return 0; } else{ printk("Led has opened!\n"); } return 0; } //這部分函式為核心呼叫後ioctl的裝置IO操作,和裸板程式一樣 static long pi_led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch(cmd){ case 0: gpiochip->set(gpiochip, led_pin, 0); printk("Led up!\n"); break; case 1: gpiochip->set(gpiochip, led_pin, 1); printk("Led down!\n"); break; } return 0; } static int pi_led_release(struct inode *inode,struct file *file){ printk("Led has release!\n"); return 0; } //file_operations使系統的open,ioctl等函式指標指向我們所寫的led_open等函式, //這樣系統才能夠呼叫 static struct file_operations pi_led_dev_fops = { .owner =THIS_MODULE, .open =pi_led_open, .unlocked_ioctl = pi_led_ioctl, .release = pi_led_release, }; static int is_right_chip(struct gpio_chip *chip, void *data) { if (strcmp(data, chip->label) == 0) return 1; return 0; } //核心載入後的初始化函式. static int __init pi_led_init(void) { struct device *dev; int major; //自動分配主裝置號 major = alloc_chrdev_region(&pi_led_devno,0,1,DRIVER_NAME); //register_chrdev 註冊字元裝置使系統知道有LED這個模組在. cdev_init(&pi_led_class_dev, &pi_led_dev_fops); major = cdev_add(&pi_led_class_dev,pi_led_devno,1); //註冊class pi_led_class = class_create(THIS_MODULE,DRIVER_NAME); dev = device_create(pi_led_class ,NULL,pi_led_devno,NULL,DRIVER_NAME); gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip); gpiochip->direction_output(gpiochip, led_pin, 1); gpiochip->set(gpiochip, led_pin, 0); printk("pi led init ok!\n"); return 0; } //核心解除安裝後的銷燬函式. void pi_led_exit(void) { gpio_free(led_pin); device_destroy(pi_led_class,pi_led_devno); class_destroy(pi_led_class); cdev_del(&pi_led_class_dev); unregister_chrdev_region(pi_led_devno, 1); printk("pi led exit ok!\n"); } module_init(pi_led_init); module_exit(pi_led_exit); MODULE_DESCRIPTION("Rasp Led Driver"); MODULE_AUTHOR("Embbnux Ji < http://blog.csdn.net/embbnux >"); MODULE_LICENSE("GPL");
二 原始碼框架分析
我們首先從核心模組的入口,module_init(pi_led_init)這個函式看起,可以看出初始化後呼叫pi_led_init這個函式.
//核心載入後的初始化函式.
static int __init pi_led_init(void)
{
struct device *dev;
int major; //自動分配主裝置號
major = alloc_chrdev_region(&pi_led_devno,0,1,DRIVER_NAME);
//register_chrdev 註冊字元裝置使系統知道有LED這個模組在.
cdev_init(&pi_led_class_dev, &pi_led_dev_fops);
major = cdev_add(&pi_led_class_dev,pi_led_devno,1);
//註冊class
pi_led_class = class_create(THIS_MODULE,DRIVER_NAME);
dev = device_create(pi_led_class ,NULL,pi_led_devno,NULL,DRIVER_NAME);
gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
gpiochip->direction_output(gpiochip, led_pin, 1);
gpiochip->set(gpiochip, led_pin, 0);
printk("pi led init ok!\n");
return 0;
}
初始化時首先分配給這個函式裝置號,註冊該裝置,通過class註冊使能夠在/dev/目錄下自動生成相應的裝置檔案,使用者通過操作這個檔案,來告訴核心怎麼做.
由於是字元裝置,所以對該檔案的操作通過open,write,ioctl等函式,所以要把這個函式和底層的操作函式對應起來,這就要用到file_operation這個結構體,來宣告:
//file_operations使系統的open,ioctl等函式指標指向我們所寫的led_open等函式,
//這樣系統才能夠呼叫
static struct file_operations pi_led_dev_fops = {
.owner =THIS_MODULE,
.open =pi_led_open,
.unlocked_ioctl = pi_led_ioctl,
.release = pi_led_release,
};
這裡就讓open函式對應到pi_led_open函式,ioctl函式對應到pi_led_ioctl函式;
然後我們就只需要編寫相應的pi_led_open以及pi_led_ioctl;這些函式裡面的操作就是最底層的GPIO操作,和微控制器是一樣的.
三 GPIO操作
核心裡面的GPIO操作函式,被定義在#include <linux/gpio.h>,這個標頭檔案裡面,樹莓派官方做好了樹莓派的GPIO在核心裡面的註冊,所以呼叫gpio.h裡面的函式即可進行樹莓派的GPIO操作.
gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
通過上面這個函式把核心的GPIO操作和BCM2708的GPIO操作關聯起來;
bcm2708的操作可以檢視/arch/arm/mach-bcm2708/bcm2708_gpio.c檔案,具體也是對記憶體地址的操作:
#define GPIOFSEL(x) (0x00+(x)*4)
#define GPIOSET(x) (0x1c+(x)*4)
#define GPIOCLR(x) (0x28+(x)*4)
#define GPIOLEV(x) (0x34+(x)*4)
#define GPIOEDS(x) (0x40+(x)*4)
#define GPIOREN(x) (0x4c+(x)*4)
#define GPIOFEN(x) (0x58+(x)*4)
#define GPIOHEN(x) (0x64+(x)*4)
#define GPIOLEN(x) (0x70+(x)*4)
#define GPIOAREN(x) (0x7c+(x)*4)
#define GPIOAFEN(x) (0x88+(x)*4)
#define GPIOUD(x) (0x94+(x)*4)
#define GPIOUDCLK(x) (0x98+(x)*4)
這裡定義的就是相應的GPIO暫存器的地址.
四 測試程式
ssh進入樹莓派,在主目錄下新建led.c
#include<stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
int main(int argc, char **argv)
{
int on;
int led_no;
int fd;
int i;
fd = open("/dev/pi_led", 0);
if (fd < 0) {
fd = open("/dev/pi_led", 0);
}
if (fd < 0) {
perror("open device led");
exit(1);
}
for(i=0;i<=20;i++){
on = i%2;
ioctl(fd, on, led_no);
sleep(1);
}
close(fd);
return 0;
}
相關推薦
基於樹莓派Raspberry: 字元裝置核心驅動程式框架編寫
之前寫了一篇移植2.4寸TFT驅動到樹莓派的文章,那篇博文中的驅動程式碼是國外大牛寫的,看了一下,還是有很多地方沒理解,是得好好再學習一下核心驅動的編寫,這裡就從字元裝置驅動開始,採用最簡單的LED驅動來建立核心驅動移植的驅動框架. 個人原創,
基於樹莓派raspberry: 移植 2.4寸TFT顯示屏以及原始碼分析
有了樹莓派,但是沒有hdmi顯示器,這是個蛋疼的事,但是樹莓派就是樹莓派,他的GPIO管腳就是我們發揮想象力的地方.可以通過它的GPIO管腳來驅動一個顯示屏.GOOGLE了一下,這個專案有個老外做好了,而且提供了patch檔案,很容易就能移植到核心裡面去.這裡我就在這裡
基於樹莓派(Raspberry Pi)平臺的MQ-2煙霧報警系統以及結合Zabbix監控的實現(一)
Raspberry Pi Zabbix和嵌入式系統的結合 Python3 樹莓派和MQ-2氣體檢測 一、前期準備 達成目標: 利用Rapberry Pi 驅動MQ-2煙霧報警模塊,對信息進行采集和提取,而後Zabbix監控系統來收集和處理信息采集到的信息。
基於樹莓派(Raspberry Pi)平臺的智能家居實現(一)----繼電器模塊,DHT11模塊
Raspberry 繼電器模塊 DHT11溫濕度模塊 智能家居 前言: ??其實做這個智能家居系統我還是因為學校的畢業設計,距離上篇文章發布已經過去了20多天了,之前想著只是做一個煙霧報警,然後通過Zabbix進行報警,但是通過這20多天的設計,我發現實現報警的功能其
樹莓派Raspberry Pi實戰之命令列下實現USB儲存裝置自動掛載
簡單介紹實現命令列下USB儲存裝置自動掛載的方法,Linux gnome/kde視窗環境下有移動儲存的管理程式,可以實現自動掛載移動儲存裝置,但是在命令列下 通常需要用mount命令手動掛載USB儲存裝置。 通過給linux下的裝置管理服務udev新增規則配置檔案,可以實現命令列下U
Linux裝置驅動程式學習(基於2440的GPIO字元裝置驅動)
GPIO驅動程式如下: #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> #include <li
基於stm32f429的uclinux-W5500網路裝置核心驅動
之前那篇寫w5500驅動只是單純的應用程式驅動,雖然可以實現一定的目的,但是沒有充分利用到linux的核心,在一些應用場合就顯得不合時宜,於是就進行w5500網路裝置核心驅動的學習,幸運的是w5500網路裝置驅動的檔案是在4.8版本的linux核心
樹莓派raspberry使用spi介面oled顯示屏:基於python和c
之前寫過一篇樹莓派使用12864介面的2.3寸顯示屏的文章,當時用的是並口,佔用了太多的gpio資源,於是考慮使用spi介面的顯示屏,最近的專案正好用到了spi介面的oled的顯示屏,於是考慮把它用到樹莓派上,先介紹下這款螢幕:0.96寸的oled屏,spi介面ssd1
樹莓派raspberry pi配置
hang 開啟 鍵盤布局設置 jin -i icon ccf ron load (1)國際化語言 樹莓派初裝系統之後,首次啟動會出現“raspi-config”工具,如下圖:(若不是初次啟動,在命令模式下,請輸入 sudo raspi-
樹莓派Raspberry命令行配置無線網絡連接
lin 成功 兩個 隱藏 無線網絡連接 studio sch ip地址 add 前言: 樹莓派有多種聯網的方式,通過有線網或者通過無線網。通過有線網連接是比較簡單的,在開啟dhcp的路由器下,直接插上網線就可以聯網,本文介紹樹莓派無線聯網的方式。再沒聯網的情況下,如果沒有屏
基於樹莓派2代的DIY無線路由器
edi 無線網卡 AD uri sub 效果 eth ipv4 ant 最近手上多了一個樹莓派2代,於是折騰就這麽開始了。 因為總是得要個顯示屏或者路由器或者插根網線才能玩,有點麻煩,所以有了此文。 設備清單: 樹莓派2代 EDUP EP-N8508GS無線網卡(USB)
樹莓派 Raspberry Pi 啟用 root 登陸賬戶
樹莓派使用指南樹莓派 Raspberry Pi 啟用 root 登陸賬戶樹莓派系統使用的linux是debian系統,所以樹莓派啟用root和debian是相同的。debian裏root賬戶默認沒有密碼,但賬戶鎖定。當需要root權限時,由默認賬戶經由sudo執行,Raspberry pi 系統中的Raspb
樹莓派 Raspberry PI基礎
數字 -c san 波特率 fin block dddddd exp org 樹莓派 Raspberry PI基礎 官網網址:https://www.raspberrypi.org 下載地址:https://www.raspberrypi.org/downloads/ 官方
樹莓派 Raspberry PI之GPIO
document ble lock back ocs 輸入輸出 indent 1.5 res 樹莓派 Raspberry PI之GPIO 樹莓派各版本硬件原理圖:https://www.raspberrypi.org/documentation/hardware/raspb
用樹莓派Raspberry Pi和Micro:bit做一個自拍器
clear microsoft 編程 告訴 pac 文本編程 裝配 -a 按鈕 在這個項目中,我們將使用Python來構建一個由Micro:bit觸發樹莓派Raspberry Pi和相機模塊的自拍器。這是開始使用硬件和簡單文本編程的好方法。 我們將學習: 如何設置Raspb
樹莓派(Raspberry Pi 3) - 系統燒錄及系統使用
樹莓派(Raspberry pi)是一塊整合度極高的ARM開發板,不僅包含了HDMI,RCA,CSI,HDMI,GPIO等埠,還支援藍芽以及無線通訊。由於Raspberry Pi幾乎是為Linux而生的一款卡片式微型電腦,所以R
基於樹莓派的語音對話機器人
第一部分程式碼 arecord -D "plughw:1" -f S16_LE -r 16000 -d 3 /home/pi/Desktop/voice.wav 第二部分程式碼 # coding: utf-8 import sys import json import url
樹莓派(Raspberry Pi 3)的系統燒錄及使用
今天我們將詳細一步一步地講解樹莓派3的燒錄和使用。樹莓派3是整合度很高的較為先進的ARM開發板,功能豐富,我們先來看一下它的結構以及40個GPIO口分別的用處,以免接線的時候搞錯。 APP開發、一元建站、貨運APP、冷練車APP、直播系統、小程式開發,找上海捌
樹莓派 raspberry pi 能象Arduino一樣外接感測器,控制器嗎
答案是YES樹莓派板子上有26只管腳,這些GPIO (general purpose I/O) 包括 SPI, I2C, 串列埠 UART, 3V3 and 5V 電源。國內論壇就有文章“Raspbmc 設定紅外線接收器”介紹如何為樹莓派安裝Raspbmc 作業系統,安裝配置紅
樹莓派Raspberry Pi的嵌入式QT平臺
在樹莓派上設計桌面應用一般情況會依賴於X11環境,如果是Windows平臺,就目前而言,我們也可以選擇Windows 10 IoT環境進行開發。UWP目前也支援在樹莓派2上進行部署。至於常見的Linux X11或者Wayland環境,相比之下比較冗餘,但是QT Emebe