Metallurgy 101 - AVR Lesson Journal

This is a continuation of my Robot Metallurgy 101 – AVR Lesson Journal

UPDATE: Now with UART(ish)! (3/2/2014)

  1. Robot Metallurgy 101: PWM
  2. Robot Metallurgy 101: UART

I thought I would journal my work as I begin to venture from the comfortable playground of Arduino C and IDE.

I’ve tried a few other IDEs and C++ to work with different chips. But each time I realize I don’t know enough about C/C++, tool-chains, and workspaces to make a robot with them.

Bdk6 gave me an LCP1114 and I was able to get a blink program to run on it, but it was from a .bin file that someone else compiled, I simply uploaded it. I tried to work through two walkthroughs to get a programming environment setup (mbed and LPC1114). Bust on both.

I spent some time Googling, trying to find out what I was doing wrong. I came to the conclusion there was not enough information for an ignorant like me to figure out how to set up the workspace; the LPC1114 is an intermediate chip and I’m a beginner.

I decided to pull up tutorials on AVR programming. I knew there was an entire community around the Atmel chips, a community besides the Arduino community, a bare-metal community. I figured that would be the “beginner” environment to work in, since there would be enough documentation for me to learn

So, that brings us to my journal. I’ve not written this out to impress anyone. I simply find I learn better if I force myself to document what I’m doing. It encourages me to understand the information, since I have to explain it to someone else. Learning by verbal-processing. That being said, I invite criticism. Anything I’ve written that is incorrect, feel free to yell at me; it’ll learn me. Also, a lot of this has been written; I know I’m not being original. I’m also not delusional in believing I explain it better, but I do plan on making this journal flow towards how AVR programming can help me build better robots. Ok. Disclaimer done.

I ordered a few samples of the ATtiny1634.

A long time ago I bought an AVR ISP MKII to program these boards

I wired up the 1634 and the ISP like so,

What do you mean the silk-screen is mislabeled…shh.

After I got the pinout all figured out, I downloaded Atmel Studio 6.1. I know there are many different opinions about what IDE to use, and a lot of them seem to favor a text editor and AVRDude, for a change I wanted to go with a commercial IDE. Also, it seems like a lot of those in the AVRFreaks group actually like Atmel Studio.

It’s pretty easy to set up. You install it. Plug in your AVR ISP MKII. Then, File–>New Project. Select “GCC C Executable Project” and name your project. Hit “Ok.” Atmel Studio will bring up a list of supported chips. I scrolled down until I found my chip, “ATtiny1634.” You’ll notice the datasheet and supported programmers are to the side.

Alright, so, here I was. IDE all set up…um, now what do I do?

I began to Google until I found an AVR Tutorial Series that looked like it would bring me from the basics, well, up to Serial communication. Really, I figure if I could learn the following I could build whatever I wanted out of it:

  1. Digital pin control (HIGH/LOW).
  2. ADC.
  3. PWM
  4. Library creation.
  5. UART.
  6. I2C.

Luckily, I found the series put together by Newbie Hack’s series.

So, I decided I would try to walk through all of his tutorials and see if I could apply them to the ATtiny1634. NOTE: The author of this series appears to be Patrick Hood-Daniel, a fellow Texan (don’t hold that against us :P).

1. Blinkin LED

Newbie Hack’s MCU First Program.

I started Newbie Hack’s AVR Series after he had his programmer setup, his “First Program.” The uC’s version of the “hello world,” the LED blink. In Arduino I’d accomplish this like so,

int led = 13;

void setup() {
  pinMode(led, OUTPUT);
}

void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

I got Newbie Hack’s code going within 3 minutes

I looked down at my breakout board, I had some “PBx” pins, so I figured I had a Port B. I located pin PB0 (the the pin marked “1” in the above image) and I threw my LED and resistor on it.

I uploaded the program and got this:

But the purpose of this journal is to understand what I’m doing, not just copy it. So, the following is an explanation to myself, in case I forget stuff.

What’s Going on in the Blinkin LED Code

Atmel chips are amazing. They are versatile little uCs and the way this versatility is utilized from programming is by changing bits within a byte. For example, a pin can work as either a INPUT or OUPUT, but how does the chip know which one? You change the Digital Direction Registry (DDR) Bit of the pin. The DDR bit is a little switch that can be flipped either on or off through programming. When it is off (0) the pin acts as an INPUT, when it is set on, it acts an OUTPUT.

Now, Atmel chips are divided into ports, and thee ports have 8 pins (or less). This allows one byte to control alot of the functions of one port.

Newbie Hacks (NB) does a great job of explaining this. He even draws out a picture;I like pictures.

I like to think in images, so I see each bit as an LED. It makes sense, an LED has two-states ON/OFF; a bit has two states 0 or 1. So, a byte for me is 8 LEDs numbered 0-7.

The above image could represent the following code:

DDRB = 0B00000001;

The Atmel chips have different ports, which usually have an array of pins. So, the DDR stands for digital direction registry of port B. Then, we assign a state to every pin on port B (PB0-PB7) by setting a bit to either 0 or 1. So, according to the image and our code, we are setting ports B1-7 as INPUTS (0 = INPUT) and PB0 as an OUTPUT.

But don’t be confused, the LED we have connected isn’t turned on yet. The voltage on PB0 still equals 0. But, we could now change the voltage from 0 to 5. We do this by changing another registry. The port state registry, PORTB.

PORTB = 0B00000001;

Actually sets pin 0 (PB0) on port B to 5 volts. The other pins are still set as inputs, so you can’t change the voltage.

That simple folks? Well, we also have to insert a delay. Delay’s are really just telling the uC how many cycles to do nothing. There is some math involved that divides the clock speed to get the exact time delay you would like in finite-ish numbers. This math is locked away as a function in the <util/delay.h> file. So, for our sake, it is a simple matter of adding:

_delay_ms(500);

This tells our Tiny to sit idle for half a second, then continue. Also, there is a _delay_us() function that will delay microseconds.

Ok. Here are my study-notes

Note #1: Adjusting the Clock Fuse.

I did have one modification I had to make to NH’s program. He uploads his program using AVRDude. Atmel Studio actually has libraries to specific to the Tiny1634, these are included when you setup your project. One of these libraries require you tell the program how fast the CPU is going to be running. The ATtiny’s have an internal 8mhz oscillator, but there is a Atmel fuse that is burned at the factory to divide 8mhz by 8, giving you a run speed of 1mhz. I wanted to be working with my 1634 at the full 8mhz.

So, I went to Tools—>Device Programming. You then have to select your “Tool,” for me the AVR ISP MKII; your device, ATtiny1634 for me; interface, ISP. Then click “Apply.” Now, under “Device Signature” click “Read.” This should bring up the Device Programmer window. Now, make sure you have your programmer wired to your chip correctly and you have a stable connection (might throw a .1uF radial capacitor between VCC and GND on the Tiny1634). Click on the “Fuses” tab.

Uncheck the “CKDIV8.” It is the fuse that does exactly what it says, divides the clock by 8, reducing the chip from 8mhz to 1mhz. Don’t change any other fuses at this time. Hit the “Program” button. This will set the fuse. If all goes well we didn’t brick your chip.

While we are under the device programming window, click on the “Memories” tab. This is where you will actually upload your compiled program onto the chip. Here, if you click on the ellipsis you can select the code you would like to upload. This ends in “.elf” (unless you are using a chip besides an Tiny, then it’ll end in .troll, hehe). So, select your code and then hit “Program.”

Now, Atmel Studio is setup to automatically program your code using the last selected devices whenever you hit “F5.” Sadly, I found this rarely worked properly. But I’m betting it’s because I have no decoupling capacitor–yes, I confirmed this. I put a 1uF radial capacitor between VCC and GND, now the “F5” programming works as expected. I’ve no idea. Seems to work if I manually program it though. Shrug.

Ok. Now we have our Tiny running at 8mhz, we will need to adjust this in our code.

#define F_CPU 8000000 // AVR clock frequency in Hz, used by util/delay.h</pre>

Here we are telling the program our chip is running at 8mhz (8,000,000 hertz).

After this, I uploaded the code and it ran just as I had hoped. The LED would be on for half a second, then off for half a second.

Alright, a few other notes.

Note #2: Pin shortcuts and Bitwise Operators.

Bitwise operators are arithmetic operations that may be performed on binary numbers. There are four main ones:

  1. AND (&)
  2. OR(|)
  3. XOR (^)
  4. NOT (~)

I will not go into much detail on Bitwise Operators because Newbie Hacks does an excellent job explaining them. And they are all over the internet. But for our purposes, building robots, it is good to know what they look like and what they’ll do to our bits (remember, your pins’ output are controlled by bit registries).

So, I’ll cover two that apply to our example and one bitwise helper: OR, XOR, and « (left shift).

The OR operator:

We learned that the following sets pin PB0 as an OUTPUT.

DDRB = 0b00000001;

But we can use the bitwise operator, OR, to do the same,

DDRB |= 0b00000001;

The “|=” is an abbreviated operation that represents the following,

DDRB = DDRB | 0b0000001;

In English, “Whatever is in DDRB is equal to whatever is in DDRB OR 0b0000001.”

That looks like this,

Bitwise operators, like OR’ing, are done on the entire byte. That is, each bit, 0-7, are OR’d, so you have to keep in mind the operation isn’t done only on the bit you want to change. This is where truth tables come in. Below is a table describing the output of the OR operation.

OR (|)

The Left Shift «:

(NOTE: I originally made some mistakes regarding the left-shift operator;6677 has given a very clear description of the left-shift operator in the comments.)

In electronics registers usually have a fixed width. For example, the PORTB registry has the width of 8 bits (0-7). The left-shift operator («) allows you to address a specific bit in a registry, it does this by moving the bits in the registry to the left. The registry itself stays at a fixed width, so when this happens the new places introduced are zero. The bits that get shifted past the width of the registry get detroyed. Going back to the PORTB registry, you could address a different pin besides PB0 by using a shift-left operator. The left-shift operator allows us to quickly create a bit-mask from a byte. In code, this looks like the following:

PORTB = DDRB | 1 << 3;

The above takes the binary number assigned in DDRB and OR’s it with a bit mask that is exactly the same, except the third pin, that pin is equal to 1. Therefore, PORTB would look like this after the operation,

This seems more complex to me, but I understand it becomes very important when you start pulling apart the metal of an AVR.

One last thing, the <avr/io.h> contains defined pin constants. So, this operation,

DDRB |= 0b00000001;

Can be written like so,

DDRB |= 1 << PINB0;

They do exactly the same thing–and I guess the latter is easier to read. Pfft.

The XOR Operator:

The XOR (^) operator is much like the OR operation. Except, if A and B are equal the result is 0. They are not equal, the result is 1. Here’s the XOR truth table.

XOR (^)

Going back to the LED example, here is the XOR operation.

We use the XOR operation to turn the LED off and on. Since a XOR operation on a bit is basically going to set it to the opposite it is in. Therefore, if it is 0 it becomes 1, if it is 1, it becomes 0. This means we can actually shorten or blink code using the operation.

So, our simplified code for Blinkin LED is,

#define F_CPU 8000000    // AVR clock frequency in Hz, used by util/delay.h
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
	DDRB = 0b00000001;

	while(1)
	{
		PORTB = 0b00000001;
		_delay_ms(500);
		PORTB = 0b00000000;
		_delay_ms(500);
	}
}

And that’s it. That is as far as I’ve gotten. Now, before I move forward I plan attempting to interface a SN754410 and two small motors. I figure, we know how to perform digital pin control and this should allow use to control motor direction, even if we can’t yet control the speed.

Robot Application Note #1: SN754410 and ATtiny1634

First thing to do is wire up the H-Bridge.

You may notice we wired both “EN” pins to 5v, I don’t know how to generate PWM with AVR yet (but I hope to get there, so I’ll revisit this). Also, I used 5v as both my motor source and the Tiny1634 source. The motors I used were these little guys. I figured since the drop voltage of the SN754410 is around 1.4-2v then I’d be pretty close to the target voltage of my motors (5v - 1.4v = 3.6v). I kept everything approximate to the Tiny’s voltage rating; I figured if I wired something wrong I’d be safer keeping the voltage sources low.

And good call, this is the wiring mess I ended up with…I thought I would start with one motor and move to two.

I began thinking code. I know the basics of the SN754410 and I wanted to be able to hit all the functions of its truth-table.

So, I figured all I needed to do was get two of my IO pins to go HIGH and LOW to turn one direction, then switch them to go opposite. This reminded me of the XOR (^) operator, since it did exactly that, turn a bit to its opposite. This is the same operator we used to blink the LED. I ended up with the following code:

#define F_CPU 8000000    // AVR clock frequency in Hz, used by util/delay.h
#include <avr/io.h>
#include <util/delay.h>

int x;
int main(void)
{
	DDRB |= 1 << PINB0; //We set the LED pin to output.
	DDRA |= 1 << PINA1; //Setup motor A IO 1
	DDRA |= 1 << PINA2; //Setup motor A IO 2

	PORTA |= 1 << PINA1; //Set motor A IO 1 high.  Motor A IO 2 will default low.

	while(1)
	{
		// "^=" changes the state of the bit to the opposite of its current.
		PORTB ^= 1 << PINB0;  //LED ON/OFF.
		PORTA ^= 1 << PINA1;  //Motor A starts HIGH, this flips it low, or back again.
		PORTA ^= 1 << PINA2;  //Motor A starts LOW, this flips it high, or back again.
		_delay_ms(500);
	}
}

This code moved my motor one direction, then the other. But there was no pause between the changes of directions. I pulled it a part pretty quick, since I’ve generally had bad luck with instantaneous reversal of inductors.

Video

Well, that wouldn’t do. But I realized another problem. The XOR operator would flip the the pins from high to low, and back again. But how would I set both pins to low? Or both to high? Now, in Arduino C it’s pretty easy, you just write digitalWrite(pin#, HIGH), but in AVR we are controlling bits.

I know I could accomplish this in long-hand, like so:

#define F_CPU 8000000    // AVR clock frequency in Hz, used by util/delay.h
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
	DDRB |= 1 << PINB0; //We set the LED pin to output.
	DDRA |= 1 << PINA1; //Setup motor A IO 1
	DDRA |= 1 << PINA2; //Setup motor A IO 2

	while(1)
	{
		//This will set the pins high or low, but it does not maintain other pin states.
		PORTB ^= 1 << PINB0; //LED ON/OFF.
		PORTA = 0b00000010;  //This sets PINA1 HIGH, and PINA2 LOW.
		_delay_ms(1500);	 //Wait 1.5 seconds.

		PORTB ^= 1 << PINB0; //LED ON/OFF.
		PORTA = 0b00000000;  //This sets PINA1 LOW, and PINA2 LOW.
		_delay_ms(1500);	 //Wait 1.5 seconds.

		PORTB ^= 1 << PINB0;  //LED ON/OFF.
		PORTA = 0b00000100;  //This sets PINA1 HIGH, and PINA2 LOW.
		_delay_ms(1500);	 //Wait 1.5 seconds.

		PORTB ^= 1 << PINB0;  //LED ON/OFF.
		PORTA = 0b00000000;  //This sets PINA1 HIGH, and PINA2 LOW.
		_delay_ms(1500);	 //Wait 1.5 seconds.
	}
}

