Categories
Arduino Raspberry Pi

I2C Communications between Raspberry Pi and Arduino – Update, BOM, and Source Control

Update

I have been working on this project over the past couple of weeks when I have free time but have not been posting updates. This is a general update which is why the title is different from the other posts regarding this project.

My boards from OSH Park arrived last week. I was able to populate them and test them out. Fortunately I did not make any errors on the PCB or schematic so they all worked as designed. There are a few things that I would change on a future version if I choose to make another version of the board.

  1. I would put the ICSP header on the bottom of the board so it does not stick out from the front. This would make it much easier to assemble and would make it possible to not have any exposed circuitry which may allow the device to be damaged from static electricity.
  2. I would move the resistors toward the bottom of the board if possible. It would allow the DHT11 sensor to stick out further from the case.
  3. I would also try to push the ATtiny85 a little further towards the bottom for the same reason as the resistors.

Currently I am looking to bit bang the I2C bus on the Raspberry Pi. I seem to have gotten around the clock stretching issue if there is only one device connected to the I2C bus but as soon as I add another device, the clock stretching becomes an issue again. I really wish that the Pi Foundation would work with Broadcom and fix the issue with the I2C bus.

Here are some pictures.

This slideshow requires JavaScript.

Bill of Materials (BOM)

Materials List (For One Sensor)

  • QTY 1 – PCB (Source: OSH Park)
  • QTY 2 – 3.5mm 4 Pole Audio Jack, J1 & J2 (Source: MCM Electronics NOTE: I ordered 27-9485 but received ones which look like 27-9487)
  • QTY 1 – 2×3 Position Male Header 2.54mm Pitch, JP1 (Source: MCM Electronics NOTE: This is a 2×13 header. You will need to cut it for 2×3 header.)
  • QTY 1 – T-1 3mm LED, LED1 (Source: MCM Electronics NOTE: May choose another color)
  • QTY 1 – CDS Photoresistor Photoelectric 5549 GL5549, PH1 (Source: Ebay)
  • QTY 2 – Resistor 1/4W 10K Ohm, R1 & R2 (Source: MCM Electronics)
  • QTY 1 – Resistor 1/4W 220 Ohm, R3 (Source: MCM Electronics)
  • QTY 1 – DHT11 Digital Temperature & Humidity Sensor Moudle, SE1 (Source: Ebay)
  • QTY 1 – ATMEL ATtiny85, U1 (Source: Newark)

Materials List for Raspberry Pi Hat

  • Qty 1 – Perfboard (Source: Adafruit)
  • Qty 1 – GPIO Header for Raspberry Pi NOTE: The one you will need depends on which model of Raspberry Pi you are using. (Source: Adafruit 2×13 Header for original Raspberry Pi or 2×20 Header for newer Raspberry Pi)
  • QTY 1 – 3.5mm 4 Pole Audio Jack (Source: MCM Electronics NOTE: I ordered 27-9485 but received ones which look like 27-9487)
  • Optional items

Source Control

I have added the source files for the Hardware and Software onto GitHub. I did this so the community may have access to the files and any updates to them. I mainly did it because I was having a hard time remembering which set of files I last worked with especially if a few days went by when I could not work on the project. I think this is a win-win for me and anyone interested in this project.

The files are located at https://github.com/TeelSys/TeelSys_THL. When you first go to the page, it may look like there are mo project files included in the project. If that is the case it is because I am still trying to get everything working properly before I commit code to the master branch. You will see a button with the text “Branch: master” and a downward arrow. Click that button and select another branch such as “dev”. You will then see the project files in their current state.

If you wish to contribute, add a comment here or if you can request through GitHub, do that. I will reply once I see the request but keep in mind that it may be a few days.

Categories
Arduino Raspberry Pi

I2C Communications between Raspberry Pi and Arduino – Part Four

It has been two weeks since my last post but it has been out of frustration on porting the code over to the ATtiny85. The first thing that I ran into was that the Wire library is not supported on the ATtiny85. I needed to modify my code to work with the TinyWireS library. This did not seem too bad and worked once in a while. It was a bit frustrating as I followed examples and it appeared that I was doing everything correctly but that is typically how it goes when coding.

I finally took a look at the specs for the ATtiny85 and realized that memory may be my issue so I started to pare down the memory requirements. The Arduino IDE was not complaining but I recalled an posting that was published on Adafruit a couple of years ago called Arduino Memories. After rereading the article and looking at a couple of other references, I determined that I needed to tackle the memory is see if it was an issue.

At some point in my debugging, I had noticed that the examples for TinyWireS were utilizing a buffer and pointer method to do fast reads and writes. I had a significant switch statement on the request data handler so I removed that and went with the buffer option. By doing so I reserved a whopping 256 bytes for the buffer. This was a very stupid move which I realized when I took a look at the specs for the the ATtiny85. The ATtiny85 has only 512 bytes of RAM so I was consuming half of it for the buffer which did not leave much room for anything else.

I dropped the buffer size down to 32 bytes which helped a great deal. After reducing the size of the buffer, I could get communications between the ATtiny85 and the Raspberry Pi to work a few times before the communications stopped working. I further refined the code to reduce memory usage and swapped out the Adafruit DHT library for one written by Rob Tillaart for the DHT11 only.

Book1

With these modifications, I was able to get the code down to using 113 bytes of RAM and 4,918 bytes (60%) of Flash.

With these changes, the code works quite well but sometimes it appears that the ATtiny85 does not read the correct request from the Raspberry Pi. After some searching it was found that there is a known issue with the Raspberry Pi and clock stretching. It appears that there is a bug which has not been fixed yet if the slave stretches the clock at the right moment and the stretching is too short. The ATtiny85 implements I2C in software so this is going to happen at some point.One of the best articles on this issue is the Raspberry Pi I2C clock-stretching bug.

There are some suggested fixes which I need to read more to understand well enough to use. The most promising fix appears to use Python to perform I2C communication in software. The recommendation is to use the PiGPIO library.

Below is the code that I have thus far on the ATtiny85.

// Uses DHT from Rob instead of Adafruit
// http://playground.arduino.cc/Main/DHTLib
// http://playground.arduino.cc/Main/DHT11Lib


#include <TinyWireS.h>
#include <dht11.h>

#define SLAVE_ADDRESS 0x23

#define PIN_DHT 4
#define PIN_PHOTORESISTOR A3
#define PIN_LED 1

unsigned long previousMillis = 0;
#define interval 2500

#define bufferSz 32
byte dataBuffer[bufferSz] = { 32 };
uint8_t bufferIdx = 0;
boolean firstByteRead = false;

dht11 DHT11;

// Union used to convert float to byte array
union u_tag {
  byte b[4];
  float fval;
} fdata;

void setup() {
  pinMode(PIN_DHT, INPUT);
  pinMode(PIN_PHOTORESISTOR, INPUT);
  pinMode(PIN_LED, OUTPUT);

  digitalWrite(PIN_LED, HIGH);

  // initialize i2c as slave
  TinyWireS.begin(SLAVE_ADDRESS);

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

  // Initialize dataBuffer
  for (int i = 0; i < bufferSz; i++) {
    dataBuffer[i] = 0xFF;
  }
  // Set LED to blink on each loop
  dataBuffer[3] = 2;
  // Load Model Info
  // T  S  0  0  0  0  0  1
  // 54 53 30 30 30 30 30 31
  String storeText = F("TS000001");
  bufferIdx = 0x10;
  for (int i = 0; i < storeText.length(); i++) {
    dataBuffer[bufferIdx] = storeText[i];
    bufferIdx++;
  }
  // Load Version Info
  // 0  0  0  0  0  0  0  3
  // 30 30 30 30 30 30 30 33
  storeText = F("00000003");
  bufferIdx = 0x18;
  for (int i = 0; i < storeText.length(); i++) {
    dataBuffer[bufferIdx] = storeText[i];
    bufferIdx++;
  }
}

void loop() {
  TinyWireS_stop_check();
  
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    if (dataBuffer[3] == 2) {
      digitalWrite(PIN_LED, !digitalRead(PIN_LED));
    }

    ReadDHT();
    ReadLightLevel();
  }
}

// callback for received data
void receiveData(uint8_t byteCount) {
  if (byteCount != 1)
  {
    // Sanity-check
    return;
  }

  while (TinyWireS.available()) {
    bufferIdx = TinyWireS.receive();
    firstByteRead = false;

    SetLedStatus();
  }
}

// callback for sending data
void sendData() {
  if (firstByteRead) {
    bufferIdx++;
  }

  firstByteRead = true;

  if(bufferIdx < 0 || bufferIdx >= bufferSz) {
    TinyWireS.send(0xFF);
    return;
  }

  TinyWireS.send(dataBuffer[bufferIdx]);
}

void ReadDHT() {
  int chk = DHT11.read(PIN_DHT);

  if(!chk==DHTLIB_OK) {
    return;
  }
  
  float humidity = (float)DHT11.humidity;
  float temperatureCelsius = (float)DHT11.temperature;
  
  SaveFloatToBuffer(0x04, temperatureCelsius);
  SaveFloatToBuffer(0x08, humidity);
}

