Tutorial: Arduino and the NXP SAA1064 4-digit LED display driver

Learn how to use the NXP SAA1064 LED display driver IC in chapter thirty-nine of a series originally titled “Getting Started/Moving Forward with Arduino!” by John Boxall – a series of articles on the Arduino universe.

Updated 19/01/2013

In this article we investigate controlling the NXP (formerly Philips) SAA1064 4-digit LED display driver IC with Arduino and the I2C bus interface. If you are not familiar with using the I2C bus, please read my tutorials (parts one and two) before moving on. Although the SAA1064 is not the newest on the market, it is still popular, quite inexpensive and easy to source. Furthermore as it is controlled over the I2C bus – you don’t waste any digital I/O pins on your Arduino, and you can also operate up to four SAA1064s at once (allowing 16 digits!). Finally, it has a constant-current output – keeping all the segments of your LED display at a constant brightness (which is also adjustable).  So let’s get started…

Here is an example of the SAA1064 in SOIC surface mount packaging:

It measures around 15mm in length. For use in a solderless breadboard, I have soldered the IC onto a through-hole adaptor:

The SAA1064 is also available in a regular through-hole DIP package. At this point, please download the data sheet (.pdf) as you will need to refer to it during the article. Next, our LED display examples. We need common-anode displays, and for this article we use two Agilent HDSP521G two-digit modules (data sheet [.pdf]) as shown below:

For the uninitiated – a common anode display has all the segments’ anodes connected together, with the cathodes terminated separately. For example, our LED displays are wired as such:

Notice the anodes for the left digit are pin 14, and the right digit pin 13. A device that is connected to all the cathodes (e.g. our SAA1064) will control the current flow through each element – thereby turning each segment on (and controlling the brightness) or off. Our SAA1064 is known as a current-sink as the current flows through the LED, and then sinks into the IC.

Now, let’s get it connected. There is an excellent demonstration circuit on page twelve of the data sheet that we will follow for our demonstrations:

It looks pretty straight-forward, and it is. The two transistors are standard NPN-type, such as PN2222. The two transistors are used to each turn on or off a pair of digits – as the IC can only drive digits 1+3 or 2+4 together. (When presented in real life the digits are numbered 4-3-2-1). So the pairs are alternatively turned on and off at a rapid rate, which is controlled by the capacitor between pin 2 and GND. The recommended value is 2.7 nF. At the time of writing, I didn’t have that value in stock, so chose a 3.3 nF instead. However due to the tolerance of the ceramic capacitor it was actually measured to be 2.93 nF:

So close enough to 2.7 nF will be OK. The other capacitor shown between pins 12 and 13 is a standard 0.1 uF smoothing capacitor. Pin 1 on the SAA1064 is used to determine the I2C bus address – for our example we have connected it straight to GND (no resistors at all) resulting in an address of 0x70. See the bottom page five of the data sheet for other address options. Power for the circuit can be taken from your Arduino’s 5V pin – and don’t forget to connect the circuit GND to Arduino GND. You will also use 4.7k ohm pull-up resistors on the SDA and SCL lines of the I2C bus.

The last piece of the schematic puzzle is how to connect the cathodes of the LED displays to the SAA1064. Display pins 14 and 13 are the common anodes of the digits.

The cathodes for the left-hand display module:

  • LED display pins 4, 16, 15, 3, 2, 1, 18 and 17 connect to SAA1064 pins 22, 21, 20, 19, 18, 17, 16 and 15 respectively (that is, LED pin 4 to IC pin 22, etc.);
  • LED display pins 9, 11, 10, 8, 6, 5, 12 and 7 also connect to SAA1064 pins 22, 21, 20, 19, 18, 17, 16 and 15 respectively.
The cathodes for the right-hand display module:
  • LED display pins 4, 16, 15, 3, 2, 1, 18 and 17 connect to SAA1064 pins 3, 4, 5, 6, 7, 8, 9 and 10 respectively;
  • LED display pins  9, 11, 10, 8, 6, 5, 12 and 7 also connect to SAA1064 pins 3, 4, 5, 6, 7, 8, 9 and 10 respectively.
