Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Thread

Bit set/clear w/ gcc

Bit set/clear w/ gcc

2006-01-06 by ee_gary

Hi everybody,

I'm wondering what is the best way to set and clear I/O bits without
keeping track of what port they are on.  For example, something like:

#define myOutput1 IO2PIN.1
#define myOutput2 IO3PIN.28

main(){
  myOutput1 = 0;
  myOutput2 = 1;
}

I'm currently using the appropriate SET, CLR, and PIN registers each
time I want to set/clear, but I'd prefer to #define them once and use
the more readable form suggested above.  I'm using GCC.  Thanks!

Gary

Re: [lpc2000] Bit set/clear w/ gcc

2006-01-07 by Tom Walsh

ee_gary wrote:

>Hi everybody,
>
>I'm wondering what is the best way to set and clear I/O bits without
>keeping track of what port they are on.  For example, something like:
>
>#define myOutput1 IO2PIN.1
>#define myOutput2 IO3PIN.28
>
>  
>
As per ANSI C, define a MACRO, For example:

============= begin ===============

typedef struct
{
  REG32 in0;                            // P0 Pin Value Register
  REG32 set0;                           // P0 Pin Output Set Register
  REG32 dir0;                           // P0 Pin Direction Register
  REG32 clr0;                           // P0 Pin Output Clear Register
  EG32 in1;                            // P1 Pin Value Register
  REG32 set1;                           // P1 Pin Output Set Register
  REG32 dir1;                           // P1 Pin Direction Register
  REG32 clr1;                           // P1 Pin Output Clear Register
  REG32 in2;                            // P2 Pin Value Register
  REG32 set2;                           // P2 Pin Output Set Register
  REG32 dir2;                           // P2 Pin Direction Register
  REG32 clr2;                           // P2 Pin Output Clear Register
  REG32 in3;                            // P3 Pin Value Register
  REG32 set3;                           // P3 Pin Output Set Register
  REG32 dir3;                           // P3 Pin Direction Register
  REG32 clr3;                           // P3 Pin Output Clear Register
} gpioRegs_t;

#define GPIO1            ((gpioRegs_t *)0xE0028000)

#ifndef BIT
#define BIT(n)              (1 << (n))
#endif

#define LED_EVENT_BIT      BIT(20)     // P1.20 output - low for EVENT LED.

#define IOPIN1           GPIO->in1       /* Pin Value Register */
#define IOSET1           GPIO->set1      /* Pin Output Set Register */
#define IODIR1           GPIO->dir1      /* Pin Direction Register */
#define IOCLR1           GPIO->clr1      /* Pin Output Clear Register */

============== THEN DO ====================

main () {
    IOCLR1 = LED_EVENT_BIT;
    IOSET1 = LED_EVENT_BIT;
}

============ OR ================

< the above defines>

static inline eventLedOff (void) { IOSET1 = LED_EVENT_BIT; }

static inline eventLedOn (void) { IOCLR1 = LED_EVENT_BIT; }

void main (void)
{
    eventLedOn ();
    eventLedOff ();
}

============  snip =====================


Making the function both static and inline will optimize (-O2 or -Os) 
into inline assembly rather than a function call.

There are no "bitwise" functions in gcc such as set_bit(LED_EVENT_BIT) 
or clear_bit(LED_EVENT_BIT), but you can write your own...


Regards,

TomW


-- 
Tom Walsh - WN3L - Embedded Systems Consultant
http://openhardware.net, http://cyberiansoftware.com
"Windows? No thanks, I have work to do..."
----------------------------------------------------

Re: Bit set/clear w/ gcc

2006-01-11 by ee_gary

Thanks Tom,

I was looking for something that would let me do:

if(LED1)
  LED2 = 1;

This would require associating LED1 and LED2 with a particular bit in
the appropriate IOPIN register.  Judging from your response, this is
not possible with GCC and ARM?

Thanks,

Gary

