| Author |
Message |
|
|
Posted: Apr 01, 2011 - 09:55 PM |
|


Joined: Jul 18, 2005
Posts: 62355
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
so i am hoping the macros will help in making them understand more easily.
Eh? You have the option of teaching them your very specific macro or the generic C & operator. With the latter they can write 1000's of programs, with the former they are tied to some very specific code for a single situation. Why not teach them how AND works? |
_________________
|
| |
|
|
|
|
|
Posted: Apr 01, 2011 - 10:57 PM |
|

Joined: Jul 21, 2010
Posts: 5
|
|
| well cos i am a student myself. and i am showing a presentation to justify the funding of my project, and the people on the panel will be staff of various departments, some of who may not know programming .that's why am using the macros to give a generalized presentation. I have even broken down my whole code into functions with general names for hopeful easier understanding. |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2011 - 01:09 AM |
|

Joined: Nov 17, 2004
Posts: 13851
Location: Vancouver, BC
|
|
|
Quote:
well cos i am a student myself.
Yet you obviously don't know yourself how the macros work. So if one of them happens to ask how the macros work, you'll have a big problem, won't you. |
_________________ Regards,
Steve A.
The Board helps those that help themselves.
|
| |
|
|
|
|
|
Posted: Apr 02, 2011 - 01:39 AM |
|

Joined: Jul 21, 2010
Posts: 5
|
|
| i do have some idea on the working of macros now,thanks to the tutorial. And i do know basic programming so i know what happens when u use a particular macro. I am already done with my coding using c. Just needed the macros to hopefully make it easier to explain. |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2011 - 08:13 AM |
|

Joined: Mar 17, 2011
Posts: 11
|
|
Thanks for the great Tutorial, it's awsome!
I just got a really crazy idea and Im not sure if it can actually be impemented.
To create a byte object in which every bit corresponds to a certain Pin on a port?
I'm not sure if Im using the right words here but an example should help:
create some object, maybe a structure (?) that looks like this:
object {Bit0 = Portb bit 3
Bit1 = Portc bit 1
...
Bit7 = Portb bit 0
}
so when you store a value into this object it will assign the respective value to those pins
for example,
object = 0xFF
would set Portb bit 3 high, Portc bit 1 high etc.
just wondering, maybe by doing a complicated macro or somethig? |
|
|
| |
|
|
|
|
|
Posted: Apr 02, 2011 - 01:08 PM |
|


Joined: Jul 18, 2005
Posts: 62355
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
To create a byte object in which every bit corresponds to a certain Pin on a port?
Search in this very forum for "bitfield". The bottom line is that struct members can be defined to be 1 bit long and so you can conglomerate 8 on a single byte address. Anyway read the tutorial.
EDIT: I meant this thread:
http://www.avrfreaks.net/index.php?name ... highlight=
Quote:
Just needed the macros to hopefully make it easier to explain.
First rule of programming: simplest is best.
"simplest" rarely involves macros. |
_________________
|
| |
|
|
|
|
|
Posted: May 14, 2011 - 06:20 AM |
|

Joined: May 13, 2011
Posts: 5
|
|
I've read this whole thread, and one topic that's not mentioned regarding port bit twiddling (with or without macros) is interrupts.
Is it considered good practice to disable interrupts when modifying a port pin? Especially if you're using some kind of bit_set() or bit_clear() macro?
The reason is that if the bit being set/cleared is not a constant expression at compile time, then the compiler will have to generate several instructions to read the current port value into a register, manipulate the value, and write it back. If an interrupt triggers after the port value is read, and that interrupt modifies another pin on the same port, when the main program resumes it will write back the stale value for that pin. This issue was previously a bug in the Arduino digitalWrite() implementation: http://code.google.com/p/arduino/issues/detail?id=146
I don't see anyone disabling interrupts in their code-- why not? Is there a reason I've overlooked why it's not necessary? |
|
|
| |
|
|
|
|
|
Posted: May 14, 2011 - 09:51 PM |
|


Joined: Mar 27, 2002
Posts: 18587
Location: Lund, Sweden
|
|
|
Quote:
the compiler will have to generate several instructions to read the current port value into a register, manipulate the value, and write it back.
The compiler will not have to generate several instructions, if only one bit is manipulated. AVRs have single machine instructions to manipulate one bit. E.g. activate the optimizer of avr-gcc and see what
Code:
PORTB |= 1;
generates.
If several bits are modified, then a read-modify-write sequence will be generated, and you will need to turn off interrupts if the port that is manipulated is shared with ISR code. The subject has been discussed in length here at 'freaks. The search words you need are e.g. "re modify write", "atomic" etc...
Ther are also tutorials on interrupt handling in general IIRC.
The avr-gcc support library avrlibc has stuff contributed by Dean Camera ('abcminiuser') that makes atomic sequences, saving and restoring state etc easy to code. |
|
|
| |
|
|
|
|
|
Posted: May 15, 2011 - 05:15 AM |
|


Joined: Jan 23, 2004
Posts: 9832
Location: Trondheim, Norway
|
|
|
Quote:
The compiler will not have to generate several instructions, if only one bit is manipulated.
It will generate several instructions for RMW if the extended IO space or SRAM is used, which can indeed lead to atomicity issues. Note that the XMEGA and AVR32s have a larger register address space with dedicated SET and CLEAR registers that allow for single-cycle RMW sequences.
On the older AVRs, you'll need to protect against interrupts if you're writing anything but a single bit to the regular IO space.
- Dean  |
_________________ Atmel Studio 6.1 is now released, grab it here.
Report AS6/ASF bugs here.
|
| |
|
|
|
|
|
Posted: May 17, 2011 - 12:55 AM |
|

Joined: May 13, 2011
Posts: 5
|
|
| Thanks, that makes sense, and I'll search for the atomic write threads. And to clarify, the situation I was asking about is when the bit being set/cleared is not a constant expression at compile time. I've looked at the disassembly for contant expressions like PORTB |= 1 and it is a single sbi machine instruction, as JohanEkdahl said. |
|
|
| |
|
|
|
|
|
Posted: May 17, 2011 - 08:27 AM |
|


Joined: Mar 27, 2002
Posts: 18587
Location: Lund, Sweden
|
|
|
Quote:
And to clarify, the situation I was asking about is when the bit being set/cleared is not a constant expression at compile time.
Oh, I missed that vital part of the question. Yes, in that case you are at risk even with single bit operations.
Sorry for any confusion. |
|
|
| |
|
|
|
|
|
Posted: Jun 09, 2011 - 04:09 PM |
|

Joined: Sep 05, 2001
Posts: 2499
|
|
I have added some predefined names to my "sbit.h".
Then you can use "PORT_cn", "DDR_cn", "PIN_cn" direct on the code (c = A..L, n = 0..7).
E.g.:
Code:
#include "sbit.h"
int main( void )
{
DDR_B3 = 1; // output
DDR_B7 = 1;
for(;;){
PORT_B3 = PIN_D0;
PORT_B7 = !PIN_D0;
}
}
Peter
P.S.:
The original article:
http://www.avrfreaks.net/index.php?name ... 198#318198 |
|
|
| |
|
|
|
|
|
Posted: Jun 14, 2011 - 03:26 PM |
|


Joined: Jun 01, 2011
Posts: 38
Location: Waterloo, Ontario, Canada
|
|
Hello, this is a very good tutorial and thank you but I was wondering if some one could explain something.
When I learned this stuff in school a few years back we only ever masked like you did in the 1st half (ie. foo &= 0x01). Why and when is it necessary to use these shift masks? I was taught using motorola micro's and I was wondering if it was some architecture thing? But as far as I can see they both do the same thing.
Thanks in advance |
|
|
| |
|
|
|
|
|
Posted: Jun 14, 2011 - 03:57 PM |
|


Joined: Jul 18, 2005
Posts: 62355
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
Why and when is it necessary to use these shift masks? I was taught using motorola micro's and I was wondering if it was some architecture thing?
Nothing says you HAVE to use bitnumbers with shifts. Some would argue that if you are only setting bit 5 of a DDR register to be an output that:
Code:
DDRB |= 0x20;
is almost as readable as:
Code:
DDRB |= (1<<5);
(thought the former may make the engineer count on his fingers to remember that 0x20 is bit 5! )
However where this bit shifting comes into play is to make SFR bit usage more self-documenting. For example in many AVRs bit 5 of the UCSRB register is the bit to enable the UART data register empty interrupt. Now if you read code that says:
Code:
UCSRB |= 0x20;
or
Code:
UCSRB |= (1<<UDRIE);
many engineers (at least those with a passing knowledge of the AVR) will instantly recognise that the second of those is enabling the UDRE interrupt. However it would require a VERY fastidious reader to know that 0x20 (or even (1<<5)) happens to be the UDRIE bit in that register.
Now one might then ask why do I have to use 1<<, if Atmel had written the XML file that is used for Assembler and C header file generation such that:
Code:
#define UDRIE 0x20
rather than
Code:
#define UDRIE 5
then the usage in C would just be:
Code:
UCSRB |= UDRIE;
but the reason they defined the bit names as 0..7 is so that the number can be used with the AVR SBI and CBI opcodes (assuming UCSRB is at the right location). This introduces the minor inconvenience of having to use (1<<UDRIE) to convert 5 into 0x20. In at least one C compiler there is a macro defined as:
Code:
#define _BV(x) (1<<x)
so that at least:
Code:
UCSRB |= _BV(UDRIE);
can be used which maybe looks a little less "complex" than (1<<UDRIE). However *all* C programmers will recognise the (1<<UDRIE) version but not all are going to know what _BV() achieves without digging into header files - which kind of destroys the readability "gain" in using it.
Remember that at the end of the day all C (and Asm) code should be written with the "next reader" in mind - which could either be the poor sap who has to fix your code 3 years after you left the company or it could simply be you in 9 months when you've forgotten that setting 0x20 in UCSRB is setting the UDRIE bit! (1<<UDRIE) tells you which bit is being set without looking it up (assuming you can at least remember the purpose of "UDRIE")
Cliff |
_________________
Last edited by clawson on Jun 14, 2011 - 03:59 PM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Jun 14, 2011 - 03:58 PM |
|


Joined: Mar 27, 2002
Posts: 18587
Location: Lund, Sweden
|
|
|
Quote:
Why and when is it necessary to use these shift masks? [...] But as far as I can see they both do the same thing.
They do. It is just about clarity of code. And it is opinous.
Which is clearer? This
Code:
something &= (1<<4) | (1<<3);
or this
Code:
something &= 0x18;
?
In the next step, e.g. when dealing with bits in a special purpose register (like a timer control register) it helps a lot to use the symbolic bit numbers rather than some magic numerical constants). Since the bit numbers are, uhmmm..., bit numbers rather than bit masks we need to construct the masks from the numbers. To do this, the shift operator is used. |
|
|
| |
|
|
|
|
|
Posted: Jun 14, 2011 - 08:27 PM |
|


Joined: Jun 01, 2011
Posts: 38
Location: Waterloo, Ontario, Canada
|
|
Cheers, Thanks both of you that makes a lot of sense. Especially since I am that sap that is fixing the code 3 years later  |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2011 - 06:10 AM |
|

Joined: Jun 15, 2011
Posts: 1
|
|
| Thanks for your information. |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2011 - 12:59 PM |
|

Joined: May 31, 2011
Posts: 13
|
|
|
bloody-orc wrote:
That means, that nr 1 is shifted left as many times as it is needed to reach bit named CS10. Where does the compiler know that CS10 is that? well you give him the AVR's name and it's smart enough to know such things thanks to some smart programmers on the GCC side
What is the difference between
TCCR1B |= (1 << CS10);
and
TCCR1B = (1 << CS10);
Is OR ('|') really needed there or both will work the same. |
|
|
| |
|
|
|
|
|
Posted: Jun 15, 2011 - 01:02 PM |
|


Joined: Jul 18, 2005
Posts: 62355
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| The first only sets one bit and leaves the other 7 bits in the register untouched. The second sets all 8 bits - the other 7 are set to 0. |
_________________
|
| |
|
|
|
|
|
Posted: Jun 15, 2011 - 01:05 PM |
|


Joined: Mar 27, 2002
Posts: 18587
Location: Lund, Sweden
|
|
|
Quote:
Is OR ('|') really needed there
That depends on the circumstances.
Quote:
or both will work the same
Definitively not.
Code:
TCCR1B |= (1 << CS10);
is a shorthand for the equivalent
Code:
TCCR1B = TCCR1B | (1 << CS10);
so all bits that was set before this operation will still be set.
OTOH, if you do
Code:
TCCR1B = (1 << CS10);
then only the CS10 bit will be set, and all other will be cleared.
I seriously suspect that this has been covered earlier in this thread, so you might have something to gain from browsing through the complete thread.. |
|
|
| |
|
|
|
|
|