This gave me the output I wanted. The motor would turn one direction for 1.5 seconds, then stop, turn the other way, then stop, and start over. Like this:

Video

This code felt bloated to me. And another problem was dawning: What if my LED was on PORTA? That means I would need to keep track the state of three bits (1) bit controlling motor connection A, (2) bit controlling motor connection B, and (3) LED. This means I would need to track 9 possible states (3 pins ^ 2 states = 9 pin states). Now, I might be able to do this mentally, but it would be taxing, especially if my code is dynamically modifying the PORTA registry. But what if all 8 pins were used? 8 pins ^ 2 sates = 64 pin states. Ummm…no. I can’t do it.

It hit me. This is why bitmasks and bitwise operators are so important; they dynamically change the states of one bit, while preserving the states of the rest of the registry. Nifty.

I spent some time with in Newbie Hack’s tutorial: MCU LED Blink tutorial. Specifically, the video there. In it he explains how to use bitwise operators and bit-masks to change the state of a pin while preserving all of the other pin states.

Now we’re cooking.

We already know the bitwise operator (and mask) to set one bit high: OR.

The OR (|)operator sets the a pin HIGH:

Sadly, clearing a bit while preserving the registry is slightly more complicated. To clear a bit we still use a bitmask, but we use two operators: AND (&) and NOT (~). Their truth-tables look like the following:

AND (&)

NOT (~) is unlike the other operators, it’s simple. It inverts the bit. If 0, it becomes 1, if 1, it turns to 0.

Instead of immediately modifying the PORT state we actually modify our bitmask with the NOT operator. This gives us the inverse mask (00000001 becomes 11111110). We then AND (&) the inverted mask with hte PORT’s original state to clear PIN0 while preserving the other bit’s state. Here’s the LED example for NOT and AND operation to clear a bit:

Ok. I could wrap my head around this. I developed the following code which did what I wanted:

#define F_CPU 8000000    // AVR clock frequency in Hz, used by util/delay.h
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
	DDRB |= 1 << PINB0; //We set the LED pin to output.
	DDRA |= 1 << PINA1; //Setup motor A IO 1
	DDRA |= 1 << PINA2; //Setup motor A IO 2

	while(1)
	{
		//Sets motor input A LOW, B HIGH.
		PORTB ^= 1 << PINB0;		//LED ON/OFF.
		PORTA |= 1 << PINA1;		//This sets PINA1 HIGH.
		PORTA &= ~ (1 << PINA2);	//This sets PINA2 LOW.
		_delay_ms(1500);			//Wait 1.5 seconds.

		//Sets both motor inputs to low.
		PORTB ^= 1 << PINB0;		//LED ON/OFF.
		PORTA &= ~ (1 << PINA1);	//This sets PINA1 LOW.
		PORTA &= ~ (1 << PINA2);	//This sets PINA2 LOW.
		_delay_ms(1500);			//Wait 1.5 seconds.

		//Sets motor input A HIGH, B LOW.
		PORTB ^= 1 << PINB0;		//LED ON/OFF.
		PORTA &= ~ (1 << PINA1);	//This sets PINA1 LOW.
		PORTA |= 1 << PINA2;		//This sets PINA2 HIGH.
		_delay_ms(1500);			//Wait 1.5 seconds.

		//Sets both motor inputs to low.
		PORTB ^= 1 << PINB0;		//LED ON/OFF.
		PORTA &= ~ (1 << PINA1);	//This sets PINA1 LOW.
		PORTA &= ~ (1 << PINA2);	//This sets PINA2 LOW.
		_delay_ms(1500);			//Wait 1.5 seconds.
		}

}

Code to NOT a PIN looks like this PORTA &= ~ (1 << PINA1);. In plain English and in order of operation, “Set PORTA PIN1 to HIGH, create a bitmask of PORTA, then NOT that bitmask. After, take the NOT’ed bitmask and AND it with PORTA’s original state.”

Whew. I’m not sure I follow that even after writing it. But I understand it. Really, PORTA &= ~ (1 << PINA1) = Set PA1 LOW.

But this is good. We now can dynamically change the state of one PIN without destroying the state of the other PINs on the same port. Booyah!

Alright, let’s go for broke; now that I understand how to set pins HIGH or LOW, I wanted an easy way to control a motor with AVR. I wrote five functions. Four control the states of the motor (HH, LL, LH, HL) and one is a delay function that will accept a variable. The functions can be called from the main loop. Each one expects three parameters, two pin numbers and the number of milliseconds you wish the function to run.

#define F_CPU 8000000    // AVR clock frequency in Hz, used by util/delay.h
#include <avr/io.h>
#include <util/delay.h>