--- In lpc2000@yahoogroups.com, Tom Walsh <tom@o...> wrote:
>
> ee_gary wrote:
> 
> >Hi everybody,
> >
> >I'm wondering what is the best way to set and clear I/O bits without
> >keeping track of what port they are on.  For example, something like:
> >
> >#define myOutput1 IO2PIN.1
> >#define myOutput2 IO3PIN.28
> >
> >  
> >
> As per ANSI C, define a MACRO, For example:
> 
> ============= begin ===============
> 
> typedef struct
> {
>   REG32 in0;                            // P0 Pin Value Register
>   REG32 set0;                           // P0 Pin Output Set Register
>   REG32 dir0;                           // P0 Pin Direction Register
>   REG32 clr0;                           // P0 Pin Output Clear Register
>   EG32 in1;                            // P1 Pin Value Register
>   REG32 set1;                           // P1 Pin Output Set Register
>   REG32 dir1;                           // P1 Pin Direction Register
>   REG32 clr1;                           // P1 Pin Output Clear Register
>   REG32 in2;                            // P2 Pin Value Register
>   REG32 set2;                           // P2 Pin Output Set Register
>   REG32 dir2;                           // P2 Pin Direction Register
>   REG32 clr2;                           // P2 Pin Output Clear Register
>   REG32 in3;                            // P3 Pin Value Register
>   REG32 set3;                           // P3 Pin Output Set Register
>   REG32 dir3;                           // P3 Pin Direction Register
>   REG32 clr3;                           // P3 Pin Output Clear Register
> } gpioRegs_t;
> 
> #define GPIO1            ((gpioRegs_t *)0xE0028000)
> 
> #ifndef BIT
> #define BIT(n)              (1 << (n))
> #endif
> 
> #define LED_EVENT_BIT      BIT(20)     // P1.20 output - low for
EVENT LED.
Show quoted textHide quoted text
> 
> #define IOPIN1           GPIO->in1       /* Pin Value Register */
> #define IOSET1           GPIO->set1      /* Pin Output Set Register */
> #define IODIR1           GPIO->dir1      /* Pin Direction Register */
> #define IOCLR1           GPIO->clr1      /* Pin Output Clear Register */
> 
> ============== THEN DO ====================
> 
> main () {
>     IOCLR1 = LED_EVENT_BIT;
>     IOSET1 = LED_EVENT_BIT;
> }
> 
> ============ OR ================
> 
> < the above defines>
> 
> static inline eventLedOff (void) { IOSET1 = LED_EVENT_BIT; }
> 
> static inline eventLedOn (void) { IOCLR1 = LED_EVENT_BIT; }
> 
> void main (void)
> {
>     eventLedOn ();
>     eventLedOff ();
> }
> 
> ============  snip =====================
> 
> 
> Making the function both static and inline will optimize (-O2 or -Os) 
> into inline assembly rather than a function call.
> 
> There are no "bitwise" functions in gcc such as set_bit(LED_EVENT_BIT) 
> or clear_bit(LED_EVENT_BIT), but you can write your own...
> 
> 
> Regards,
> 
> TomW
> 
> 
> -- 
> Tom Walsh - WN3L - Embedded Systems Consultant
> http://openhardware.net, http://cyberiansoftware.com
> "Windows? No thanks, I have work to do..."
> ----------------------------------------------------
>

Re: [lpc2000] Re: Bit set/clear w/ gcc

2006-01-11 by Robert Adsett

At 04:54 PM 1/11/06 +0000, ee_gary wrote:
>Thanks Tom,
>
>I was looking for something that would let me do:
>
>if(LED1)
>   LED2 = 1;
>
>This would require associating LED1 and LED2 with a particular bit in
>the appropriate IOPIN register.  Judging from your response, this is
>not possible with GCC and ARM?

You could go to C++ and overload the assignment operator appropriately.  If 
the only benefit you are getting is bit manipulation that seems a little 
overboard to me but it would work.  Toms solution did rely on some C99 
construct which as yet are far from widespread.  The C++ version might 
actually be more portable.

Or you could simply realize that there is a legion of embedded 
microcontroller families out there without bit manipulation instructions 
and addressing and become comfortable with the common methods of dealing 
with those in C with out the use of either extensions to the language or 
C99s additions.

Robert

" 'Freedom' has no meaning of itself.  There are always restrictions,   be 
they legal, genetic, or physical.  If you don't believe me, try to chew a 
radio signal. "  -- Kelvin Throop, III
http://www.aeolusdevelopment.com/

Re: [lpc2000] Re: Bit set/clear w/ gcc

2006-01-11 by Tom Walsh

Robert Adsett wrote:

>At 04:54 PM 1/11/06 +0000, ee_gary wrote:
>  
>
>>Thanks Tom,
>>
>>I was looking for something that would let me do:
>>
>>if(LED1)
>>  LED2 = 1;
>>
>>This would require associating LED1 and LED2 with a particular bit in
>>the appropriate IOPIN register.  Judging from your response, this is
>>not possible with GCC and ARM?
>>    
>>
>
>  
>

Bit fields simply do not exist in gcc.  Initially when porting a massive 
amount of 8051 source I had looked to see how I could construct them.  
Then I realized that the only reason I used a bit field was to conserve 
memory, the 8051 has such a miniscule amount of "Fast Access" RAM, 
external RAM required either a DPTR operation or register indirection 
(e.g. mov P2, #HIGH variable ; mov R1, #LOW variable ; mov ACC, @R1 ; ... ).

Since MIPS were comparatively low, the bits located in IRAM were hugely 
important, mostly as semaphores between various functions  / 
interrupts.  With ARM, the instruction set allows inexpensive access to 
the memory field and , therefore, inexpensive IRAM bitfields are moot.


>You could go to C++ and overload the assignment operator appropriately.  If 
>the only benefit you are getting is bit manipulation that seems a little 
>overboard to me but it would work.  Toms solution did rely on some C99 
>construct which as yet are far from widespread.  The C++ version might 
>actually be more portable.
>  
>
Then there are the legion of discussions that we could have regarding 
C++ value, or lack of, for use on an embedded platform...  ;-)


>Or you could simply realize that there is a legion of embedded 
>microcontroller families out there without bit manipulation instructions 
>and addressing and become comfortable with the common methods of dealing 
>with those in C with out the use of either extensions to the language or 
>C99s additions.
>
>  
>
<RANT>

The portability issue seems a bit silly to me.  Probably this is due to 
the fact that I support the code I write on a single type of processor 
and am not moving constantly from MIPS, to ARM, to 80C188, to ColdFire, 
to...  processors on a regular basis.  Write once, sell many.  heh.

Portability does become an issue when moving from an Archemedes C 
compiler to a GNU C compiler.  But, the recent move of my code from 
Archemedes to GNU was relatively painless.  I did some sed operations to 
change "BOOL" to "bool", "set_bit(foo)" to "foo = True", etc..  For the 
most part, the transition from an ancient 8051 development environ to a 
GNU environ was relatively painless.

I can see people who use a development system which allows cute little 
things like "AT" to dictate where sections are placed, or "BIT" to 
automagically built psuedo bitfields.  IMO, those are the people that 
will suffer vendor lock-in and run into portability issues!  Keep 
relying on stuff outside of ANSI and you will run into problems.

</RANT>

I'm just an old K&R programmer, fairly conservative in how I write my code.

Regards,

TomW


-- 
Tom Walsh - WN3L - Embedded Systems Consultant
http://openhardware.net, http://cyberiansoftware.com
"Windows? No thanks, I have work to do..."
----------------------------------------------------

RE: [lpc2000] Re: Bit set/clear w/ gcc

2006-01-12 by Joel Winarske

> I was looking for something that would let me do:
> 
> if(LED1)
>   LED2 = 1;
> 
> This would require associating LED1 and LED2 with a particular bit in
> the appropriate IOPIN register.  Judging from your response, this is
> not possible with GCC and ARM?

If you're ok with bit fields, try this (it works in IAR, should work in
GCC):

struct PORT  {
     unsigned bit0:1;
     unsigned bit1:1;
     unsigned bit2:1;
     unsigned bit3:1;
     unsigned bit4:1;
     unsigned bit5:1;
     unsigned bit6:1;
     unsigned bit7:1;
     unsigned bit8:1;
     unsigned bit9:1;
     unsigned bit10:1;
     unsigned bit11:1;
     unsigned bit12:1;
     unsigned bit13:1;
     unsigned bit14:1;
     unsigned bit15:1;
     unsigned bit16:1;
     unsigned bit17:1;
     unsigned bit18:1;
     unsigned bit19:1;
     unsigned bit20:1;
     unsigned bit21:1;
     unsigned bit22:1;
     unsigned bit23:1;
     unsigned bit24:1;
     unsigned bit25:1;
     unsigned bit26:1;
     unsigned bit27:1;
     unsigned bit28:1;
     unsigned bit29:1;
     unsigned bit30:1;
     unsigned bit31:1;
};

volatile struct PORT *port0_reg = ((volatile struct PORT *) FIO_BASE_ADDR);

#define LED1 (port0_reg->bit13)
#define LED2 (port0_reg->bit12)

if(LED1)
	LED2 = 1;


Joel

RE: [lpc2000] Re: Bit set/clear w/ gcc

2006-01-12 by Joel Winarske

> > I was looking for something that would let me do:
> >
> > if(LED1)
> >   LED2 = 1;
> >
> > This would require associating LED1 and LED2 with a particular bit in
> > the appropriate IOPIN register.  Judging from your response, this is
> > not possible with GCC and ARM?
> 

Of course if portability is a concern use bit shifting and masking instead.
Macros make quick work of this.


> If you're ok with bit fields, try this (it works in IAR, should work in
> GCC):
> 
> struct PORT  {
>      unsigned bit0:1;
>      unsigned bit1:1;
>      unsigned bit2:1;
>      unsigned bit3:1;
>      unsigned bit4:1;
>      unsigned bit5:1;
>      unsigned bit6:1;
>      unsigned bit7:1;
>      unsigned bit8:1;
>      unsigned bit9:1;
>      unsigned bit10:1;
>      unsigned bit11:1;
>      unsigned bit12:1;
>      unsigned bit13:1;
>      unsigned bit14:1;
>      unsigned bit15:1;
>      unsigned bit16:1;
>      unsigned bit17:1;
>      unsigned bit18:1;
>      unsigned bit19:1;
>      unsigned bit20:1;
>      unsigned bit21:1;
>      unsigned bit22:1;
>      unsigned bit23:1;
>      unsigned bit24:1;
>      unsigned bit25:1;
>      unsigned bit26:1;
>      unsigned bit27:1;
>      unsigned bit28:1;
>      unsigned bit29:1;
>      unsigned bit30:1;
>      unsigned bit31:1;
> };
> 
> volatile struct PORT *port0_reg = ((volatile struct PORT *)
FIO_BASE_ADDR);
Show quoted textHide quoted text
> 
> #define LED1 (port0_reg->bit13)
> #define LED2 (port0_reg->bit12)
> 
> if(LED1)
> 	LED2 = 1;
> 
> 
> Joel

Re: [lpc2000] Re: Bit set/clear w/ gcc

2006-01-12 by Robert Adsett

At 02:09 PM 1/11/06 -0500, Tom Walsh wrote:
>Robert Adsett wrote:
>
> >At 04:54 PM 1/11/06 +0000, ee_gary wrote:
> >
> >
> >>Thanks Tom,
> >>
> >>I was looking for something that would let me do:
> >>
> >>if(LED1)
> >>  LED2 = 1;
> >>
> >>This would require associating LED1 and LED2 with a particular bit in
> >>the appropriate IOPIN register.  Judging from your response, this is
> >>not possible with GCC and ARM?
> >>
> >>
> >
> >
> >
>
>Bit fields simply do not exist in gcc.

Bit fields exist, bit types don't.  Bit fields are useful for compactly 
storing small integers such as flags.  Mostly counter productive for 
dealing with hardware.

> >You could go to C++ and overload the assignment operator appropriately.  If
> >the only benefit you are getting is bit manipulation that seems a little
> >overboard to me but it would work.  Toms solution did rely on some C99
> >construct which as yet are far from widespread.  The C++ version might
> >actually be more portable.
> >
> >
>Then there are the legion of discussions that we could have regarding
>C++ value, or lack of, for use on an embedded platform...  ;-)

Yep.

><RANT>

:)

>The portability issue seems a bit silly to me.  Probably this is due to
>the fact that I support the code I write on a single type of processor
>and am not moving constantly from MIPS, to ARM, to 80C188, to ColdFire,
>to...  processors on a regular basis.  Write once, sell many.  heh.
>
>Portability does become an issue when moving from an Archemedes C
>compiler to a GNU C compiler.  But, the recent move of my code from
>Archemedes to GNU was relatively painless.  I did some sed operations to
>change "BOOL" to "bool", "set_bit(foo)" to "foo = True", etc..  For the
>most part, the transition from an ancient 8051 development environ to a
>GNU environ was relatively painless.

Portability from chip to chip is actually the least issue for me, it can be 
nice but it ends up not being the primary driver.  I see the two biggest 
benefits of it as being

         - portability of knowledge.  If you can mostly stick with the 
standard subset then when you do switch chips and or compilers and you 
will, if not frequently, then at least occasionally.  This was the reason 
for my C99 comment.  It appears to have some nice stuff in it, but until 
it's support is more widespread I'd least stay away from those parts that 
can't be implemented with a  simple header file or library support 
routine.  YMMV
         - Tool support.  Things like lexical analyzers, code generators 
etc.. are much happier with standard C than files riddled with extensions.

Add to that, nearly every C compiler I've used has broken under serious use 
and the most vulnerable spot has always been the extensions and ... well I 
stay away from them unless I really need them (which is very seldom).  I 
long ago gave up on interrupt keywords, I always write my own shell 
function in assembly that way I know I not at the mercy of a temperamental 
compiler.

>I can see people who use a development system which allows cute little
>things like "AT" to dictate where sections are placed, or "BIT" to
>automagically built psuedo bitfields.  IMO, those are the people that
>will suffer vendor lock-in and run into portability issues!  Keep
>relying on stuff outside of ANSI and you will run into problems.

Ah we agree, after all :)

></RANT>
>
>I'm just an old K&R programmer, fairly conservative in how I write my code.


That's all I'm saying.

Robert

" 'Freedom' has no meaning of itself.  There are always restrictions,   be 
they legal, genetic, or physical.  If you don't believe me, try to chew a 
radio signal. "  -- Kelvin Throop, III
http://www.aeolusdevelopment.com/

Re: [lpc2000] Re: Bit set/clear w/ gcc

2006-01-12 by Rob Jansen

Just my 2 cents ...

Using bit fields is defenitely not the best way to do bitwise I/O on the 
lpc21xx

The LED2 = 1 instruction will not be an atomic instruction when done 
using bit fields.
Use:

    #define LED2 (1<<12)
    port0_set = LED2

makes use of the special I/O set register. This is faster (it saves a 
read from port0_reg) and atomic

Bit fields will do the job. But if - in the end - you discover that you 
need to optimize your code this will cost you some time ...

        Rob

Joel Winarske wrote:

