eswww / pi-snap-cam-driver

pi-snap cam driver (light sensor, button)
GNU General Public License v2.0
0 stars 0 forks source link

빛 센서 연결 #3

Closed punkyoon closed 6 years ago

punkyoon commented 6 years ago
punkyoon commented 6 years ago

49fcb5afec0853c8859987b36e30bbbee18fcff0

heaeat commented 6 years ago

이것저것 찾다가 줍줍했읍니다..

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static void pabort(const char *s)
{
    perror(s);
    abort();
}

static const char *device = "/dev/spidev0.0";

static const int MCP3208_STARTBIT=  0x10;   /*  Always 1 */
static const int MCP3208_SE=        0x08;   /*   Single end mode (bit3='1')  */

// SPI mode must be setup in here!!
static uint8_t mode=SPI_MODE_0;
// 0 : clock normaly Lo & dat on Rising edge, CE active Lo, MSB first
// options for mode setup
/*
#define SPI_CPHA                0x01  Clock Phase
#define SPI_CPOL                0x02  Clock Pol
#define SPI_MODE_0              (0|0)
#define SPI_MODE_1              (0|SPI_CPHA)
#define SPI_MODE_2              (SPI_CPOL|0)
#define SPI_MODE_3              (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH             0x04  CS pol
#define SPI_LSB_FIRST           0x08  bit order
#define SPI_3WIRE               0x10
#define SPI_LOOP                0x20
#define SPI_NO_CS               0x40  CS on/off
#define SPI_READY               0x80
*/

static uint8_t bits = 8;
static uint32_t speed = 100000;
static uint16_t delay;
static uint8_t ad_mode=0;
static uint8_t channel=0;

static void transfer(int fd, uint8_t cmd[], uint8_t cmd_size)
{
    int ret;

        uint8_t rx[cmd_size];
        struct spi_ioc_transfer tr = {
                .tx_buf = (unsigned long)cmd,
                .rx_buf = (unsigned long)rx,
                .len = cmd_size,
                .delay_usecs = delay,
                .speed_hz = speed,
                .bits_per_word = bits,
        };

//  printf("transfer: size of command= %d \n",cmd_size);

    while(1){
    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    if (ret < 1)

        pabort("can't send spi message");

    /* data uses rx1, rx2 */ 
    for (ret = 1; ret < cmd_size ; ret++) {
        if (!(ret % 6))
            puts("");
        printf("%x ",rx[ret]);
//      printf("%.2X", rx[ret]);
    }   
    printf("\n");
    sleep(1);
    }
}

static void print_usage(const char *prog)
{
    printf("Usage: %s [-Dsdsc]\n", prog);
    puts("  -D --device   device to use (default /dev/spidev0.0)\n"
         "  -s --speed    max speed (Hz)\n"
         "  -d --delay    delay (usec)\n"
         "  -m --mode     Single End mode\n"
         "  -c --channel    channel number \n"
    );
    exit(1);
}

static void parse_opts(int argc, char *argv[])
{
    while (1) {
        static const struct option lopts[] = {
            { "device",  1, 0, 'D' },
            { "speed",   1, 0, 's' },
            { "delay",   1, 0, 'd' },
            { "mode",    0, 0, 'm' },
            { "channel", 1, 0, 'c' },
            { NULL, 0, 0, 0 },
        };
        int c;

        c = getopt_long(argc, argv, "D:s:d:b:mc:", lopts, NULL);

        if (c == -1)
            break;

        switch (c) {
        case 'D':
            device = optarg;
            break;
        case 's':
            speed = atoi(optarg);
            break;
        case 'd':
            delay = atoi(optarg);
            break;
        case 'm':
            ad_mode=1;
            break;
        case 'c':
            channel=atoi(optarg);
            break;
        default:
            print_usage(argv[0]);
            break;
        }
    }
}

