SAA1064 data format | Kickoff

SAA1064 data format

10 May

SAA1064 data format: The process of displaying digits with the SAA1064 LED display driver is simple: you send it an array of data containing the commands and data. The array is seven bytes long, and the format is illustrated in the chart shown in Table 11-5.
Table 11-5: Chart showing SAA1064 data format

A1, A0 = configurable address bits.
SC, SB, SA = subaddress bits that are set to 0 for our purposes.
X = don’t care (set to 0).
C6 – C0 are further explained in the text.
Source: Excerpt from the SAA1064 Data Sheet, dated Feb 1991, page 5.

The slave address
The slave address is seven bits long, with the most significant five bits fixed at 01110. The remaining two bits are programmable, based on the value of the ADR pin. We will tie our ADR pin low, which means the least significant two bits of our 7-bit address will be 00. Our 7-bit address makes up the “upper” seven bits of the first 8- bit byte in the data array that we send to the SAA1064. The eighth bit, the least significant bit of that byte, is the read/write bit. Since our data array will be written to the SAA1064, the read/write bit will be set to 0. Our slave address is 0111000, and the first data byte in our data array is 01110000, or 0×70.

The instruction byte
The instruction byte contains three subaddress bits, SC, SB, SA, which can be used to control where in the SAA1064 our data array gets written. We’re not going to be making use of this feature, and all of our subaddressing bits are going to be set to zero. The second byte in the data array that we’re going to send to the SAA1064 becomes 00000000.

The control byte
The control byte consists of an unused bit, which is the most significant bit of this byte, and seven control bits. The meaning of the seven control bits is shown below. Our control byte will be 0×26, or 00100110, which, from the table below, means that we are in static mode as opposed to multiplexed, sinking a current of 3 mA in each segment of the display.

Table 11-6: Chart showing SAA1064 control bytes

Data bytes
The four data bytes each represent one of the four possible 7-segment LED displays that we can control with the SAA1064. Since we aren’t using it in the dynamic, or multiplexed, mode, we are only concerned with two of the digits. In the static, two- digit mode, we only need to be concerned with the contents of the first two bytes. The last two bytes we set to 0×00. The coding that relates how the individual bits map into illuminated segments is specific to the individual design. Our encoding is illustrated in Table 11-4. With that as background, if we wanted to display the number “38” on our system, we would write the following data array to the device: 0×70, 0×00, 0×26, 0xBC, 0xFD, 0×00, 0×00. Let’s take a look at a generic Java class called Digits that takes in an integer and displays it on an SAA1064 controlled by TINI. We’ll present the whole program, then study it in detail. It should be noted that making I2C work with TINI is actually quite simple, but it requires attention to detail. The I2Cport class handles some of the low-level details for us, which is a good thing. But it also means that the device address and the data array that we send the device have two different contexts. There’s the address and data array that we use in our Java program, and then there’s the address byte and the data array that gets transmitted on the I2C bus itself. They’re not the same. Our Digits class is designed to take in a two-digit number and display it on two 7- segment LED displays. If the number is less than 0, it displays “UF” for “underflow” and if the number is more than 99, it displays “OF” for “overflow.” The class has a method to display a byte, and a method to turn the digits off. It has a main() method that acts as a test, displaying all of the digits.

Listing 11-1: Digits.java
import com.dalsemi.system.*;
import java.io.*;
public class Digits {
private static byte LETTER_U = (byte) 0×6D;
private static byte LETTER_F = (byte) 0xD1;
private static byte LETTER_O = (byte) 0xED;
private static byte BLANK = 0×00;
byte[] data = new byte[6];
I2CPort LEDPort;
public Digits() {
LEDPort = new I2CPort();
LEDPort.setAddress((byte)0×38);
LEDPort.setClockDelay((byte)0×7F);
data[0] = 0×00;                                                   // instruction byte
data[1] = 0×26;                                                   // control byte
data[2] = 0×00;                                                   //  digit 1 data
data[3] = 0×00;                                                   //  digit 2 data
data[4] = 0×00;                                                   //  digit 3 data
data[5] = 0×00;                                                   //  digit 4 data
}
public byte getBits(byte displayChar) {
switch (displayChar) {
case 1: return (byte)(0×28);
case 2: return (byte)(0xB5);
case 3: return (byte)(0xBC);
case 4: return (byte)(0×78);
case 5: return (byte)(0xDC);
case 6: return (byte)(0xDD);
case 7: return (byte)(0xA8);
case 8: return (byte)(0xFD);
case 9: return (byte)(0xFC);
case 0: return (byte)(0xED);
default: return (byte)(0);
}
}
public void setValue(byte displayValue) {
byte char1, char2;
int i;
if (displayValue < 0) {
// Underflow (UF)
char1 = LETTER_U;
char2 = LETTER_F;
}
else if (displayValue > 99) {
// Overflow (OF)
char1 = LETTER_O;
char2 = LETTER_F;
}
else {
char2 = getBits((byte)(displayValue%10));
char1 = getBits((byte)(((displayValue-(displayValue%10))/10)));
}
this.data[2] = char1;
this.data[3] = char2;
try {
i = this.LEDPort.write(data, 0, 6);
System.out.print( “Stat: “ + i );
} catch (Exception e) {System.out.println(e);}
}
public void turnOff() {
int i;
this.data[2] = BLANK;
this.data[3] = BLANK;
try {
i = this.LEDPort.write(data, 0, 6);
} catch (Exception e) {System.out.println(e);}
}
public static void main(String[] args) {
Digits displayChars = new Digits();
for (int i=-5; i<105; i++) {
System.out.print( “N: “ + i + “ “ );
displayChars.setValue((byte)i);
try {
Thread.sleep(500);
} catch(Exception e){}
}
displayChars.turnOff();
}
}

The program begins with a couple of import statements, gaining access to the necessary Java class libraries.
import com.dalsemi.system.*;
import java.io.*;

Shown below is our class and data member declarations. The byte array data is only six bytes long. In our discussion of the SAA1064 we noted that the data array that gets sent to the device is seven bytes long. The difference comes from the fact that, in the I2Cport class, we don’t have to explicitly put the address byte in the data array. Instead, we use the setAddress() method to set the address, and the class handles the details of putting the address into the data array. LEDPort is a I2CPort object that will give us access to the I2CPort methods.

public class Digits {
private static byte LETTER_U = (byte) 0×6D;
private static byte LETTER_F = (byte) 0xD1;
private static byte LETTER_O = (byte) 0xED;
private static byte BLANK = 0×00;
byte[] data = new byte[6];
I2CPort LEDPort;

Following is our constructor. It creates an I2CPort object, sets its device address, the clock delay, and initializes its data array. Here, we run into one source of confusion: the address. The actual device address is seven bits, and in our case it will be 0111000. The data field called slaveAddress in the I2CPort class, which is set by the setAddress() method, is a byte. Our 7-bit address is right justified. That is, they give it a leading zero, turning 0111000 into 00111000, or 0×38. When that address actually gets written out on the bus, it won’t appear as 0×38. The I2CPort class extracts the actual 7-bit address from the byte, left justifies it, and makes the least significant bit the read/write bit, which in our case (writing), will be a 0. So, on the I2C bus itself, the address byte will turn out to be 01110000, or 0×70. With respect to the clock delay, the value of 0×7F represents the slowest possible clock. Theoretically, the clock can vary between 2.5 kbits/sec and 250 kbits/sec. When measured with a scope, this example had a clock speed of 6 kbits/sec. In practice, with this example, this value hasn’t proven to be critical. Experimentally, any value larger than 1 worked.

public Digits() {
LEDPort = new I2CPort();
LEDPort.setAddress((byte)0×38);
LEDPort.setClockDelay((byte)0×7F);
data[0] = 0×00;                                                                            // instruction byte
data[1] = 0×26;                                                                            // control byte
data[2] = 0×00;                                                                            //  digit 1 data
data[3] = 0×00;                                                                            //  digit 2 data
data[4] = 0×00;                                                                            //  digit 3 data
data[5] = 0×00;                                                                            //  digit 4 data
}

The getBits() method takes a single digit between 0 and 9 and returns the 7-segment encoding for that digit. A bit value of “1” means that segment “a” will be illuminated. Refer to Table 11-4.

public byte getBits(byte displayChar) {
switch (displayChar) {
case 1: return (byte)(0×28);
case 2: return (byte)(0xB5);
case 3: return (byte)(0xBC);
case 4: return (byte)(0×78);
case 5: return (byte)(0xDC);
case 6: return (byte)(0xDD);
case 7: return (byte)(0xA8);
case 8: return (byte)(0xFD);
case 9: return (byte)(0xFC);
case 0: return (byte)(0xED);
default: return (byte)(0);
}
}

The setValue() method takes in a byte that represents the 2-digit number we want to display, extracts the two digits from it, gets the bit encoding from the getBits()

method, and writes the data to the SAA1064 using the write() method of the I2CPort class. If the number is less than zero, it puts “UF” into the variables that will be displayed. If it’s greater than 99, it puts “0F” into them. If between the two, it converts a number into two digits.

public void setValue(byte displayValue) {
byte char1, char2;
int i;
if (displayValue < 0) {
// Underflow (UF)
char1 = LETTER_U;
char2 = LETTER_F;
}
else if (displayValue > 99) {
// Overflow (OF)
char1 = LETTER_O;
char2 = LETTER_F;
}
else {
char2 = getBits((byte)(displayValue%10));
char1 = getBits((byte)(((displayValue-(displayValue%10))/10)));
}

We’ve established what characters to display, so we place them into the third and fourth byte positions in the data array. The data array is passed to the write() method with an offset of 0 and a length of six. The 0 offset indicates start with the 0 element in the array. The method returns an integer: 0 if the write functioned properly, and -1 if there was no Acknowledge bit sent from the slave.

this.data[2] = char1;
this.data[3] = char2;
try {
i = this.LEDPort.write(data, 0, 6);
System.out.print( “Stat: “ + i );
} catch (Exception e) {System.out.println(e);}
}
The  turnOff() method turns off all segments in both displays. We do this by setting
all bits to 0 in both data bytes. Note that we’re not telling them to write the digit 0,
we’re telling the SAA1064 to put 0s on all 8 bits of both data buses.
public void turnOff() {
int i;
this.data[2] = BLANK;
this.data[3] = BLANK;
try {
i = this.LEDPort.write(data, 0, 6);
} catch (Exception e) {System.out.println(e);}
}

The main() method tests the functionality of the Digit class. It simply counts up from -5 to 100. In doing so, it exercises all segments in both digits and tests for the correct encoding of all the numbers plus the “UF” (underflow) and “OF” (overflow) cases.

public static void main(String[] args) {
Digits displayChars = new Digits();
for (int i=-5; i<101; i++) {
displayChars.setValue((byte)i);
try {
Thread.sleep(500);
} catch(Exception e){}
}
displayChars.turnOff();
}
}

If you compile this into Digits.tini, then you will need to send it to TINI using FTP and execute it under the Slush operating system. If you compile it into Digits.tbin, then you would load it into TINI with JavaKit. This program provides no output to the screen, unless there is an exception. The commands used to compile this program into a .tini file are shown below.

C:\> javac -bootclasspath %TINI_HOME%\bin\tiniclasses.jar
-classpath                                                                                %TINI_HOME%\bin\owapi_dependencies_TINI.jar;.
-d bin   src\Digits.java
C:\> java -classpath %TINI_HOME%\bin\tini.jar;. BuildDependency
-p                                                                                        %TINI_HOME%\bin\owapi_dependencies_TINI_001.jar
-f bin
-x                                                                                        %TINI_HOME%\bin\owapi_dep.txt
-o bin
-d %TINI_HOME%\bin\tini.db

Chapter 7 as well as the thermometer example at the end of  Chapter 10 has a discussion of what some of these options mean. Command options have been shown on separate lines for readability. In practice, they need to be on the same line.



Random Posts

Comments are closed.