ARM40-A5应用——内核线程之于W1LED的应用

ARM40-A5应用——内核线程之于W1LED的应用

2018.11.01
版权声明:本文为博主原创文章,允许转载。
  
  ARM40的一些产品上需要用到较多的LED指示灯,此时推荐使用W1LED的方法来实现。
  W1LED监测GPIO、串口(RS232和RS485)、CAN等外设的输入/输出状态,定期(例如每200ms)给LED指示灯板发送数据,控制LED指示灯的亮/灭。
  LED灯板上有一颗MCU,接收W1LED发来的数据,根据接收到的指令,来控制灯板上的LED。
  W1LED使用3根线(VCC、GND、1-wire)即可,并且多个灯板可共享主板上的3根线,根据各自的ID来执行发给自己的指令。
  W1LED方法占用IO少,使用灵活方便,并且LED反应了主机的工作状态,而不仅仅是反应了局部硬件电路的状态。当然,也可以在电路板上增加硬件控制的指示设备,与W1LED的方法并无冲突。

一、内核线程

1.1、内核线程源码

  W1LED需定期(例如200ms)给LED灯板发数据。内核线程启动后按周期性间隔运行,能够实现这个任务。代码见附(1),共包含3个文件:

w1led_kthread.c
w1led_io.c
w1led_io.h

1.2、Makefile

MODULE_NAME             := w1led

obj-m                   += $(MODULE_NAME).o
$(MODULE_NAME)-objs     := w1led_kthread.o w1led_io.o

PWD      := $(shell pwd)
KDIR     := /home/arm40_a5d3_kernel/linux-at91-master
CC       := /home/arm-2014.05/bin/arm-none-linux-gnueabi-gcc
all:
        make -C $(KDIR) M=$(PWD) modules
clean:
        rm -rf *.o *.mod.c *.symvers *.order

  make后生成 w1led.ko文件。
  注意:
    拷贝Makefile后,需要将命令前面的空格修正为"TAB空格“。对Makefile文件来说,"TAB空格"用于指示本行为命令。

1.3、安装内核模块

  将w1led.ko文件拷贝到ARM40:

rmmod w1led.ko
lsmod
insmod w1led.ko

  安装内核模块详情如下:

root@ARM40:~# insmod w1led.ko 
create ktrhead ok.
root@ARM40:~# rmmod w1led.ko
w1led free
Leaving w1_process.
kw1ledd stopped.
root@ARM40:~# insmod w1led.ko 
create ktrhead ok.
root@ARM40:~# lsmod
Module                  Size  Used by    Tainted: G  
w1led                   1515  0 

二、运行情况

  安装内核模块后,内核线程立即就会运行,top -b命令摘录如下:
在这里插入图片描述
  可以看到kw1ledd的运行情况。
  另外可以看到LED灯板上的LED在闪烁了。
  

参考文章

  Linux内核drivers/w1/w1_io.c
  linux模块编程(二)——运行不息的内核线程kthread
  https://blog.csdn.net/qb_2008/article/details/6835783
  Linux内核多线程(二)
  https://www.cnblogs.com/zhuyp1015/archive/2012/06/11/2545702.html
  ARM40-­A5应用程序——温度传感器DS18B20的驱动与应用
  https://blog.csdn.net/vonchn/article/details/83586870

附:

(1)w1led线程源码
  (1a) w1led_kthread.c

#include "w1led_io.h"
#include <linux/sched.h>
#include <linux/kthread.h>

static struct task_struct * _tsk;

int w1_process(void* data)
{
        unsigned char buf[2];
        const unsigned long jtime = msecs_to_jiffies(100);      //100ms

        do {
                w1_reset_bus();
                w1_write_8(0xcc);
                w1_write_8(0x44);

                w1_reset_bus();
                w1_write_8(0xcc);
                w1_write_8(0xbe);

                buf[0] = w1_read_8();
                buf[1] = w1_read_8();
                DPRINTK("b0=%x,b1=%x\n",buf[0],buf[1]);
                
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(jtime);
        } while(!kthread_should_stop());

        DPRINTK("Leaving w1_process.\n");
        return 0;
}

