標籤

2015年9月29日 星期二

[Banana Pro] Device driver study - LED control

There is my first device driver in Banana Pro board.

My idea is using this device driver module to control the LED board as below:


Here is the build process and source code:

Setup the build env:
Step 1. Download and rebuild the bsp 
git clone https://github.com/LeMaker/lemaker-bsp.git
refer to my another bolg - Banana Pro] Building u-boot, script.bin and linux-kernel

I strong suggest rebuild the BSP on PC, and replace the uboot, kernel and modules to SD card, this is an important process to make sure the version of driver match with kernel. Otherwise, you may got fail when you insert your driver to kernel by insmod command.

Step 2.  Copy the linux kernel tree from PC to Banana board(using scp)
PC side -> Banana side 
scp -r ~/lemarker-bsp/linux-sunxi/ regis@192.168.0.111:/home/regis/ddv/3.4.103/

Programming:
Source code: led_drv.c

/*
 * led_drv:
 *      LED device driver test program for banana Pro
 *      Copyright (c) 2015 Regis Hsu
 *
 *      Thanks to code samples from Gordon Henderson
 ***********************************************************************
 *
 *    led_drv is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as
 *    published by the Free Software Foundation, either version 3 of the
 *    License, or (at your option) any later version.
 *
 *    led_drv is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with wiringPi.
 *    If not, see <http://www.gnu.org/licenses/>.
 ***********************************************************************
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/spinlock.h>
#include <asm/io.h>


// BananaPro GPIO I/O memory address
#define GPIO_BASE (0x01C20800)

#define LED_DRV_MAJOR 31
/*
    IOCTL command
*/
#define LED_ON  1
#define LED_OFF 0

static volatile uint32_t *gpio ;

MODULE_LICENSE("Dual BSD/GPL");

/*add for BananaPro by LeMaker team*/ 
uint32_t readl_1(uint32_t addr)
{
        uint32_t val = 0;
        uint32_t mmap_base = (addr & ~MAP_MASK);
        uint32_t mmap_seek = ((addr - mmap_base) >> 2);
        val = ioread32(gpio + mmap_seek);
        printk("func:%s phyaddr:0x%x val:0x%x\n",__func__, gpio + mmap_seek, va$
        return val;
}

void writel_1(uint32_t val, uint32_t addr)
{
        uint32_t mmap_base = (addr & ~MAP_MASK);
        uint32_t mmap_seek = ((addr - mmap_base) >> 2);
        printk("func:%s phyaddr:0x%x val:0x%x\n",__func__, gpio + mmap_seek, va$
        iowrite32(val, gpio + mmap_seek); 
}

int get_gpio_mode(int pin)
{
        uint32_t regval = 0;
        int bank = pin >> 5;
        int index = pin - (bank << 5);
        int offset = ((index - ((index >> 3) << 3)) << 2);
        uint32_t reval=0;
        uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + ((index >> 3) << 2);
        printk("func:%s pin:%d,  bank:%d index:%d phyaddr:0x%x\n",__func__, pin$
        regval = readl_1(phyaddr);
        return reval;
}

void set_gpio_mode(int pin,int mode)
{
        uint32_t regval = 0;
        int bank = pin >> 5;
        int index = pin - (bank << 5);
        int offset = ((index - ((index >> 3) << 3)) << 2);
        uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + ((index >> 3) << 2);
        printk("func:%s pin:%d, MODE:%d bank:%d index:%d phyaddr:0x%x\n",__func$
        regval = readl_1(phyaddr);
        printk("read reg val: 0x%x offset:%d\n",regval,offset);
        if(INPUT == mode)
        {
                regval &= ~(7 << offset);
                writel_1(regval, phyaddr);
                // for debug
                regval = readl_1(phyaddr);
                printk("Input mode set over reg val: 0x%x\n",regval);
        }
        else if(OUTPUT == mode)
        {
                regval &= ~(7 << offset);
                regval |=  (1 << offset);
                printk("Output mode ready set val: 0x%x\n",regval);
                writel_1(regval, phyaddr);
                // for debug
                regval = readl_1(phyaddr);
                printk("Output mode set over reg val: 0x%x\n",regval);
        } 
        else 
        {
                printk("line:%dpin number error\n",__LINE__);
        }

        return ;
}

void digitalWrite(int pin, int value)
         uint32_t regval = 0;
         int bank = pin >> 5;
         int index = pin - (bank << 5);
         uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + 0x10; // +0x10 -> d$
        printk("func:%s pin:%d, value:%d bank:%d index:%d phyaddr:0x%x\n",__fun$
        regval = readl_1(phyaddr);

        printk("befor write reg val: 0x%x,index:%d\n",regval,index);
        if(0 == value)
        {
                regval &= ~(1 << index);
                writel_1(regval, phyaddr);
                // for debug
                regval = readl_1(phyaddr);
               printk("LOW val set over reg val: 0x%x\n",regval);
        }
        else
        {
                regval |= (1 << index);
                writel_1(regval, phyaddr);
                // for debug
                regval = readl_1(phyaddr);
                printk("HIGH val set over reg val: 0x%x\n",regval);
        }
}

int digitalRead(int pin)
        uint32_t regval = 0;
        int bank = pin >> 5;
        int index = pin - (bank << 5);
        uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + 0x10; // +0x10 -> da$
        printk("func:%s pin:%d,bank:%d index:%d phyaddr:0x%x\n",__func__, pin,b$
        regval = readl_1(phyaddr);
        regval = regval >> index;
        regval &= 1;
        printk("***** read reg val: 0x%x,bank:%d,index:%d,line:%d\n",regval,ban$
        return regval;
}

int led_open (struct inode *pnode, struct file *pfile)
{
        printk("enter %s!\n", __FUNCTION__);
        // remap the physical address to virtual address
        gpio = ioremap(GPIO_BASE, 2*1024);
        return 0;
}

ssize_t led_read(struct file *pfile, char __user *buffer, size_t lenght, loff_t$
{
        printk("enter %s!\n", __FUNCTION__);
        return 0;
}

ssize_t led_write(struct file *pfile, const char __user *buffer, size_t lenght,$
{
        printk("enter %s!\n", __FUNCTION__);
        return lenght;
}
long led_ioctl(struct file *pfile, unsigned int cmd, unsigned long data)
{
    switch (cmd)
    {
        case LED_ON :
            printk ("%s %d!\n", __FUNCTION__, cmd);
            set_gpio_mode(data, OUTPUT);
            digitalWrite (data, HIGH) ;
            break;
        case LED_OFF:
            printk ("%s %d!\n", __FUNCTION__, cmd);
            set_gpio_mode(data, OUTPUT);
            digitalWrite (data, LOW) ;
            break;
        default :
            printk ("%s CMD Error!\n", __FUNCTION__);
            break;
    }
        return 0;
}


static struct file_operations io_dev_fops = {
    .owner = THIS_MODULE,
    .read = led_read,
    .write = led_write,
    .open = led_open,
    .release = led_close,
    .unlocked_ioctl = led_ioctl,
};


int __init led_init(void)
{
        register_chrdev(LED_DRV_MAJOR, "led",&io_dev_fops);
        printk("enter %s!\n", __FUNCTION__);
        return 0;
}

void __exit led_exit(void)
{
        unregister_chrdev(LED_DRV_MAJOR, "led");
        printk("enter %s!\n", __FUNCTION__);
}

module_init(led_init);
module_exit(led_exit);


And, create a make file names "Makefile"
Makefile
obj-m := led_drv.o

It is almost done for the coding!!!
Let's start build the device driver module~~~

regis@lemaker:~/ddr/led$ make -C /home/regis/ddv/3.4.103 M=$PWD modules
make: Entering directory `/home/regis/ddv/3.4.103'
  Building modules, stage 2.
  MODPOST 1 modules
make: Leaving directory `/home/regis/ddv/3.4.103'
regis@lemaker:~/ddr/led$


ok, now, write a test program to test this device driver:

ddr_test.c

/*
 * ddr_test:
 *      LED device driver test program for banana Pro
 *      Copyright (c) 2015 Regis Hsu
 *
 *      Thanks to code samples from Gordon Henderson
 ***********************************************************************
 *
 *    led_drv is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as
 *    published by the Free Software Foundation, either version 3 of the
 *    License, or (at your option) any later version.
 *
 *    led_drv is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with wiringPi.
 *    If not, see <http://www.gnu.org/licenses/>.
 ***********************************************************************
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>

#define DEVICE_NAME "/dev/led_drv"
#define LED_ON  1
#define LED_OFF 0

// the PIN7 of BananaPro J6 output is related 
// the port PH2 of Allwinner A20 GPIO (Port Group"H") 
// it is 32 x 7 + 2 = 226

#define PIN_NO 226

int main(void)
{
    int fd;
    int ret;
    int i;

    printf("\nstart led driver test\n\n");

    fd = open(DEVICE_NAME, O_RDWR);
    printf("fd = %d\n",fd);
    if (fd == -1)
    {
        printf("open device %s error\n",DEVICE_NAME);
    }
    else
    {
        //while(1)
        for (i=0; i<128; i++)
        {
                printf("i=%d _ON\n", i);
                //fgetc(stdin);
                ioctl(fd,LED_ON, PIN_NO);
                sleep(.8);
                printf("i=%d _OFF\n", i);
                //fgetc(stdin);
                ioctl(fd,LED_OFF, PIN_NO);
                sleep(.8);
        }
        ret = close(fd);
       printf ("ret=%d\n",ret);
        printf ("close led driver test\n");
    }
    return 0;
}// end main

Finally, finish the test code and compile it.

regis@lemaker:~/ddr/led$ gcc ddr_test.c -o ddr_test


It is the show time!!!!!
How to test the device driver?

Step 1:
create a device node:
regis@lemaker:~/ddr/led$ sudo mknod -m 666 /dev/led_drv c 31 0

step 2:
load the driver to system to link with the device node
regis@lemaker:~/ddr/led$ sudo insmod led_drv.ko

check where is the led_drv
regis@lemaker:~/ddr/led$ lsmod
Module                  Size  Used by
led_drv                 5049  0 
dm_crypt               17240  0 
rfcomm                 58954  0 
bnep                   14608  2 
bluetooth             266122  10 bnep,rfcomm
ap6210                624941  0 
mali_drm                2607  0 
drm                   215174  1 mali_drm
mali                  114752  0 
ump                    58497  1 mali

step 3:
regis@lemaker:~/ddr/led$ ./ddr_test 

start led driver test

fd = 3
i=0 _ON
i=0 _OFF
i=1 _ON
i=1 _OFF
.......
i=126 _ON
i=126 _OFF
i=127 _ON
i=127 _OFF
ret=0
close led driver test
regis@lemaker:~/ddr/led$ 

You will see the LED flash 128 times.


/////////////////////////////////////////////////////////////////
Some information for reference:
Find an available device node number by this way,

1. Install the Code::Blocks IDE tools
 regis@lemaker:~/ddr/led$  sudo apt-get install codeblocks    

2. List down the device node
regis@lemaker:~/ddr/led$  cat /proc/devices 


Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  4 ttyS
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
 10 misc
 13 input
 14 sound
 29 fb
 81 video4linux
 89 i2c
108 ppp
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
216 rfcomm
226 drm
241 mali
242 ump
243 hdmi
244 lcd
245 roccat
246 hidraw
247 pa_chrdev
248 ace_chrdev
249 usbmon
250 g2d_chrdev
251 disp
252 bsg
253 media
254 rtc

Block devices:
  1 ramdisk
259 blkext
  7 loop
  8 sd
  9 md
 11 sr
 65 sd
 66 sd
 67 sd
 68 sd
 69 sd
 70 sd
 71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
253 device-mapper
254 mdp

Linux - BnanaPi - 2

Linux - BnanaPi - 1

蜘蛛Robot - Quadruped Robot - 《PCB handmade》《PCB 製作 v2.0》



PCBv1.0的經驗讓我洗PCB的信心大增,雖然Power鍵設計錯誤而且I2C與analog的IO都需要跳線才能使用。。。

這次升級v2.0,把零件重新排列,以線距離最短為主要placement的要件,經過幾天的實驗,終於設計出完全不用跳線而且PCB尺寸還更小,真是棒極了!!!

《銅箔面》

《正面》

我還把零件位置圖轉印到正面,看起來又往前進一步。

再用腐蝕劑把銅箔洗掉,




哈,我設計一個icon,好玩吧!

然後,鑽孔擺零件上錫。
與V1.0比比看,如何?






開心!!!



蜘蛛Robot - Quadruped Robot - 《PCB change》《PCB 更換》

2015﹣09﹣21
今天同好 Wing Hui在facebook發文通知,我的蜘蛛Robot上了Arduino官網的首頁
開心!!




Anyway,今天還是要繼續蜘蛛robot的改造計劃。

上篇完成了PCB handmade手工洗板,準備換腦。



先把舊板子的連接線全部拆除,拆的時候要小心一些,不要把線拉斷了。



板子拆下來了,新舊板子比比看!



側邊看看:



再來,正面看看:嗯,比較專業一點點~~~



背面看看:因為單面板,本來預期3條跳線而已,結果button switch 的pin定義設計弄錯,多跳了一些。。。XD
不過,看起來清爽多了,而且不擔心掉線。



《待續》



spider 2

Here are the parts:
1x Arduino Pro Mini
1x DC-DC(12-5v/3A output)
1x HC-06 Bluetooth module(option)
12x SG90 servo(3DOF for 4 legs)
1x 3000mhA Li battery
1x 12V Jack
1x 680 Ohm 1/4 watt 5% Resistor
1x 3mm Blue LED
1x Tactile Switch
1x 5x7cm perfboard
Some male and female pin headers
Small guage wire(Solid or Stranded)
I believe that these parts are most popular and not expensive. They are just cost me about 2,000 Taiwan dollar.

spider 1

This is my first project for the 4 legs robot and it took me about 1 year development.
It is a robot that relies on calculations to position servos and pre-programmed sequences of legs.
I'm doing this by handmade way is because of it could be fun and educational for 3D design/printing and robot control.
This is the fourth generation of my design, you can take a look here if you are interested the history.
Building this project is fun, however, it should take you more time and patient to implement.
If it is a hard job to you, the product comes from Sunfounder might a good choice.
Before going to next step, please aware that the soldering tools and 3D printer will be used in this project.
Let's get start and have fun!