int main(int argc, char *argv[])
{
    int ret = 0;
    int fd;
    uint8_t commands[]={0x11,0x22,0XFF};

    parse_opts(argc, argv);

    fd = open(device, O_RDWR);
    if (fd < 0)
        pabort("can't open device");

    /*
     * spi mode
     */
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
    if (ret == -1)
        pabort("can't set spi mode");

    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
    if (ret == -1)
        pabort("can't get spi mode");

    /*
     * bits per word
     */
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't set bits per word");

    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't get bits per word");

    /*
     * max speed hz
     */
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't set max speed hz");

    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't get max speed hz");

//  printf("spi mode: %d\n", mode);
//  printf("bits per word: %d\n", bits);
//  printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
//
//  printf("AD mode=%d, channel=%d\n",ad_mode,channel);
//  printf("channel=%d \n",channel);
//  printf("mode =%d \n",MCP3208_SE*ad_mode);
//  printf("command =0x%x \n",MCP3208_STARTBIT | MCP3208_SE*(ad_mode)|channel);

    // put the command code into two bytes to fit hole transmission into 24 bit(8x3)
    // See MCP3208 datasheet
    //  xxxx x1..   ..XX XXXX   XXXX XXXX
    //        |||   ||
    //        ||2   10 Channel select(3bits)
    //        ||
    //    |SE/!DIFF mode
    //        StartBit
    channel=channel & 0x07;
    commands[0]=(MCP3208_STARTBIT | MCP3208_SE*(ad_mode & 1) | channel)/4;
    commands[1]=(channel*64) & 0xFF;

    transfer(fd, commands, ARRAY_SIZE(commands));

    close(fd);

    return ret;
}
heaeat commented 6 years ago
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mutex.h>

#define DRIVER_NAME "mcp3208"

#define MCP320X_PACKET_SIZE 3
#define MCP320X_DIFF        0
#define MCP320X_SINGLE      1
#define MCP3208_CHANNELS    4

struct mcp3208_drvdata {
    struct spi_device *spi;
    struct mutex lock;
    unsigned char tx[MCP320X_PACKET_SIZE]  ____cacheline_aligned;
    unsigned char rx[MCP320X_PACKET_SIZE]  ____cacheline_aligned;
    struct spi_transfer xfer ____cacheline_aligned;
    struct spi_message msg ____cacheline_aligned;
};

/* set bus_num & chip in parameter */
static int spi_bus_num     = 0;
static int spi_chip_select = 0;
module_param( spi_bus_num, int, S_IRUSR | S_IRGRP | S_IROTH |  S_IWUSR );
module_param( spi_chip_select, int, S_IRUSR | S_IRGRP | S_IROTH |  S_IWUSR );

static unsigned int mcp3208_get_value( struct mcp3208_drvdata *data, int channel )
{
    unsigned int r = 0;
    unsigned char c = channel & 0x03;

    mutex_lock( &data->lock );
    data->tx[0] = 1 << 2;       // start bit
    data->tx[0] |= 1 << 1;      // Single
    data->tx[1] = c << 6;       // channel
    data->tx[2] = 0;

    if( spi_sync( data->spi, &data->msg) ) { 
        printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
    }
    mutex_unlock(&data->lock);

    r =  (data->rx[1] & 0x0F) << 8;
    r |= data->rx[2];

    return r;
}

static int ch_show(struct device *dev, struct device_attribute *attr, char *buf)
{
    struct mcp3208_drvdata *data = (struct mcp3208_drvdata *)dev_get_drvdata(dev);
    int c = attr->attr.name[2] - 0x30;
    int v = 0;

    if( (c > -1) && (c < MCP3208_CHANNELS) ) {
        v = mcp3208_get_value(data, c);
    }
    return snprintf (buf, PAGE_SIZE, "%d\n", v);
}
static DEVICE_ATTR(ch0, S_IRUSR|S_IRGRP|S_IROTH, ch_show,NULL );
static DEVICE_ATTR(ch1, S_IRUSR|S_IRGRP|S_IROTH, ch_show,NULL );
static DEVICE_ATTR(ch2, S_IRUSR|S_IRGRP|S_IROTH, ch_show,NULL );
static DEVICE_ATTR(ch3, S_IRUSR|S_IRGRP|S_IROTH, ch_show,NULL );

static struct spi_board_info mcp3208_info = {
    .modalias = "mcp3208",
    .max_speed_hz = 1000000,
    .bus_num = 0,
    .chip_select = 0,
    .mode = SPI_MODE_3,
};

static int mcp3208_probe(struct spi_device *spi)
{
    struct mcp3208_drvdata *data;
    int ret;

    printk(KERN_INFO "mcp3208 probe\n");

    /* set SPI */
    spi->max_speed_hz = mcp3208_info.max_speed_hz;
    spi->mode = mcp3208_info.mode;
    spi->bits_per_word = 8;
    if( spi_setup( spi ) ) {
        printk(KERN_ERR "spi_setup returned error\n");
        return -ENODEV;
    }

    data = kzalloc( sizeof(struct mcp3208_drvdata), GFP_KERNEL );
    if(data == NULL ) {
        printk(KERN_ERR "%s: no memory\n", __func__ );
        return -ENODEV;
    }
    data->spi = spi;
    mutex_init( &data->lock );

    data->xfer.tx_buf = data->tx;
    data->xfer.rx_buf = data->rx;
    data->xfer.bits_per_word = 8;
    data->xfer.len = MCP320X_PACKET_SIZE;
    data->xfer.cs_change = 0;
    data->xfer.delay_usecs = 0;
    data->xfer.speed_hz = 1000000;
    spi_message_init_with_transfers( &data->msg, &data->xfer, 1 );

    spi_set_drvdata( spi, data );

    ret = device_create_file( &spi->dev, &dev_attr_ch0 );
    if(ret) {
        printk(KERN_ERR "failed to add ch0 attribute\n" );
    }   
    ret = device_create_file( &spi->dev, &dev_attr_ch1 );
    if(ret) {
        printk(KERN_ERR "failed to add ch1 attribute\n" );
    }   
    ret = device_create_file( &spi->dev, &dev_attr_ch2 );
    if(ret) {
        printk(KERN_ERR "failed to add ch2 attribute\n" );
    }   
    ret = device_create_file( &spi->dev, &dev_attr_ch3 );
    if(ret) {
        printk(KERN_ERR "failed to add ch3 attribute\n" );
    }   

    return 0;
}

static int mcp3208_remove(struct spi_device *spi)
{
    struct mcp3208_drvdata *data;
    data = (struct mcp3208_drvdata *)spi_get_drvdata(spi);

    device_remove_file( &spi->dev, &dev_attr_ch0 );
    device_remove_file( &spi->dev, &dev_attr_ch1 );
    device_remove_file( &spi->dev, &dev_attr_ch2 );
    device_remove_file( &spi->dev, &dev_attr_ch3 );

    kfree(data);
    printk(KERN_INFO "mcp3208 removed\n");

    return 0;
}

static struct spi_device_id mcp3208_id[] = {
    { "mcp3208", 0 },
    { },
};
MODULE_DEVICE_TABLE(spi, mcp3208_id);

static struct spi_driver mcp3208_driver = {
    .driver = {
        .name   = DRIVER_NAME,
        .owner  = THIS_MODULE,
    },
    .id_table = mcp3208_id,
    .probe  = mcp3208_probe,
    .remove = mcp3208_remove,
};

static void spi_remove_device(struct spi_master *master, unsigned int cs)
{
   struct device *dev;
   char str[128];

    snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
    // find SPI device
    dev = bus_find_device_by_name(&spi_bus_type, NULL, str);

    // if exist, delete device
    if( dev ){
        printk(KERN_INFO "Delete %s\n", str);
        device_del(dev);
    }
}

static int mcp3208_init(void)
{
    struct spi_master *master;
    struct spi_device *spi_device;

    spi_register_driver(&mcp3208_driver);

    mcp3208_info.bus_num = spi_bus_num;
    mcp3208_info.chip_select = spi_chip_select;
    master = spi_busnum_to_master(mcp3208_info.bus_num);

    if( ! master ) {
        printk( KERN_ERR "spi_busnum_to_master returned NULL\n");
        spi_unregister_driver(&mcp3208_driver);
        return -ENODEV;
    }

    // Since it is exclusive to spidev 0.0 in the initial state, it must be removed
    spi_remove_device(master, mcp3208_info.chip_select);
    spi_device = spi_new_device( master, &mcp3208_info );

    if( !spi_device ) {
        printk(KERN_ERR "spi_new_device returned NULL\n" );
        spi_unregister_driver(&mcp3208_driver);
        return -ENODEV;
    }

    return 0;
}
module_init(mcp3208_init);

static void mcp3208_exit(void)
{
    struct spi_master *master;

    master = spi_busnum_to_master(mcp3208_info.bus_num);
    if( master ) {
        spi_remove_device(master, mcp3208_info.chip_select );
    }
    else {
        printk( KERN_INFO "mcp3208 remove error\n");
    }
    spi_unregister_driver(&mcp3208_driver);
}
module_exit(mcp3208_exit);

MODULE_AUTHOR("Satoshi Yoneda");
MODULE_LICENSE("GPL v2");
punkyoon commented 6 years ago

MCP3208 and Light Sensor

image

heaeat commented 6 years ago

https://github.com/SystemTera/SystemTera.Server-S-2.6-Kernel/blob/580d3866d266f4c9bb45f4af721e1e7c790cbea8/drivers/misc/mcp3208.c

heaeat commented 6 years ago

http://linux-sunxi.org/SPIdev

punkyoon commented 6 years ago

https://github.com/toru-ver4/raspberry/blob/master/src/Chapter5/mcp3204/mcp3204.c

punkyoon commented 6 years ago

spidev.h?!

http://sslab.konkuk.ac.kr/xe/index.php?mid=class_2018_esw1&document_srl=6074

http://sslab.konkuk.ac.kr/xe/index.php?mid=class_2018_esw1&page=2&document_srl=5899

SoYoung210 commented 6 years ago

언젠가 필요할지도 모르는... app단에서 gpio 값 읽어오는 파이썬 코드.

https://github.com/mrichardson23/mrBBIO/blob/master/mrbbio.py

punkyoon commented 6 years ago

https://github.com/evinrude/libmcp3008/blob/master/lib/libmcp3008.h

punkyoon commented 6 years ago

https://github.com/drewt/mcp3008-cli

punkyoon commented 6 years ago

https://github.com/prityaa/aartyaa_mcp3008/blob/master/aartyaa_mcp3008.c

punkyoon commented 6 years ago

https://github.com/MartinMiller/mcp3008lib-spi/blob/master/mcp3008read_client.c

punkyoon commented 6 years ago

https://github.com/wargio/spidev/blob/master/example.c

heaeat commented 6 years ago

https://github.com/cfoale/ILOCI/tree/c9ef35c6ff2a02128f86fe866f4498198c45543e/Sender-ILOCI/pi/projects/spidev_mcp3008

punkyoon commented 6 years ago
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

static const char DEVICE[] = "/dev/spidev0.1";
static uint8_t MODE = SPI_MODE_0;
static uint8_t BITS = 8;
static uint32_t CLOCK = 2000000;
static uint16_t DELAY = 0;

#define DIO11   17
#define DIO12   27

static struct timer_list blink_timer;
struct file *mcp3008;

static int setupadc(void)
{

  if (mcp3008->f_op->unlocked_ioctl(mcp3008, SPI_IOC_WR_MODE,(long unsigned int)(&MODE)) == -1) {
    printk(KERN_INFO "Can't set MODE");
    return -1;
  }
  if (mcp3008->f_op->unlocked_ioctl(mcp3008, SPI_IOC_RD_MODE,(long unsigned int)(&MODE)) == -1) {
    printk(KERN_INFO "Can't set MODE");
    return -1;
  }
  if (mcp3008->f_op->unlocked_ioctl(mcp3008, SPI_IOC_WR_BITS_PER_WORD,(long unsigned int)(&BITS)) == -1) {
    printk(KERN_INFO "Can't set number of BITS");
    return -1;
  }
  if (mcp3008->f_op->unlocked_ioctl(mcp3008, SPI_IOC_RD_BITS_PER_WORD,(long unsigned int)(&BITS)) == -1) {
    printk(KERN_INFO "Can't set number of BITS");
    return -1;
  }
  if (mcp3008->f_op->unlocked_ioctl(mcp3008, SPI_IOC_WR_MAX_SPEED_HZ,(long unsigned int)(&CLOCK)) == -1) {
    printk(KERN_INFO "Can't set write CLOCK");
    return -1;
  }
  if (mcp3008->f_op->unlocked_ioctl(mcp3008, SPI_IOC_RD_MAX_SPEED_HZ,(long unsigned int)(&CLOCK)) == -1) {
    printk(KERN_INFO "Can't set read CLOCK");
    return -1;
  }
  return 0;
}

uint16_t readadc(uint8_t channel)
{
  uint8_t tx[3];
  uint8_t rx[3];
  uint16_t ret ;

  struct spi_ioc_transfer tr = {
    .tx_buf = (unsigned long)tx,
    .rx_buf = (unsigned long)rx,
    .len = ARRAY_SIZE(tx),
    .delay_usecs = DELAY,
    .speed_hz = CLOCK,
    .bits_per_word = BITS,
  };

  tx[0] = 0x01 ;
  tx[1] = 0x80 | (channel&7)<<4;
  tx[2] = 0;

  if (mcp3008->f_op->unlocked_ioctl(mcp3008, SPI_IOC_MESSAGE(1),(long unsigned int)(&tr)) == -1) {
    printk(KERN_INFO "IO Error");
  }
  ret = (((uint16_t)rx[1] << 8) & 0x300) | ((uint16_t)rx[2] & 0xFF) ;

  return (ret);
}

static void blink_timer_func(unsigned long data)
{
  printk(KERN_INFO "spi read data1  %d\n", readadc(1));
  ndelay(1000);
  printk(KERN_INFO "spi read data2  %d\n", readadc(1));
  ndelay(1000);

  blink_timer.expires = jiffies + (1*HZ);
  add_timer(&blink_timer);
}

static int __init gpiomod_init(void)
{
  int ret = 0;

  mcp3008 = filp_open(DEVICE,O_RDWR,O_RDWR);

  printk(KERN_INFO "mcp3008 opened %d  \n",PTR_RET(mcp3008));

  if (IS_ERR(mcp3008)) {
    printk(KERN_INFO "error no is %ld\n", PTR_ERR(mcp3008));
  }
  if (!mcp3008) {
    printk(KERN_INFO "can't open device file \n");
  }

  if(setupadc() == -1){
    printk(KERN_INFO "prepare failed \n");
  }
  ndelay(1000);

  printk(KERN_INFO "spi read data  %d\n", readadc(1));
  ndelay(1000);
  printk(KERN_INFO "%s\n", __func__);

  ret = gpio_request_one(DIO11, GPIOF_OUT_INIT_LOW, "DIO11");
  if (ret) {
    printk(KERN_ERR "Unable to request DIO11: %d\n", ret);
    return ret;
  }

  ret = gpio_request_one(DIO12, GPIOF_OUT_INIT_LOW, "DIO12");
  if (ret) {
    printk(KERN_ERR "Unable to request DIO12: %d\n", ret);
    return ret;
  }

  init_timer(&blink_timer);
  blink_timer.function = blink_timer_func;
  blink_timer.expires = jiffies + (1*HZ);
  add_timer(&blink_timer);

  return ret;
}

static void __exit gpiomod_exit(void)
{
  printk(KERN_INFO "%s\n", __func__);

  del_timer_sync(&blink_timer);

  if(!IS_ERR_OR_NULL(mcp3008))
    filp_close(mcp3008, 0);

  gpio_set_value(DIO11, 0);
  gpio_set_value(DIO12, 0);

  gpio_free(DIO11);
  gpio_free(DIO12);
}

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kensuke TAKITA");
MODULE_DESCRIPTION("Kernel module using SPI.");

module_init(gpiomod_init);
module_exit(gpiomod_exit);
heaeat commented 6 years ago

http://cfile27.uf.tistory.com/attach/25561E3D556EC00904FB0D

heaeat commented 6 years ago

https://universalflowuniversity.com/Books/Computer%20Programming/Linux%20Programming/Linux%20Device%20Drivers%20Development_%20Develop%20customized%20drivers%20for%20embedded%20Linux.pdf