Grant,

You can define all ports and pins in a single file and only need to
change that file if you move pins around.  I always put defines in
io_pins.h and do the following


#define ADC_ENABLE_BIT  0x08
#define ADC_PORT        P3OUT

#define ADC_ENABLE      ( ADC_PORT |= ADC_ENABLE_BIT )
#define ADC_DISABLE     ( ADC_PORT &= ~(ADC_ENABLE_BIT) )

Sincerely,

David Smead
www.amplepower.com
www.amplepower.net


On Mon, 3 Jul 2006, Grant Edwards wrote:

I'm experimenting with using ports declared as bitfields for
single bit I/O.

For some of the the other gcc targets I'm currently using (e.g.
H8/300) that's how all of the example code is done, and the gcc
port includs headers that declare the I/O ports and peripheral
registers as both uintN_t and as structs of bitfields.

I find bitfields are particularly nice for single-bit I/O
lines, since there's only a single point in the source code
that defines which port-pin is assigned to a signal.  If you
use the port-name and bitmask method, you always end up with
mutiple places that must be changed when a signal moves to a
different port pin.  Having the same piece of information in
multiple places is a bug just waiting to happen.

Here's my test program:

-------------------------8<-------------------------
#include <io.h>

typedef struct
{
 unsigned b0: 1;
 unsigned b1: 1;
 unsigned b2: 1;
 unsigned b3: 1;
 unsigned b4: 1;
 unsigned b5: 1;
 unsigned b6: 1;
 unsigned b7: 1;
} tPortBits;

#define sfrbb__(x,x_)  volatile tPortBits x ## bit asm(#x_)
#define sfrbb_(x,x_)   sfrbb__(x,x_)
#define sfrbb(x)  sfrbb_(x, x ## _)

sfrbb(P6OUT);
sfrbb(P6IN);
sfrbb(P1IN);

#define Bit(n) (1<<(n))

void foo(void)
{
 P6OUTbit.b0 = 1;
 P6OUTbit.b0 = 0;
 P6OUTbit.b7 = 1;
 P6OUTbit.b7 = 0;
}

void bar(void)
{
 P6OUT |=  Bit(0);
 P6OUT &= ~Bit(0);
 P6OUT |=  Bit(7);
 P6OUT &= ~Bit(7);
}

extern void zxcv(void);

void asdf(void)
{
 if (P1INbit.b0)
   zxcv();
 if (P1INbit.b7)
   zxcv();
}

void qwer(void)
{
 if (P1IN & Bit(0))
   zxcv();
 if (P1IN & Bit(7))
   zxcv();
}
-------------------------8<-------------------------


Output pins appear to work well:

void foo(void)
{
 P6OUTbit.b0 = 1;
 P6OUTbit.b0 = 0;
 P6OUTbit.b7 = 1;
 P6OUTbit.b7 = 0;
}


foo:
       bis.b        #llo(1), &0x0035
       bic.b        #llo(1),&0x0035
       bis.b        #llo(-128), &0x0035
       and.b        #llo(127), &0x0035
       ret

This is the same as the code generated for the byte/mask
version of the same function as long as optimization is
enabled.  With -O0, the bitfield version is unchanged, but the
byte/mask version ends up with an extra instruction:

void bar(void)
{
 P6OUT |=  Bit(0);
 P6OUT &= ~Bit(0);
 P6OUT |=  Bit(7);
 P6OUT &= ~Bit(7);
}

bar:
       bis.b        #llo(1), &0x0035
       bic.b        #llo(1),&0x0035
       bis.b        #llo(-128), &0x0035
       mov.b        #llo(127), r15
       and.b        r15, &0x0035

It's still atomic, so it's not a big deal.


However, reading input pins generates a lot of useless code:

void asdf(void)
{
 if (P1INbit.b0)
   zxcv();
 if (P1INbit.b7)
   zxcv();
}

asdf:
       mov.b  &0x0020, r15
       and    #llo(1), r15
       jne    .L6
.L4:
       bit.b  #llo(128), &0x0020
       clr.b  r15                    ****
       adc.b  r15                    ****
       and.b  #-1,r15                ****
       cmp    #llo(0), r15           ****
       jne    .L7
.L3:
       ret
.L7:
       call   #zxcv
       jmp    .L3
.L6:
       call   #zxcv
       jmp    .L4


Reading bit 0 wasn't too bad (though a bit.b would have been
better, wouldn't it?).  Reading bit 7 isn't good.  The lines
that appear to be useless are the four marked with asterisks.
AFAICT, you can just delete those four lines and the code is
still correct.

Compare that to the byte/mask version:

void qwer(void)
{
 if (P1IN & Bit(0))
   zxcv();
 if (P1IN & Bit(7))
   zxcv();
}

qwer:
       bit.b  #llo(1),&0x0020
       jeq    .L9
       call   #zxcv
.L9:
       cmp.b  #llo(0), &0x0020
       jl     .L11
.L8:
       ret
.L11:
       call   #zxcv
       jmp    .L8


Much better.

In either case, I don't see why the calls to zxcv() are pushed
out past the "ret" which results in an extra jump.  Why not
leave the call inline and jump around it like this?

qwer:
       bit.b  #llo(1),&0x0020
       jeq    .L9
       call   #zxcv
.L9:
       cmp.b  #llo(0), &0x0020
       jge    .L8
       call   #zxcv
.L8:
       ret

It only saves one instruction, but that instruction is a
"jmp", so it's a big one if you're counting cycles.


--
Grant Edwards                   grante             Yow!  My haircut is totally
                                 at               traditional!
                              visi.com


Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Mspgcc-users mailing list
Mspgcc-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mspgcc-users


Reply via email to