Exclude io.h

Go To Last Post
29 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, Newbie here. I'm just starting out on an ATMEGA2560 on the STK600 using AVR studio . I want to do something simple like turn on all the LEDs. I'm trying to learn the nuts and bolts of it, so I don't want just do an #include <avr.io.h>. I thought I could do something like make my own .h file and define my ports there:

 

//something.h

 

#define DDRB 0x24

#define PORTB 0x25

 

#include "something.h"

int main(void)
{

    // DDRB as output
    DDRB = 0xff;

     // Turn ON all LEDS
     PORTB = 0x0; 

}

 

I know, I'm being incredibly naive and ignorant. I tried looking at avr32/io.h, but I couldn't find my device. I'm guessing there are multiple files that are being included and I just don't recognize them.

 

How are ports defined? Or, can you recommend a good resource?

 

Thanks

Last Edited: Mon. Oct 26, 2015 - 12:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

THis does not belong in the tutorials, moving to Tiny/Mega forum

 

JIm

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The standard AVR/io.h is all you need as everything is in it already.  Why would you want to re-write the wheel?

 

Jim

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define DDRB 0x24

    DDRB = 0xff;

Well, think about it.  #defines result in text substitutions, so that's going to result in "0x24 = 0xFF", which obviously isn't going to work.

You want a pointer to memory location 0x24 (IO location 4), and you want to modify the contents, so you'd need something like:

    *((unsigned char *)(0x24)) = 0xFF;

(which, frankly, is pretty ugly C, and doesn't really reflect the "nuts and bolts" of the AVR at all.   Which are reasons that it's good that things are usually hidden in io.h)

 

I tried looking at avr32/io.h, but I couldn't find my device.   How are ports defined?

the ATmega2560 is NOT an "avr32" - you need to look at avr/io.h (and specifically avr/sfr_defs.h)

Except that you really shouldn't.   The purpose of io.h is not to obscure details of the AVR, but to remove that "ugly C" problem.

If you were to write "OUT 0x4, r17" in assembler, you really shouldn't have to do "*((unsigned char *)(0x4 + 0x20)) = myvar;" in C...

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:

 

the ATmega2560 is NOT an "avr32" - you need to look at avr/io.h (and specifically avr/sfr_defs.h)

 

 

I started by looking in avr, but I didn't find io.h the first time around. I thought possibly there might be some overlap.

 

westfw wrote:

 

Except that you really shouldn't.   The purpose of io.h is not to obscure details of the AVR, but to remove that "ugly C" problem.

 

 

If I blindly trust everything that's going on behind the scenes,how am I supposed reach the "Raving Lunatic" level?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If I blindly trust everything that's going on behind the scenes,how am I supposed reach the "Raving Lunatic" level?

THat has nothing to do with what is going on behind the scenes.  the 'Raving Lunatic' is a moniker that the site tags you with when you hit a certain post count.  Ignore the monikers and go for the knowledge. smiley

 

Jim

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

pauliegone wrote:
thought I could do something like make my own .h file and define my ports there:
You are taking on a lot for a beginner.

 

pauliegone wrote:
I tried looking at avr32/io.h, but I couldn't find my device. I'm guessing there are multiple files that are being included and I just don't recognize them.
I assume you mean <avr/io.h>

 

pauliegone wrote:
How are ports defined?
It starts in <avr/io.h>.  That is the top level header which you must include at the top of every source file which needs the device-specific macros.  It contains preprocessor directives which will, in turn, include the correct device header.

 

Here's the part relevant to your device:

#if defined (__AVR_AT94K__)
#  include <avr/ioat94k.h>
.
.
.
#elif defined (__AVR_ATmega2560__)
#  include <avr/iom2560.h>
#elif defined (__AVR_ATmega2561__)
.
.
.
#else
#  if !defined(__COMPILING_AVR_LIBC__)
#    warning "device type not defined"
#  endif
#endif

 

Note also that before all of this is:

#include <avr/sfr_defs.h>

 

Now, the ATmega2560 is one member of a family of devices, and there is a common header file which serves them.  The iom2560.h file defines macros which are specific to the ATmega2560 and are not covered by the common header file.  That common header file is #included by iom2560.h:

#include <avr/iomxx0_1.h>

So, with all of this, we can answer your question of how the ports are defined.  Let's look specifically at PORTB.

 

In iomxx0_1.h you'll find a this macro:

#define PORTB   _SFR_IO8(0x05)

In sfr_defs.h you'll find this:

#define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET)

However, that's not the one that your C program will use (it's for assembly programs).  C will see this one:

#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)

OK so we have to dig deeper:

#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
#  if __AVR_ARCH__ >= 100
#    define __SFR_OFFSET 0x00
#  else
#    define __SFR_OFFSET 0x20
#  endif

That's where we hit a wall, because __AVR_ARCH__ isn't defined anywhere in a header file.  Instead, it is defined by the compiler when you invoke it with -mmcu=whatever.  Here's a clue as to how it does that:

http://www.atmel.com/webdoc/AVRLibcReferenceManual/using_tools_1using_avr_gcc_mach_opt.html

That document contains:

avr6    atmega2560    __AVR_ATmega2560__

... and for avr6 we find:

avr6[2]    __AVR_ARCH__=6 __AVR_MEGA__[5] __AVR_ENHANCED__[5] __AVR_HAVE_JMP_CALL__[4] __AVR_HAVE_MOVW__[1] __AVR_HAVE_LPMX__[1] __AVR_HAVE_MUL__[1] __AVR_HAVE_RAMPZ__[4] __AVR_HAVE_ELPM__[4] __AVR_HAVE_ELPMX__[4] __AVR_3_BYTE_PC__[2]

We can get the compiler to confirm this with:

$ avr-gcc -mmcu=atmega2560 -E -dM - < /dev/null | grep AVR_ARCH
#define __AVR_ARCH__ 6
$

 

OK, so now we know:

#  if __AVR_ARCH__ >= 100
#    define __SFR_OFFSET 0x00
#  else
#    define __SFR_OFFSET 0x20
#  endif

... and can finally answer the question.

 

This:

#define PORTB   _SFR_IO8(0x05)

... becomes:

#define PORTB   _MMIO_BYTE((0x05) + __SFR_OFFSET)

... becomes:

#define PORTB   (*(volatile uint8_t *)((0x05) + __SFR_OFFSET))

... becomes:

#define PORTB   (*(volatile uint8_t *)((0x05) + 0x20))

... which is equivalent to:

#define PORTB   (*(volatile uint8_t *)(0x25))

So, what the heck does that mean?  In C, that means the wherever you put PORTB in your program, it will be treated as though it is a reference to a volatile uint8_t, where that volatile uint8_t is stored in SRAM memory at address 0x25.  Co-incidentally, that's where PORTB is.

 

Why does it mean that?  Let's break it down and built it back up:

(0x25)

That's just a number.

(volatile uint8_t *)(0x25)

That will treat that number like it is a pointer to something, where that something is a volatile uint8_t.

*(volatile uint8_t *)(0x25)

Finally we dereference that pointer to get at the contents of the volatile uint8_t.

 

It's complicated, true, but once you've done it for PORTB, you can clearly do it for any other register.

 

I get that you want to understand how things work.  I even get that you want to re-invent the wheel, if only for a learning exercise.  Start by looking at a well-made, widely used wheel.  That's <avr/io.h>.

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Mon. Oct 26, 2015 - 03:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

WEll written joey,

 

But I think this will confuse the OP quite a bit into thinking that he must go through all of that work when it's all done in the background for him.  Simply placing the avr/io.h at the top of the program before teh main loop is all that needs to be done, then simple use the associated registers by name as pointed out in the datasheet for the AVR they are using as all the referencing is done by the .h file and read by the compiler..

 

DDRB

PINB

PORTB

 

in this case.

 

Jim

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If I blindly trust everything that's going on behind the scenes,how am I supposed reach the "Raving Lunatic" level?

 well, you COULD just say that you want to do all your programming in assembler...

 :-)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:
But I think this will confuse the OP quite a bit into thinking that he must go through all of that work when it's all done in the background for him.
Possibly.  But:

pauliegone wrote:
I'm trying to learn the nuts and bolts of it

 

However, to summarise the salient points: ;-)

joeymorin wrote:
You are taking on a lot for a beginner.

joeymorin wrote:
It starts in <avr/io.h>.  That is the top level header which you must include at the top of every source file which needs the device-specific macros.

joeymorin wrote:
I get that you want to understand how things work.  I even get that you want to re-invent the wheel, if only for a learning exercise.  Start by looking at a well-made, widely used wheel.  That's <avr/io.h>.

 

BTW, "pauliegone"... brilliant ;-)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Mon. Oct 26, 2015 - 03:35 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you, I'll try and wrap my brain around all of that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I get that you want to understand how things work.  I even get that you want to re-invent the wheel, if only for a learning exercise.  Start by looking at a well-made, widely used wheel.  That's <avr/io.h>.

 

Thanks for going along with my lunacy.

 

Quote:
BTW, "pauliegone"... brilliant ;-)

 

Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Seems like there should be an environment variable for AVR so a new guy could just #include <io.h> and all the textbook examples would work. That double directory thing always threw me for a loop, but I guess its a side effect of the gcc compiler being targeted to dozens of computers.

 

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:

Seems like there should be an environment variable for AVR so a new guy could just #include <io.h> and all the textbook examples would work.


Um. They do. You must of course specify the correct target with -mmcu= but the same is true of any multi-target toolchain.
bobgardner wrote:

That double directory thing always threw me for a loop, but I guess its a side effect of the gcc compiler being targeted to dozens of computers.

 

Double directory? Huh?
Oh I see... I guess you mean 'why the 'avr/'?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Mon. Oct 26, 2015 - 07:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I could never compile a gcc example with the imagecraft compiler. The first thing that kicked out was the avr directory. I could compile c examples using microsoft c and pelles c and watcom c and somehow the compiler magically knew where include was for that compiler. I bet that kicks every new guy right off the bat.

 

Imagecraft compiler user