static int __init w1led_init(void)
{
        int ret;

        ret = gpio_request(DQ, "W1LED");
        if (ret) {
                DPRINTK("unable to request GPIO for W1LED.\n");
                return ret;
        }

        gpio_direction_output(DQ,1);            //初始时DQ为1
        udelay(1);

        _tsk = kthread_run(w1_process, NULL, "kw1ledd");
        if (IS_ERR(_tsk)) {                     //判断线程是否有效
                DPRINTK("create kthread fail.\n");
                return -1;
        } else
                DPRINTK(KERN_INFO "create ktrhead ok.\n");

        return 0;
}

static void __exit w1led_exit(void)
{
        DPRINTK("w1led free\n");

        if (!IS_ERR(_tsk)){
                kthread_stop(_tsk);
                printk(KERN_INFO "kw1ledd stopped.\n");
        }

        gpio_free(DQ);
}

module_init(w1led_init);
module_exit(w1led_exit);

MODULE_AUTHOR("rit <[email protected]>");
MODULE_DESCRIPTION("ds18b20 driver");
MODULE_LICENSE("GPL");

  (1b) w1led_io.h

#include <linux/delay.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>

#define DEBUG 
#if defined(DEBUG)                      
#define DPRINTK(fmt,arg...) printk(fmt,##arg); 
#else
#define DPRINTK(fmt,arg...)
#endif

#define DQ              57              //148=PE20(32*4+20),57=PB25(32*1 + 25)

int w1_reset_bus(void);
void w1_write_8(unsigned char byte);
unsigned char w1_read_8(void);

  (1c) w1led_io.c

#include "w1led_io.h"

int w1_reset_bus(void)
{
        //向ds18b20发送一个500us低电平复位信号
        gpio_direction_output(DQ,0);    //Drives DQ low
        udelay(500);

        gpio_direction_input(DQ);       //Releases the bus
        udelay(70);

        //检测到DQ上为高, 复位失败; 为低电平,复位成功
        if(gpio_get_value(DQ))          // Sample for presence pulse from slave
                return -1;

        //等待复位时隙完毕后,继续将DQ置为高电平
        udelay(410);                    // Complete the reset sequence recovery
        gpio_direction_output(DQ,1);

        return 0;
}

static inline void w1_write_bit(int bit)
{
        if (bit) {                       // Write '1' bit
                gpio_direction_output(DQ,0); // Drives DQ low
                udelay(6);
                gpio_direction_input(DQ);    // Releases the bus
                udelay(64);
        } else {                         // Write '0' bit
                gpio_direction_output(DQ,0); // Drives DQ low
                udelay(60);
                gpio_direction_input(DQ);    // Releases the bus
                udelay(10);
        }
}

void w1_write_8(unsigned char byte)
{
        int i;

        for (i = 0; i < 8; i++) {
                w1_write_bit((byte >> i) & 0x1);
        }
}

static inline unsigned char w1_read_bit(void)
{
        int result;

        //sample timing is critical here
        gpio_direction_output(DQ,0);            //Drives DQ low
        udelay(6);
        gpio_direction_input(DQ);               //Releases the bus
        udelay(2);                              //udelay(9); for some situation
        result = gpio_get_value(DQ) ? 1 : 0;    //Sample the bit value from the slave
        udelay(55);                             //Complete the time slot and 10us recovery

        return result & 0x1;
}

unsigned char w1_read_8(void)
{
        int i;
        unsigned char result = 0;

        for (i = 0; i < 8; ++i)
                result |= (w1_read_bit() << i);

        return result;
}
                               

猜你喜欢

转载自blog.csdn.net/vonchn/article/details/83619734