void delay_ms(int ms)
{
	//We make our own millisecond delay function because
	//the _delay_ms does not like dynamic variables.  Meaning
	//you cannot pass it a variable.  By making our own, we can.
	while (ms--) {
		_delay_us(1000);  // one millisecond
	}
}

int forward(int motPinA, int motPinB, int motorFireDuration)
{
	//Sets motor input A LOW, B HIGH.
	PORTB ^= 1 << PINB0;		//LED ON/OFF.
	PORTA |= 1 << motPinA;		//This sets PINA1 HIGH.
	PORTA &= ~ (1 << motPinB);	//This sets PINA2 LOW.
	delay_ms(motorFireDuration);			//Wait 1.5 seconds.
}

int backward(int motPinA, int motPinB, int motorFireDuration)
{
	//Sets motor input A HIGH, B LOW.
	PORTB ^= 1 << PINB0;		//LED ON/OFF.
	PORTA &= ~ (1 << motPinA);	//This sets PINA1 LOW.
	PORTA |= 1 << motPinB;		//This sets PINA2 HIGH.
	delay_ms(motorFireDuration);			//Wait 1.5 seconds.
}

int coast(int motPinA, int motPinB, int motorFireDuration)
{
	//Sets both motor inputs to low.
	PORTB ^= 1 << PINB0;		//LED ON/OFF.
	PORTA &= ~ (1 << motPinA);	//This sets PINA1 LOW.
	PORTA &= ~ (1 << motPinB);	//This sets PINA2 LOW.
	delay_ms(motorFireDuration);			//Wait 1.5 seconds.
}

int brake(int motPinA, int motPinB, int motorFireDuration)
{
	//Sets both motor inputs to HIGH.
	PORTB ^= 1 << PINB0;	//LED ON/OFF.
	PORTA |= 1 << motPinA;	//This sets PINA1 HIGH.
	PORTA |= 1 << motPinB;	//This sets PINA2 HIGH.
	delay_ms(motorFireDuration);			//Wait 1.5 seconds.
}


int main()
{
	DDRB |= 1 << PINB0; //We set the LED pin to output.
	DDRA |= 1 << PINA1; //Setup motor A IO 1
	DDRA |= 1 << PINA2; //Setup motor A IO 2

	while(1)
	{
		//This function spins the motor in one direction for X milliseconds. (L, H)
		forward(PINA1, PINA2, 750);
		//This function lets the motor free spin for X milliseconds (L, L).
		coast(PINA1, PINA2, 1500);
		//This function spins the motor in the other direction for X milliseconds. (H, L)
		backward(PINA1, PINA2, 800);
		//This function brakes the motor for X milliseconds (H, H).
		brake(PINA1, PINA2, 500);
	}

}

Nifty, eh? Now all we need to do is add a second motor and then we can pass the functions the second motor pins and we can use the same set of code to control both motors. Aren’t we efficient!

Some time later…

Well, that didn’t not work as I wanted. I’m tired and didn’t think through how the delay would work in the function. The function would be called for motor A, but motor B wouldn’t be called until A was done. Doh.

Yes, this could be rewritten a hundred ways to salvage it. But! Right now I’m tired, so here’s our working code.

#define F_CPU 8000000    // AVR clock frequency in Hz, used by util/delay.h
#include <avr/io.h>
#include <util/delay.h>

void delay_ms(int ms)
{
	//We make our own millisecond delay function because
	//the _delay_ms does not like dynamic variables.  Meaning
	//you cannot pass it a variable.  By making our own, we can.
	while (ms--) {
		_delay_us(1000);  // one millisecond
	}
}

int forward(int motPinA, int motPinB)
{
	//Sets motor input A LOW, B HIGH.
	PORTA |= 1 << motPinA;		//This sets PINA1 HIGH.
	PORTA &= ~ (1 << motPinB);	//This sets PINA2 LOW.
}

int backward(int motPinA, int motPinB)
{
	//Sets motor input A HIGH, B LOW.
	PORTB ^= 1 << PINB0;		//LED ON/OFF.
	PORTA &= ~ (1 << motPinA);	//This sets PINA1 LOW.
	PORTA |= 1 << motPinB;		//This sets PINA2 HIGH.
}

int coast(int motPinA, int motPinB)
{
	PORTA &= ~ (1 << motPinA);	//This sets PINA1 LOW.
	PORTA &= ~ (1 << motPinB);	//This sets PINA2 LOW.
}

int brake(int motPinA, int motPinB)
{
	//Sets both motor inputs to HIGH.
	PORTA |= 1 << motPinA;	//This sets PINA1 HIGH.
	PORTA |= 1 << motPinB;	//This sets PINA2 HIGH.
}


int main()
{
	DDRB |= 1 << PINB0; //We set the LED pin to output.
	DDRA |= 1 << PINA1; //Setup motor A IO 1
	DDRA |= 1 << PINA2; //Setup motor A IO 2
	DDRA |= 1 << PINB3; //Setup motor A IO 1
	DDRA |= 1 << PINC4; //Setup motor A IO 1

	while(1)
	{
		//This function spins the motor in one direction for X milliseconds. (L, H)
		forward(PINA1, PINA2);
		forward(PINA4, PINA3);
		delay_ms(1000);

		//This function lets the motor free spin for X milliseconds (L, L).
		coast(PINA1, PINA2);
		coast(PINA4, PINA3);
		delay_ms(1000);

		//This function spins the motor in the other direction for X milliseconds. (H, L)
		backward(PINA1, PINA2);
		backward(PINA4, PINA3);
		delay_ms(1000);

		//This function brakes the motor for X milliseconds (H, H).
		brake(PINA1, PINA2);
		brake(PINA4, PINA3);
		delay_ms(1000);
	}

}

Something else I realized. I couldn’t wire motors to a different PORT (my schematic shows PB3 and PC0) since my functions call upon PORTA specifically. Eh, oh well. I’m tired. I’m sure I’ll clean this up over the next few days.

SO! Here’s what we ended with:

Video

Next up! Inputs…ooooohhhh…

ATtiny Bitsy Spider

Originally posted on www.letsmakerobots.com

ATtiny Bitsy Spider

UPDATE: Added BOM corrections. (Sorry for floating.)

Ok. Here’s a finished board I’ve been working on for a bit.

In essence, it is a BLE node board. It combines an HM-10 board with an ATtiny 85. This board builds off:

  1. Bluetooth 4.0 (HM-10)
  2. ATtiny 85

The idea of the Bitsy Spider board is diminutive controller node. I wanted it to be cheap and versatile enough to use as a node, but I think the final price is around $11 each.

Here’s the ole GitHub:

The BOM:

  1. OSHPark Board: $1.68 each ($5.05 minimum).
  2. 1 x 20k Resistor – 0402: $.04
  3. 3 x 10k Resistor – 0402: $.04
  4. 2 x 1uF 0402 $.20
  5. 3 x BSS138: $.60
  6. 1 x ATtiny 85 – SOIC: $.80
  7. 1 x HM-10: $6.50
  8. 1 x 0603 LED $.11
  9. 1 x 3.3V LDO 300mA – SOT-23-5 - Voltage Regulator: $.58

Total (approximate): $10.55

There are lots of solder-jumpers on this board, given it is meant to be versatile.

Here is the programming pinout to use an Arduino as ISP

The board is intended to harness the serial connection of the HM-10. In this version I made it straight forward, you leave the jumpers between the RX/TX line of the HM-10 and the ATtiny unsoldered, program the ATtiny as many times as you like. To test your serial connection between the ATtiny and the HM-10 simply breadboard the PCB and put jumpers like so:

PB0 <—> TX

** PB1 <—> RX**

This will allow you to test your code, without having to solder and unsolder. Then, after your code is perfectish, solder the jumpers marked “PB1 & HM10 RX” and “PB0 & HM10 TX,” then embed the Bitsy Spider.

This is an option that’ll probably continue throughout different versions of the board. I ran the GND connection of the ATtiny through a N-Chan MOSFET, and tied the gate of the FET to the PIO1. The PIO1 pin of the HM-10’s function is for a Connection Status LED. But one of the options one can set on the HM-10 is for the PIO1 to stay low unless the HM-10 has a connection. This can be set on the HM-10 when it’s in AT mode by typing:

  1. Type: AT+PIO11
  2. Response: OK+PIO11

When done, the ATtiny 85 will only power-up if the HM-10 has a connection. Of course, the solder-jumper is meant to bypass this feature.

The last solder jumper controls the HM-10’s reset. If soldered, the ATtiny 85 can reset the HM-10 by sending PB4 high for ~100mS. I added this as I hope to create a star-network with the ATtiny Bitsy Spider.

Here’s a summary explanation; the HM-10 has a time out feature after it losses connection from one HM-10 that prevents it from connecting to another for approximately 10 seconds. So far, there is no option to bypass this “lost connection” time-out. But resetting the HM-10 (<150mS power-cycle) bypasses this time-out. I’ll update more on this setup when I’ve completely tested it. If there are questions, I’ve written a lot in the comments of my original HM-10 post. But also feel fre to contact me.

One last thing I should mention.

I expect one major mistake and two minors on the first run of every board I send off. This board is no exception. I forgot the decoupling capacitors on the voltage regulator and the HM-10. I’ve added them on the v.02 board. Of course, this shouldn’t be a major flaw, but with a capacitor on the voltage regulator it causes it to spit out 3.6v instead of 3.3v. Major problem. I saved this set of boards by soldering a 0402 1uF between the legs of the SOT-23-5 regulator. Not fancy, but saved $5.

OLED via I2C

Originally posted on www.letsmakerobots.com

imagesI guess it’s been an I2C weekend. I found these organic light-emitting diode displays (OLED)images imagesat Itead studio for $5. images

imagesNifty little buggers.images

They might be small, but their extraordinary contrast and viewing angle more than make up for it. Plus, I mean, c’mon, they’re $5. I will say I was a little annoyed that they operate at 3.3v. And I’m sure this means I’ll be making a small little level converter board for them pretty soon. I estimate the converter board would be around $1.25, simagestill a good price.images

