PiScope (Raspberry Pi baserat oscilloskop) (6 / 10 steg)
Steg 6: Skriva kärnmodulen
Skapa en C-fil som heter Scope-drv.c som innehåller följande kod
#include < linux/kernel.h >
#include < linux/module.h >
#include < linux/fs.h >
#include < asm/uaccess.h >
#include < linux/time.h >
#include < linux/io.h >
#include < linux/vmalloc.h >
int init_module(void);
void cleanup_module(void);
static int device_open (struct inode *, struct fil *);
static int device_release (struct inode *, struct fil *);
statisk ssize_t device_read (struct fil *, char *, size_t, loff_t *);
statisk ssize_t device_write (struct fil *, const char *, size_t, loff_t *);
#define framgång 0
#define hårddisknamn "chardev"
#define BUF_LEN 80
/ * inställningen och makron för GPIO anslutningarna * /
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x20000000)
#define INP_GPIO(g) * (gpio.addr + ((g) / 10)) & = ~ (7 << (((g) % 10) * 3))
#define SET_GPIO_ALT(g,a) * (gpio.addr + (((g) / 10))) | = (((a) < = 3? () en) + 4:(a)==4?3:2) << (((g) % 10) * 3))
/ * GPIO klocka * /
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x00101000)
#define GZ_CLK_BUSY (1 << 7)
/ * Antal prover att fånga * /
#define SAMPLE_SIZE 10000
/ * Definiera GPIO stift * /
/ * ADC 1 * /
#define BIT0_PIN 7
#define BIT1_PIN 8
#define BIT2_PIN 9
#define BIT3_PIN 10
#define BIT4_PIN 11
#define BIT5_PIN 25
/ * ADC 2 * /
#define BIT0_PIN2 17
#define BIT1_PIN2 18
#define BIT2_PIN2 22
#define BIT3_PIN2 23
#define BIT4_PIN2 24
#define BIT5_PIN2 27
struct bcm2835_peripheral {
osignerade långa addr_p;
int mem_fd;
void * karta;
volatile unsigned int * addr;
};
static int map_peripheral (struct bcm2835_peripheral * p);
statisk void unmap_peripheral (struct bcm2835_peripheral * p);
statisk void readScope(void);
statisk int Major;
statisk int Device_Open = 0;
statiska char msg [BUF_LEN];
statiska char * msg_Ptr;
statiska unsigned char * buf_p;
statiska struct file_operations fops = {
.read = device_read,
.Write = device_write,
.Open = device_open,
.release = device_release
};
statiska struct bcm2835_peripheral myclock = {CLOCK_BASE};
statiska struct bcm2835_peripheral gpio = {GPIO_BASE};
struct DataStruct {
uint32_t buffert [SAMPLE_SIZE];
uint32_t tid.
};
struct DataStruct dataStruct;
statiska unsigned char * ScopeBufferStart;
statiska unsigned char * ScopeBufferStop;
static int map_peripheral (struct bcm2835_peripheral * p) {
p -> addr =(uint32_t *) ioremap (GPIO_BASE, 41 * 4);
Return 0;
}
statisk void unmap_peripheral (struct bcm2835_peripheral * p) {
iounmap (p -> addr).
}
statisk void readScope() {
int counter = 0;
struct timespec ts_start, ts_stop;
local_irq_disable();
local_fiq_disable();
getnstimeofday(&ts_start);
While(Counter<SAMPLE_SIZE) {
dataStruct.Buffer[counter++]= * (gpio.addr + 13);
}
getnstimeofday(&ts_stop);
local_fiq_enable();
local_irq_enable();
dataStruct.time = timespec_to_ns (och ts_stop) - timespec_to_ns (& ts_start);
buf_p = (unsigned char *) & dataStruct;
ScopeBufferStart = (unsigned char *) & dataStruct;
ScopeBufferStop = ScopeBufferStart + sizeof (struct DataStruct);
}
int init_module(void) {
struct bcm2835_peripheral * p = & myclock;
int speed_id = 6;
Stora = register_chrdev (0, enhetsnamn, & fops);
om (Major < 0) {
printk (KERN_ALERT "Reg. char dev misslyckas %d\n",Major);
returnera Major;
}
printk (KERN_INFO "Stora antal %d.\n", Major);
printk (KERN_INFO "skapat en dev filen with\n");
printk (KERN_INFO "" mknod /dev/%s c %d 0'. \n ", enhetsnamn, Major);
om (map_peripheral(&gpio) == -1) {
printk (KERN_ALERT "Kunde inte mappa GPIO\n");
återvända -1;
}
INP_GPIO(BIT0_PIN);
INP_GPIO(BIT1_PIN);
INP_GPIO(BIT2_PIN);
INP_GPIO(BIT3_PIN);
INP_GPIO(BIT4_PIN);
INP_GPIO(BIT5_PIN);
INP_GPIO(BIT0_PIN2);
INP_GPIO(BIT1_PIN2);
INP_GPIO(BIT2_PIN2);
INP_GPIO(BIT3_PIN2);
INP_GPIO(BIT4_PIN2);
INP_GPIO(BIT5_PIN2);
/ * ställa in klocksignal till stift 4 * /
p -> addr =(uint32_t *) ioremap (CLOCK_BASE, 41 * 4);
INP_GPIO(4);
SET_GPIO_ALT(4,0);
*(myclock.addr+28)=0x5A000000 | speed_id;
While(*(myclock.addr+28) & GZ_CLK_BUSY) {};
*(myclock.addr+29)= 0x5A000000 | (0x32 << 12) | 0;
*(myclock.addr+28)=0x5A000000 | speed_id;
returnera framgång;
}
void cleanup_module(void) {
unregister_chrdev (Major, enhetsnamn);
unmap_peripheral(&gpio);
unmap_peripheral(&myclock);
}
static int device_open (struct inode * inode, struct fil * fil) {
statisk int counter = 0;
IF(Device_Open) återvända - EBUSY;
Device_Open ++;
sprintf (msg, "Called device_open %d times\n", counter ++);
msg_Ptr = msg;
readScope();
try_module_get(THIS_MODULE);
returnera framgång;
}
static int device_release (struct inode * inode, struct fil * fil) {
Device_Open--;
module_put(THIS_MODULE);
Return 0;
}
statisk ssize_t device_read (struct fil * filp, char * buffert, size_t längd, loff_t * offset) {
int bytes_read = 0;
om (* msg_Ptr == 0) return 0;
medan (längd & & buf_p < ScopeBufferStop) {
IF(0!=put_user(*(buf_p++), buffert ++))
printk (KERN_INFO "Problemet med kopiera\n");
längd--;
bytes_read ++;
}
återvända bytes_read;
}
statisk ssize_t device_write (struct fil * filp, const char * buff, size_t len, loff_t * off) {
printk (KERN_ALERT "den här åtgärden stöds inte. \n");
återvända - EINVAL;
}
Programmet innehåller några viktiga funktioner. För att en kernel modul fungerar. modulen behöver vissa särskilda posten funktioner. En av dessa fungerar är init_module(), som kallas när kärnmodulen är laddad. Funktionen device_open() anropas när enhetsfilen associeras med kärnmodulen öppnas. Öppna enhetsfilen orsakar ADC läsas ut 10 000 gånger, där resultaten sparas i minnet. Funktionen device_release() anropas när enheten stängs. Funktionen device_read() anropas när en process läser från enhetsfilen. Den här funktionen returnerar de mätningar som gjordes när enhetsfilen öppnades. Den senaste funktionen device_write() behövs för att hantera fallet när en process försöker skriva till den enheten.
Mer om kärna modul: http://www.tldp.org/LDP/lkmpg/2.6/html/lkmpg.html
Hela programmet är ansluten, kan du ladda upp den med hjälp av FileZilla.