void ReadLightLevel() {
  int photocellReading = analogRead(PIN_PHOTORESISTOR);
  float lightReading = ((float)photocellReading / 1023.0) * 100.0;
  SaveFloatToBuffer(0x0C, lightReading);
}

void SaveFloatToBuffer(uint8_t bufIdx, float val) { 
  dataBuffer[bufIdx] = 0;
  dataBuffer[bufIdx + 1] = 0;
  dataBuffer[bufIdx + 2] = 0;
  dataBuffer[bufIdx + 3] = 0;
  
  fdata.fval = val;

  dataBuffer[bufIdx] = fdata.b[3];
  dataBuffer[bufIdx + 1] = fdata.b[2];
  dataBuffer[bufIdx + 2] = fdata.b[1];
  dataBuffer[bufIdx + 3] = fdata.b[0];
  
  //dataBuffer[bufIdx] = (int)val;
}

void SetLedStatus() {
  if (bufferIdx > 2)
    return;

  dataBuffer[3] = 2;
  if (bufferIdx < 2) {
    digitalWrite(PIN_LED, bufferIdx);
    dataBuffer[3] = 0;
    if (digitalRead(PIN_LED) == HIGH) {
      dataBuffer[3] = 1;
    }
  }
}

Here is the code on the Raspberry Pi to verify that things are working.

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>

#define CMD_GET_TEMPERATURE 1
#define CMD_GET_HUMIDITY 2
#define CMD_SET_LIGHT 3
#define CMD_SET_LED_ON 4
#define CMD_SET_LED_OFF 5
#define CMD_SET_LED_FLASH 6
#define CMD_GET_MODEL 250
#define CMD_GET_VERSION 251
#define CMD_GET_HELLO_WORLD 254

// The PiWeather board i2c address
#define ADDRESS 0x23

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
char *devName = "/dev/i2c-0";
int file;
int devices[128];
int sensorDevices[128];

union u_tag {
	char b[4];
	float fval;
} fdata;

float computeHeatIndex(float temperature, float percentHumidity, int isFahrenheit);
float convertCtoF(float c);
float convertFtoC(float f);
void displayConnectedI2cDevices();
void dumpDeviceInfo(int deviceAddress);
void findAllI2cDevices();
void findI2cBus();
void findSensors();
float receiveFloat();
int receiveInt();
void receiveString(char *str, int bufSize);
int sendCommand(int deviceAddress, int cmdCode);

int main(int argc, char** argv) {
	// Look for the I2C bus device

  printf("I2C: Connecting\n");
	findI2cBus();
  
  // Find Devices
  findAllI2cDevices();
  
  // Display devices found (Simlar to i2cdetect -y 0)
  displayConnectedI2cDevices();
  
  dumpDeviceInfo(0x23);
  
  sendCommand(0x23, 0x04);
  float temperature = receiveFloat();
  sendCommand(0x23, 0x08);
  float percentHumidity = receiveFloat();
  sendCommand(0x23, 0x0C);
  float lightLevel = receiveFloat();
  
  printf("Temperature = %1.2f (C)\n", temperature);
  printf("Humidity = %1.2f\n", percentHumidity);
  printf("Light Level = %1.2f\n", lightLevel);

  close(file);
  return (EXIT_SUCCESS);
}

float computeHeatIndex(float temperature, float percentHumidity, int isFahrenheit) {
  // Using both Rothfusz and Steadman's equations
  // http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml
  float hi;

  if (isFahrenheit==0)
    temperature = convertCtoF(temperature);

  hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (percentHumidity * 0.094));

  if (hi > 79) {
    hi = -42.379 +
             2.04901523 * temperature +
            10.14333127 * percentHumidity +
            -0.22475541 * temperature*percentHumidity +
            -0.00683783 * pow(temperature, 2) +
            -0.05481717 * pow(percentHumidity, 2) +
             0.00122874 * pow(temperature, 2) * percentHumidity +
             0.00085282 * temperature*pow(percentHumidity, 2) +
            -0.00000199 * pow(temperature, 2) * pow(percentHumidity, 2);

    if((percentHumidity < 13) && (temperature >= 80.0) && (temperature <= 112.0))
      hi -= ((13.0 - percentHumidity) * 0.25) * sqrt((17.0 - abs(temperature - 95.0)) * 0.05882);

    else if((percentHumidity > 85.0) && (temperature >= 80.0) && (temperature <= 87.0))
      hi += ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2);
  }

  return isFahrenheit ? hi : convertFtoC(hi);
}

float convertCtoF(float c) {
  return c * (9.0/5.0) + 32;
}

float convertFtoC(float f) {
  return (f - 32) * (5.0/9.0);
}

void displayConnectedI2cDevices() {
	int idx=0;
	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f");
	for(idx=0; idx<=0x7F; idx++) {
		if(idx%16==0) {
			printf("\n%d0:",idx/16);
		}
		if(idx>0x07 && idx<0x78) {
			if(devices[idx]>0) {
				if(devices[idx]==-9) {
					printf(" UU");
				}
				else {
					printf(" %02x", idx);
				}
			}
			else {
				printf(" --");
			}
		}
		else {
				printf("   ");
		}
  }
  printf("\n");
}

void dumpDeviceInfo(int deviceAddress) {
	int i=0;
	
	sendCommand(deviceAddress, 0x03);
	
	for(i=0x03; i<0x20; i++) {
		int val = receiveInt();
		
		printf("0x%02x: 0x%02x (%d)\t%c\n", i, val, val, val);
	}
}

void findAllI2cDevices() {
	int idx=0;
  for(idx=0; idx<=0x7F; idx++) {
  	int device=0;
  	
  	if(idx>0x07 && idx<0x78) {
	  	if (ioctl(file, I2C_SLAVE, idx) < 0) {
	  		if(errno == EBUSY) {
	  			device = -9;
	  		}
	  		else {
		  		device = -1;
		  	}
	  	}
	  	else {
	  		char buf[1];
	  		if(read(file, buf, 1) == 1 && buf[0] >= 0) {
	  			device = idx;
	  		}
	  	}
  	}
  	
  	devices[idx] = device;
  }
}

void findI2cBus() {
	if ((file = open(devName, O_RDWR)) < 0) {
  	devName = "/dev/i2c-1";
  	if ((file = open(devName, O_RDWR)) < 0) {
	    fprintf(stderr, "I2C: Failed to access %d\n", devName);
	    exit(1);
	  }
  }
  
  printf("Found I2C bus at %s\n", devName);
}

void findSensors() {
	char *sensorType="TeelSys Data and Light Sensor";
	char buf[256];
	int idx=0;
	int sensorIdx=0;
	// sensorDevices
	// devices
	
	// Clear the sensorDevices array
	for(idx=0; idx<128; idx++) {
		sensorDevices[idx] = 0;
	}
	
  for(idx=0x08; idx<=0x78; idx++) {
  	int device=0;
  	
  	if(devices[idx]==idx) {
  		if(sendCommand(0x22, CMD_GET_MODEL)==1) {
  			int bufSize = sizeof(buf)/sizeof(buf[0]);
  			receiveString(buf, bufSize);
  			if(strlen(sensorType)==strlen(buf) && strcmp(sensorType, buf)==0) {
  				sensorDevices[sensorIdx]=devices[idx];
  				sensorIdx++;
  				printf("Found Sensor at: 0x%02x\n", devices[idx]);
  			}
  		}
  	}
  }
}

void receiveString(char *buf, int bufSize) {
  int charCount=0;
  
	if(read(file, buf, bufSize) == bufSize) {
		for(charCount=0; charCount<bufSize; charCount++) {
			int temp = (int) buf[charCount];
			
			if(temp==255) {
				buf[charCount]=0;
			}
		}
  }
}

int receiveChar() {
  char buf[1];
  char retVal = 0x00;
  
  if (read(file, buf, 1) == 1) {
  	retVal=buf[0];
  }
  
	usleep(10000);
  return retVal;
}

float receiveFloat() {	
	fdata.b[3] = 0;
	fdata.b[2] = 0;
	fdata.b[1] = 0;
	fdata.b[0] = 0;
	
	fdata.b[3] = receiveChar();
	fdata.b[2] = receiveChar();
	fdata.b[1] = receiveChar();
	fdata.b[0] = receiveChar();
	
	return fdata.fval;
	//return (float)fdata.b[3];
}

int receiveInt() {
  return (int)receiveChar();
}

int sendCommand(int deviceAddress, int cmdCode) {
	int retVal = 0;
	unsigned char cmd[16];
	cmd[0] = cmdCode;
	
	if (ioctl(file, I2C_SLAVE, deviceAddress) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", deviceAddress);
    exit(1);
  }
  
  if (write(file, cmd, 1) == 1) {
  	// As we are not talking to direct hardware but a microcontroller we
    // need to wait a short while so that it can respond.
    //
    // 1ms seems to be enough but it depends on what workload it has
    usleep(10000);
    retVal = 1;
  }
  
  return retVal;
}

Running the Raspberry Pi program produces the following result.

pi@raspberrypi:~ $ ./testi2c07a
I2C: Connecting
Found I2C bus at /dev/i2c-0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- 23 -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
0x03: 0x02 (2)
0x04: 0x41 (65) A
0x05: 0xb8 (184)        ▒
0x06: 0x00 (0)
0x07: 0x00 (0)
0x08: 0x42 (66) B
0x09: 0x0c (12)

0x0a: 0x00 (0)
0x0b: 0x00 (0)
0x0c: 0x42 (66) B
0x0d: 0x2d (45) -
0x0e: 0xff (255)        ▒
0x0f: 0x80 (128)        ▒
0x10: 0x54 (84) T
0x11: 0x53 (83) S
0x12: 0x30 (48) 0
0x13: 0x30 (48) 0
0x14: 0x30 (48) 0
0x15: 0x30 (48) 0
0x16: 0x30 (48) 0
0x17: 0x31 (49) 1
0x18: 0x30 (48) 0
0x19: 0x30 (48) 0
0x1a: 0x30 (48) 0
0x1b: 0x30 (48) 0
0x1c: 0x30 (48) 0
0x1d: 0x30 (48) 0
0x1e: 0x30 (48) 0
0x1f: 0x33 (51) 3
Temperature = 23.00 (C)
Humidity = 35.00
Light Level = 43.50

 

Next step is to see if I can resolve the clock stretching issue and then connect to adafruit.io to post data. If it is not possible to address the clock stretching issue, it would be possible to identify when it occurs and reset the power to the I2C slave devices. I am trying to avoid that solution but I may need to resort to that solution.

Categories
Arduino Raspberry Pi

I2C Communications between Raspberry Pi and Arduino – Part Three

Today’s goal is to send a string from the Arduino to the Raspberry Pi. The setup is the same as from day two.

After several attempts and stupid mistakes, I was finally able to get a “Hello World” message from the Arduino to the Raspberry Pi.

Here is the code for the Arduino

#include <Wire.h>
#include "DHT.h"

#define SLAVE_ADDRESS 0x04

#define PIN_DHT 4
#define PIN_PHOTORESISTOR A3
#define PIN_LED 1

#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

int humidity = 0;
int temperatureCelsius = 0;
int lightReading = 0;

int number = 0;

unsigned long previousMillis = 0;
const long interval = 1000;

bool flashLed = true;
bool respondWithText = false;
String responseText = "The Message";

// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors.  This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(PIN_DHT, DHTTYPE);

void setup() {
  pinMode(PIN_DHT, INPUT);
  pinMode(PIN_PHOTORESISTOR, INPUT);
  pinMode(PIN_LED, OUTPUT);

  digitalWrite(PIN_LED, LOW);

  dht.begin();

  // initialize i2c as slave
  Wire.begin(SLAVE_ADDRESS);

  // define callbacks for i2c communication
  Wire.onReceive(On_WireReceive);
  Wire.onRequest(On_WireRequest);
}

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    if (flashLed) {
      digitalWrite(PIN_LED, HIGH);
    }
    ReadDHT();
    ReadLightLevel();
    if (flashLed) {
      digitalWrite(PIN_LED, LOW);
    }
  }
}

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

  while (Wire.available()) {
    number = Wire.read();
    respondWithText = false;

    switch (number) {
      case 1: // Temperature in Celsius
        number = temperatureCelsius;
        break;
      case 2: // Humidity
        number = humidity;
        break;
      case 3: // Light Level
        number = lightReading;
        break;
      case 4: // LED On
        digitalWrite(PIN_LED, HIGH);
        flashLed = false;
        break;
      case 5: // LED Off
        digitalWrite(PIN_LED, LOW);
        flashLed = false;
        break;
      case 6: // LED Flash on read
        digitalWrite(PIN_LED, LOW);
        flashLed = true;
        break;
      case 250: // Send Model Info
        respondWithText = true;
        responseText = "TeelSys Data and Light Sensor";
        break;
      case 251: // Send Version Info
        respondWithText = true;
        responseText = "version 0.0.3";
        break;
      case 254: // Send Hello World
        respondWithText = true;
        responseText = "Hello World";
        break;
      default:
        break;
    }
  }
}

// callback for sending data
void On_WireRequest() {
  if(respondWithText) {
    ProcessRequestString();
  }
  else {
    sendData();
  }
}

void ReadDHT() {
  humidity = 0;
  temperatureCelsius = 0;

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  humidity = dht.readHumidity();
  // Read temperature as Celsius (the default)
  temperatureCelsius = dht.readTemperature();
}

void ReadLightLevel() {
  int photocellReading = analogRead(PIN_PHOTORESISTOR);
  lightReading = ((float)photocellReading / 1023.0) * 100.0;
}

void sendData() {
  Wire.write(number);
}

void ProcessRequestString() {
  Wire.write(responseText.c_str());
}

Here is the code for the Raspberry Pi

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

// The PiWeather board i2c address
#define ADDRESS 0x04

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
static const char *devName = "/dev/i2c-0";

int main(int argc, char** argv) {

  if (argc == 1) {
    printf("Supply one or more commands to send to the Arduino\n");
    exit(1);
  }

  printf("I2C: Connecting\n");
  int file;

  if ((file = open(devName, O_RDWR)) < 0) {
    fprintf(stderr, "I2C: Failed to access %d\n", devName);
    exit(1);
  }

  printf("I2C: acquiring buss to 0x%x\n", ADDRESS);

  if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS);
    exit(1);
  }

  int arg;

  for (arg = 1; arg < argc; arg++) {
    int val;
    unsigned char cmd[16];

    if (0 == sscanf(argv[arg], "%d", &val)) {
      fprintf(stderr, "Invalid parameter %d \"%s\"\n", arg, argv[arg]);
      exit(1);
    }

    printf("Sending %d\n", val);

    cmd[0] = val;
    if (write(file, cmd, 1) == 1) {

      // As we are not talking to direct hardware but a microcontroller we
      // need to wait a short while so that it can respond.
      //
      // 1ms seems to be enough but it depends on what workload it has
      usleep(10000);
      
      if(val<250) {	// Receiving int
	      char buf[1];
	      if (read(file, buf, 1) == 1) {
		    int temp = (int) buf[0];
		
		    printf("Received %d\n", temp);
		      }
		  }
      else {	// Receiving String
	      char buf[256];
	      int charCount=0;
	      
	      for(charCount=0; charCount<256; charCount++) {
	      	buf[charCount]=89;
	      }
	      
				if(read(file, buf, 256) == 256) {
					for(charCount=0; charCount<256; charCount++) {
	    			int temp = (int) buf[charCount];
	
	    			printf("%d:\tReceived %d\t%c\n", charCount, temp, temp);
	    		}
		    }
      }
		}
		
    // Now wait else you could crash the arduino by sending requests too fast
    usleep(10000);
  }

  close(file);
  return (EXIT_SUCCESS);
}

Compile the code
gcc testi2c03.c -o testi2c03
Config_I2C_103

Run the code
./testi2c03 254
Config_I2C_104
Config_I2C_105

We can see that once the string ends, the data on the I2C buss is 255. Let’s tweak the code on the Raspberry Pi to stop once we receive 255.

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

// The PiWeather board i2c address
#define ADDRESS 0x04

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
static const char *devName = "/dev/i2c-0";

int main(int argc, char** argv) {

  if (argc == 1) {
    printf("Supply one or more commands to send to the Arduino\n");
    exit(1);
  }

  printf("I2C: Connecting\n");
  int file;

  if ((file = open(devName, O_RDWR)) < 0) {
    fprintf(stderr, "I2C: Failed to access %d\n", devName);
    exit(1);
  }

  printf("I2C: acquiring buss to 0x%x\n", ADDRESS);

  if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS);
    exit(1);
  }

  int arg;

  for (arg = 1; arg < argc; arg++) {
    int val;
    unsigned char cmd[16];

    if (0 == sscanf(argv[arg], "%d", &val)) {
      fprintf(stderr, "Invalid parameter %d \"%s\"\n", arg, argv[arg]);
      exit(1);
    }

    printf("Sending %d\n", val);

    cmd[0] = val;
    if (write(file, cmd, 1) == 1) {

      // As we are not talking to direct hardware but a microcontroller we
      // need to wait a short while so that it can respond.
      //
      // 1ms seems to be enough but it depends on what workload it has
      usleep(10000);
      
      if(val<250) {	// Receiving int
	      char buf[1];
	      if (read(file, buf, 1) == 1) {
		    int temp = (int) buf[0];
		
		    printf("Received %d\n", temp);
		      }
		  }
      else {	// Receiving String
	      char buf[256];
	      int charCount=0;
	      
	      for(charCount=0; charCount<256; charCount++) {
	      	buf[charCount]=89;
	      }
	      
				if(read(file, buf, 256) == 256) {
					for(charCount=0; charCount<256; charCount++) {
	    			int temp = (int) buf[charCount];
	    			
	    			if(temp==255) {
	    				break;
	    			}
	
	    			printf("%d:\tReceived %d\t%c\n", charCount, temp, temp);
	    		}
		    }
      }
		}
		
    // Now wait else you could crash the arduino by sending requests too fast
    usleep(10000);
  }

  close(file);
  return (EXIT_SUCCESS);
}

Compile the code
gcc testi2c03b.c -o testi2c03b

Then run the application
./testi2c03b 254
Config_I2C_107

We can see that the output is now cleaner.

Let’s do even better and print the string as a string instead of a list of characters.

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

// The PiWeather board i2c address
#define ADDRESS 0x04

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
static const char *devName = "/dev/i2c-0";

int main(int argc, char** argv) {

  if (argc == 1) {
    printf("Supply one or more commands to send to the Arduino\n");
    exit(1);
  }

  printf("I2C: Connecting\n");
  int file;

  if ((file = open(devName, O_RDWR)) < 0) {
    fprintf(stderr, "I2C: Failed to access %d\n", devName);
    exit(1);
  }

  printf("I2C: acquiring buss to 0x%x\n", ADDRESS);

  if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS);
    exit(1);
  }

  int arg;

  for (arg = 1; arg < argc; arg++) {
    int val;
    unsigned char cmd[16];

    if (0 == sscanf(argv[arg], "%d", &val)) {
      fprintf(stderr, "Invalid parameter %d \"%s\"\n", arg, argv[arg]);
      exit(1);
    }

    printf("Sending %d\n", val);

    cmd[0] = val;
    if (write(file, cmd, 1) == 1) {

      // As we are not talking to direct hardware but a microcontroller we
      // need to wait a short while so that it can respond.
      //
      // 1ms seems to be enough but it depends on what workload it has
      usleep(10000);
      
      if(val<250) {	// Receiving int
	      char buf[1];
	      if (read(file, buf, 1) == 1) {
		    int temp = (int) buf[0];
		
		    printf("Received %d\n", temp);
		      }
		  }
      else {	// Receiving String
	      char buf[256];
	      int charCount=0;
	      char receivedText[256];
	      
	      for(charCount=0; charCount<256; charCount++) {
	      	receivedText[charCount]=0;
	      }
	      
				if(read(file, buf, 256) == 256) {
					for(charCount=0; charCount<256; charCount++) {
	    			int temp = (int) buf[charCount];
	    			
	    			if(temp==255) {
	    				break;
	    			}
	    			
	    			receivedText[charCount] = buf[charCount];
	
	    			//printf("%d:\tReceived %d\t%c\n", charCount, temp, temp);
	    		}
	    		printf("Received %s\n", receivedText);
		    }
      }
		}
		
    // Now wait else you could crash the arduino by sending requests too fast
    usleep(10000);
  }

  close(file);
  return (EXIT_SUCCESS);
}

Compile the code
gcc testi2c03c.c -o testi2c03c

Then run the application
./testi2c03c 1 2 3 254 250 251
Config_I2C_108

Yes, I included additional arguments this time. The code was setup to handle this which is really nice. This allows us to teak the code if we like to print out what the values actually are and get some additional information. So let’s create a new application which will do exactly that but will not take in any arguments. I am also going to add a few other things such as detecting if we are using a Raspberry Pi Rev 1 or Rev 2 as well as scanning the I2C Bus.

I was doing some searching on valid I2C addresses and found a great reference article from Total  Phase at 7-bit, 8-bit, and 10-bit I2C Slave Addressing. The article provides a diagram showing the valid range of 7-bit I2C addresses.

slave-address-fig3

From this diagram, we can see that the address used in the examples is a reserved address. I will change the address in the Arduino code so that it is in the valid address range.

Here is a modified version of the code which finds all connected I2C devices. Determines which ones are the sensors that we are interested in, and reads values from each one. This will be a great program for making certain that the design works and all of the sensors are working.

Arduino Code

#include <Wire.h>
#include "DHT.h"

#define SLAVE_ADDRESS 0x22

#define PIN_DHT 4
#define PIN_PHOTORESISTOR A3
#define PIN_LED 1

#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

int humidity = 0;
int temperatureCelsius = 0;
int lightReading = 0;

int number = 0;

unsigned long previousMillis = 0;
const long interval = 1000;

bool flashLed = true;
bool respondWithText = false;
String responseText = "The Message";

// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors.  This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(PIN_DHT, DHTTYPE);

void setup() {
  pinMode(PIN_DHT, INPUT);
  pinMode(PIN_PHOTORESISTOR, INPUT);
  pinMode(PIN_LED, OUTPUT);

  digitalWrite(PIN_LED, LOW);

  dht.begin();

  // initialize i2c as slave
  Wire.begin(SLAVE_ADDRESS);

  // define callbacks for i2c communication
  Wire.onReceive(On_WireReceive);
  Wire.onRequest(On_WireRequest);
}

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    if (flashLed) {
      digitalWrite(PIN_LED, HIGH);
    }
    ReadDHT();
    ReadLightLevel();
    if (flashLed) {
      digitalWrite(PIN_LED, LOW);
    }
  }
}

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

  while (Wire.available()) {
    number = Wire.read();
    respondWithText = false;

    switch (number) {
      case 1: // Temperature in Celsius
        number = temperatureCelsius;
        break;
      case 2: // Humidity
        number = humidity;
        break;
      case 3: // Light Level
        number = lightReading;
        break;
      case 4: // LED On
        digitalWrite(PIN_LED, HIGH);
        flashLed = false;
        break;
      case 5: // LED Off
        digitalWrite(PIN_LED, LOW);
        flashLed = false;
        break;
      case 6: // LED Flash on read
        digitalWrite(PIN_LED, LOW);
        flashLed = true;
        break;
      case 250: // Send Model Info
        respondWithText = true;
        responseText = "TeelSys Data and Light Sensor";
        break;
      case 251: // Send Version Info
        respondWithText = true;
        responseText = "version 0.0.3";
        break;
      case 254: // Send Hello World
        respondWithText = true;
        responseText = "Hello World";
        break;
      default:
        break;
    }
  }
}

// callback for sending data
void On_WireRequest() {
  if(respondWithText) {
    ProcessRequestString();
  }
  else {
    sendData();
  }
}

void ReadDHT() {
  humidity = 0;
  temperatureCelsius = 0;

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  humidity = dht.readHumidity();
  // Read temperature as Celsius (the default)
  temperatureCelsius = dht.readTemperature();
}

void ReadLightLevel() {
  int photocellReading = analogRead(PIN_PHOTORESISTOR);
  lightReading = ((float)photocellReading / 1023.0) * 100.0;
}

void sendData() {
  Wire.write(number);
}

void ProcessRequestString() {
  Wire.write(responseText.c_str());
}

Raspberry Pi Code

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>

#define CMD_GET_TEMPERATURE 1
#define CMD_GET_HUMIDITY 2
#define CMD_SET_LIGHT 3
#define CMD_SET_LED_ON 4
#define CMD_SET_LED_OFF 5
#define CMD_SET_LED_FLASH 6
#define CMD_GET_MODEL 250
#define CMD_GET_VERSION 251
#define CMD_GET_HELLO_WORLD 254

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
char *devName = "/dev/i2c-0";
int file;
int devices[128];
int sensorDevices[128];

float computeHeatIndex(float temperature, float percentHumidity, int isFahrenheit);
float convertCtoF(float c);
float convertFtoC(float f);
void displayConnectedI2cDevices();
void findAllI2cDevices();
void findI2cBus();
void findSensors();
int receiveInt();
void receiveString(char *str, int bufSize);
int sendCommand(int deviceAddress, int cmdCode);

int main(int argc, char** argv) {
	// Look for the I2C bus device

  printf("I2C: Connecting\n");
	findI2cBus();
  
  // Find Devices
  findAllI2cDevices();
  
  // Display devices found (Simlar to i2cdetect -y 0)
  displayConnectedI2cDevices();
  
  // Find the sensors for this project
  findSensors();
  
  printf("\n");
  
  // Read information from each sensor
  int deviceIdx = 0;
  
  while(sensorDevices[deviceIdx] > 0) {
  	int bufSize=256;
  	char buf[bufSize];
  	// int bufSize = sizeof(buf)/sizeof(buf[0]);
  	int val=0;
  	
  	/*
  		Model
  		Version
  		Temperature
  		Humidity
  		Light Level
  	*/
  	float degreesC=0.0;
  	float degreesF=0.0;
  	float humidity=0.0;
  	float lightLevel=0.0;
  	float heatIndexC=0.0;
  	float heatIndexF=0.0;
  	char model[bufSize];
  	char version[bufSize];
  	
  	// Get the values
  	sendCommand(sensorDevices[deviceIdx], CMD_SET_LED_ON);
  	if(sendCommand(sensorDevices[deviceIdx], CMD_GET_MODEL)==1) {
  		receiveString(model, bufSize);
  	}
  	if(sendCommand(sensorDevices[deviceIdx], CMD_GET_VERSION)==1) {
  		receiveString(version, bufSize);
  	}
  	if(sendCommand(sensorDevices[deviceIdx], CMD_GET_TEMPERATURE)==1) {
  		val=receiveInt();
  		degreesC = (float)val;
  	}
  	if(sendCommand(sensorDevices[deviceIdx], CMD_GET_HUMIDITY)==1) {
  		val=receiveInt();
  		humidity = (float)val;
  	}
  	if(sendCommand(sensorDevices[deviceIdx], CMD_SET_LIGHT)==1) {
  		val=receiveInt();
  		lightLevel = (float)val;
  	}
  	sendCommand(sensorDevices[deviceIdx], CMD_SET_LED_OFF);
  	
  	// Calculate Values
  	degreesF=convertCtoF(degreesC);
  	heatIndexC=computeHeatIndex(degreesC, humidity, 0);
  	heatIndexF=computeHeatIndex(degreesF, humidity, 1);
  	
  	// Display values
  	printf("Sensor Address: 0x%02x\n", sensorDevices[deviceIdx]);
  	printf("Model: %s\n", model);
  	printf("Version: %s\n", version);
		printf("Temperature: %3.2f C\n", degreesC);
		printf("Temperature: %3.2f F\n", degreesF);
  	printf("Humidity: %3.2f%% RH\n", humidity);
		printf("Heat Index: %3.2f C\n", heatIndexC);
		printf("Heat Index: %3.2f F\n", heatIndexF);
  	printf("Light Level: %3.2f%%\n", lightLevel);
  	printf("\n");
  	
  	deviceIdx++;
  }
  
  close(file);
  return (EXIT_SUCCESS);
}

float computeHeatIndex(float temperature, float percentHumidity, int isFahrenheit) {
  // Using both Rothfusz and Steadman's equations
  // http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml
  float hi;

  if (isFahrenheit==0)
    temperature = convertCtoF(temperature);

  hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (percentHumidity * 0.094));

  if (hi > 79) {
    hi = -42.379 +
             2.04901523 * temperature +
            10.14333127 * percentHumidity +
            -0.22475541 * temperature*percentHumidity +
            -0.00683783 * pow(temperature, 2) +
            -0.05481717 * pow(percentHumidity, 2) +
             0.00122874 * pow(temperature, 2) * percentHumidity +
             0.00085282 * temperature*pow(percentHumidity, 2) +
            -0.00000199 * pow(temperature, 2) * pow(percentHumidity, 2);

    if((percentHumidity < 13) && (temperature >= 80.0) && (temperature <= 112.0))
      hi -= ((13.0 - percentHumidity) * 0.25) * sqrt((17.0 - abs(temperature - 95.0)) * 0.05882);

    else if((percentHumidity > 85.0) && (temperature >= 80.0) && (temperature <= 87.0))
      hi += ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2);
  }

  return isFahrenheit ? hi : convertFtoC(hi);
}

float convertCtoF(float c) {
  return c * (9.0/5.0) + 32;
}

float convertFtoC(float f) {
  return (f - 32) * (5.0/9.0);
}

void displayConnectedI2cDevices() {
	int idx=0;
	printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f");
	for(idx=0; idx<=0x7F; idx++) {
		if(idx%16==0) {
			printf("\n%d0:",idx/16);
		}
		if(idx>0x07 && idx<0x78) {
			if(devices[idx]>0) {
				if(devices[idx]==-9) {
					printf(" UU");
				}
				else {
					printf(" %02x", idx);
				}
			}
			else {
				printf(" --");
			}
		}
		else {
				printf("   ");
		}
  }
  printf("\n");
}

void findAllI2cDevices() {
	int idx=0;
  for(idx=0; idx<=0x7F; idx++) {
  	int device=0;
  	
  	if(idx>0x07 && idx<0x78) {
	  	if (ioctl(file, I2C_SLAVE, idx) < 0) {
	  		if(errno == EBUSY) {
	  			device = -9;
	  		}
	  		else {
		  		device = -1;
		  	}
	  	}
	  	else {
	  		char buf[1];
	  		if(read(file, buf, 1) == 1 && buf[0] >= 0) {
	  			device = idx;
	  		}
	  	}
  	}
  	
  	devices[idx] = device;
  }
}

void findI2cBus() {
	if ((file = open(devName, O_RDWR)) < 0) {
  	devName = "/dev/i2c-1";
  	if ((file = open(devName, O_RDWR)) < 0) {
	    fprintf(stderr, "I2C: Failed to access %d\n", devName);
	    exit(1);
	  }
  }
  
  printf("Found I2C bus at %s\n", devName);
}

void findSensors() {
	char *sensorType="TeelSys Data and Light Sensor";
	char buf[256];
	int idx=0;
	int sensorIdx=0;
	// sensorDevices
	// devices
	
	// Clear the sensorDevices array
	for(idx=0; idx<128; idx++) {
		sensorDevices[idx] = 0;
	}
	
  for(idx=0x08; idx<=0x78; idx++) {
  	int device=0;
  	
  	if(devices[idx]==idx) {
  		if(sendCommand(0x22, CMD_GET_MODEL)==1) {
  			int bufSize = sizeof(buf)/sizeof(buf[0]);
  			receiveString(buf, bufSize);
  			if(strlen(sensorType)==strlen(buf) && strcmp(sensorType, buf)==0) {
  				sensorDevices[sensorIdx]=devices[idx];
  				sensorIdx++;
  				printf("Found Sensor at: 0x%02x\n", devices[idx]);
  			}
  		}
  	}
  }
}

void receiveString(char *buf, int bufSize) {
  int charCount=0;
  
	if(read(file, buf, bufSize) == bufSize) {
		for(charCount=0; charCount<bufSize; charCount++) {
			int temp = (int) buf[charCount];
			
			if(temp==255) {
				buf[charCount]=0;
			}
		}
  }
}

int receiveInt() {
  char buf[1];
  int retVal=0;
  
  if (read(file, buf, 1) == 1) {
  	retVal=(int)buf[0];
  }
  
  return retVal;
}

int sendCommand(int deviceAddress, int cmdCode) {
	int retVal = 0;
	unsigned char cmd[16];
	cmd[0] = cmdCode;
	
	if (ioctl(file, I2C_SLAVE, deviceAddress) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", deviceAddress);
    exit(1);
  }
  
  if (write(file, cmd, 1) == 1) {
  	// As we are not talking to direct hardware but a microcontroller we
    // need to wait a short while so that it can respond.
    //
    // 1ms seems to be enough but it depends on what workload it has
    usleep(10000);
    retVal = 1;
  }
  
  return retVal;
}

 

Compiling the Raspberry Pi code is a bit different as we need to link the math library. In order to do this, we need to add -lm to the command line.

gcc testi2c03d.c -o testi2c03d -lm

Config_I2C_110

Here is the results of running the application.
Config_I2C_112

 

The passing of a string was successful however there are several standards which may be better suited to the goal that I have in mind. One worth further consideration is the System Management Bus (SMBus). For the moment, I am leaving the code as is since the information that I need to send may be sent as simple integer responses. A future enhancement will be to get a better messaging system in place.

The next step is to replace the Arduino with a ATTiny85 and get it all working.

Categories
Arduino Raspberry Pi

I2C Communications between Raspberry Pi and Arduino – Part Two

The goal of the day is to get the Raspberry Pi and Arduino talking to each other over I2C.

I followed a few examples provided on the internet and was able to get the two to talk to each other. Just to be clear, the Raspberry Pi will be the I2C master and the Arduino will be the slave. One of the nice advantages to this configuration is that it is not necessary to do any voltage level shifting between the two devices. If you are not aware, the Raspberry Pi GPIO is at 3.3V and the Arduino is at 5V. If the Arduino were to supply 5V to any of the Raspberry Pi’s GPIO pins, the Raspberry Pi will be toast.

I followed the tutorial at http://blog.retep.org/2014/02/15/connecting-an-arduino-to-a-raspberry-pi-using-i2c/. Below are some of the high level steps.

  1. Download the latest Raspbian image from https://www.raspberrypi.org/downloads/raspbian/
  2. Unzip the file and write the image to the SD Card using Win32DiskImager from https://sourceforge.net/projects/win32diskimager/
  3. Once the Raspberry Pi boots, open a terminal window and run raspi-config to enable I2C Support
    sudo raspiconfig
    Config_I2C_000
  4. Select “Advanced Options” from the menu
    Config_I2C_001
  5. Select “I2C” from the Advanced Options menu
    Config_I2C_002
    Select “Yes”
    Config_I2C_003
    Select “OK”
    Config_I2C_004
    Select “Yes”
    Config_I2C_005
    Select “OK”
    Config_I2C_006
    ”Select “Finish”
    Config_I2C_007
  6. Install i2c-tools
    sudo apt-get update
    Config_I2C_011
    sudo apt-get install i2c-tools
    Config_I2C_012
  7. Run i2cdetect to make certain that i2c-tools installed properly
    i2cdetect –y 0
    or
    i2cdetect –y 1
    Config_I2C_013
    If all worked well, you will see the following output
    Config_I2C_014
    If there are devices connected to the I2C pins, you will see the devices listed as in this example.
    Config_I2C_015
  8. Wire up the Arduino and Raspberry Pi
    Raspberry PI        Arduino
    GPIO 0 (SDA)    <–>    Pin 4 (SDA)
    GPIO 1 (SCL)    <–>    Pin 5 (SCL)
    Ground    <–>    Ground
    Step002_bb
    Step002_schem
  9. Upload Code to the Arduino
    #include <Wire.h>
    #include "DHT.h"
    
    #define SLAVE_ADDRESS 0x04
    
    #define PIN_DHT 4
    #define PIN_PHOTORESISTOR A3
    #define PIN_LED 1
    
    #define DHTTYPE DHT11   // DHT 11
    //#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
    //#define DHTTYPE DHT21   // DHT 21 (AM2301)
    
    int humidity = 0;
    int temperatureCelsius = 0;
    int lightReading = 0;
    
    int number = 0;
    
    unsigned long previousMillis = 0;
    const long interval = 1000;
    
    bool flashLed = true;
    
    // Initialize DHT sensor.
    // Note that older versions of this library took an optional third parameter to
    // tweak the timings for faster processors.  This parameter is no longer needed
    // as the current DHT reading algorithm adjusts itself to work on faster procs.
    DHT dht(PIN_DHT, DHTTYPE);
    
    void setup() {
      pinMode(PIN_DHT, INPUT);
      pinMode(PIN_PHOTORESISTOR, INPUT);
      pinMode(PIN_LED, OUTPUT);
    
      digitalWrite(PIN_LED, LOW);
    
      dht.begin();
    
      // initialize i2c as slave
      Wire.begin(SLAVE_ADDRESS);
    
      // define callbacks for i2c communication
      Wire.onReceive(receiveData);
      Wire.onRequest(sendData);
    }
    
    void loop() {
      unsigned long currentMillis = millis();
    
      if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;
    
        if (flashLed) {
          digitalWrite(PIN_LED, HIGH);
        }
        ReadDHT();
        ReadLightLevel();
        if (flashLed) {
          digitalWrite(PIN_LED, LOW);
        }
      }
    }
    
    // callback for received data
    void receiveData(int byteCount) {
    
      while (Wire.available()) {
        number = Wire.read();
    
        switch (number) {
          case 1: // Temperature in Celsius
            number = temperatureCelsius;
            break;
          case 2: // Humidity
            number = humidity;
            break;
          case 3: // Light Level
            number = lightReading;
            break;
          case 4: // LED On
            digitalWrite(PIN_LED, HIGH);
            flashLed = false;
            break;
          case 5: // LED Off
            digitalWrite(PIN_LED, LOW);
            flashLed = false;
            break;
          case 6: // LED Flash on read
            digitalWrite(PIN_LED, LOW);
            flashLed = true;
            break;
          default:
            break;
        }
      }
    }
    
    // callback for sending data
    void sendData() {
      Wire.write(number);
    }
    
    void ReadDHT() {
      humidity = 0;
      temperatureCelsius = 0;
    
      // Reading temperature or humidity takes about 250 milliseconds!
      // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
      humidity = dht.readHumidity();
      // Read temperature as Celsius (the default)
      temperatureCelsius = dht.readTemperature();
    }
    
    void ReadLightLevel() {
      int photocellReading = analogRead(PIN_PHOTORESISTOR);
      lightReading = ((float)photocellReading / 1023.0) * 100.0;
    }
    
  10. Write the application on the Raspberry Pi
    nano testi2c02.c
    Config_I2C_020
  11. Type of copy paste the following code
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <linux/i2c-dev.h>
    #include <sys/ioctl.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    // The PiWeather board i2c address
    #define ADDRESS 0x04
    
    // The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
    static const char *devName = "/dev/i2c-0";
    
    int main(int argc, char** argv) {
    
      if (argc == 1) {
        printf("Supply one or more commands to send to the Arduino\n");
        exit(1);
      }
    
      printf("I2C: Connecting\n");
      int file;
    
      if ((file = open(devName, O_RDWR)) < 0) {
        fprintf(stderr, "I2C: Failed to access %d\n", devName);
        exit(1);
      }
    
      printf("I2C: acquiring buss to 0x%x\n", ADDRESS);
    
      if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
        fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS);
        exit(1);
      }
    
      int arg;
    
      for (arg = 1; arg < argc; arg++) {
        int val;
        unsigned char cmd[16];
    
        if (0 == sscanf(argv[arg], "%d", &val)) {
          fprintf(stderr, "Invalid parameter %d \"%s\"\n", arg, argv[arg]);
          exit(1);
        }
    
        printf("Sending %d\n", val);
    
        cmd[0] = val;
        if (write(file, cmd, 1) == 1) {
    
          // As we are not talking to direct hardware but a microcontroller we
          // need to wait a short while so that it can respond.
          //
          // 1ms seems to be enough but it depends on what workload it has
          usleep(10000);
    
          char buf[1];
          if (read(file, buf, 1) == 1) {
        int temp = (int) buf[0];
    
        printf("Received %d\n", temp);
          }
        }
    
        // Now wait else you could crash the arduino by sending requests too fast
        usleep(10000);
      }
    
      close(file);
      return (EXIT_SUCCESS);
    }
  12. Save the file by pressing <Ctrl> + o

    Config_I2C_022
    Config_I2C_023
  13. Exit the editor by pressing <Ctrl> + x
    Config_I2C_024
  14. Compile the application
    gcc testi2c02.c -o testi2c02
    Config_I2C_025
    If you do see errors, go back and edit the file to correct them.
    Config_I2C_025
    Once the changes are made, recompile and if you do not see any error messages, you are good to go.
    Config_I2C_026
  15. Run the application
    ./testi2c02 1 {Gets the temperature in Celsius}
    Config_I2C_030
    ./testi2c02 2 {Gets the relative humidity in percent}
    Config_I2C_031

    ./testi2c02 3 {Gets the light level}
    Config_I2C_032

    ./testi2c02 4 {Turns the LED On}
    Config_I2C_033

    ./testi2c02 5 {Turns the LED Off}
    Config_I2C_034

    ./testi2c02 6 {Flashes the LED when reading sensors. This is the default behavior of the LED}
    Config_I2C_035

    ./testi2c02 7 {Echos the number 7. This may be repeated with any other number up to 255}
    Config_I2C_036

    Config_I2C_037

That’s all for the day. Next I plan to try to send strings and develop a format for messages.

Categories
Arduino Raspberry Pi

I2C Communications between Raspberry Pi and Arduino – Part One

My daughter has a science project for school on bread mold growth. She will need to monitor the temperature, humidity, and light level of 3 separate environments. Being the geeky dad that I am, I decided to make her some data loggers to monitor each environment. I would also like to take this further by connecting to an online IoT site such as adafruit.io to store and graph the data. There are a few options available such as using an Arduino with a Wi-Fi shield to connect to the site and monitor the environment but that is not an elegant solution. What I have opted to do is to use a Raspberry Pi instead and use I2C to communicate to the sensors using ATTiny85 microcontrollers. One of the reasons for this choice was that she will need to monitor the growth with 10 to 30 slices of bread for each environment. With that many slices in one batch,  there could be a considerable variation throughout the area containing the bread so more than one data logger/sensor cluster should be used. I2C is the perfect solution as you may have up to 127 devices connected with just 3 wires.

Use an Arduino Uno R3 to get information from the sensors and verify that the code works correctly.

Step001_bb

Step001_schem

Arduino Code

#include "DHT.h"

#define PIN_DHT 4
#define PIN_PHOTORESISTOR A3
#define PIN_LED 1

#define debugCode 1

#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
//#define DHTTYPE DHT21 // DHT 21 (AM2301)




float humidity = 0;
float temperatureCelsius = 0;
float temperatureFahrenheit = 0;
float heatIndexCelsius = 0;
float heatIndexFahrenheit = 0;
float lightLevelPercent = 0;

int photocellReading = 0;


// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors. This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(PIN_DHT, DHTTYPE);

void setup() {
 pinMode(PIN_DHT, INPUT);
 pinMode(PIN_PHOTORESISTOR, INPUT);
 pinMode(PIN_LED, OUTPUT);

 digitalWrite(PIN_LED, LOW);

 if (debugCode) {
 Serial.begin(9600);
 while (!Serial) {
 ; // wait for serial port to connect. Needed for native USB
 }
 Serial.println("DHTxx test!");
 }
 dht.begin();
}

void loop() {
 // Wait a few seconds between measurements.
 delay(2000);
 digitalWrite(PIN_LED, HIGH);
 ReadDHT();
 ReadLightLevel();
 if (debugCode) {
 PrintDebug();
 }
 digitalWrite(PIN_LED, LOW);
}

