1.5 LS2K0300-字符设备-点灯(修订1)

分为3个模块,一个驱动模块、一个测试模块、一个编译模块

1、驱动模块(以字符设备驱动为主)

//ls2k300_LED_drv.c

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/io.h>

#define DEVICE_NAME "ls2k_gpioled"  // /dev/ls2k_gpioled
#define CLASS_NAME  "ls2k_led"      // 设备类名称
#define GPIO_PIN     83              // 龙芯板实际GPIO编号

// 全局设备对象
static int major;
static dev_t devno;
static struct class *led_class;
static struct device *led_device;

// 文件操作函数集
static ssize_t led_write(struct file *filp, const char __user *buf,
                         size_t count, loff_t *ppos)
{
    char val;
    int valid = 0; // 有效指令标志
    int i;

    for(i=0; i<count; i++) {
        if(copy_from_user(&val, buf+i, 1)) 
            return -EFAULT;
        if(val == '\n') 
            continue;

        // 仅处理首个有效字符
        if (val == '0' || val == '1') {
            gpio_set_value(GPIO_PIN, val == '0' ? 0 : 1); //关键修正点
            printk("Setting GPIO %d to value %c\n", GPIO_PIN, val); 
            valid = 1;
            break; //退出循环,后续字符不处理
        }
    }
    //三元运算符的语法是condition ? expr1 : expr2,如果条件为真,则返回expr1,否则返回expr2。
    return valid ? count : -EINVAL; 
}


static int led_open(struct inode *inode, struct file *filp)
{
    printk(KERN_INFO "LED device opened\n");
    return 0;
}

static int led_release(struct inode *inode, struct file *filp)
{
    printk(KERN_INFO "LED device closed\n");
    return 0;
}

static struct file_operations fops = {
    .owner   = THIS_MODULE,
    .open    = led_open,
    .release = led_release,
    .write   = led_write,
};

static int __init led_init(void)
{
    // GPIO配置
    if (gpio_request(GPIO_PIN, "ls2k_led")) {
        printk(KERN_ERR "Failed to request GPIO %d\n", GPIO_PIN);
        return -EBUSY;
    }
    gpio_direction_output(GPIO_PIN, 0);

    // 动态申请主设备号
    major = register_chrdev(0, DEVICE_NAME, &fops);
    
    if (major < 0) {
        printk(KERN_ERR "Register char device failed\n");
        gpio_free(GPIO_PIN);
        return major;
    }


    // 创建设备类
    led_class = class_create(THIS_MODULE, CLASS_NAME);
    if (IS_ERR(led_class)) {
        unregister_chrdev(major, DEVICE_NAME);
        gpio_free(GPIO_PIN);
        printk(KERN_ERR "Failed to create device class\n");
        return PTR_ERR(led_class);
    }

    // 创建设备节点
    devno = MKDEV(major, 0);
    led_device = device_create(led_class, NULL, devno, NULL, DEVICE_NAME);
    if (IS_ERR(led_device)) {
        class_destroy(led_class);
        unregister_chrdev(major, DEVICE_NAME);
        gpio_free(GPIO_PIN);
        printk(KERN_ERR "Failed to create device\n");
        return PTR_ERR(led_device);
    }

    printk(KERN_INFO "ls2k0300 LED: Device registered (major=%d)\n", major);
    printk(KERN_INFO "ls2k0300 LED: Driver loaded (GPIO:%d)\n", GPIO_PIN);
    return 0;
}

static void __exit led_exit(void)
{
    device_destroy(led_class, devno);  // 先销毁设备
    class_destroy(led_class);          // 再销毁类
    unregister_chrdev(major, DEVICE_NAME);
    gpio_free(GPIO_PIN);
    printk(KERN_INFO "Driver unloaded\n");
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

2、测试模块(类似stm32中逻辑开发的main函数)

//ls2k300_LED_test.c--例程500ms闪烁一次,类似延时函数

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <signal.h>  // 新增信号处理头文件

#define DEV_PATH "/dev/ls2k_gpioled"

static volatile int keep_running = 1;  // 循环控制标志

int main(int argc, char **argv)
{
    int fd;
    char led_state;

    // 打开设备文件
    if ((fd = open(DEV_PATH, O_WRONLY)) < 0) {
        perror(" 打开设备失败");
        return EXIT_FAILURE;
    }
    
    printf("例程1: LED开始500ms交替闪烁\n");
    fflush(stdout); // 确保立即输出提示--强制刷新输出缓冲区
    
    led_state = '0';
    while(keep_running) {
        printf("\rLED: %c → ", led_state);
        fflush(stdout);

        // 写入驱动
        if (write(fd, &led_state, 1) < 0) {
            printf("\n 写入失败: %s\n", strerror(errno));
            break;
        }
        
        // 切换状态
        led_state = (led_state == '0') ? '1' : '0';
        
        // 精确延时500ms
        usleep(500000);  // 相较于sleep提高精度
    }

    // 清理资源
    close(fd);
    printf("\n 程序退出,最后状态:%c\n", led_state);
    return EXIT_SUCCESS;
}

3、编译模块(编译驱动模块、测试模块)

KERNELDIR := /home/user/Desktop/linux-4.19        #内核路径
CURRENT_PATH := $(shell pwd)                    #当前路径
obj-m := $(ls2k0300_LED_drv).o


all:
    $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

执行一下命令:

//生成的*.ko文件

make       

//生成的ls2k0300_LED_test  文件

loongarch64-linux-gnu-gcc ls2k0300_LED_test .c -o ls2k0300_LED_test 

//将*.ko和ls2k0300_LED_test 上传到ls2k0300(可以使用带有ssh协议或串口协议的软件)

确保ls2k0300的目录下有上述2个文件

 可以看到日志正在输出、板子上的小灯正在闪烁,至此,例程1:LED-500ms交替闪烁效果实现。

(若有用,请多点赞,关注,支持!!!)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值