-
-
Save fazibear/f1fe97c9799501e0e0955859e12ef4f8 to your computer and use it in GitHub Desktop.
The Beginner’s Guide to Linux Kernel Module, Raspberry Pi and LED Matrix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/init.h> | |
#include <linux/module.h> | |
#include <linux/kthread.h> | |
#include <linux/delay.h> | |
#include <linux/gpio.h> | |
MODULE_LICENSE("GPL"); | |
/* GPIO */ | |
#define A1 17 // 0 | |
#define A2 18 // 1 | |
#define A3 27 // 2 | |
#define OE 22 // 3 | |
#define LE 23 // 4 | |
#define SDI 24 // 5 | |
#define CLK 25 // 6 | |
#define LINES 8 | |
#define PER_LINE 12 | |
static u8 pix_screen[LINES][PER_LINE] = { | |
{ | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
}, | |
{ | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
}, | |
{ | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
}, | |
{ | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
}, | |
{ | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
}, | |
{ | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
}, | |
{ | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
}, | |
{ | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
0b00000000,0b00000000,0b00000000,0b00000000, | |
}, | |
}; | |
void pix_line(u8 row){ | |
gpio_set_value(A1, !(row & 0b00000001)); | |
gpio_set_value(A2, !(row & 0b00000010)); | |
gpio_set_value(A3, !(row & 0b00000100)); | |
} | |
void pix_dot(int x, int y, int r, int g, int b) { | |
uint8_t l,p,t; | |
if(y % 2){ | |
x = (x + 16); | |
} | |
y = (y / 2) - ((y / 2) % 1); | |
l = x / 8; | |
p = 7 - x % 8; | |
t = pix_screen[y][l]; | |
//printf("line:%i, l:%i, p:%i, t:%i\n", y,l,p,t); | |
if(r) { | |
t |= 1 << p; | |
}else{ | |
t &= ~(1 << p); | |
} | |
pix_screen[y][l] = t; | |
l = x / 8 + 4; | |
p = 7 - x % 8; | |
t = pix_screen[y][l]; | |
if(g) { | |
t |= 1 << p; | |
}else{ | |
t &= ~(1 << p); | |
} | |
pix_screen[y][l] = t; | |
l = x / 8 + 8; | |
p = 7 - x % 8; | |
t = pix_screen[y][l]; | |
if(b) { | |
t |= 1 << p; | |
}else{ | |
t &= ~(1 << p); | |
} | |
pix_screen[y][l] = t; | |
} | |
void pix_gpio_init(void){ | |
printk(KERN_INFO "PIX: starting gpio..."); | |
gpio_request(A1, "A1"); | |
gpio_request(A2, "A2"); | |
gpio_request(A3, "A3"); | |
gpio_request(OE, "OE"); | |
gpio_request(LE, "LE"); | |
gpio_request(SDI, "SDI"); | |
gpio_request(CLK, "CLK"); | |
gpio_direction_output(A1, 0); | |
gpio_direction_output(A2, 0); | |
gpio_direction_output(A3, 0); | |
gpio_direction_output(OE, 1); | |
gpio_direction_output(LE, 0); | |
gpio_direction_output(SDI, 0); | |
gpio_direction_output(CLK, 0); | |
printk(KERN_INFO "PIX: starting gpio done."); | |
} | |
void pix_gpio_exit(void){ | |
printk(KERN_INFO "PIX: stopping gpio..."); | |
gpio_free(A1); | |
gpio_free(A2); | |
gpio_free(A3); | |
gpio_free(OE); | |
gpio_free(LE); | |
gpio_free(SDI); | |
gpio_free(CLK); | |
printk(KERN_INFO "PIX: stopping gpio done."); | |
} | |
/* SYSFS */ | |
static struct kobject *pix_kobject; | |
static ssize_t set_pix(struct kobject *kobj, struct kobj_attribute *attr, const char *buff, size_t count) { | |
u8 x = 0; | |
u8 y = 0; | |
u8 r = 0; | |
u8 g = 0; | |
u8 b = 0; | |
sscanf(buff, "%hhd %hhd %hhd %hhd %hhd", &x, &y, &r, &g, &b); | |
pix_dot(x,y,r,g,b); | |
// printk(KERN_INFO "PIX: %d %d %d %d %d", x,y,r,g,b); | |
return count; | |
} | |
static struct kobj_attribute pix_attribute =__ATTR(dot, (S_IWUSR | S_IRUGO), NULL, set_pix); | |
void pix_sysfs_init(void){ | |
printk(KERN_INFO "PIX: starting sysfs..."); | |
pix_kobject = kobject_create_and_add("pix", NULL); | |
if (sysfs_create_file(pix_kobject, &pix_attribute.attr)) { | |
pr_debug("failed to create pix sysfs!\n"); | |
} | |
printk(KERN_INFO "PIX: starting sysfs done."); | |
} | |
void pix_sysfs_exit(void){ | |
printk(KERN_INFO "PIX: stopping sysfs..."); | |
kobject_put(pix_kobject); | |
printk(KERN_INFO "PIX: stopping sysfs done."); | |
} | |
/* THREAD */ | |
#define THREAD_PRIORITY 45 | |
#define THREAD_NAME "pix" | |
struct task_struct *task; | |
int pix_thread(void *data){ | |
u8 line, pos, bit; | |
struct task_struct *TSK; | |
struct sched_param PARAM = { .sched_priority = MAX_RT_PRIO - 50 }; | |
//struct sched_param PARAM = { .sched_priority = DEFAULT_PRIO }; | |
TSK = current; | |
PARAM.sched_priority = THREAD_PRIORITY; | |
sched_setscheduler(TSK, SCHED_FIFO, &PARAM); | |
while(1) { | |
for(line = 0; line < LINES; line++) { | |
pix_line(line); | |
for(pos = 0; pos < PER_LINE; pos++) { | |
for (bit = 0; bit < 8; bit++) { | |
gpio_set_value(SDI, !!(pix_screen[line][pos] & (1 << (7 - bit)))); | |
gpio_set_value(CLK, 1); | |
gpio_set_value(CLK, 0); | |
} | |
} | |
gpio_set_value(LE, 1); | |
gpio_set_value(LE, 0); | |
gpio_set_value(OE, 0); | |
usleep_range(2000, 2000); | |
gpio_set_value(OE, 1); | |
} | |
if (kthread_should_stop()) break; | |
} | |
return 0; | |
} | |
void pix_thread_init(void){ | |
printk(KERN_INFO "PIX: starting thread..."); | |
task = kthread_run(pix_thread, NULL, THREAD_NAME); | |
printk(KERN_INFO "PIX: starting thread done."); | |
} | |
void pix_thread_exit(void){ | |
printk(KERN_INFO "PIX: stopping thread..."); | |
kthread_stop(task); | |
printk(KERN_INFO "PIX: stopping thread done."); | |
} | |
/* MODULE */ | |
static int __init pix_init(void){ | |
printk(KERN_INFO "PIX: staring..."); | |
pix_gpio_init(); | |
pix_thread_init(); | |
pix_sysfs_init(); | |
printk(KERN_INFO "PIX: staring done."); | |
return 0; | |
} | |
static void __exit pix_exit(void){ | |
printk(KERN_INFO "PIX: stopping..."); | |
pix_sysfs_exit(); | |
pix_thread_exit(); | |
pix_gpio_exit(); | |
printk(KERN_INFO "PIX: stopping done."); | |
} | |
module_init(pix_init); | |
module_exit(pix_exit); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment