Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
jbrain
PostPosted: Feb 05, 2008 - 04:17 PM
Wannabe


Joined: Apr 06, 2004
Posts: 71


I know this is compiler generic, but I do have a related question:

I've been using (1<<PIN_NAME) for some time in my code, but I am working on a project now where the developer is using _BV(PIN_NAME) all over. Is there a best practice on which to use?

Jim

_________________
Jim Brain
 
 View user's profile Send private message  
Reply with quote Back to top
Taco_Bell
PostPosted: Apr 13, 2008 - 08:52 PM
Hangaround


Joined: Oct 14, 2007
Posts: 112
Location: U.S.A. Rules Yaaaaaaaaaahhhhh!!!!

Will this blink an LED?

Code:

#inculde <avr/io.h>
#inculde <util/delay.h>


DDRB = 0b11111111;

while(1)
{
PORTB |= (0x01 << 7);
_delay_ms(250);
PORTB &= (0x00 << 7);
_delay_ms(250);
}


_________________
Life Is Like A Bucket Of Chicken.
 
 View user's profile Send private message  
Reply with quote Back to top
Koshchi
PostPosted: Apr 13, 2008 - 10:19 PM
10k+ Postman


Joined: Nov 17, 2004
Posts: 13956
Location: Vancouver, BC

Quote:
Will this blink an LED?

Well, yes, but it isn't doing what you really want.
Code:
PORTB |= (0x01 << 7);

This sets bit 7 (and only bit 7) to 1. This is because it translates into:
Code:
PORTB = PORTB | 0b10000000;

So bit 7 is changed, and the rest of the bits remain what they were.
Code:
PORTB &= (0x00 << 7);

This sets all bits to 0, not just bit 7.
This is because this translates into:
Code:
PORTB = PORTB & 0b00000000;

since 0 shifted by any amount is still going to be 0, and 0 ANDed with anything is 0. You want:
Code:
PORTB &= ~(0x01 << 7);

_________________
Regards,
Steve A.

The Board helps those that help themselves.
 
 View user's profile Send private message  
Reply with quote Back to top
Taco_Bell
PostPosted: Apr 14, 2008 - 07:04 PM
Hangaround


Joined: Oct 14, 2007
Posts: 112
Location: U.S.A. Rules Yaaaaaaaaaahhhhh!!!!

Thank You Koshchi,
That is exactly what I wanted. I was going to ask this next:

Quote:

This sets all bits to 0, not just bit 7.
This is because this translates into:

Code:
PORTB = PORTB & 0b00000000;


since 0 shifted by any amount is still going to be 0, and 0 ANDed with anything is 0. You want:
Code:
Code:
PORTB &= ~(0x01 << 7);



Thanks again,

_________________
Life Is Like A Bucket Of Chicken.
 
 View user's profile Send private message  
Reply with quote Back to top
mikey_G
PostPosted: Apr 30, 2008 - 02:42 PM
Newbie


Joined: May 26, 2007
Posts: 6


Taco_Bell wrote:
Will this blink an LED?

Code:

#inculde <avr/io.h>
#inculde <util/delay.h>


DDRB = 0b11111111;

while(1)
{
PORTB |= (0x01 << 7);
_delay_ms(250);
PORTB &= (0x00 << 7);
_delay_ms(250);
}


It would blink a led, but it would be a inefficient way to do so.

This is how I would solve it:
Code:

#include <avr/io.h>
#include <util/delay.h>

int main(void) {
   DDRB = 0xFF;
   
   while(1) {
      PORTB ^= (1 << 7);
      _delay_ms(250);
   }
}

Here I use the XOR operator which is ideal for flipping a bit. Using the 1 XOR as opposed to 1 OR and 1 AND also reduced the code size from 443 bytes (your example) to 398 bytes (my example)

The logic behind it is that on the first run the 8th bit of PORTB, which is 0, is XOR'ed with a 1 which results in a 1.
0 XOR 1 = 1
On the next loop iteration the 8th bit of PORTB, which is now 1, will be XOR'ed with a 1 which will result in a 0.
1 XOR 1 = 0
 
 View user's profile Send private message  
Reply with quote Back to top
dandumit
PostPosted: May 30, 2008 - 08:52 AM
Newbie


Joined: Sep 13, 2005
Posts: 9
Location: Bucharest

Hello ,
Please excuse my dumb question :
how do I do octet/byte rotation in avrgcc ?
I mean how do I wrote in C the equivalent of asm rol cmd ?
Kind regards,
Daniel
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: May 30, 2008 - 11:22 AM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England

I guess the first question is WHY you'd want to. But there's no easy way, you'd need to use something like
Code:
topbit = (bytevar & 0x80) ? 0 : 1;
bytevar <<= 1;
bytevar |= topbit;

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
dandumit
PostPosted: May 30, 2008 - 02:50 PM
Newbie


Joined: Sep 13, 2005
Posts: 9
Location: Bucharest

First of all thanks for answer.
I will answer why I need to do this : I writing an dmx receiver and I need to read the address of that receiver from a dipswitch pack. Because I was restricted to single side pcb I have inverted the traces to get the routing done.

I will abuse of your kindness and I would like to ask if it is possible to wrote an inline asm macro like :
http://www.nongnu.org/avr-libc/user-man ... e_asm.html

something like this would work ?
asm volatile("rol %0" : "=r" (value) : "0" (value));

Thanks
Daniel
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
tigrezno
PostPosted: Jun 15, 2008 - 09:41 PM
Rookie


Joined: May 19, 2008
Posts: 35


those are my definitions, i find them more user-friendly, tell me what you think.

Code:
#define LOW 0
#define HIGH 1

#define INPUT(port,pin) DDR ## port &= ~(1<<pin)
#define OUTPUT(port,pin) DDR ## port |= (1<<pin)
#define CLEAR(port,pin) PORT ## port &= ~(1<<pin)
#define SET(port,pin) PORT ## port |= (1<<pin)
#define TOGGLE(port,pin) PORT ## port ^= (1<<pin)
#define READ(port,pin) (PIN ## port & (1<<pin))


usage:
Code:
OUTPUT(D, 3); // port D, pin 3 as output
SET(D, 3); // set port D pin 3 to HIGH
CLEAR(D, 3); // set it to LOW

INPUT(B, 5);
if (READ(B, 5) == HIGH)
...


feel free to add them to the tutorial Smile
[updated]


Last edited by tigrezno on Jun 17, 2008 - 04:56 PM; edited 1 time in total
 
 View user's profile Send private message  
Reply with quote Back to top
MotoDog
PostPosted: Jun 16, 2008 - 08:59 PM
Newbie


Joined: Apr 17, 2008
Posts: 18
Location: Crestline, Ca. USA

Tigrezno,
I am been C ing with AVR for a few months. I am a novice. I got an A/D working with interrupts and putting the data to RS232 to RealTerm on a PC working!
Big accomplishment for me, lots of hours.

I have tried a few of the examples on this topic posted here and ran into problems. Mostly with the fact that PORTs need indirection methods to do bit fiddling? I think?
I just tried your "toggle" on a mega128 PORTA Bit 1 and it compiled and the hardware worked! Thanks, I wanted PORT bit setting and flipping, not just variables. This seems to be the best method discussed here yet? I will try the rest of thems soon.
Where is the #Define documentation for AVR C, or is it per standard C practice and I find it in a C book?
In the DOC directory in my AVR C installation there are many many HTML files. They seem to just compare features to standard C, with no examples? Not much help for a beginner?
Am I missing a manual for this AVR C somewhere?
I didn't know you could use # for parameter subsitution.
Thanks, I put your defines in my first AVR learning C project!
Mike
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jun 16, 2008 - 10:15 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England

#define is just one of the C Pre Processor functions. The facilities available are standard to most c compilers so this manual for the GCC variant should be as good as any:

http://gcc.gnu.org/onlinedocs/cpp/

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
MotoDog
PostPosted: Jun 16, 2008 - 11:15 PM
Newbie


Joined: Apr 17, 2008
Posts: 18
Location: Crestline, Ca. USA

Thanks!

I am looking at it now. Lots there.

The use of the # # to pass those port parameters still confuses me? I'll keep thinkin on it!
 
 View user's profile Send private message  
Reply with quote Back to top
Koshchi
PostPosted: Jun 17, 2008 - 12:54 AM
10k+ Postman


Joined: Nov 17, 2004
Posts: 13956
Location: Vancouver, BC

## is just the concatenation operator in macros. #define is just a text replacement tool, not a C programming construct. So something like:
Quote:
READ(B, 5)

simply gets replaced by:
Quote:
PORTB & (1<<5)

_________________
Regards,
Steve A.

The Board helps those that help themselves.
 
 View user's profile Send private message  
Reply with quote Back to top
MotoDog
PostPosted: Jun 17, 2008 - 02:00 AM
Newbie


Joined: Apr 17, 2008
Posts: 18
Location: Crestline, Ca. USA

Got it! Very Happy

Thanks, this if from the manual Clawson sent the link too! "I wooda never known!"


"This is called token pasting or token concatenation. The `##' preprocessing operator performs token pasting. When a macro is expanded, the two tokens on either side of each `##' operator are combined into a single token, which then replaces the `##' and the two original tokens in the macro expansion."
 
 View user's profile Send private message  
Reply with quote Back to top
Lajon
PostPosted: Jun 17, 2008 - 11:42 AM
Posting Freak


Joined: Mar 12, 2004
Posts: 1177
Location: Linköping, Sweden

Code:
#define READ(port,pin) PORT ## port & (1<<pin)
tigrezno, did you actually use this? To read you have to use the PIN register. Additionally you can not compare the & result with 1 as you do here:
Code:
if (READ(B, 5) == HIGH)
This would work if you need to compare:
Code:
#define READ(port,pin) ((PIN ## port & (1<<pin)) != 0)

or just
Code:
#define READ(port,pin) ((PIN ## port & (1<<pin))
if you are ok with the simpler test condition:
Code:
if (READ(B,5)) {

/Lars
 
 View user's profile Send private message  
Reply with quote Back to top
tigrezno
PostPosted: Jun 17, 2008 - 04:54 PM
Rookie


Joined: May 19, 2008
Posts: 35


ouch that was a typo!

You're correct, it should be PIN and not PORT, sorry, i'll change it.

The comparation issue is true too, me bad, very very bad.

I wrote them without using the "input" defines, sorry.
I hope you found the other methods usefull.
 
 View user's profile Send private message  
Reply with quote Back to top
dandumit
PostPosted: Sep 02, 2008 - 11:25 AM
Newbie


Joined: Sep 13, 2005
Posts: 9
Location: Bucharest

I'm a beginner in embedded development and for small applications I really enjoy a simple mode to access a port pin directly ( like PORTA.1 or PORTA_1).
I have found this example a while ago and I would like to hear your comments on it :
Quote:
#include <avr/io.h>

// Define the bits in the port
typedef struct
{
unsigned char bit0 : 1,
bit1 : 1,
bit2 : 1,
bit3 : 1,
bit4 : 1,
bit5 : 1,
bit6 : 1,
bit7 : 1;
} bit_field;

// Define macro to get the value of each bit
#define GET_BIT(port) (*(volatile bit_field *) (_SFR_ADDR(port)))

// Define functions for each bit of the I/O ports in the program
#define SIG GET_BIT(PINB).bit0
#define LED GET_BIT(PORTD).bit0

int main (void)
{
for (;;)
{
if (SIG) LED = 1;
else LED = 0;
}
}

I would really like to understood how this code is working ... especially part with setting a bit.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Sep 02, 2008 - 11:58 AM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England

Well break it down as the pre-processor will be doing for you. Let's say you use:
Code:
LED = 1;

firstly that becomes:
Code:
GET_BIT(PORTD).bit0;

which in turn is:
Code:
(*(volatile bit_field *) (_SFR_ADDR(PORTD))).bit0;

and from the GCC header files the _SFR_ADDR() and PORTD macros further break this down to be:
Code:
 (*(volatile bit_field *) (((uint16_t) &((*(volatile uint8_t *)((0x12) + 0x20)))))).bit0 = 1;

The 0x12 in there will vary depending on your AVR - the above is correct for mega16.

So ultimately it's casting a bitfield structure onto memory address 0x32 and then setting 1 into "bit0" of that struct.

When you see:
Code:
struct {
 :1
 :1
}

it's effectively assigning one bit for each element. So this is just allowing individual bit access to the 8 bits being held in memory location 0x32.

Cliff

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
MIchael_J
PostPosted: Sep 12, 2008 - 12:30 AM
Newbie


Joined: Sep 11, 2008
Posts: 5
Location: Poland

Thank you for the tutorial. I found it very useful coming from beeing used to only sbi(), cbi() macros.

Somewhere else on the net i found these two macros beeing called obsolete... Any idea why is it so? Is it indeed more justified to acces the bits as shown in the tutorial?

This article is helping a lot in understanding many other articles around here.
Thanks once more.

Take care.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 12, 2008 - 12:10 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62922
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:
Somewhere else on the net i found these two macros beeing called obsolete... Any idea why is it so? Is it indeed more justified to acces the bits as shown in the tutorial?

There are three ways to change a single bit using the AVR. If the register in question is in IO space locations 0x00..0x1F then SBI/CBI can be used to set/clear individual bits. Those opcodes occupy 16 bits and execute in 1 cycle. If the register is between 0x20..0x3F then it is no longer reachable using SBI/CBI but it is using IN/OUT but in this case to set a bit it wil require IN/OR/OUT and to clear a bit it will require IN/AND/OUT which is 3 16 bit opcodes and takes 3 cycles. If the register is beyond IO address 0x3F (that is beyond RAM address 0x5F) then the only access is LDS/STS and to set it wil be LDS/OR/STS and to clear it will be LDS/AND/STS. In this case it's five 16 bit opcodes (LDS and STS are 2 each) and takes 5 cycles to execute.

Now when the early versions of the GCC compiler appeared it did not have an optimisation to spot when LDS/OR/STS could be reduced to IN/OR/OUT or even SBI so a macro sbi() was defined to use inline assembler so the programer could force SBI to be used even though the compiler didn't realise it.

In later compiler versions the code generator was improved so that it would always generate the most optimal code (as long as -O0 was not used!) so the need for the programmer to take control and force when SBI should be used was no longer required.

In the latest GCC (and the other AVR C compilers) the totally portable, totally standard PORTB |= (1<<PB5) will always generate just an SBI PORTB,5 as long as PORTB is between 0x00 and 0x1F and the optimiser is enabled.

The joy of using that standard construct is that you don't need the code to rely on some extra .h file that provides sbi()/cbi() so it makes it more portable between copilers and other architectures.

If using GCC then (for the time being) there is still <compat/deprecated.h> and this now includes:
Code:
#define sbi(port, bit) (port) |= (1 << (bit))
#define cbi(port, bit) (port) &= ~(1 << (bit))

so, as you can see, this is just supporting "old" code and turning the macro into the "standard" construct that's been explained above anyway.

As the file is deprecated there's a chance it may be withdrawn from future distributions so it's unwise to write code these days to use it because next time you upgrade compiler you may find that the file has gone.

Cliff

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits