What's the stock code on the Orangutan these days?

Aaaaaah! Much better!

Thanks for the code, Jan. The LCD works fine, everything came up great, and I’m back in business.

Neat thing is, it’s not that different from the stuff I’ve been trying. LCD Commands you’re loading in, all of it. So I think I was close, but not quite there. One big difference I could see on a quick glance was how you’re handling delays. I hope this bodes well. (I may have almost known what I was doing! Yahoo!)

Thanks again.

Tom

Dear Folks:

The delay loops in the LCD code are critical. The Orangutan uses a controller that is compatible with the standard HD44780, for which documentation is widely available. For example, a typical LCD can take up to 1.6 milliseconds to clear the display and it will ignore commands sent before it is finished.

I found that the delay loops that were posted for the Orangutan operating at 1 MHz as shipped did work, but just barely. The delay procedure depends on the clock speed. The call delay_loop_2(), supplied with avr_libc, executes 3 cpu cycles per loop (1 microsecond per cpu cycle at 1 MHz clock). Thus, the delay gets shorter as the clock speed increases. It will not work to redefine the clock speed with F_CPU!

A typical example calls Delay(200), which translates to delay_loop_2(200) = 3x200 microseconds, 1 MHz clock. In my case, after switching the clock speed on the orangutan to 8 MHz, it was not sufficient to multiply the marginal numbers in Delay() by 8. Result: BLANK LCD, or garbage in the display.

Since it is not harmful to exceed the minimum delay, in case of difficulty start by making those numbers larger. Otherwise, you will need to do your research and use the correct length delays. A working example for my 8 MHz Orangutan is posted below.

It is sad that Polulu is unable to support their hardware with well documented, functional example code. They thereby alienate many potential return customers–but that seems to be their business model.

Cheers, Jim

PS: Jan, why not post what you sent to Tom? It might help out some other folks!

/*
** lcd_or8M.c
**
** LCD Routines modified from a post on the Pololu forum. Needed includes: delay.h
** These delays work for my example of the Orangutan, operating at 8 MHz internal clock
** but they are not optimized! If you have difficulties, make the numbers in LCDDelay larger.
** For the baby Orangutan operating at 20 MHz, at first try multipying the numbers within the () by 2.5
** Jim Remington, sjames_remington at yahoo dot com
**
*/
#define LCD_Clear 0x01
#define LCD_Line1 0x80
#define LCD_Line2 0xC0
#define LCDDelay _delay_loop_2

void LCDSendNibble( unsigned char data )
{
data &= 0x0F;
data <<= 3;
PORTB &= ~0x38;
PORTB |= (data & 0x38);
data <<= 1;
PORTD &= ~0x80;
PORTD |= (data & 0x80);
PORTD |= _BV(4); // LCD_STROBE = 1;
LCDDelay( 1200 );
PORTD &= ~_BV(4); // LCD_STROBE = 0;
LCDDelay( 1200 );
}

void LCDData( unsigned char data )
{
PORTD |= _BV(2); // LCD_RS = 1;
LCDSendNibble( data >> 4 );
LCDSendNibble( data );
}

void LCDString( const unsigned char *str )
{
while (*str != 0) {
LCDData( *str++ );
}
}

void LCDCommand( unsigned char data )
{
PORTD &= ~_BV(2); // LCD_RS = 0;
LCDSendNibble( data >> 4 );
LCDSendNibble( data );
LCDDelay( 1000 ); //was 800
}

void LCDHexNibble( unsigned char data )
{
data &= 0x0F;
if ( data > 9 ) {
data += (‘A’ - ‘9’ - 1);
}
LCDData( data + ‘0’ );
}

void LCDHex( unsigned char data )
{
LCDHexNibble( data >> 4 );
LCDHexNibble( data );
}

