t r o n i x s t u f f

fun and learning with electronics

Exploring the TI Stellaris platform with Energia Arduino-compatible IDE

Introduction

In the same manner as their MSP430 development board, Texas Instruments also have another LaunchPad board with their powerful Stellaris LM4F120H5QR microcontroller. It’s an incredibly powerful and well-featured MCU – which offers an 80 MHz, 32-bit ARM Cortex-M4 CPU with floating point, 256 Kbytes of 100,000 write-erase cycle FLASH and many peripherals such as 1MSPS ADCs, eight UARTs, four SPIs, four I2Cs, USB & up to 27 timers, some configurable up to 64-bits.

That’s a bucket of power, memory and I/O for not much money – you can get the LaunchPad board for around $15. This LaunchPad has the in-circuit debugger, two user buttons, an RGB LED and connectors for I/O and shield-like booster packs:

and the other side:

However the good news as far as we’re concerned is that you can now use it with the Energia Arduino-compatible IDE that we examined previously. Before rushing out to order your own Stellaris board, install Energia and examine the available functions and libraries to make sure you can run what you need. And if so, you’re set for some cheap Arduino power.

Installation

Installation is simple, just get your download from here. If you’re running Windows 7 – get the USB drivers from here. When you plug your LaunchPad into the USB for the first time, wait until after Windows attempts to install the drivers, then install drivers manually after download via Device manager … three times (JTAG, virtual serial port and DFU device). Use the debug USB socket (and set the switch to debug) when installing and uploading code. If you get the following warning from Windows, just click “Install this driver software anyway”:

Once the drivers are installed, plug in your LaunchPad, wait a moment – then run Energia. You can then select your board type and serial port just like the Arduino IDE. Then go ahead and upload the “blink” example…

Awesome – check out all that free memory space. In the same manner as the MSP430, there are some hardware<>sketch differences you need to be aware of. For example, how to refer to the I/O pins in Energia? A map has been provided for front:

… and back:

As you can imagine, the Stellaris MCUs are different to an AVR, so a lot of hardware-specific code doesn’t port over from the world of Arduino. One of the first things to remember is that the Stellaris is a 3.3V device. Code may or may not be interchangeable, so a little research will be needed to match up the I/O pins and rewrite the sketch accordingly. For example, instead of digital pins numbers, you use PX_Y - see the map above. So let’s say you want to run through the RGB LED… consider the following sketch:

int wait = 500;
void setup() 
{ 
 // initialize the digital pin as an output.
 pinMode(PF_1, OUTPUT); // red 
 pinMode(PF_3, OUTPUT); // green
 pinMode(PF_2, OUTPUT); // blue
}
void loop() 
{
 digitalWrite(PF_1, HIGH); 
 delay(wait); 
 digitalWrite(PF_1, LOW); 
 digitalWrite(PF_3, HIGH); 
 delay(wait); 
 digitalWrite(PF_3, LOW); 
 digitalWrite(PF_2, HIGH); 
 delay(wait); 
 digitalWrite(PF_2, LOW); 
}

Which simply blinks the red, green and blue LED elements in series. Using digital inputs is in the same vein, and again the buttons are wired so when pressed they go LOW. An example of this in the following sketch:

void setup() 
{ 
 // initialize the digital pins
 pinMode(PF_1, OUTPUT); // red 
 pinMode(PF_3, OUTPUT); // green
 pinMode(PF_2, OUTPUT); // blue

 pinMode(PF_4, INPUT_PULLUP); // left - note _PULLUP
 pinMode(PF_0, INPUT_PULLUP); // right - note _PULLUP 
}
void blinkfast() 
{
 for (int i=0; i<10; i++)
 {
 digitalWrite(PF_1, HIGH); 
 delay(250); 
 digitalWrite(PF_1, LOW); 
 digitalWrite(PF_3, HIGH); 
 delay(250); 
 digitalWrite(PF_3, LOW); 
 digitalWrite(PF_2, HIGH); 
 delay(250); 
 digitalWrite(PF_2, LOW); 
 }
}
void blinkslow() 
{
 for (int i=0; i<5; i++)
 {
 digitalWrite(PF_1, HIGH); 
 delay(1000); 
 digitalWrite(PF_1, LOW); 
 digitalWrite(PF_3, HIGH); 
 delay(1000); 
 digitalWrite(PF_3, LOW); 
 digitalWrite(PF_2, HIGH); 
 delay(1000); 
 digitalWrite(PF_2, LOW); 
 }
}
void loop()
{
 if (digitalRead(PF_4)==LOW) { blinkslow(); }
 if (digitalRead(PF_0)==LOW) { blinkfast(); }
}

And for the non-believers:

Where to from here? 

Sometimes you can be platform agnostic, and just pick something that does what you want with the minimum of time and budget. Or to put it another way, if you need a fast CPU and plenty of space but couldn’t be bothered don’t have time to work with Keil, Code Composer Studio, IAR etc – the Energia/Stellaris combination could solve your problem. There’s a growing Energia/Stellaris forum, and libraries can be found here. At the time of writing we found an I2C library as well.

However to take full advantage of the board, consider going back to the TI tools and move forward with them. You can go further with the tutorials and CCS etc from Texas Instruments own pages.

In the meanwhile have fun and keep checking into tronixstuff.com. Why not follow things on twitterGoogle+, subscribe  for email updates or RSS using the links on the right-hand column? And join our friendly Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other –  and we can all learn something.

February 2, 2013 Posted by | arduino, arm cortex, energia, launchpad, LM4F120H5QR, MSP430, product review, software review, TI, tiva-c, tutorial | , , , , , , , , , , , , , , , | Leave a Comment

RF Wireless Data with the Seeedstudio RFbee

Introduction

In this article we examine the Seeedstudio RFbee Wireless Data Transceiver nodes. An RFbee is a small wireless data transceiver that can be used as a wireless data bridge in pairs, as well as a node in mesh networking or data broadcasting. Here is an example of an RFbee:

You may have noticed that the RFbee looks similar to the Xbee-style data transceivers – and it is, in physical size and some pinouts, for example:

However this is where the similarity ends. The RFbee is in fact a small Arduino-compatible development board based on the Atmel ATmega168 microprocessor (3.3V at 8MHz – more on this later) and uses a Texas Instruments CC1101 low-power sub1-GHz RF transceiver chip for wireless transfer. Turning over an RFbee reveals this and more:

But don’t let all this worry you, the RFbee is very simple to use once connected. As a transceiver the following specifications apply:

  • Data rate – 9600, 19200, 38400 or 115200bps
  • Adjustable transmission power in stages between -30dBm and 10 dBm
  • Operating frequency switchable between 868MHz and 915MHz
  • Data transmission can be point-to-point, or broadcast point-to-many
  • Maximum of 256 RFbees can operate in one mesh network
  • draws only 19.3mA whilst transmitting at full power

The pinout for the RFbee are similar to those of an Xbee for power and data, for example:

There is also the ICSP pins if you need to reprogram the ATmega168 direcly with an AVRISP-type programmer.

Getting Started

Getting started is simple – RFbees ship with firmware which allows them to simply send and receive data at 9600bps with full power. You are going to need two or more RFbees, as they can only communicate with their own kind. However any microcontroller with a UART can be used with RFbees – just connect 3.3V, GND, and the microcontroller’s UART TX and RX to the RFbee and you’re away. For our examples we will be using Arduino-compatible boards. If Arduino is new to you, consider our tutorials first.

If you ever need to update the firmware, or reset the RFbee to factory default after some wayward experimenting – download the firmware which is in the form of an Arduino sketch (RFBee_v1_1.pde) which can be downloaded from the repository. (This has been tested with Arduino v23). In the Arduino IDE, set the board type to “Arduino Pro or Pro Mini (3.3V, 8MHz) w/ATmega168″. From a hardware perspective, the easiest way to update the firmware is via a 3.3V FTDI cable or an UartSBee board, such as:

You will also find a USB interface useful for controlling your RFbee via a PC or configuration (see below). In order to do this,  you will need some basic terminal software. A favourite and simple example is called … “Terminal“. (Please donate to the author for their efforts).

Initial Testing

After connecting your RFbee to a PC, run your terminal software and set it for 9600 bps – 8 – None – no handshaking, and click the check box next to “+CR”. For example (click to enlarge):

Select your COM: port (or click “ReScan” to find it) and then “Connect”. After a moment “OK” should appear in the received text area. Now, get yourself an Arduino or compatible board of some sort that has the LED on D13 (or substitute your own) and upload the following sketch:

