Use RaspberryPI as a file server

###Preparation Mount the partition automatically, add following lines into the /etc/fstab:

	/dev/sda3	/media/ntfs    	ntfs-3g    permissions,locale=en_US.utf8  	  0	  2

I decide to use samba to share the files, so I have to install samba

	apt-get install samba

The samba server will start automatically, but we have to configure it to adapte to our situation.
Add the configuration to the samba config file:

	/etc/samba/smb.conf
	[raspshare]
	   comment = raspberry PI Share
	   path = /media/ntfs
	   valid users = Trusty
	   public = no
	   writable = yes
	   printable = no
	   create mask = 0765

Restart the samba server

	/etc/init.d/samba restart

For using smbpasswd, you have to install samba-common-bin:

	apt-get install samba-common-bin

Add some users to the samba sharing:

	smbpasswd -a xxx

###Mount the shared partition in client List all of the available samba shared items:

	$ smbclient -L 10.0.0.230 -U%

Then we can mount it, I add following command into the .bashrc, so everytime I enter ‘mountraspsamba’ is ok

	alias mountraspsamba='sudo mount -t cifs //10.0.0.230/raspshare/ -o user=xxxx,password=XXXX,workgroup=WORKGROUP /media/raspsamba'

I2C between raspberryPI and Arduino

###连线 Arduino I2C 连线:
arduino.jpg
RaspberryPI I2C 连线:
rasp.jpg
连线图:

	RPI               Arduino (Uno/Duemillanove)
	--------------------------------------------
	GPIO 0 (SDA) <--> Pin 4 (SDA)
	GPIO 1 (SCL) <--> Pin 5 (SCL)
	Ground       <--> Ground

rasp-arduino.jpg

###Arduino端代码

#include <Wire.h>

#define SLAVE_ADDRESS 0x04
int number = 0;
int state = 0;

void setup() {
    pinMode(13, OUTPUT);
    Serial.begin(9600);         // start serial for output
    // initialize i2c as slave
    Wire.begin(SLAVE_ADDRESS);

    // define callbacks for i2c communication
    Wire.onReceive(receiveData);
    Wire.onRequest(sendData);

    Serial.println("Ready!");
}

void loop() {
    delay(100);
}

// callback for received data
void receiveData(int byteCount){

    while(Wire.available()) {
        number = Wire.read();
        Serial.print("data received: ");
        Serial.println(number);

        if (number == 1){

            if (state == 0){
                digitalWrite(13, HIGH); // set the LED on
                state = 1;
            }
            else{
                digitalWrite(13, LOW); // set the LED off
                state = 0;
            }
         }
     }
}

// callback for sending data
void sendData(){
    Wire.write(number);
}

###RaspberryPI端准备 在/etc/modules中增加一行:

	i2c-dev

注释掉黑名单:

	$ cat /etc/modprobe.d/raspi-blacklist.conf
	# blacklist spi and i2c by default (many users don't need them)
	# blacklist spi-bcm2708
	#blacklist i2c-bcm2708

安装i2c工具:

	apt-get install i2c-tools

安装python库:

	apt-get install python-smbus

探测i2c设备

	i2cdetect -y 0

如果不是root用户,例如,如果是pi用户,则需要将当前用户增加到i2c组中:

	$ sudo adduser pi i2c

###RaspberryPI端代码

import smbus
import time
# for RPI version 1, use "bus = smbus.SMBus(0)"
bus = smbus.SMBus(0)

# This is the address we setup in the Arduino Program
address = 0x04

def writeNumber(value):
    bus.write_byte(address, value)
    # bus.write_byte_data(address, 0, value)
    return -1

def readNumber():
    number = bus.read_byte(address)
    # number = bus.read_byte_data(address, 1)
    return number

while True:
    var = input("Enter 1 - 9: ")
    if not var:
        continue

    writeNumber(var)
    print "RPI: Hi Arduino, I sent you ", var
    # sleep one second
    time.sleep(1)

    number = readNumber()
    print "Arduino: Hey RPI, I received a digit ", number
    print

运行代码时要注意,0~255的数字输入进去,会在arduino i2c slave端收到对应的数据,并原封不动的被返回。超过255的数值将溢出。

Little tricky on SPI

接着上一个日志来,玩一个小tricky,通过SPI总线自己想输入的字符。
主机端,添加下列头文件 #include <string.h> 这使得可以使用strcpy等函数。
重写transfer()函数

static void transfer_mine(int fd, char *buf)
{
	int ret;

	uint8_t tx[140];
	int len = strlen(buf)+1;
	memcpy(tx, buf, strlen(buf)+1);
	tx[strlen(tx)] = '\n';

	uint8_t rx[ARRAY_SIZE(tx)] = {0, };
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		//.len = ARRAY_SIZE(tx),
		.len = len,
		.delay_usecs = delay,
		.speed_hz = speed,
		.bits_per_word = bits,
	};
 
	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1)
		pabort("can't send spi message");
}

在main()函数里,改写调用的方式:

	char myinput[140]="Trustywill, Hi, this is Trusty";
	transfer_mine(fd, myinput);

这样就可以将自定义的字符传输过去了,140是随便设置的值,可以设置为别的更大或者更小的值。
当然你也可以从命令行输入想传输的字符, 这里就不深入了。。

SPI连接raspberryPI和Arduino

下面是使用SPI在RaspberryPI和Arduino Nano w之间进行双机通信的一个例子。借助它可以很好的理解SPI的工作原理。
###背景知识 RaspberryPI GPIO布局图:
/images/GPIOs.png
从图中我们可以看到,RaspberryPI上与SPI通信相关的主要是GPIO 10(MOSI), GPIO 9(MISO)和GPIO 11(SCLK).
Arduino布局图:
SPI: 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK). These pins support SPI communication using the SPI library. SS代表Slava Select.
事实上我们要使用的仅仅是11/12/13三个口而已。
###连线图 如下图进行连线,简单来说,R(10 MOSI)->A(12 MISO), R(9, MISO)->A(11, MOSI), R(11, SCLK) ->A(13, SCK):
/images/spiconnector.jpg ###Arduino端程序

// Written by Nick Gammon
// February 2011
/**
 * Send arbitrary number of bits at whatever clock rate (tested at 500 KHZ and 500 HZ).
 * This script will capture the SPI bytes, when a '\n' is recieved it will then output
 * the captured byte stream via the serial.
 */
 
#include <SPI.h>
 
char buf [100];
volatile byte pos;
volatile boolean process_it;
 
void setup (void)
{
  Serial.begin (115200);   // debugging
 
  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);
  
  // turn on SPI in slave mode
  SPCR |= _BV(SPE);
  //SPCR is  Arduino SPI Control Register
  // __BV's definition is like : #define _BV(bit) (1 << (bit))
  // SPE is the register of the SPI Enable
  
  // get ready for an interrupt 
  pos = 0;   // buffer empty
  process_it = false;
 
  // now turn on interrupts
  SPI.attachInterrupt();
 
}  // end of setup
 
 
// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;  // grab byte from SPI Data Register
  
  // add to buffer if room
  if (pos < sizeof buf)
    {
    buf [pos++] = c;
    
    // example: newline means time to process buffer
    if (c == '\n')
      process_it = true;
      
    }  // end of room available
}  // end of interrupt routine SPI_STC_vect
 
// main loop - wait for flag set in interrupt routine
void loop (void)
{
  if (process_it)
    {
    buf [pos] = 0;  
    Serial.println (buf);
    pos = 0;
    process_it = false;
    }  // end of flag set
    
}  // end of loop

Code Walking through:
Arduino SPI Control Register (SPCR), set it to

	SPCR |= _BV(SPE);

SPI Data Register (SPDR), SPI数据寄存器。 中断程序中,每次从SPDR中取回一个byte 并存储在c中。

	if (c == '\n')
		process_it = true;

这里通过设置全局变量process_it来影响loop中对接收数据的处理,在loop()中有如下代码段:

	if (process_it)
	{
		//.....
	}

从上面看到,如果process_it为0,则loop中一直在空循环,只有当所有的数据全部接收完毕后,才会一次性打印出所有的数据。在打印完数据后,程序将自动将buf清0, 清0是通过将pos简单置0而实现的,实际的数据其实还在。 ###RaspberryPI 端程序

/*
 * SPI testing utility (using spidev driver)
 *
 * Copyright (c) 2007  MontaVista Software, Inc.
 * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License.
 *
 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
 */
 
#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 uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
 
static void transfer(int fd)
{
	int ret;
	uint8_t tx[] = {
        0x48, 0x45, 0x4C, 0x4C, 0x4F,
        0x20, 
        0x57, 0x4F, 0x52, 0x4C, 0x44,
        0x0A 
	};
	uint8_t rx[ARRAY_SIZE(tx)] = {0, };
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		.len = ARRAY_SIZE(tx),
		.delay_usecs = delay,
		.speed_hz = speed,
		.bits_per_word = bits,
	};
 
	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1)
		pabort("can't send spi message");
 
    /*
	for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
		if (!(ret % 6))
			puts("");
		printf("%.2X ", rx[ret]);
	}
	puts("");
    */
}
 
static void print_usage(const char *prog)
{
	printf("Usage: %s [-DsbdlHOLC3]\n", prog);
	puts("  -D --device   device to use (default /dev/spidev1.1)\n"
	     "  -s --speed    max speed (Hz)\n"
	     "  -d --delay    delay (usec)\n"
	     "  -b --bpw      bits per word \n"
	     "  -l --loop     loopback\n"
	     "  -H --cpha     clock phase\n"
	     "  -O --cpol     clock polarity\n"
	     "  -L --lsb      least significant bit first\n"
	     "  -C --cs-high  chip select active high\n"
	     "  -3 --3wire    SI/SO signals shared\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' },
			{ "bpw",     1, 0, 'b' },
			{ "loop",    0, 0, 'l' },
			{ "cpha",    0, 0, 'H' },
			{ "cpol",    0, 0, 'O' },
			{ "lsb",     0, 0, 'L' },
			{ "cs-high", 0, 0, 'C' },
			{ "3wire",   0, 0, '3' },
			{ "no-cs",   0, 0, 'N' },
			{ "ready",   0, 0, 'R' },
			{ NULL, 0, 0, 0 },
		};
		int c;
 
		c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", 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 'b':
			bits = atoi(optarg);
			break;
		case 'l':
			mode |= SPI_LOOP;
			break;
		case 'H':
			mode |= SPI_CPHA;
			break;
		case 'O':
			mode |= SPI_CPOL;
			break;
		case 'L':
			mode |= SPI_LSB_FIRST;
			break;
		case 'C':
			mode |= SPI_CS_HIGH;
			break;
		case '3':
			mode |= SPI_3WIRE;
			break;
		case 'N':
			mode |= SPI_NO_CS;
			break;
		case 'R':
			mode |= SPI_READY;
			break;
		default:
			print_usage(argv[0]);
			break;
		}
	}
}
 
int main(int argc, char *argv[])
{
	int ret = 0;
	int fd;
 
	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);
 
	transfer(fd);
 
	close(fd);
 
	return ret;
}

解析: 在main()函数中,设置完spi总线的相关参数后,调用transfer(fd)来传递参数。
transfer()函数的实现如下:

static void transfer(int fd)
{
	int ret;
	uint8_t tx[] = {
        0x48, 0x45, 0x4C, 0x4C, 0x4F,
        0x20, 
        0x57, 0x4F, 0x52, 0x4C, 0x44,
        0x0A 
	};
	uint8_t rx[ARRAY_SIZE(tx)] = {0, };
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		.len = ARRAY_SIZE(tx),
		.delay_usecs = delay,
		.speed_hz = speed,
		.bits_per_word = bits,
	};
 
	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1)
		pabort("can't send spi message");
 
    /*
	for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
		if (!(ret % 6))
			puts("");
		printf("%.2X ", rx[ret]);
	}
	puts("");
    */
}

tx即为字符串,‘H'=0x48, ‘E'=0x45, ‘L'=0x4c, ‘L'=0x4c, ‘O'=0x4f, ' ‘=0x20, ‘W'=0x57, ‘O'=0x4f, ‘R'=0x52, ‘L'=0x4c, ‘D'=0x44, ‘\n'=0x0a.
实际传送则是调用: ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); 有关它的解释如下:

	SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync().
	  72 * Pass it an array of related transfers, they'll execute together.
	  73 * Each transfer may be half duplex (either direction) or full duplex.
	  74 *
	  75 *      struct spi_ioc_transfer mesg[4];
	  76 *      ...
	  77 *      status = ioctl(fd, SPI_IOC_MESSAGE(4), mesg);

	#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])

调用完transfer()函数后,调用close()来关闭文件描述符。

TSC3200 on Arduino

###Introduction The detailed information could be seen as in :
http://www.eefocus.com/zhang700309/blog/13-08/296390_6c438.html
###Wiring: Notice we use the interrupt 1.
images/tsc3200d.jpg ###Code

#include <TimerOne.h>
 
#define S0     6   // Please notice the Pin's define
#define S1     5
#define S2     4
#define S3     2
#define OUT    3
 
int   g_count = 0;    // count the frequecy
int   g_array[3];     // store the RGB value
int   g_flag = 0;     // filter of RGB queue
float g_SF[3];        // save the RGB Scale factor
 
 
// Init TSC230 and setting Frequency.
void TSC_Init()
{
  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);
  pinMode(OUT, INPUT);
 
  digitalWrite(S0, LOW);  // OUTPUT FREQUENCY SCALING 2%
  digitalWrite(S1, HIGH); 
}
 
// Select the filter color 
void TSC_FilterColor(int Level01, int Level02)
{
  if(Level01 != 0)
    Level01 = HIGH;
 
  if(Level02 != 0)
    Level02 = HIGH;
 
  digitalWrite(S2, Level01); 
  digitalWrite(S3, Level02); 
}
 
void TSC_Count()
{
  g_count ++ ;
}
 
void TSC_Callback()
{
  switch(g_flag)
  {
    case 0: 
         Serial.println("->WB Start");
         TSC_WB(LOW, LOW);              //Filter without Red
         break;
    case 1:
         Serial.print("->Frequency R=");
         Serial.println(g_count);
         g_array[0] = g_count;
         TSC_WB(HIGH, HIGH);            //Filter without Green
         break;
    case 2:
         Serial.print("->Frequency G=");
         Serial.println(g_count);
         g_array[1] = g_count;
         TSC_WB(LOW, HIGH);             //Filter without Blue
         break;
 
    case 3:
         Serial.print("->Frequency B=");
         Serial.println(g_count);
         Serial.println("->WB End");
         g_array[2] = g_count;
         TSC_WB(HIGH, LOW);             //Clear(no filter)   
         break;
   default:
         g_count = 0;
         break;
  }
}
 
void TSC_WB(int Level0, int Level1)      //White Balance
{
  g_count = 0;
  g_flag ++;
  TSC_FilterColor(Level0, Level1);
  Timer1.setPeriod(1000000);             // set 1s period
}
 
void setup()
{
  TSC_Init();
  Serial.begin(9600);
  Timer1.initialize();             // defaulte is 1s
  Timer1.attachInterrupt(TSC_Callback);  
  attachInterrupt(1, TSC_Count, RISING);  
 pinMode(8, OUTPUT);
 pinMode(9, OUTPUT);
 pinMode(10, OUTPUT);
 digitalWrite(8,HIGH);
 digitalWrite(9,HIGH);
 digitalWrite(10,HIGH);
 
  delay(4000);
 
  for(int i=0; i<3; i++)
    Serial.println(g_array[i]);
 
  g_SF[0] = 255.0/ g_array[0];     //R Scale factor
  g_SF[1] = 255.0/ g_array[1] ;    //G Scale factor
  g_SF[2] = 255.0/ g_array[2] ;    //B Scale factor
 
  Serial.println(g_SF[0]);
  Serial.println(g_SF[1]);
  Serial.println(g_SF[2]);
 
}
 
void loop()
{
   g_flag = 0;
   for(int i=0; i<3; i++)
    Serial.println(int(g_array[i] * g_SF[i]));
   if(((g_array[0]*g_SF[0])>(g_array[1]*g_SF[1])) && ((g_array[0]*g_SF[0])>(g_array[2]*g_SF[2])))
   {
      digitalWrite(8,HIGH);
      digitalWrite(9,LOW);
      digitalWrite(10,LOW);
   }
   else if(((g_array[1]*g_SF[1])>(g_array[0]*g_SF[0])) && ((g_array[1]*g_SF[1])>(g_array[2]*g_SF[2])))
   {
      digitalWrite(8,LOW);
      digitalWrite(9,HIGH);
      digitalWrite(10,LOW);
   }     
   else if(((g_array[2]*g_SF[2])>(g_array[1]*g_SF[1])) && ((g_array[2]*g_SF[2])>(g_array[0]*g_SF[0])))
   {
      digitalWrite(8,LOW);
      digitalWrite(9,LOW);
      digitalWrite(10,HIGH);
   }        
   else
   {
      digitalWrite(8,LOW);
      digitalWrite(9,LOW);
      digitalWrite(10,LOW);
   }
   delay(4000);
 
}

###Effect First, the program will caculate the RBG base value out.
If you put the sensor on a red object, red LED will be lighten, turn the sensor facing a green object, green LED will be lighten; blue object for blue LED.