void LCDInit( void )
{
DDRB |= _BV( 3 ) | _BV( 4 ) | _BV( 5 );
DDRD |= _BV( 7 ) | _BV( 4 ) | _BV( 3 ) | _BV( 2 );
PORTD &= ~_BV(4); // LCD_STROBE = 0;
PORTD &= ~_BV(3); // r/w = 0
LCDDelay( 1600 );
LCDCommand( 0x20 );
LCDCommand( 0x1C );
LCDCommand( LCD_Clear );
LCDCommand( 0x28 );
LCDCommand( 0x06 );
LCDCommand( 0x0C );
}

I can definitely understand Jim’s frustration or disappointment, but the “business model” line suggests that it is our intent not to provide more support; that is not the case. What happens is that much of our business comes from customizing our products for industrial customers with higher volumes, so our resources are directed there first. We will be expanding our staff next year, and one of our goals is to add application examples for our products.

The reason we are reluctant to post the test code is that it is not a good, clean example. It’s good enough for us to verify that the hardware works, but I don’t think it’s particularly approachable to a beginner since it’s a multi-file project with lots of un-commented code specific to the test rig.

- Jan

Yowza! I didn’t mean to stir anything up with my question. (Well… aside from getting help with the LCD, but that was kinda the point.)

As far as user-supported hardware and software, I don’t have a huge problem with it so long as people post what they do. Jim, I hope you don’t mind but I’ve cruised through the code you posted on your site over and over to learn how these little beasties work. Same goes for the code Cathy Saxton has posted on her site.

I don’t mind this because it’s familiar ground from another one of my hobbies: home shop machining. The manufacturer for the tools I use has very little information on their site (which is a shame, because the president of the company, Forrest, is a phenomenal machinist). But there’s a user community of several thousand machinists who are adamant about sharing as much as they can. As a result “problems” rarely remain problems for long, provided someone’s willing to ask and at least one other person is willing to answer. Usually answers run into the tens of replies, with the merits and drawbacks of each approach being discussed until some measure of consensus is reached. We all learn, so it’s all good.

My biggest trip-up with the Orangutan is that it’s a product that’s undergoing development, so it’s a moving target. Code that ran on earlier models won’t run on mine (which runs at 20MHz.) But even this is familiar ground in terms of a user-support base. Earlier versions of the tools I use had a proprietary collet system. Newer ones use the ER-20 collet system, so a lot of the same tips and tricks don’t apply. People tend to preface their answers to questions with “On the ER collet headstock, you’d…” There’s a little confusion, but not too much to function.

I wouldn’t mind seeing a little more information on the Orangutan (let’s face it, getting the timing right for an LCD is not the same as indicating in a part in a four-jaw). But I asked, Jan answered, so I’m still doing ok.

For what it’s worth I’m trying to put together everything I find into an Orangutan / Baby-Orangutan library. I’m posting works in progress on my own web site, but I’d happily post the whole shebang here, too.

The WIP code is half-commented, not always consistent in terms of indentation, etc., but it’s getting there. In addition to the library itself I like Jan’s idea of single-file examples that demonstrate (or rather TEST) functionality of a given component. I’ve more or less done that with the LCD, using my own code, the code on your site, Jim, and the code from Jan. I would be more than happy to put all the “one-filers” up on my site as well, to serve as examples.

But eventually what I’m aiming at is a library, be it single file or multiple file, that gives anyone who picks up an Orangutan or Baby-O easy to use routines that let them use what they’ve got.

As I learned from Jan’s code, this won’t be entirely straightforward. His timer code (which is how he got around the delay issue you raised) uses the same timer I used for my PWM routines. His PWM routines use a different timer, one I was earmarking for other things. Buffet style works, but only if the code is guaranteed not to have cross-dependencies. That’s what I’m trying to do as I include things I find.

For what it’s worth I got around the timer issue by using the _delay_ms() command from <util/delay.h> (which does use the F_CPU define and scales appropriately so it still returns milliseconds.) It’s limited (you can’t toss it a thousand ms delay!) but for the short delays involved it appears to be working fine. There’s still some asm(“nop”) style delays in there, but with some judicious #ifdef switches it can likely be made to work with different clock speeds. (And since I wrote it to work on the 20MHz Orangutan, it should still work on the slower ones, even with no changes in the code.)

I’m still putting together the web site to host all this stuff. I’m still a little brain-dead from dinking around in the LCD code for the last several days, so my ability to write human-language code has suffered a little. Bear with me. I should have something put together in the next week or so. I’ll happily post it.

Tom

Here’s a start at a C library and some single-file examples for the Orangutan and Baby-O:

vix.dyndns.org/~benedict/robotics/orangutan

The single-file examples should more or less cover everything in the library so far plus a little extra. As things get added to the library, I’ll post more single-file examples.

It’s not where I want it to be right now: There are two motor examples, one for PWM and one for relay-style. The library only has the PWM routines. The PWM routines use TIMER1 with no option to use TIMER0, so if someone is trying to get it to work with another library that ties up TIMER1, it won’t work. I still don’t have code to run the buzzer or to drive servos. For SPI I was going to look at AVRlib and more or less use it unmodified if I can, but it’s not done yet. I’d like to add RS-232 and I2C, but I need more hardware before I can really get going.

In any case I hope it’s a start toward what you’re both looking for. It’s a lot further along than the 68HC11 Miniboard library I used to use, and that’s kinda what I was looking for when my Baby-O first showed up in my mailbox.

For what it’s worth I’m going to be showing both boards and the library off at our club’s next meeting on the 8th. I hope to get some feedback from people there, and will likely have a new to-do list afterward.

Tom

I just took a brief look at your page, so you might have addressed this elsewhere. The Orangutan does not include an external clock, so it runs at 8 MHz off of its internal oscillator. If you want to add a crystal, you can, but you lose the use of two I/O lines. (The Baby Orangutan has more I/O lines since there is less dedicated hardware, so we hard-wired in the 20 MHz crystal.)

- Jan

AAAaaaah! Ok, I hadn’t realized that. Thanks. Give me a bit to roll that back through all the examples.

Tom

Tom, I don’t have an Orangutan yet, in part because I’ve been worried that I may not have sufficient time to learn how to use it. So your project looks like exactly the sort of thing I will need. Please keep up the good work, and know that your efforts are appreciated!

Best,
— Joe

You bet! And thanks for letting me know you plan to use the library, such as it is.

For what it’s worth I’ve moved it to Sourceforge, and plan to keep developing it. Not much change in the library from earlier in the month, but the comments should be easier to read and it’s a little more tested now. Here’s the new URL:

orangutan-lib.sourceforge.net

The web site is as much a work in progress as the library is, but it’s more readable than the old one, I hope.

Tom

Greetings Tom,

I wanted to say that I also appreciate your and Jim’s efforts.
:slight_smile:

I’m new to AVR and my programming skills aren’t so great, so I’m reading through your library to get up to speed. (I just got the Baby-O.)
:wink:

I have a few questions:

What exactly is going on in the following #define statements? I understand that #define replaces the first text with the second, but I’m confused by what is going on with the *'s and &'s (pointers?):

#define _PORTB (((volatile bitfield)&PORTB))
#define _PINB (((volatile bitfield)&PINB))
#define _DDRB (((volatile bitfield)&DDRB))

Also, where do I find out what all of those AVR codes mean, such as TCCR1A, WGM11, OCR1A, ADCSRA, etc. (Or, where in the ATmega datasheet should I look, if that’s the right place?)

Also, In the “motor_init” method, the resolution=9 and =10 code looks the same the me. What’s the difference?

if(resolution == 9)
{
TCCR1A |= _BV(WGM11);
TCCR1A &= ~_BV(WGM10);
}
else if(resolution == 10)
{
TCCR1A |= _BV(WGM11);
TCCR1A &= ~_BV(WGM10);
}

Thanks again for all your help and keep up the good work!
:slight_smile:

I may be able to help here. In C, read & as “address of” and * as “pointer” or “contents of” (except, of course, when it means “times”, i.e. when it appears between two terms). So, the ugly mess above for PORTB (for example) would mean:

  1. Take the address of PORTB
  2. Typecast this to a volatile bitfield pointer
  3. Get the contents

In other words, it’s looking in the location of PORTB, but reading it as if it were a volatile bitfield instead of whatever PORTB is actually declared as.

C tends to be rife with such uglyisms… but it could be worse (it could be Perl!).

Hope this helps,
— Joe

Okey doke! Those #defines are a way to make a particular location in memory look like a variable of a particular type. The typedef bitfield that comes above it defines what that variable type is.

The typedef bitfield stuff defines a variable type called bitfield that packs eight one-bit variables into an eight-bit area of memory.

The #defines that come right after that basically say, “Make this place in memory act like it’s a variable of this type.” For _PORTB it’s pointed at the location in memory where PORTB lives. For _PINB it’s where PINB lives. For _DDRB it’s where DDRB lives.

The bitfield typedef is a definition of a record. To get at a value in a record, you give the variable name, then a dot, then the name of the field inside the record you want to get at the value of. In the typedef bitfield statement, each field in the record is called B0, B1, B2, B3, etc. up to B7, each corresponding to a bit inside an 8-bit patch of memory.

So the upshot is to get at the third bit of the PORTB register, you could do:

_PORTB.B3

(I hope that explanation helps…)

How this is nifty is that you can use it like a variable (because it is.) So, for example, if you wanted to toggle a bit in DDRD, you could do:

_DDRD.B3 ^= 1;

Doing that using more conventional notation is a bit more of a pain.

One caveat on all this: I haven’t really played around to see what this compiles to in assembly. So I don’t know if you’re saving a lot in terms of actual assembly calls. It could be a break-even kind of thing. It could be more expensive in terms of clock cycles. I really don’t know.

On the AVR codes, all of that’s in the datasheet for the ATMega48/88/168 from Atmel. When I first got my Baby-O I didn’t take too much of a look at the datasheet. I should’ve! They have all kinds of examples in there, and there are way WAY more ways to use the AVR than anything I’ve found online so far. The datasheet covers it very very well.

The motor_init bit you found is a bug. It looks the same because it really is the same. DOH! This is what happens when you write faster than you test. (Big forehead slap on my end…)

That PWM motor code came from Jim, but the bug comes from me. In any case it uses TIMER1, the 16-bit timer. Since I wanted to do a set of servo routines, I kinda wanted TIMER1 to be available. So I went back and did a new set of PWM routines for the motors using TIMER0. (If you look at the schematic on the Orangutan and Baby-O, each motor can be driven directly using either timer.) This version is included in the new code on Sourceforge.

TIMER0 is an 8-bit timer, so the new motor_init() routine doesn’t take any arguments to set the resolution. It’s 8-bit resolution PWM only. To keep things straight, rather than using “motor” at the front of each of the commands it uses “pwm0”. My apologies for changing command names, but it really is a work in progress.

I do need to go back and fix the TIMER1 motor_init code, though. I’ve got an application that may need more than 256 bits of PWM resolution. Only time will tell. As soon as I have it nailed down a little more, I’ll post the hardware and software. It’s a magnetic levitation setup similar to what you see with those levitating globes and things. Basically it’s a neat example of a PID position feedback loop, and would be a good illustration for how PID loops work. (Besides, how often do you get to make things float in mid-air at a robot club meeting?)

I’m going to try to nail that down this week, so I really do hope to post details soon.

Tom

The codes you are referring to are the names of registers and bits within the ATmega that control the internal devices. The register functions are descibed in the data sheet for each particular MPU – for the new Orangutans, this is the ATmega168. You can download this 347 page document from Atmel.

For example, TCCR1A stands for “timer counter1 control register A”. You can read about its function in the section describing Timer/Counter1, under “Register description”. The timers are very complicated, but very handy. I wish there were a few more of them!

Be warned that it takes a fair bit of effort to absorb the information in the data sheet, and the information is not presented in a very logical order or easily readable. But, if you really want to understand programs that use devices like the timers, uarts, ADCs etc., that is what you have to do.

Cheers, Jim

Man, I second you on the timers. I could use twice as many and not feel spoiled.

As it is I’m shuffling stuff around to see how much I can double up on a single counter using a single prescale value.

Tom

Seems like a good third-party opportunity… has nobody written an “ATmega Programming for Dummies” book, that basically contains the same info as the data sheet but presented in a more readable, newbie-friendly way?

Cheers,
— Joe

Mmmmyesandno. Sort of, anyway. I picked up one, “C Programming for Microcontrollers” by Joe Pardue. It uses the Atmel AVR Butterfly for all of its examples. It’s an ATMega169, which is actually pretty darned different from the ATMega168 used in the Orangutan. (I haven’t compared either with the ATMega644 used in the Orangutan-X2.) I picked up a Butterfly at the same time I picked up the book.

It’s good in terms of introducing someone with a little programming experience to the idea of programming a micro. Not all of it applies to the Orangutans (the whole chapter on the LCD is out). It also assumes you’re using the Butterfly’s serial bootloader, but it’s not too hard to make the mental jump to using the AVRISP MkII (which the Butterfly will do as well.)

What I wasn’t 100% stoked about with the book is that there’s tons of whys and hows in the text section of the book, but almost no comments in the code itself. Granted, the assumption is you’re typing the stuff in straight out of the book (it does come with a CD with all the source on it), so comments would just slow down someone going through the exercises by hand. But it’s also a bummer for someone who’s trying to read through it and think, “But how would I do this on an Orangutan?”

There are other books. Check out Amazon’s list by searching on “avr”. This is the only one I’ve looked at.

By far one of the best how-to texts I’ve seen has been Pascal Stang’s AVRlib. It gets dense in places (hey, it IS source code), and it’s a library, so there’s no punchline… er… main() routine, but if you want to see how to do a particular thing on an AVR, it’s likely there.

But if someone ever does write an ATMega Programming for Dummies books, I’ll be at the first book signing event to get my copy autographed.

Tom

Thank you for the reply Joe.

I still don’t quite get what the very first * is doing (is this step 3?).

Is the following correct?

Step 1. Take the address of PORTB:

-> &PORTB

Step 2. Typecast this to a volatile bitfield pointer:

-> volatile bitfield*

-> (volatile bitfield*)&PORTB

Step 3. Get the contents(?):

-> *((…

-> ((volatile bitfield)&PORTB)

I don’t think I see quite how step 3 is working.

Thanks again!
:slight_smile:

Thank you for the reply Tom.

I like your method better than the whole bit value “BV” thing. To me, the code looks more self-explanatory with the bitfields.

Sounds cool! :wink:

Thanks again!
:slight_smile:

Thank you for the reply Jim.

Initially, I did try scanning through the datasheet for the codes, but I guess I’ll have to do some more thorough reading to really figure this stuff out. Since I’m new to ATmega/AVR, all of the abbreviations/codes look like “greek” to me. :wink:

Thanks again!
:slight_smile:

The one catch with the whole bitfield thing is that it’s not standard C, and may not work on all compilers. It DOES work in WinAVR and should work in avr-gcc in UNIX and OSX. I haven’t tried them, though.

The catch is how the compiler decides to pack its variables. Some compilers may say, “Ok, this is a bit-sized variable, but my smallest variable storage space is one byte.” So you wind up with eight byte-long single-bit variables. They don’t line up right in memory, and things don’t work.

Since that code was written specifically for WinAVR, I don’t see a problem using it. But if you later move to another microprocessor or another compiler, the same thing may or may not work.

But the same can be said of all kinds of things people do when programming, including the CodeVision notation I copied the idea from:

PORTB.2

Works in CodeVision, but nothing else. I can’t tell you how many programs I’ve downloaded that don’t compile right off the bat because of quirky things like that.

Thank goodness porting software keeps the mind nimble.

Tom