// RFbee demonstration sketch
int ledPin = 13;
byte incoming=0;
void setup()
{
 Serial.begin(9600);
 pinMode(ledPin, OUTPUT);
}
void blinkLED(int i)
{
  for (int a=0; a<i; a++)
  {
    digitalWrite(ledPin, HIGH);
    delay(250);
    digitalWrite(ledPin, LOW);
    delay(250);
  }
}
void loop()
{
  if (Serial.available() > 0)
  {
    incoming = Serial.read();
    switch(incoming)
    {
      case 'A':
      blinkLED(1);
      break;
      case 'B':
      blinkLED(2);
      break;
      case 'C':
      blinkLED(3);
      break;
      default:
      blinkLED(5);
   }
  Serial.println("Blinking completed!");
  delay(2000);
  Serial.flush();
  }
}

Finally, connect the Arduino board to an RFbee in this manner:

  • Arduino D0 to RFbee TX
  • Arduino D1 to RFbee RX
  • Arduino 3.3V to RFbee Vcc
  • Arduino GND to RFbee GND
and the other RFbee to your PC and check it is connected using the terminal software described earlier. Now check the terminal is communicating with the PC-end RFbee, and then send the character ‘A’, ‘B’ or ‘C’. Note that the LED on the Arduino board will blink one, two or three times respectively – or five times if another character is received. It then reports back “Blinking completed!” to the host PC. For example (click to enlarge):

Although that was a very simple demonstration, in doing so you can prove that your RFbees are working and can send and receive serial data. If you need more than basic data transmission, it would be wise to get a pair of RFbees to experiment with before committing to a project, to ensure you are confident they will solve your problem.

More Control

If you are looking to use your RFbees in a more detailed way than just sending data at 9600 bps at full power, you will need to  control and alter the parameters of your RFbees using the terminal software and simple AT-style commands. If you have not already done so, download and review the RFbee data sheet downloadable from the “Resources” section of this page. You can use the AT commands to easily change the data speed, power output (to reduce current draw), change the frequency, set transmission mode (one way or transceive) and more.

Reading and writing AT commands is simple, however at first you need to switch the RFbee into ‘command mode’ by sending +++ to it. (When sending +++ or AT commands, each must be followed with a carriage return (ASCII 13)). Then you can send commands or read parameter status. To send a command, just send AT then the command then the parameter. For example, to set the data rate (page ten of the data sheet) to 115200 bps, send ATBD3 and the RFbee will respond with OK.

You can again use the terminal software to easily send and receive the commands. To switch the RFbee from command mode back to normal data mode, use ATO0 (that’s AT then the letter O then zero) or power-cycle the RFbee.

RFbee as an Arduino-compatible board with inbuilt wireless

As mentioned previously the RFbee is based around an Atmel ATmega168 running at 8MHz with the Arduino bootloader. In other words, we have a tiny Arduino-compatible board in there to do our bidding. If you are unfamiliar with the Arduino system please see the tutorials listed here. However there are a couple of limitations to note – you will need an external USB-serial interface (as noted in Getting Started above), and not all the standard Arduino-type pins are available. Please review page four of the data sheet to see which RFbee pins match up to which Arduino pins.

If for some reason you just want to use your RFbee as an Arduino-compatible board, you can do so. However if you upload your own sketch you will lose the wireless capability. To restore your RFbee follow the instructions in Getting Started above.

The firmware that allows data transmission is also an Arduino sketch. So if you need to include RF operation in your sketch, first use a copy of the RFBee_v1_1.pde included in the repository – with all the included files. Then save this somewhere else under a different name, then work your code into the main sketch. To save you the effort you can download a fresh set of files which are used for our demonstration. But before moving forward, we need to learn about controlling data flow and device addresses…

Controlling data flow

As mentioned previously, each RFbee can have it’s own numerical address which falls between zero and 255. Giving each RFbee an address allows you to select which RFbee to exchange data with when there is more than two in the area. This is ideal for remote control and sensing applications, or to create a group of autonomous robots that can poll each other for status and so on.