images imagesimagesSome perks of OLEDs:images

  1. imagesWider viewing angle (i.e., you don’t have to look straight down at it).images
  2. imagesNo back light, making them flatter and use less power (not a lot less).images
  3. imagesHigh refresh rate. The only time I saw a flicker is through my video camera. And I had delay(10); in my code :) images
  4. imagesThey are cheap(er?).images
  5. imagesThey’re the future :) images

The only downside that really jumped out at me was the libraries are about 9k flash uploaded. The 64x64 LMR Bot was around 1k.

imagesWhen I got them I was worried I wouldn’t be able to use them without digging into the datasheets. But come to find out, they were exactly the same unit as on Adafruit’s boards. Sorry, I love you Ada…but…can’t afford $19.50. Now, maybe if Becky Stern came with them. Erm. Anyway, with Ada’s excellent guides and software I had the LMR Bot moving around in about 10 minutes. So, I’ll end up buying something from Ada to monetarily say, “Thank you, love.”images

The connections go something like this:

  • imagesArduino Uno 3.3v <————> OLED VCCimages
  • imagesArduino Uno 3.3v <————> LV of Logic Converterimages
  • imagesArduino Uno 5v <————> HV of Logic Converterimages
  • imagesArduino Uno Gnd <——————> OLED GNDimages
  • imagesArduino Uno Gnd <——————> LV Logic Converter GNDimages
  • imagesArduino Uno Gnd <——————> HV Logic Converter GNDimages
  • imagesArduino Uno A5 (SCL) <——— Channel 1 Logic Converter ——–> OLED SCLimages
  • imagesArduino Uno A4 (SDA) <——— Channel 2 Logic Converter ——–> OLED SDAimages
  • imagesArduino Uno D4 (SCL) <——— Channel 3 Logic Converter ——–> OLED RESETimages

I know, I know; I’m working on a converter adapter to make tha all those wires go away.

images

ATtiny Adventure -- I2C on ATtiny 84/85

Originally posted on www.letsmakerobots.com

Code

UPDATE: Added info on making SPI programming jig (makes life a lot easier).

UPDATE: Added ATtiny 84 info (though, the post is meant for the ATtiny 85).

I’ve been non-traditional microcontroller curious for a bit. Then, I had to put a Digi-Key order together for some real cheap stupid stuff (some SOT-23 N-Channels for the LiPo charger circuit) and I thought, “What the hell, let’s order some ATTiny 85s.” Being cheap like I am, I ordered SMD:

I then ran over to OSHPark and made a little breakout for it:

This brought the price for one ATTiny 85 board to $1.53 each. This is great, since the ATTiny 85 has an internal oscillator up to 8mhz, allowing it run without any passives.

I was pretty excited the day they came in. I soldered them together, put some headers on them, and tossed them into a bread board. I switched over to Goggle and searched how to program these little guys. The first article I hit was the one I eventually used, I just warn you, dear reader, read careful not to miss the bit about ignoring the error. Personally, like the dumb-arse I am, programmed my first little ATtiny 85 a hundred times thinking it wasn’t working before I caught the caveat in the instructable:

“It should give the following error twice: avrdude: please define PAGEL and BS2 signals in the configuration file for part ATtiny 85”

This error means you programmed it successfully.

But you all probably got that.

The easiest way to get going with I2C with the ATtiny 85 is using the TinyWireS and TinyWireM libraries for Arduino.

  • TinyWireS (this is Rambo’s library, he updated the original with onRequest, onReceive functions)
  • TinyWireM

To get the ATtiny 84 to work you’ll need to add support:

They were developed to be comparable to the Wire library for Arduino. To install them, just unzip them and place them in your Arduino libraries folder (e.g., C:\Program Files\Arduino\libraries).

(Here’s the pinoutfor the ATtiny 84)

The I2C connections are pretty straight forward:

  • Arduino SDA <— 4.7k Resistor Tied to 5v —-> ATtiny 85 – PB0
  • Arduino SCL <— 4.7k Resistor Tied to 5v —-> ATtiny 85 – PB3
  • ATtiny 85 – PB1 <— 330 Resistor —- LED —- > GND

Below is code meant to demonstrate the purpose of this projects. It sets the ATtiny 85 as an I2C slave. It receives data over the I2C line, parses it into an integer, then writes this value of the integer to pin 1 (PB1).

// the 7-bit address (remember to change this when adapting this example)
#define I2C_SLAVE_ADDRESS 0x4

// Get this from https://github.com/rambo/TinyWire
#include <TinyWireS.h>

// The default buffer size, Can't recall the scope of defines right now
#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 16 )
#endif

//Character variable used to echo data back.
char chrSendData;

//Variables used in getting and parsing data.
char rxChrData; //Receives the data.
char rxString[12];  //Varbiable for holding one string of data.
int rxIndex = 0; //Used to index rxString.

//Integer for holding the pwm value received from master.
int pwmValA;

void requestEvent(){  
  TinyWireS.send(chrSendData);
}

//Handles receiving i2c data.
void receiveEvent(uint8_t howMany)
{
    if (TinyWireS.available()){  
      if (howMany < 1)
      {   // Sanity-check
          return;
      }
      if (howMany > TWI_RX_BUFFER_SIZE)
      {   // Also insane number
          return;
      }

      howMany--;
      if (!howMany)
      {   // This write was only to set the buffer for next read
          return;
      }
      while(howMany--)
      {   //Gets i2c data.
          rxChrData = TinyWireS.receive();
          //Places the characters in an array one at a time.
          rxString[rxIndex] = char(rxChrData);
          //Increment the data array.
          rxIndex++;
          //If a stop character is read, parse the char array and convert it to a single integer.  
          if (rxChrData == ':'){
              //This is a low memory form of parsing the char array into an intger
              pwmValA = int(100*rxString[2]+10*rxString[3]+rxString[4]);
              //Prints the parsed value.
              Serial.println(pwmValA);
              //Writes the parsed value to pin 1 (PB1).
              analogWrite(1, pwmValA);
              //Resets the char array index.
              rxIndex = 0;  
         }
      }
    }
}

void setup()
{
    Serial.begin(9600);
    pinMode(1, OUTPUT); // OC1A, also The only HW-PWM -pin supported by the tiny core analogWrite
    TinyWireS.begin(I2C_SLAVE_ADDRESS);
    //Sets up the onReceive function (what we do if we get stuff).
    TinyWireS.onReceive(receiveEvent);
    //Sets up the onRequest function (what we do if asked to send something).
    TinyWireS.onRequest(requestEvent);
}

void loop()
{
//Detects a stop sending command.
TinyWireS_stop_check();

//Puts the data we got into a variable to send back for error checking.
chrSendData = char(rxChrData);

}

I’ve also included the code I used on my Arduino Mega, which was setup as the master.

Your setup should not look like this :P

I’ve got several ideas I’d like to attempt with this setup. But, it is somewhat silly. The I2C reduces the ATtiny 85 to four pins. But one of those is the reset pin (PB5), so really, only 3 usable pins.

Before I started working with the Tiny I was lurking in the shoutbox and oversaw Protowrx chatting about making an ATtiny into a serially controlled motor driver. So, I set to it. I had chosen I2C because I wanted to make a setup like the DRV8830 (Spark fun has a breakout). Of course, like the numbskull I am I didn’t do the simple math before sinking hours into interfacing with a chip.

Most H-Bridge ICs require three pins a motor. Two digital pins for direction and one for PWM. Even cheaping out and using one PWM pin for both motors, that’s still five. _And…_the ATtiny 85 has 8 pins. 1 x Power, 1 x Ground, 2 x I2C line, which leaves us with….4 pins. Oh wait! One of those is the reset pin and cannot be used without losing the ability to program it without an AVR programmer (which I have, but what a pain in the ass). So! In short, there are 3 usable pins after interfacing with the ATtiny. I’d have done myself a favor if I had remembered an 80s classic.

Still, I’ve I got it in my head to attempt doing something like this: 2 Pin HBridge control. Only, tying the PWM line together. Not having much luck right now (only spent about 20 minutes, wanted to get this typed up before I forgot crap).

Another idea is to use a Software Serial to send one way communication through the serial line. But it doesn’t make much sense, since 4 pins aren’t much better than 3, given my intentions.

Ok. In conclusion, I’m not sure why I did this. It really doesn’t make much sense, other than the adventure. I’m sure it’s one of those things I work out now and I won’t find a use until much later. The real killer is thinking about how you can buy a full Arduino Pro Mini on the eBay for $3.45. A little more than double the cost of an ATtiny 85 but triple the pins and utility. Eh!

Making a ATtiny Jig:

I hate breadboarding. Let me admit that. Mainly, it is having wires everywhere, my little dyslexic brain can’t keep up. And when I first started working with the ATtiny uCs I found it to be a pain to have to move my little ATtiny’s between my full circuit and the SPI programming circuit. So, I thought, “Why not make a SMD programming pad and jig interface?”

Well, here is the crude son-of-a-bitch:

It’s nothing fancy, but it is a time saver.

I put both the interface pads and the jig in my Eagle library.

POGO_PIN_JIG_SPI

POGO_PIN_SPI_PAD

Ladvien’s Eagle Library

Here is my ATtiny 84 with the pads and the Jig PCB:

Jig ($.60

ATtiny 84 PCB ($1.85)

These are the pogo pins I used:

P100-B1 – 1.36mm diameter

It was not too hard to put together, I set it up something like this. Then, it is all about added flux to where the pins meet the PCB and soldering like you would usual header pins.

And here it is in action. It surprised the hell out of me, worked exactly like I wanted it.

I’m sure I’ll eventually add some stabilizer bars between the two-PCBs and maybe a guide pin to prevent me from pressing the pins in the wrong holes :(

Still, it is MUCH easier than pulling it from the breadboard and moving it to a new circuit. Makes me happy.