void ReadDHT() {
 humidity = 0;
 temperatureCelsius = 0;
 temperatureFahrenheit = 0;
 heatIndexCelsius = 0;
 heatIndexFahrenheit = 0;

 // Reading temperature or humidity takes about 250 milliseconds!
 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
 humidity = dht.readHumidity();
 // Read temperature as Celsius (the default)
 temperatureCelsius = dht.readTemperature();
 // Read temperature as Fahrenheit (isFahrenheit = true)
 temperatureFahrenheit = dht.readTemperature(true);

 // Check if any reads failed and exit early (to try again).
 if (isnan(humidity) || isnan(temperatureCelsius) || isnan(temperatureFahrenheit)) {
 Serial.println("Failed to read from DHT sensor!");
 return;
 }

 // Compute heat index in Fahrenheit (the default)
 heatIndexFahrenheit = dht.computeHeatIndex(temperatureFahrenheit, humidity);
 // Compute heat index in Celsius (isFahreheit = false)
 heatIndexCelsius = dht.computeHeatIndex(temperatureCelsius, humidity, false);
}

void ReadLightLevel() {
 photocellReading = analogRead(PIN_PHOTORESISTOR);
 lightLevelPercent = ((float)photocellReading / 1023.0) * 100.0;
}

void PrintDebug() {
 Serial.print("Humidity: ");
 Serial.print(humidity);
 Serial.print(" %\t");
 Serial.print("Temperature: ");
 Serial.print(temperatureCelsius);
 Serial.print(" *C ");
 Serial.print(temperatureFahrenheit);
 Serial.print(" *F\t");
 Serial.print("Heat index: ");
 Serial.print(heatIndexCelsius);
 Serial.print(" *C ");
 Serial.print(heatIndexFahrenheit);
 Serial.print(" *F\t");
 Serial.print("Light Level: ");
 Serial.print(photocellReading); // the raw analog reading
 Serial.print("\t");
 Serial.print(lightLevelPercent); // the raw analog reading
 Serial.println(" %");
}

Output

DHTxx test!
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 198	19.35 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 183	17.89 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 182	17.79 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 182	17.79 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 193	18.87 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 194	18.96 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 188	18.38 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 181	17.69 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 178	17.40 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 183	17.89 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 198	19.35 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 189	18.48 %
Humidity: 34.00 %	Temperature: 21.00 *C 69.80 *F	Heat index: 20.04 *C 68.08 *F	Light Level: 187	18.28 %

 

 

Next Step -> Add Raspberry Pi and I2C Communication

Categories
Project Ideas Raspberry Pi

Portable PI – Power Supply and Power Switch

Finally nearing the end of completing the power supply and soft latching power switch. The components have changed slightly but the principle design is the same. The components include two li-ion batteries connected in parallel with protection circuit, soft latching switch, Adafruit Powerboost 1000 with charging circuit (Product #2465) , and a Teensy 3.1. Along with the hardware components, there are two software pieces with one residing on the Teensy and the other running in the background of the Raspberry Pi.

The design utilizes a soft latching power switch has three functions. It powers the device on from an off state, signals the Teensy that the user has pressed the power button to request a shutdown, and power off. One of the main requirements besides those mentioned above is that the soft latching power switch must not draw current or very little current when in the off state. This is necessary as we do not want the batteries to be drained when the device is in the off state.

These requirements were met with a modified version of the soft latching power circuit described in my earlier post. The circuit was modified for a couple of reasons. First of all, the circuit needed to be able to operate from 3 to 4.5 VDC rather than at 5 VDC. Another reason the circuit needed to be modified is that the output was floating when off so the enable signal to the powerboost circuit would cause the power to cycle back on after a few seconds.

There are two pieces of software working together which allows the Raspberry Pi to safely shutdown when the user presses the power button. The Teensy has software which monitors the power button to see if it is pressed and monitors the USB power from the Raspberry Pi. If the user presses the power button, the Teensy changes the state of a pin on the Raspberry Pi. The Raspberry Pi has a program running in the background which checks if the logic level on the pin has changed. If the logic level changes, the script will issue a shutdown command.

The next thing was to determine the best way to know when the shutdown was complete.

Categories
Project Ideas Raspberry Pi

Soft Latching Power Switch

The Raspberry Pi ON/OFF Power Controller that I looked at from Mosaic Industries, Inc. does a good job at 5 VDC but I need the circuit to be able to switch LiPo batteries which have a voltage range of between 2.7 and 4.35 VDC between discharged and fully charged. I looked for dual MOSFET devices which could operate in this range and found the following.

Both of these devices function at these lower voltages however I have been having some oscillation issues with these. When the button is held down to turn off the load, which is a LED, the output is switched off but it turns back on after a few seconds. I have not been able to investigate why this is happening. I suspect that I miswired something but I need to take some time to check.

The International Rectifier device seems to behave a bit better so it may be the one I use but I will need to investigate what the issue is and resolve that before I can move on. I can’t wait to wrap this project up.

If you have an idea as to what my problem may be, please leave a comment to let me know.

UPDATE – 16 May 2015

I determined the reason for the odd behavior was that the N-Channel MOSFET’s gate was floating. I was able to fix this by using a pull-down resistor of 100KΩ. Looking at the schematic, I connected the resistor between Pin 7 and ground. This pulls the gate to ground through the 330KΩ and 1KΩ resistors.

Categories
Raspberry Pi

Raspberry PI B+

Hardware

Needed

  • Raspberry Pi
  • MicroSD Card 4GB or larger
  • USB Keyboard
  • USB Power Supply and cable with micro USB Connector
  • Display (Composite or HDMI)
  • Display cable (Type of cable depends on monitor)
  • MicroSD Card to SD Card Adapter (Needed only if your PC has a SD Card Reader but not a MicroSD Card Reader)

Nice to Have

  • Raspberry Pi B+ Case (Note cases for other models may not work)
  • WiFi module or Ethernet Cable

Steps

  1. Download the Raspbian Image from http://www.raspberrypi.org/downloads/ (As of this post, the file is 2014-06-20-wheezy-raspbian.zip)
  2. Unzip the Raspbian Image File
    Image2
  3. Follow the instructions at http://www.raspberrypi.org/documentation/installation/installing-images/README.md for your operating system. I will be using Windows and will mirror the steps from the installation instructions page

Windows Installation

  1. Insert your MicroSD card into the card reader on your PC (NOTE: You may need a MicroSD to SD Card Adapter)
  2. Download the Win32DiskImager utility from http://sourceforge.net/projects/win32diskimager/ (As of this post, the file is Win32DiskImager-0.9.5-install.exe)
  3. Install the Win32DiskImager Utility by double clicking the downloaded file
  4. Click on the “Next >” button on the setup wizard
    Welcome to the Win32DiskImager Setup Wizard
  5. Select the “I accept the agreement” radio button and click the “Next >” button
    License Agreement
  6. Click the “Next >” button on the destination location dialog
    Select Destination Location
  7. Click the “Next >” button on the Select Start Menu Folder dialog
    Select Start Menu Folder
  8. If you do not want a desktop shortcut, uncheck the “Create a desktop icon” checkbox
  9. Click the “Next >” button on the Select Additional Tasks dialog
    Select Additional Tasks
  10. Click the “Install” button on the Ready to Install dialog
    Ready to Install
  11. Wait for the installation to complete
    Installing
  12. Click the “Finish” button on the Completing the Win32DiskImager Setup Wizard dialog
    Completing the Win32DiskImager Setup Wizard
  13. It is possible that you may see the following error message
    Unable to execute file
  14. If you see the error message above
    1. Click the “OK” button
    2. Right-click on the desktop shortcut and select “Run as administrator” from the pop-up menu
      Run as administrator
    3. When the User Access Control dialog is displayed, click the “Yes” button
      User Access Control dialog
  15. The application is now open
    Win32 Disk Imager
  16. Click the folder icon and select the Raspbian image file downloaded earlier
    Selecting the image file
  17. Select the drive letter for your MicroSD Card
    WARNING: Be very careful to select the correct drive letter as the utility will erase all data on the drive! You have been warned!
    Select the MicroSD Card
  18. Click the “Write” button
    Write the image
  19. Click the “Yes” button on the confirmation dialog
    Confirm Write
    If you see the following error (), check that there are no open Explorer Windows or other applications attempting to access the SD Card
    Write Error
    If you see the following error, check the write lock switch on the MicroSD Card Adapter
    Lock Error  SD Card Lock Switch
    Wait for the process to complete
    Wait
  20. When the process is complete, click the “OK” button
    Write Sucessful
  21. The main window will display the status as “Done.” Click the “Exit” button to exit the utility
    Done.
  22. Eject the MicroSD Card

Once the Raspbian Image has been written to the MicroSD Card, you are ready to boot and configure the Operating System (OS).

Booting and Configuring the Raspberry Pi using Raspbian OS

  1. Insert the MicroSD Card in the Raspberry Pi
  2. Connect the monitor, keyboard, mouse (optional), and power
  3. The Raspberry Pi Software Configuration Tool (raspi-config) will launch
Categories
Raspberry Pi

Setting up the WiFi Part I – Supported Adapters

Video Coming Soon

<<FIRST  <PREVIOUS

This entry is for configuring the Asus USB-N10 USB Wireless-N USB Adapter. If you have any other WiFi adapter please refer to Chapter 4 Network Configuration of the Raspberry Pi User Guide book or perform Google Searches for your adapter.

003_001

NOTE: There is a WiFi Config tool included with Raspbian “wheezy” distribution however I have not had much luck with it. I t did work one time for me and that was it. You may give it a try but I recommend using the steps below as they have worked 100% of the time for me.

 

You will need to perform these steps from the command line. If you have the desktop loaded, open a terminal window by double clicking on the the LXTerminal shortcut on the desktop.

  1. At the command line, type the following command and press enter to view available wireless networks.
    sudo iwlist scan | less
  2. On the wlan interface, you will see the SSIDs listed on the lines starting with ESSID:. Verify that the network you wish to connect to is listed.
    003-002
  3. Press Ctrl+z to return to the command line
  4. Edit the network configuration file by typing the following command and press enter.
    sudo nano /etc/network/interfaces
  5. You should see the following content in the interfaces file.
    auto loiface lo inet loopback
    iface eth0 inet dhcpallow-hotplug wlan0
    iface wlan0 inet manual
    wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
    iface default inet dhcp

     

  6. Replace the bottom block with the following.
    auto wlan0
    iface wlan0 inet dhcp
    wpa-conf /etc/wpa.conf

     

  7. The resulting file should have the following contents.
    auto loiface lo inet loopback
    iface eth0 inet dhcpauto wlan0
    iface wlan0 inet dhcp
    wpa-conf /etc/wpa.conf

     

  8. Save the file and exit
    • Press Ctrl+o
    • Press Enter
    • Press Ctrl+x
  9. Now edit the wpa.conf file by typing the following command and pressing enter.
    sudo nano /etc/wpa.conf
  10. Enter the following for the contents of your file based on the type of security used by your WiFi network.
    NOTE: Do not type the word [Tab]. It indicates that you need to include a tab.

    No Encryption network={
    [Tab] ssid=”Your_SSID
    [Tab] key_mgmt=NONE
    }
    WEP Encryption network={
    [Tab] ssid=”Your_SSID
    [Tab] key_mgmt=NONE
    [Tab] wep_key0=”Your_WEP_Key
    }
    WPA/WPA2 Encryption network={
    [Tab] ssid=”Your_SSID
    [Tab] key_mgmt=WPA-PSK
    [Tab] psk=”Your_WPA_Key
    }

     

  11. Save the file and exit
    • Press Ctrl+o
    • Press Enter
    • Press Ctrl+x
  12. Connect to the wireless network by typing the following command and pressing enter.
    sudo ifup wlan0
  13. If you see the message “ifup: interface wlan0 already configured,” type the following command and repeat the previous step again.
    sudo ifdown wlan0
  14. If you are successful, you will see several lines starting with DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 … with the last line stating that the adapter is bound to an IP address on your network
    .
    003-003
  15. If you are successful at this point, you may close the terminal window and open a web browser to verify that you are connected to the internet.
    003-004
<<FIRST  <PREVIOUS
Categories
Raspberry Pi

Initial Configuration of the Raspberry Pi

First Step – Getting the Raspberry Pi to Boot

Required Items

  • Raspberry Pi
  • 2 GB or larger SD Card
  • Keyboard
  • Monitor (Composite or HDMI)
  • Display cable (Composite or HDMI)
  • USB Power Supply
  • USB Cable for power (Micro USB)
  • PC connected to the internet with a card reader

Optional Items

  • Case for Raspberry Pi
  • USB Mouse
  • Book – Raspberry Pi User Guide
    by Eben Upton & Gareth Halfacree
    ISBN: 978-1-118-46446-5 (Amazon Link)

NOTE: I am running these steps from a Windows 7 PC. If you are running from another OS be certain you read the information on the http://www.raspberrypi.org/downloads page for information for your OS. I am also using a 16 GB SDHC Card.

Steps

  1. Go to the download section at http://www.raspberrypi.org/downloads
  2. If you are running a Windows PC, download Win32DiskImager
    I downloaded the version 0.5 binary (win32diskimager-binary.zip)
  3. Download the Raspbian “wheezy” image
    I downloaded via the direct download.
    The version at the time of this blog entry is 2012-12-16-wheezy-raspbian.zip
  4. Open the zip file (2012-12-16-wheezy-raspbian.zip) and extract the image file (2012-12-16-wheezy-raspbian.img)
    The following steps are modified from the “Easy Way” section from http://elinux.org/RPi_Easy_SD_Card_Setup
  5. Insert the SD card into your SD card reader and check what drive letter it was assigned. You can easily see the drive letter (for example G:) by looking in the left column of Windows Explorer. If the card is not new, you should format it; otherwise Win32DiskImager may hang.
  6. Extract the Win32DiskImager utility files from the zip file (win32diskimager-binary.zip) and run the Win32DiskImager utility (Win32DiskImager.exe). You should run the utility as Administrator! (Right click on Win32DiskImager.exe and select “Run as administrator from the context menu.)
    001
  7. Select the 2012-12-16-wheezy-raspbian.img image file you extracted earlier
    002
  8. Select the drive letter of the SD card in the device box. Be careful to select the correct drive; if you get the wrong one you can destroy your computer’s hard disk!
    003
  9. Click Write and wait for the write to complete.
    004005
  10. Exit the imager and eject the SD card.
  11. Insert the card in the Raspberry Pi, power it on, and it should boot up. There is an option in the configure script that comes up to expand the partitions to use all of the SD card if you have used one larger than 4 GB

Second Step – Initial Configuration of the Raspbian “wheezy” distribution

When you boot up the Raspberry Pi, the Raspi-config utility will launch.

There are a few things that you should configure right away or you may have problems later.

  • Expand the root partition if your SD Card is greater than 4 GB (Optional)
    1. Select “expand_rootfs” from the Raspi-config menu
    2. The Raspi-config widow will disappear for a bit then a new window will display telling you that the root partition has been resized and the file system will be enlarged upon the next reboot. Click enter to close the dialog.
  • Configure the keyboard (You must do if you are not using a UK keyboard!)
    I did not perform this step the first time I booted up the Raspberry Pi and I had issues as I could not use the pipe symbol. The “|” was mapped as a tilde “~” symbol. 

    1. Select “configure_keyboard” from the Raspi-config menu
    2. You may keep the default “Generic 105-key (Intl) PC” model or change it to match your keyboard
    3. Press enter or Tab to the bottom options and select “<OK”>” and press enter
    4. If you are not using a UK keyboard, select “Other”
    5. Press enter or Tab to the bottom options and select “<OK”>” and press enter
    6. Select your country of origin from the list (i.e. English (US))
    7. Press enter or Tab to the bottom options and select “<OK”>” and press enter
    8. Select the keyboard layout (i.e. English (US))
    9. Press enter or Tab to the bottom options and select “<OK”>” and press enter
    10. Select the option for the AltGr modifier (i.e. The default for the keyboard layout)
    11. Press enter or Tab to the bottom options and select “<OK”>” and press enter
    12. Select the option for the Compose key (i.e. No compose key)
    13. Press enter or Tab to the bottom options and select “<OK”>” and press enter
    14. Select an option for the Control+Alt+Backspace key combination
    15. Press enter
    16. There will be some delay as the options are saved
    17. The Raspi-config menu will reappear
  • Change the locale (You should do if you are not in the UK)
    1. Select “change_locale” from the Raspi-config menu
    2. Scroll down to the “en_GB.UTF-8 UTF-8 option and deselect it by pressing the spacebar (You do not need to remove it. You may keep it if you like.)
    3. Scroll through the list to find the locale(s) you wish to install and select it/them by pressing the spacebar (i.e. en_US.UTF-8 UTF-8)
    4. Tab to the bottom options and select “<OK”>” and press enter
    5. Select the default locale for the system (i.e. en_US.UTF-8 UTF-8)
    6. Press enter or Tab to the bottom options and select “<OK”>” and press enter
    7. There will be some delay as the options are saved
    8. The Raspi-config menu will reappear
  • Change the time zone (Unless you want to stick to UTC)
    1. Select “change_timezone” from the Raspi-config menu
    2. Select your geographic area (i.e. US)
    3. Press enter or Tab to the bottom options and select “<OK”>” and press enter
    4. Select your time zone (i.e. Eastern)
    5. Press enter or Tab to the bottom options and select “<OK”>” and press enter
    6. There will be some delay as the options are saved
    7. The Raspi-config menu will reappear
  • If you have a hardwired internet connection, you may try to update Raspi-config
    1. Select “update” from the Raspi-config menu
    2. Press enter or Tab to the bottom options and select “<OK”>” and press enter
  • Once you are done making changes, press the tab key to jump to the options at the bottom of the screen and select “<Finish>”
  • Depending on the options selected, you may be prompted to reboot. If given the option, reboot your Raspberry Pi as most options do not take effect until the Raspberry Pi reboots.
<<FIRST  <PREVIOUS | NEXT>