Skip to content

Instantly share code, notes, and snippets.

@fazibear
Last active November 7, 2021 23:35
  • Star 11 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
Star You must be signed in to star a gist
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
#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