>>I was looking for something that would let me do:
>>
>>if(LED1)
>>  LED2 = 1;
>>
>>This would require associating LED1 and LED2 with a particular bit in
>>the appropriate IOPIN register.  Judging from your response, this is
>>not possible with GCC and ARM?
>>    
>>
>
>If you're ok with bit fields, try this (it works in IAR, should work in
>GCC):
>
>struct PORT  {
>     unsigned bit0:1;
>  
>
...

Re: [lpc2000] Re: Bit set/clear w/ gcc

2006-01-12 by Tom Walsh

Robert Adsett wrote:

>
>Add to that, nearly every C compiler I've used has broken under serious use 
>and the most vulnerable spot has always been the extensions and ... well I 
>stay away from them unless I really need them (which is very seldom).  I 
>long ago gave up on interrupt keywords, I always write my own shell 
>function in assembly that way I know I not at the mercy of a temperamental 
>compiler.
>
>  
>
LOL, BTDT (been there done that)!

>That's all I'm saying.
>
>
>  
>
NP, I'm not sure how I came across but I was in agreement with you (not 
defensive).

Regards,

TomW



-- 
Tom Walsh - WN3L - Embedded Systems Consultant
http://openhardware.net, http://cyberiansoftware.com
"Windows? No thanks, I have work to do..."
----------------------------------------------------

RE: [lpc2000] Re: Bit set/clear w/ gcc

2006-01-12 by Joel Winarske

> The LED2 = 1 instruction will not be an atomic instruction when done
> using bit fields.
> Use:
> 
>     #define LED2 (1<<12)
>     port0_set = LED2
> 
> makes use of the special I/O set register. This is faster (it saves a
> read from port0_reg) and atomic


This may be informative for some.  I compiled two lines of the same code
that lie at the start of a function. 

#define LED31_BIT 		  31
#define LED31_BIT_MSK 	0x80000000

(Bit Field Method as referenced in earlier post)
LED1 = LED_OFF;
        LDR         R4,??main_0+0xC    ;; port_reg
        LDR         R0,[R4, #+0]
        MVN         R1,#+0x2000
        LDR         R2,[R0, #+0]
        AND         R2,R1,R2
        STR         R2,[R0, #+0]
LED1 = LED_OFF;
        LDR         R2,[R0, #+0]
        AND         R1,R1,R2
        STR         R1,[R0, #+0]


FIO0PIN |= (1 << LED31_BIT);		// read and write
        MVN         R0,#-1073741781
        BIC         R0,R0,#+0x3FC0
        LDR         R1,[R0, #+0]
        ORR         R1,R1,#-2147483648
        STR         R1,[R0, #+0]
FIO0PIN |= (1 << LED31_BIT);
        LDR         R1,[R0, #+0]
        ORR         R1,R1,#-2147483648
        STR         R1,[R0, #+0]


FIO0PIN |= LED31_BIT_MSK;		// read and write
        MVN         R0,#-1073741781
        BIC         R0,R0,#+0x3FC0
        LDR         R1,[R0, #+0]
        ORR         R1,R1,#-2147483648
        STR         R1,[R0, #+0]
FIO0PIN |= LED31_BIT_MSK;
        LDR         R1,[R0, #+0]
        ORR         R1,R1,#-2147483648
        STR         R1,[R0, #+0]


FIO0SET = (1 << LED31_BIT);		// write only
        MVN         R0,#-1073741785
        BIC         R0,R0,#+0x3FC0
        MOV         R1,#-2147483648
        STR         R1,[R0, #+0]
FIO0SET = (1 << LED31_BIT);
        STR         R1,[R0, #+0]


FIO0SET = LED31_BIT_MSK;		// write only
        MVN         R0,#-1073741785
        BIC         R0,R0,#+0x3FC0
        MOV         R1,#-2147483648
        STR         R1,[R0, #+0]
FIO0SET = LED31_BIT_MSK;
        STR         R1,[R0, #+0]


Joel

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.