To enable this method of communication in a simple form several things need to be done. First, you set the address of each RFbee with the AT command ATMAx (x=address). Then set each RFbee with ATOF2. This causes data transmitted to be formatted in a certain method – you send a byte which is the address of the transmitting RFbee, then another byte which is the address of the intended receipient RFbee, then follow with the data to send. Finally send command ATAC2 – which enables address checking between RFbees. Data is then sent using the command

transmitData(*byte data, byte length, byte sourceAddress, byte destinationAddress)

Where data is … the data to send. You can send a single byte, or an array of bytes. length is the number of bytes you are sending. sourceAddress and destinationAddress are relevant to the RFbees being used – you set these addresses using the ATMAx described earlier in this section.

If you open the file rfbeewireless.pde in the download bundle, scroll to the end of the sketch which contains the following code:

byte testData[4] = {'A','B','C','D'};
void sendTestData()
{
 // send the four bytes of data in the byte testData[] from address 1 to address 2
 transmitData(testData,4,1,2);
 delay(1000);
}

This is a simple example of sending data out from the RFbee. The RFbee with this sketch (address 1) sends the array of bytes (testdata[]) to another RFbee with address 2.  You can disable address checking by a receiving RFbee with ATAC0 – then it will receive any data send by other RFbees.

To receive data use the following function:

result=receiveData(rxData, &len, &sourceAddress, &destinationAddress, (byte *)&rssi , &lqi);

The variable result will hold the incoming data, len is the number of bytes to expect, sourceAddress and destinationAddress are the source (transmitting RFbee) and destination addresses (receiving RFbee). rssi and lqi are the signal strength and link quality indicator – see the TI CC1101 datasheet for more information about these. By using more than two RFbees set with addresses you can selectively send and receive data between devices or control them remotely. Finally, please note that RFbees are still capable of sending and receiving data via the TX/RX pins as long as the sketch is not executing the sendTestData() loop.

I hope you found this introduction interesting and useful. The RFbees are an inexpensive and useful alternative to the popular Xbee modules and with the addition of the Arduino-compatible board certainly useful for portable devices, remote sensor applications or other data-gathering exercises.

For more information and product support, visit the Seeedstudio product pages.

RFbees are available from Seeedstudio and their network of distributors.

Disclaimer - RFbee products used in this article are promotional considerations made available by Seeedstudio.

In the meanwhile have fun and keep checking into tronixstuff.com. Why not follow things on twitterGoogle+, subscribe  for email updates or RSS using the links on the right-hand column? And join our friendly Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other –  and we can all learn something.

March 19, 2012 Posted by | arduino, education, RF, wireless, xbee | , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a Comment

Tutorial: Arduino and the I2C bus – Part Two

The first chapter is here, the complete series is detailed here. Please note from November 1, 2010 files from tutorials will be found here.

[Updated 10/01/2013]

Today we are going to continue learning about the I2C bus and how it can work for us. If you have not already, please read and understand the first I2C article before continuing.

First of all, there are some limitations of I2C to take into account when designing your projects. One of these is the physical length of the SDA and SCL lines. If all your devices are on the same PCB, then there is nothing to worry about, however if your I2C bus is longer than around one metre, it is recommended that you use an I2C bus extender IC. These ICs reduce electrical noise over the extended-length bus runs and buffer the I2C signals to reduce signal degradation and chance of errors in the data. An example of such an IC is the NXP P82B715 (data sheet). Using a pair of these ICs, you can have cable runs of 20 to 30 metres, using shielded twisted-pair cable. Below is a good example of this, from the aforementioned NXP data sheet:

Several applications come to mind with an extended I2C bus, for example remote temperature monitoring using the the ST Microelectronics CN75 temperature sensor from part one; or controlling several I/O ports using an I2C expander without the expense or worry of using a wireless system. Speaking of which, let’s do that now…

Example 21.1

A very useful and inexpensive part is the PCF8574 I/O expander (data sheet.pdf). This gives us another eight outputs, in a very similar method to the 74HC595; or can be used as eight extra inputs. In fact, if you were to use more than one 74HC595 this IC might be preferable, as you can individually address each chip instead of having to readdress every IC in line as you would with shift registers. So how do we do this? First, let’s consult the pinout:

There should not be any surprises for you there. A2~A0 are used to select the last three bits of the device address, P0~P7 are the I/O pins, and INT is an interrupt output which we will not use. To address the PCF8574 we need two things, the device address, and a byte of data which represents the required output pin state. Huh? Consider:

