1. 程式人生 > >ARM40-A5應用——核心執行緒之於W1LED的應用

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

  安裝核心模組詳情如下:

[email protected]:~# insmod w1led.ko 
create ktrhead ok.
[email protected]:~# rmmod w1led.ko
w1led free
Leaving w1_process.
kw1ledd stopped.
[email protected]
:~# insmod w1led.ko create ktrhead ok. [email protected]:~# 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;
}