Once your connections have been made, you could end up with spaghetti junction like this…
Now it is time to consider the Arduino sketch to control out SAA1064. Each write request to the SAA1064 requires several bytes. We either send a control command (to alter some of the SAA1064 parameters such as display brightness) or a display command (actually display numbers). For our example sketches the I2C bus address “0x70 >> 1” is stored in the byte variable saa1064. First of all, let’s look at sending commands, as this is always done first in a sketch to initiate the SAA1064 before sending it data.
As always, we send the address down the I2C bus to awaken the SAA1064 using

Then the next byte is the instruction byte. If we send zero:

… the IC expects the next byte down the bus to be the command byte. And finally our command byte:

The control bits are described on page six of the data sheet. However – for four-digit operation bits 0, 1 and 2 should be 1; bit 3 should be 0; and bits 4~6 determine the amount of current allowed to flow through the LED segments. Note that they are cumulative, so if you set bits 5 and 6 to 1 – 18 mA of current will flow. We will demonstrate this in detail later on.

Next, to send actual numbers to be displayed is slightly different. Note that the digits are numbered (from left to right) 4 3 2 1. Again, we first send the address down the I2C bus to awaken the SAA1064 using

Then the next byte is the instruction byte. If we send 1, the next byte of data will represent digit 1. If that follows with another byte, it will represent digit 2. And so on. So to send data to digit 1, send

Although sending binary helps with the explanation, you can send decimal equivalents. Next, we send a byte for each digit (from right to left). Each bit in the byte represents a single LED element of the digit as well as the decimal point. Note how the elements are labelled (using A~G and DP) in the following image:

The digit bytes describe which digit elements to turn on or off. The bytes are described as such: Bpgfedcba. (p is the decimal point). So if you wanted to display the number 7, you would send B00000111 – as this would turn on elements a, b and c. To add the decimal point with 7 you would send B10000111. You can also send the byte as a decimal number. So to send the digit 7 as a decimal, you would send 7 – as 00000111 in base-10 is 7. To include the decimal point, send 135 – as 100000111 in base-10 is 135. Easy! You can also create other characters such as A~F for hexadecimal. In fact let’s do that now in the following example sketch:

In the function initDisplay() you can see an example of using the instruction then the control byte. In the function clearDisplay() you can see the simplest form of sending digits to the display – we send 0 for each digit to turn off all elements in each digit. The bytes that define the digits 0~9 and A~F are stored in the array digits[]. For example, the digit zero is 63 in decimal, which is B00111111 in binary – which turns on elements a,b,c,d,e and f. Finally, notice the second loop in displayDigits() – 128 is added to each digit value to turn on the decimal point. Before moving on, let’s see it in action:

Our next example revisits the instruction and control byte – we change the brightness of the digits by setting bits 4~6 in the control byte. Each level of brightness is separated into a separate function, and should be self-explanatory. Here is the sketch:

And again, see it in action:

For our final example, there is a function displayInteger(a,b) which can be used to easily display numbers from 0~9999 on the 4-digit display. The parameter a is the number to display, and b is the leading-zero control – zero – off, one – on. The function does some maths on the integet to display and separates the digits for each column, then sends them to the SAA1064 in reverse order. By now you should be able to understand the following sketch:

And the final example in action:

So there you have it – another useful IC that can be used in conjunction with our Arduino systems to make life easier and reduce the required digital output pins.


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.

The following two tabs change content below.

John Boxall

Person. Founder and original author for tronixstuff.com. VK3FJBX

27 thoughts on “Tutorial: Arduino and the NXP SAA1064 4-digit LED display driver

  1. Dawson Robertson

    This is great stuff… thank you.
    I may have mistakenly ordered the wrong display. I have a 4 digit, 4 common anode, 12 pin chip. I’m novice enough that it’s not obvious to me if I can still connect it to the SAA1064.
    Any thought/advice would be appreciated.

      1. Dawson Robertson

        That’s very good of you John. Thank you.
        Feeling even more like a dummy, I don’t see how to attach a file like a data sheet. However, I got the info via the Digi-Key site; the part is the LDQ-M516RI

  2. Russ

    Hi John,

    Another great article – every project I do involves a visit to your site!

    I’m considering using an SAA1064 in a clock project – could you tell me if it possible to use less than the recommended 5v to drive the 7-Segs? I will use the brightness control built into the chip but want to make sure they can go extremely dim on the lowest setting so it’s not too bright at night and also to lower the power consumption.

    Many thanks


    1. John Boxall

      The brightness is controlled by the SAA1064 itself, which will need the 5V. From my own experience you can go quite dim, for example setting the display current to 3mA – however it’s subjective.

  3. Lui

    thanks for the Tutorial! i´m a bloody beginner – can you tell me which pins i should use on an Arduino Duemilanove? I can´t see where to connect SCL and SDA… segments on my display are shining, but nothing is happening like in your videos.


  4. Mike Grice

    Ive got a lot of work to do, I need to run 8 x 4-digit displays. Is this chip suitable, do I need to just buy more? Completely new to Arduino and have jumped in at the deep end. Happy doing programming stuff as I have an IT background and have done stuff like run relays, temp probes, but this massive ball of wiring is all new to me 🙂



  5. elanii

    Hi, my name is Carlo and I’m using graytech 7segment display with and arduino duemilanove for displaying an analog sensor reading. First of all I’m really a newbie so I got some problem with code implementation. Anyway reusing some block of code my application work fine. My goal is to basicly display some reading from the analog sensor. Everything works fine but to refine my project I need to display a decimal dot between two number. I’ll place here my code, please forgive me for any conceptual errors or so on. Also forgive me for my bad english. I need to place the decimal dot only when i display two number. e.g if val2 value is 45 the number must be 4.5, if 35 must be 3.5 and so on … can You help me please?

    Best regards from Italy


    here is the code:

    const byte LedDrive = 0x38; /* I2C address for 7-Segment */
    // lookup array containing segments to light for each digit
    const int lookup[10] = {
    void setup()
    Wire.begin(); // join I2C bus (address optional for master)
    void loop()
    int val;
    int val2;
    val=analogRead(0); //connette il sensore ad Analog 0

    Wire.write(B01000111); // inizializza il display a 7 segmenti – see data sheet
    //attribuisce il valore della lettura
    if (val=106 & val=110 & val=113 & val=116 & val=123 & val=129 & val=141 & val=159 & val<=191){
    val2 = 1;
    // funzione per visulaizzare fino a due cifre sul 7-segment I2C display
    void displayNumber( int number)
    number = constrain(number, 0, 99);
    for(int i =0; i 0) //elimina gli zeri inutili
    number = number / 10;

    thanks in advance

  6. Rubina

    hey John,

    I am trying my luck interfacing 8051with a dual 7 segment(cathode) led display in Proteus. It has 10 pins in all. I am making the following connections:

    As far as I understood, DP allows display(I guess),pin 1 & pin 2 allows selecting which 7-seg display to use from the dual display. I dont know till where am I correct. Also let me know if I need any other hardware.
    Later my plan is to proceed with 6/8 digit led-display. Plz guide me accordingly.

      1. Rubina

        Its actualy not about 8051 that I am asking, I want to know of the pins…Pin DP, 1 & 2, what are they for..? where to connect(any rough idea is also useful enough)

      2. Rubina

        I did some research and found DP=DECIMAL point, Pin1 & Pin 2 should be connected to supply in case of dual Anode display 7 segment. Still I don’t know how to control a single 7-segment display out of the dual 7-segment display. Coz now I have commn connections(A, B,C,D,E,F,G)

  7. Ralf J.


    very good tutorial! Example 39.1 and 39.3 work also with my ELD-516GWA/P18 Dual Digit Display. But 39.2 (adjusting segment current) does not work properly 🙁 I see a short flickering only and after that all digits are dark…

      1. Ralf J.

        OK, it was worth a question. The wiring is ok. I use Phillips SAA1064 not NXP…
        Could that be the reason?

  8. Maarten

    Thank John,

    this is the LED display driver used in my Remeha Quinta 35 central heating furnace to display the current status with numbers. Unfortunately it’s up in the attic so I’m trying to reverse it and spy on the codes with an Arduino, so I can store and send them to the computer for analysis.
    Interesting application is that on the PCB I’m investigating the digit you call 3 is missing. Instead the pins are wired to 4 individual status LED’s place above buttons, so you can also drive singe LED’s with it.
    I found what I did wrong in my reverse engineering: VEE needs connection to ground and VCC to 5V, not the other way round.


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.