So if we set pins A0 to A2 to GND, our device address in binary will be 0100000, or 0×20 in hexadecimal. And the same again to set the output pins, for example to turn them all on we send binary 0 in hexadecimal which is 0; or to have the first four on and the second four off, use 00001111 which is Ox0F. Hopefully you noticed that those last two values seemed backwards – why would we send a zero to turn all the pins on?

The reason is that the PCF8574 is a current sink. This means that current runs from +5v, through into the I/O pins. For example, an LED would have the anode on the +5V, and the cathode connected to an I/O pin. Normally (for example with a 74HC595) current would run from the IC, through the resistor, LED and then to earth. That is a current source. Consider the following quick diagram:

In the example above, please note that the PCF8574N can take care of current limitation with LEDs, whereas the 74HC595 needs a current-limiting resistor to protect the LED.

Luckily this IC can handle higher volumes of current, so a resistor will not be required. It sounds a bit odd, but like anything is easy once you spend a few moments looking into it. So now let’s use three PCF8574s to control 24 LEDs. To recreate this masterpiece of blinkiness you will need:

  • Arduino Uno/Duemilanove or Freetronics Eleven board
  • A large solderless breadboard
  • Three PCF8574 I/O extenders
  • Eight each of red, green and yellow (or your choice) LEDs, each with a current draw of no more than 20mA
  • Two 4.7 kilo ohm resistors
  • Hook-up wires
  • Three 0.1 uF ceramic capacitors

Here is the schematic:

… and the example board layout:


and the example sketch. Note that the device addresses in the sketch match the schematic above. If for some reason you are wiring your PCF8574s differently, you will need to recalculate your device addresses: (download sketch)

/*
 Example 21.1
 Texas Instruments PCF8574N demonstration sketch
 element-14 part number 7527718; RS part number 517-0687
 http://tronixstuff.com/tutorials > chapter 21
 CC by-sa v3.0
 */
#include "Wire.h"
#define redchip 0x20 // device addresses for PCF8547Ns on each LED colour bank 
#define yellowchip 0x22 // addresses in this example match the published schematic in the tutorial
#define greenchip 0x21 // you will need to change addresses if you vary from the schematic
int dd=20; // used for delay timing
void setup()
{
 Wire.begin();
 allOff(); // the PCF8574N defaults to high, so this functions turns all outputs off
}
// remember that the IC "sinks" current, that is current runs fro +5v through the LED and then to I/O pin
// this means that 'high' = off, 'low' = on.
void testfunc()
{
 Wire.beginTransmission(redchip);
 Wire.write(0); 
 Wire.endTransmission();
 delay(dd+50);
 Wire.beginTransmission(redchip);
 Wire.write(255); 
 Wire.endTransmission();
 delay(dd+50);
 Wire.beginTransmission(yellowchip);
 Wire.write(0); 
 Wire.endTransmission();
 delay(dd+50);
 Wire.beginTransmission(yellowchip);
 Wire.write(255); 
 Wire.endTransmission();
 delay(dd+50);
 Wire.beginTransmission(greenchip);
 Wire.write(0); 
 Wire.endTransmission();
 delay(dd+50);
 Wire.beginTransmission(greenchip);
 Wire.write(255); 
 Wire.endTransmission();
 delay(dd+50);
}
void testfunc2()
{
 for (int y=1; y<256; y*=2)
 {
 Wire.beginTransmission(redchip);
 Wire.write(255-y); // we need the inverse, that is high = off
 Wire.endTransmission();
 delay(dd);
 Wire.beginTransmission(redchip);
 Wire.write(255); 
 Wire.endTransmission();
 delay(dd);
 }

 for (int y=1; y<256; y*=2)
 {
 Wire.beginTransmission(yellowchip);
 Wire.write(255-y); 
 Wire.endTransmission();
 delay(dd);
 Wire.beginTransmission(yellowchip);
 Wire.write(255); 
 Wire.endTransmission();
 delay(dd);
 }
 for (int y=1; y<256; y*=2)
 {
 Wire.beginTransmission(greenchip);
 Wire.write(255-y); 
 Wire.endTransmission();
 delay(dd);
 Wire.beginTransmission(greenchip);
 Wire.write(255); 
 Wire.endTransmission();
 delay(dd);
 }
}
void testfunc3()
{
 Wire.beginTransmission(redchip);
 Wire.write(0); 
 Wire.endTransmission();
 Wire.beginTransmission(yellowchip);
 Wire.write(0); 
 Wire.endTransmission();
 Wire.beginTransmission(greenchip);
 Wire.write(0); 
 Wire.endTransmission();
 delay(dd+50);
 allOff();
 delay(dd+50);
}
void allOff()
{
 Wire.beginTransmission(redchip);
 Wire.write(255); 
 Wire.endTransmission();
 Wire.beginTransmission(yellowchip);
 Wire.write(255); 
 Wire.endTransmission();
 Wire.beginTransmission(greenchip);
 Wire.write(255); 
 Wire.endTransmission();
}
void loop()
{
 for (int z=0; z<10; z++)
 {
 testfunc();
 }
 for (int z=0; z<10; z++)
 {
 testfunc2();
 }
 for (int z=0; z<10; z++)
 {
 testfunc3();
 }
}

And finally our demonstration video:


That was a good example of controlling many outputs with our humble I2C bus. You could literally control hundreds of outputs if necessary – a quite inexpensive way of doing so. Don’t forget to take into account the total current draw of any extended circuits if you are powering from your Arduino boards.

The next devices to examine on our I2C bus ride are EEPROMs - Electrically Erasable Programmable Read-Only Memory. These are memory chips that can store data without requiring power to retain memory. Why would we want to use these? Sometimes you might need to store a lot of reference data for use in calculations during a sketch, such as a mathematical table; or perhaps numerical representations of maps or location data; or create your own interpreter within a sketch that takes instruction from data stored in an array.

In other words, an EEPROM can be used to store data of a more permanent use, ideal for when your main microcontroller doesn’t haven enough memory for you to store the data in the program code. However, EEPROMs are not really designed for random-access or constant read/write operations – they have a finite lifespan. But their use is quite simple, so we can take advantage of them.

EEPROMS, like anything else come in many shapes and sizes. The model we will examine today is the Microchip 24LC256 (data sheet.pdf). It can hold 256 kilobits of data (that’s 32 kilobytes) and is quite inexpensive. This model also has selectable device addresses using three pins, so we can use up to eight at once on the same bus. An example:

The pinouts are very simple:

Pin 7 is “write protect” – set this low for read/write or high for read only. You could also control this in software if necessary. Once again we need to create a slave I2C device address using pins 1, 2 and 3 – these correlate to A2, A1 and A0 in the following table:

So if you were just using one 24LC256, the easiest solution would be to set A0~A2 to GND – which makes your slave address 1010000 or 0×50 in hexadecimal. There are several things to understand when it comes to reading and writing our bytes of data. As this IC has 32 kilobytes of storage, we need to be able to reference each byte in order to read or write to it. There is a slight catch in that you need more than one byte to reference 32767 (as in binary 32767 is 11111111 0100100 [16 bits]).

So when it comes time to send read and write requests, we need to send two bytes down the bus – one representing the higher end of the address (the first 8 bits from left to right), and the next one representing the lower end of the address (the final 8 bits from left to right) – see figure 6.1 on page 9 of the data sheet.

An example – we need to reference byte number 25000. In binary, 25000 is 0110000110101000. So we split that up into 01100001 and 10101000, then covert the binary values to numerical bytes with which to send using the Wire.send(). Thankfully there are two operators to help us with this. This first is >>, known as bitshift right. This will take the higher end of the byte and drop off the lower end, leaving us with the first 8 bits. To isolate the lower end of the address, we use another operator &, known as bitwise and. This unassuming character, when used with 0XFF can separate the lower bits for us. This may seem odd, but will work in the examples below.

Writing data to the 24LC256

Writing data is quite easy. But first remember that a byte of data is 11111111 in binary, or 255 in decimal. First we wake up the I2C bus with

Wire.beginTransmission(0x50); // if pins A0~A2 are set to GND

then send down some data. The first data are the two bytes representing the address (25000) of the byte (12) we want to write to the memory.

Wire.write(25000 >> 8);  // send the left-hand side of the address down
Wire.write(25000 & 0xFF); // send the right-hand side of the address down

And finally, we send the byte of data to store at address 25000, then finish the connection:

Wire.write(12);
Wire.endTransmission();

