top of page

Senior Capstone: I2C 7Seg Drivers [Project]

My Senior Design project seemed a bit silly at first; the professor stared out at the class with a stoic expression: "You are to build a Skittle sorting machine".

Personally, I felt as though the professor choose this project to cleverly inject sugar into his students so the sugar high could push us through all the late nights we would have. Still... silly right? As electrical engineering students, we wanted to be seen as men: frail, nerdy, socially awkward men. Men, who, were reduced to playing with Skittles for a Senior Design Project.

The EE students, however, were victim to something of an evil facade; this project, akin to an atom bomb, was masked with the friendly childhood memories of beloved Skittles. We did not know what was lurking for us behind those damned 'S's. Imagine, working until your hands looked like you punched a Picasso painting; or reaching for your laptop, only to find a Skittle somehow jammed under the escape key. It was a special kind of hell, one that smelled like artificial flavors and a sugar overdose.

The Division of Labor

SkittleMachine_edited.jpg

There were 10 teams, and we were a team of 7. We consisted of 3 MEs, 3 EEs and a single CE major. There was no limitations on what platforms a team could use for their project, so of course we chose the most trivial of them all: Arduino.

In my heart, there is nothing but respect for Arduino, but it does not belong in an EE Senior Design project. I know this. However in this case, I was willing to sacrifice my pride for practicality, so Arduino it was. Unofficially, I was elected the programmer so I imported the "SortSkittlesByColor" class and was done with it.

Then came another problem: the counting of Skittles. There were 7 Skittle colors, and for each color, a count must be made and displayed somehow.

Many teams decided to take their dignity and put it in a meat shredder by using additional Arduinos to carry out the task; however I cared for and loved my diginity way too much to see it destroyed. I even gave it a name: Burden.

I could not bear to use an Arduino again; for some reason, I actually wanted to treat it like an EE Senior Design project. It was because of that, that I designed a home brewed counting system.

Designing the System

Seven colors, seven pipes that the sorted Skittle candies shot from. Using photogates to detect the passage of a single Skittle, I developed the following system:

TopLeve.png

A single system can only handle 4 Skittle pipes (I'll explain later), so I needed to build 2 duplicate systems.

It was simple. A Skittle would pass the gate, the raw signal would be processed by some debouncing HW. The signal would then input to interrupt pins on the ATtiny48. Through simple logic, the MCU would increment the appropriate color and transmit the new value through an I2C bus.

Breaking down the top level piece by piece

Photo Gate and Debounce HW

ThresholdCircuit.png

EAGLE doesn't have a photo gate component readily available in their database so I created a mock up using the LED and photo-transistor to represent the gate. It's really straightforward how the gate works. By default, there is no Skittle and the LED shines on the transistor. The transistor is NPN so this creates a flow from the collector to emittor and the output approaches VCC. When the Skittle passes the gate, the Skittle blocks the light from the LED and the transistor becomes dark. Resistor R2 then pulls the output node down to zero.

Let's consider the output node of the photogate: which is the node that connects to R2 and the emittor of the transistor. This is the raw sensing of the Skittle. Probing with an oscilloscope, this is what the signal looks like when a Skittle passes the gate:

BeforeInput.jpg

The Orange wave is said node. You can see the gradual drop from 3.5V to 1V. This analog signal is kind of messy so this signal feeds into the Schmidt trigger which can be seen in the circuit above.

A Schmidt trigger is pretty neat. It's normally used for debouncing inputs and has this sort of "thresholding". The Schmidt only has one output, either HIGH or LOW. If all but one input are tied HIGH, and the last input is used to debounce, then that input must reach a certain threshold HIGH for the trigger to output LOW (notice the bubble on the ouput, a Schmidt trigger is essentially a NAND).

This turns my analog signal to a digital signal. Now see what happens when the Skittle passes the gate:

AfterInput.jpg

Sorry for cutting off the scale, but if you count the horizontal grid lines, you'll see the Schmidt goes from 0V to 4V with a nice clean digital waveform.

This digital signal is then fed to one of the AVR interrupt pins.

Programming the ATtiny48

There are two sections when programming the ATtiny48 for this application, the Interrupts and the TWI.

Interrupts

The ATtiny48 has 6 different interrupt channels:

ScreenHunter_109 Nov. 24 12.10.jpg

I'll be dealing with the PCINT interrupts specfically, these specific interrupts are not interrupts that occur from a single pin. Rather, they are for groups of pins.

ScreenHunter_111 Nov. 24 12.41.jpg

The DIP of the ATtiny is shown here to the left. These pins all have names: PC5, PD0, PB4 etc. In the parenthesises, are shorthand names that roughly describe what other tasks these pins can be configured to handle. For instance, the pin PC2, may also be configured to be an Analog to Digtal convertor, the 2nd one, in fact. This is appropriately named ADC2.

However these pins also have names PCINTx, where 'x' is some arbitrary number from 0 to 23.

This is a bit awkwardly named because one may intuitively think: "Oh, so interrupt PCINT0 belongs to pin PB0, or PCINT0".

Well, you're right, but from coincidence, not from reasoning. Actually, the interrupt PCINT0 is triggered by pins PCINT0 to PCINT7.

It's discussed in the ATtiny48 datasheet, see here:

ScreenHunter_110 Nov. 24 12.41.jpg

If you're especially acute, you may have noticed the DIP of the ATtiny48 does not have any PCINT[24:27] pins. These extra ones are used on other packages like the 32 pin QFP.

Luckily I have the INT0 and INT1 interrupt sources still, so one of those will need to be used.

Ok, ok! I know what some of you may be thinking: "You could just hook up the 4 Schmidt Trigger outputs to 4 pins under a single PCINT interrupt and only have ONE interrupt to deal with".

True, but if you do that, then you have to introduce further logic to see which pin specifically triggered the interrupt. If you have all your interrupt sources connected to the interrupt PCINT0, and PCINT0 triggers, then you only know that ONE of your sources have triggered. You still don't know which input it was specifically.

By using 4 seperate interrupts, then you simplify the logic by saying: "This interrupt tripped, which means this specific pipe had a Skittle pass".

Twin Wire Interface (TWI)

Awesome, interrupt logic done; now onto I2C. I have to be honest, this was the first time I messed with I2C so this section was difficult for me, especially with this TWI hardware that I had to deal with. For me, there was a learning curve to it.

So with the interrupts, we have a way of knowing how many Skittles have passed in each of four separate pipes. But now we must display the count. The idea is that I'd have 4 display modules that communicate on an I2C bus.

First, we want our bus running at 100kHz, this is done with the TWBR register on the ATtiny48.

ScreenHunter_112 Nov. 24 13.11.jpg

It's pretty simple, there's a formula in the ATtiny48 datasheet on what value to set this to in order to get 100kHz. This is the formula:

ScreenHunter_117 Nov. 24 13.47.jpg

The numerator (clk i/o) is the AVR clock speed, then the TWBR and a prescaler register is used to generate the clock speed of the bus.

Now that we have the bus speed down, let's look at the generic message scheme to write to a slave device. In this case, the AVRs we are programming are the Masters, and the display modules are the Slaves. So we are writing the number to display to a slave:

TWI_procedure.png

This above scheme takes in consideration all the start bits, stop bits, and ACK bits recieved from the slave device.

In my own words, this is what we are doing:

  1. Send the Start bit on the I2C bus

  2. Write the Address of the Slave device onto the bus

  3. Wait for ACK bit from Slave

  4. Now that the Slave is listening, send it a byte

  5. Wait for ACK

  6. Repeat steps 4 and 5 until we've sent all the information we've wanted to

  7. Send Stop bit

The Slave device is an IC called the SAA1064. It acts as a slave on an I2C bus and has pins to control particular 7 segment displays.

This is all the information required to send:

ScreenHunter_116 Nov. 24 13.11.jpg

So to control the SAA1064, we need to send out the address of the SAA1064, when it responds, we then send an instruction byte, a control byte, then 4 bytes for each of the digits.

The instruction and control bytes are just "settings" for the SAA1064.

I mentioned before that I could only monitor four Skittle pipes with a single system, This is because you can only configure the SAA1064 for four unique address: 0x70, 0x72, 0x74, 0x76. It is because of this, that it is impossible to control more than 4 SAA1064s independently on a single I2C bus.

Let's look at the other TWI registers. To send the START bit, set the TWSTA bit in the TWCR:

ScreenHunter_113 Nov. 24 13.11.jpg

Next, we need to send the address of the slave we want to control. Put the address of the Slave device into the TWDR register:

ScreenHunter_114 Nov. 24 13.11.jpg

At this point, I'd create a SW delay that simply waits for the ACK bit. To check to see if the ACK has been recieved, you must check the TWSR:

ScreenHunter_115 Nov. 24 13.11.jpg

This TWSR has many different values, here is a table that shows all the different codes the TWSR could hold:

ScreenHunter_118 Nov. 24 14.05.jpg

So, if you just sent the Slave address, check to see if TWSR is equal to 0x18 to see if ACK has been sent back to you.

Then, you must reload TWDR with a data byte to send. Just keep sending as many bytes as you like, and then send the STOP bit to halt communication.

Let's look at the communication between the ATtiny48 and the SAA1064 device. I annotated the picture to understand easily:

OutputWaveForm_I2C.jpg

In this case, I'm telling the Slave with address 0x70 to display 0593. The blue waveform is the data line, and the orange waveform is the clock line. It's hard to see, but after sending each data byte, the SAA1064 pulls the data line LOW to send the ACK bit.

Building the Display Modules

As mentioned, the display modules use the SAA1064 and 4 digit 7 segment display module. The datasheet for the SAA1064 shows how the circuit is put together. Here I laid out the circuit for a smallish footprint:

I2C_layout.png

Connecting the display module to the ATtiny48 setup will allow the module to light up and display 0593:

IMG_20140409_112403_edited.jpg

Conclusions; fustrations

I think my big takeaway on this project is that pride is a terrible thing. I specifically recall being the only individual in my 80+ class of peers to design my own embedded system with a fabricated PCB.

Pride can slow you down, pride can make your performance suffer; however maintaining pride: can sometimes result in a great sense of self satisfaction.

bottom of page