[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-libc-dev] A sugestion for avr-libc
From: |
E. Weddington |
Subject: |
Re: [avr-libc-dev] A sugestion for avr-libc |
Date: |
Fri, 22 Aug 2003 18:44:50 GMT |
> First of all I'd like to thank the developers of avr-
libc, you've done a
> fantastic job thus far.
>
> I haven't been using avr-libc for all that long now
(about 2 months) but
> one
> of the more useful features that appears to be missing is
the ability to
> assign and test individual bits in IO registers. Ie
PA0=1; or if (DDRA
> == 1)
>
> Whilst some of this functionality is provided by current
releases using
> the
> sbi, and cbi functions, I believe adding the capability
to read and
> write
> bits without requiring the use of these instructions
would enhance
> avr-libc.
>
> I have attached a cut down IO header (myIO.h) and a
simple test program
> (main.c) that demonstrate how this functionality would be
implemented
> into
> the current avr-libc and used in programs.
>
> I think you'll agree that it provides a much simpler
means of accessing
> bits
> in the IO registers than the current mechanisms. This
method of access
> also
> seems to be relatively common across other
compilers/libraries I have
> come
> across (Mitsubishi M16C, some 8051 compilers etc).
>
> I have found avr-libc useful so if the general concessus
is that this
> would
> be a useful addition I am happy enough to implement it. I
would however
> like
> to make sure that I am not duplicating someone else's
effort, if someone
> else out there is already working on this I would like to
offer them my
> assistance.
>
> P.S. Could anyone replying to this email please send me a
copy
> (craig_AT_student.usyd.edu.au) as I'm having some
difficulty joining the
> mailing list.
>
> Regards
>
> Craig Rodgers
Thanks for your submission.
However, there are some issues with this method that you're
probably not aware about.
1. There are already capabilites within the C language to
test and assign individual bits within a byte. See more
below.
2. The sbi and cbi macros are deprecated and no longer used.
3. Modeling a byte as a bitfield has limitations and
inefficiencies. Namely, a bitfield is declared as an int,
which is 16 bits, and not an unsigned char. Also, when you
use the bitfield model, you are limited to assigning only
to members of the bitfield structure, whether this is a
single bit, or multiple sequential bits. Using the C
language capabilites gives the programmer much more freedom.
4. In the C language one assigns and tests bits using bit
operators, the assign operator, and the concept of bit
masks:
PORTC |= 0x01; // Set bit 0 only.
PORTC &= ~0x01; // Clear bit 0 only.
PORTC ^= 0x01; // Toggle bit 0 only.
PORTC & 0x01; // Test bit 0 only.
PORTC |= 0x80; // Set bit 7 only.
Now we can introduce macros to make this easier to read.
The _BV() macro in avr-libc takes a number as the argument
and converts it to the appropriate bit mask. (The BV stands
for Bit Value). The _BV() macro is defined as:
#define _BV(x) (1 << x)
this allows:
PORTC |= _BV(0); // Set bit 0 only.
PORTC &= _BV(1); // Clear bit 1 only.
PORTC ^= _BV(7); // Toggle bit 7 only.
This can be further enhanced with the defines found in the
processor header files:
// For atmega128
#include <avr/io.h>
UCSR0B |= _BV(TXEN0); // Set bit 3 in UCSR0B only.
Using bit operators, one can do multiple, non-contiguous
bits at a time:
PORTC |= (_BV(0) | _BV(2) | _BV(7)); // Set bits 0,2,7
PORTC &= ~(_BV(1) | _BV(2) | _BV(6)); // Clear bits 1,2,6
PORTC ^= (_BV(5) | _BV(3)); // Toggle bits 3,5
For more readability, you can define these macros:
#define bit_set(v,m) ((v) |= (m))
#define bit_clear(v,m) ((v) &= ~(m))
#define bit_toggle(v,m) ((v) ^= (m))
#define bit_test(v, m) ((v) & (m))
bit_set(PORTC, _BV(0));
bit_clear(PORTC, _BV(3) | _BV(5));
// Check if transmit is complete
if(bit_test(UCSR0A, _BV(TXC0)))
{
// Send data.
}
Better still, with the last example, you can make it even
more readable with an additional macro layer:
#define usart0_transmit_complete() \
bit_test(UCSR0A, _BV(TXC0)
That way you can write:
if(usart0_transmit_complete())
{
// Send data.
}
and this hides the implementation in header files which can
be easily changed if you're using USART1 instead of USART0
(on the mega128) or if you moving to a different type of
processor altogether.
Also take a look at the various assembly output of these
macros (be sure to optimizations on). It's really quite
instructive.
So, in the end, bitfields are really not a good model of
the processors registers and actions that can be done on
their bits.
Eric