There we have it. Now for getting it back…

Reading data from the 24LC256

Reading is quite similar. First we need to start things up and move the pointer to the data we want to read:

Wire.beginTransmission(0x50); // if pins A0~A2 are set to GND
Wire.write(25000 >> 8);  // send the left-hand side of the address down
Wire.write(25000 & 0xFF); // send the right-hand side of the address down
Wire.endTransmission();

Then, ask for the byte(s) of data starting at the current address:

Wire.beginTransmission(0x50); // if pins A0~A2 are set to GND
Wire.requestFrom(0x50,1);
Wire.read(incomingbyte);

In this example, incomingbyte is a byte variable used to store the data we retrieved from the IC. 

Example 21.2

Now we have the theory, let’s put it into practice with the test circuit below, which contains two 24LC256 EEPROMs. To recreate this you will need:

  • Arduino Uno or Freetronics Eleven board
  • A large solderless breadboard
  • Two Microchip 24LC256 EEPROMs
  • Two 4.7 kilo ohm resistors
  • Hook-up wires
  • Two 0.1 uF ceramic capacitors

Here is the schematic:

… the board layout:

and the example sketch. Note that the device addresses in the sketch match the schematic above. If for some reason you are wiring your 24LC256s differently, you will need to recalculate your device addresses. To save time with future coding, we have our own functions for reading and writing bytes to the EEPROM – readData() and writeData(). Consider the sketch for our example: (download sketch)

/*
 Example 21.2
 Reading and writing data to Microchip 24LC256 EEPROMS over I2C
 tronixstuff.com/tutorials > Chapter 21
 CC by-sa v3.0 
*/
#include  // for I2C
#define chip1 0x50 // device address for left-hand chip on our breadboard
#define chip2 0x51 // and the right
// always have your values in variables
unsigned int pointer = 69; // we need this to be unsigned, as you may have an address > 32767
byte d=0; // example variable to handle data going in and out of EERPROMS
void setup()
{
 Serial.begin(9600); // for screen output
 Wire.begin(); // wake up, I2C!
}
void writeData(int device, unsigned int add, byte data) 
// writes a byte of data 'data' to the chip at I2C address 'device', in memory location 'add'
{
 Wire.beginTransmission(device);
 Wire.write((int)(add >> 8)); // left-part of pointer address
 Wire.write((int)(add & 0xFF)); // and the right
 Wire.write(data);
 Wire.endTransmission();
 delay(10);
}
byte readData(int device, unsigned int add) 
// reads a byte of data from memory location 'add' in chip at I2C address 'device' 
{
 byte result; // returned value
 Wire.beginTransmission(device); // these three lines set the pointer position in the EEPROM
 Wire.write((int)(add >> 8)); // left-part of pointer address
 Wire.write((int)(add & 0xFF)); // and the right
 Wire.endTransmission();
 Wire.requestFrom(device,1); // now get the byte of data...
 result = Wire.read();
 return result; // and return it as a result of the function readData
}
void loop()
{
 Serial.println("Writing data...");
 for (int a=0; a<20; a++)
 {
 writeData(chip1,a,a);
 writeData(chip2,a,a); // looks like a tiny EEPROM RAID solution!
 }
 Serial.println("Reading data...");
 for (int a=0; a<20; a++)
 {
 Serial.print("chip1 pointer ");
 Serial.print(a);
 Serial.print(" holds ");
 d=readData(chip1,a);
 Serial.println(d, DEC);
 }
 for (int a=0; a<20; a++)
 {
 Serial.print("chip2 pointer ");
 Serial.print(a);
 Serial.print(" holds ");
 d=readData(chip2,a);
 Serial.println(d, DEC);
 } 
}

And the output from the example sketch:

Although the sketch in itself was simple, you now have the functions to read and write byte data to EEPROMS. Now it is up to your imagination to take use of the extra memory.

Have fun and keep checking into tronixstuff.com. Why not follow things on twitterGoogle+, subscribe  for email updates or RSS using the links on the right-hand column, or join our Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other –  and we can all learn something.

October 29, 2010 Posted by | arduino, I2C, learning electronics, microcontrollers, tutorial | , , , , , , , , , , , , , , , , , , , , , , | 11 Comments

Review – Texas Instruments TLC5940 16-channel LED driver IC

Hello readers

Today we are going to examine the Texas Instruments TLC5940 16-channel LED driver IC. My reason for doing this is to demonstrate another, easier way of driving many LEDs as well as LED display modules that are common-anode. If you have a common-cathode display module, you should have a look at the Maxim MAX7219. Moving along, here is the IC:

Another nice big DIP IC. Also available in HTSSOP and QFN packaging. What can this IC do for us? It can control 16 LEDs per IC, and also be cascaded to control more and more, with the display data arriving via a serial line in the same manner as a 74HC595 shift register. Furthermore, another benefit of this IC is that you don’t need matching current-limiting resistors for your LEDs, as this IC is a current sink, in that the current flows from the 5V rail, through the LED, then into the IC. However, it can control the brightness of the LEDs using pulse-width modulation over 4096 steps via software, or using a single resistor.

What is pulse-width modulation? Normally an LED might be on, or off. But if you switch it on and off very quickly, it does not look as bright (as it is not on 100% of the time). If you alter the period of time between on and off, you can alter the perceived brightness of the LED. Here is an example, compare the brightness of the LED bars against the display of the CRO – as the brightness increases, the voltage (amplitude [vertical thickness]) spreads across the entire time period (horizontal axis); as the brightness decreases, the voltage spread across time retreats:

Using the IC is very easy on the hardware front. Here is the data sheet: TLC5940.pdf. The pinout diagram is quite self-explanatory:

Pins OUT0~OUT15 are the current-sink pins for each LED. When one is selected they allow current to flow into the IC from the 5V rail, with the LED in between – turning it on. However it is easier to understand with a practical example, such as this (click to enlarge):

If you are using an Arduino Mega-style board, the wiring is a little different, please see here for the instructions.

Here we have our Arduino board or compatible sending serial data to the TLC5940 to control sixteen LEDs. The 2k ohm resistor is required to set the maximum current available to flow through the LEDs, thereby adjusting their brightness. Using software you can adjust the brightness with PWM for each LED by itself. Very important: this circuit will need external power into the Arduino or a separate 5V power supply. The circuitry on the breadboard draws up to ~318 mA by itself – running the Arduino from USB only made it somewhat flaky in operation. Here is the circuit in action with an ammeter between the breadboard and 5V out on the Arduino:

Anyhow, let’s get moving once more - here is the assembled demonstration circuit:

For our example, we will be using the Arduino way of doing things. Thankfully (once more) there is a library to make controlling the IC exponentially easier. The library page and download files are available from here.  If you need guidance on installing a library, please visit here. However the commands to control the IC are quite simple with the Arduino library.

First of all, include the TLC5940 library, as such:

#include “Tlc5940.h”

Then in void setup(); you create the object using the function:

Tlc.init();

You can insert a number between 0 and 4095 to set the starting PWM (LED brightness) value, however this is optional.

Setting an output for display requires two functions, first Tlc.set(l, p); where l is the output (0~15) and p is the PWM brightness level – then execute Tlc.update(); which sends the command to the IC to be executed. The sketch below is easy to follow and understand the process involved.

Moving forward with the demonstration, here is the sketch  - TLC5940demo.pdf, and the video clip of operation:

When the LEDs are glowing from dim to bright and return, we are altering the PWM value of the LEDs to adjust their brightness. This also occurs during the last operation where the LEDs are operating like the bonnet of KITT.

Below is an example of TLC5940 use by JM – he has made an awesome RGB LED cube:

Well once again that’s enough blinkiness for now, again this is another useful IC that helps simplify things and be creative. As always, avoid the risk of counterfeit ICs  – so please avoid disappointment, support your local teams and buy from a reputable distributor. Living in Australia, mine came from element-14 (part number 1226306). So have fun!

Remember, if you have any questions at all please leave a comment (below). We also have a Google Group dedicated to the projects and related items on the website – please sign up, it’s free and we can all learn something. High resolution photos are available from flickr.

Otherwise, have fun, stay safe, be good to each other – and make something! :)

[Note - the TLC5940 was purchased by myself personally and reviewed without notifying the manufacturer or retailer]

July 19, 2010 Posted by | arduino, part review | , , , , , , , , , , , , , , , , , , , , , , | 25 Comments

   

Follow

Get every new post delivered to your Inbox.

Join 3,837 other followers

%d bloggers like this: