Yahoo Groups archive

Lpc2000

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

Thread

C union not working

C union not working

2005-03-17 by Leonardo Santos

Hello All:
	I'm working with a LPC2106 using the GCC 3.4.4 toolchain (GCC + binutils 2.15 
+ newlib 1.13).	I wrote a union and a structure to access the P0 pins 
individually, like this:

typedef struct {
	int p0	: 1;
	int p1	: 1;
	int p2	: 1;
(...)
	int p30	: 1;
	int p31	: 1;
}port_t;

typedef union {
	port_t pins;
	unsigned int reg;
} ioreg;

typedef struct {
	ioreg iopin;
	ioreg ioset;
	ioreg iodir;
	ioreg ioclr;
}gpio_t;

So I declare a pinter like

	volatile gpio_t *gpio = 0xE0028000;

If I access the registers using 

	if( gpio->iopin.reg & 0x01 )

or 

	gpio->ioset.reg |= 0x00008000;

Everithing works fine! But if I try a code like this:

	gpio->ioset.pins.p15 = 1;

To set P0.15, P0.23 and P0.31 are set too! I had tried this code in my Linux 
workstaion and it works just fine. The compiles setting I'm using are 

arm-elf-gcc -c -Wall -D GCC_ARM7 -mcpu=arm7tdmi -Tlpc2106-rom.ld -Wcast-align 
-O3

So I'm compiling it in ARM mode. Any clues? Is this a compiler issue ( I'm not 
using the right parameters)?

Thanks a lot!

-- 
This is Linux country.
On a quiet night, you can hear Windows reboot.

Leonardo Pereira Santos
Engenheiro de Projetos
PD3 Tecnologia
av. ParĂ¡ 330/202
(51) 3337 1237

Today Fortune tells us:
The most important service rendered by the press is that of educating
people to approach printed matter with distrust.

Re: [lpc2000] C union not working

2005-03-17 by Micron Engineering

Leonardo Santos wrote:

>Hello All:
>	I'm working with a LPC2106 using the GCC 3.4.4 toolchain (GCC + binutils 2.15 
>+ newlib 1.13).	I wrote a union and a structure to access the P0 pins 
>individually, like this:
>
>typedef struct {
>	int p0	: 1;
>	int p1	: 1;
>	int p2	: 1;
>(...)
>	int p30	: 1;
>	int p31	: 1;
>}port_t;
>
>typedef union {
>	port_t pins;
>	unsigned int reg;
>} ioreg;
>
>typedef struct {
>	ioreg iopin;
>	ioreg ioset;
>	ioreg iodir;
>	ioreg ioclr;
>}gpio_t;
>
>So I declare a pinter like
>
>	volatile gpio_t *gpio = 0xE0028000;
>
>If I access the registers using 
>
>	if( gpio->iopin.reg & 0x01 )
>
>or 
>
>	gpio->ioset.reg |= 0x00008000;
>
>Everithing works fine! But if I try a code like this:
>
>	gpio->ioset.pins.p15 = 1;
>
>To set P0.15, P0.23 and P0.31 are set too! 
>
Seems as if the bit field is a short int...

>I had tried this code in my Linux 
>workstaion and it works just fine. The compiles setting I'm using are 
>
>arm-elf-gcc -c -Wall -D GCC_ARM7 -mcpu=arm7tdmi -Tlpc2106-rom.ld -Wcast-align 
>-O3
>
>So I'm compiling it in ARM mode. Any clues? Is this a compiler issue ( I'm not 
>using the right parameters)?
>
>Thanks a lot!
>
>  
>



-- 
No virus found in this outgoing message.
Checked by AVG Anti-Virus.
Version: 7.0.308 / Virus Database: 266.7.3 - Release Date: 15/03/2005

Re: [lpc2000] C union not working

2005-03-17 by Robert Adsett

At 12:06 PM 3/17/05 -0300, Leonardo Santos wrote:

>Hello All:
>         I'm working with a LPC2106 using the GCC 3.4.4 toolchain (GCC + 
> binutils 2.15
>+ newlib 1.13). I wrote a union and a structure to access the P0 pins
>individually, like this:
>
>typedef struct {
>         int p0  : 1;
>         int p1  : 1;
>         int p2  : 1;
>(...)
>         int p30 : 1;
>         int p31 : 1;
>}port_t;
>
>typedef union {
>         port_t pins;
>         unsigned int reg;
>} ioreg;
>
>typedef struct {
>         ioreg iopin;
>         ioreg ioset;
>         ioreg iodir;
>         ioreg ioclr;
>}gpio_t;
>
>So I declare a pinter like
>
>         volatile gpio_t *gpio = 0xE0028000;
>
>If I access the registers using
>
>         if( gpio->iopin.reg & 0x01 )
>
>or
>
>         gpio->ioset.reg |= 0x00008000;
>
>Everithing works fine! But if I try a code like this:
>
>         gpio->ioset.pins.p15 = 1;

P15 is a 1 bit int so its only values are 0 and -1 but I don't think that's 
the problem.   Provided your bit order is correct I don't see any reason 
they shouldn't give the same result.  I'd use unsigned int for bitfields 
unless you wanted them to be signed for some particular purpose.


>To set P0.15, P0.23 and P0.31 are set too! I had tried this code in my Linux
>workstaion and it works just fine. The compiles setting I'm using are

Hmm, those are 8 bits apart.  Have you taken a look at the assembly output 
for the two cases?  They should be similar if not identical. Unless the 
compiler is getting confused by some sort of sign extension issue?  Seems a 
stretch though.

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] C union not working

2005-03-17 by Anton Erasmus

On 17 Mar 2005 at 12:06, Leonardo Santos wrote:

> 
> Hello All:
>  I'm working with a LPC2106 using the GCC 3.4.4 toolchain (GCC +
>  binutils 2.15 
> + newlib 1.13).	I wrote a union and a structure to access the P0 pins 
> individually, like this:
> 
> typedef struct {
>  int p0	: 1;
>  int p1	: 1;
>  int p2	: 1;
> (...)
>  int p30	: 1;
>  int p31	: 1;
> }port_t;
> 
> typedef union {
>  port_t pins;
>  unsigned int reg;
> } ioreg;
> 
> typedef struct {
>  ioreg iopin;
>  ioreg ioset;
>  ioreg iodir;
>  ioreg ioclr;
> }gpio_t;
> 
> So I declare a pinter like
> 
>  volatile gpio_t *gpio = 0xE0028000;
> 
> If I access the registers using 
> 
>  if( gpio->iopin.reg & 0x01 )
> 
> or 
> 
>  gpio->ioset.reg |= 0x00008000;
> 
> Everithing works fine! But if I try a code like this:
> 
>  gpio->ioset.pins.p15 = 1;
> 
> To set P0.15, P0.23 and P0.31 are set too! I had tried this code in my
> Linux workstaion and it works just fine. The compiles setting I'm
> using are 
> 
> arm-elf-gcc -c -Wall -D GCC_ARM7 -mcpu=arm7tdmi -Tlpc2106-rom.ld
> -Wcast-align -O3
> 
> So I'm compiling it in ARM mode. Any clues? Is this a compiler issue (
> I'm not using the right parameters)?
> 

If you are using packed structs, then this will fail. The compiler generates byte
accesses to structures.  The best thing is to look at the assembler output 
to see what is actually happening.

Regards
  Anton Erasmus


-- 
A J Erasmus

Re: C union not working

2005-03-19 by jamesasteres

I don't believe the ARM has bit access instructions.  So when the 
compiler reads the ioset register (or a byte of it?) according to 
the datasheet you will read what was previously written.  So you 
risk setting unwanted pins (likely).
James

--- In lpc2000@yahoogroups.com, Leonardo Santos <lsantos@p...> wrote:
> Hello All:
> 	I'm working with a LPC2106 using the GCC 3.4.4 toolchain 
(GCC + binutils 2.15 
> + newlib 1.13).	I wrote a union and a structure to access 
the P0 pins 
> individually, like this:
> 
> typedef struct {
> 	int p0	: 1;
> 	int p1	: 1;
> 	int p2	: 1;
> (...)
> 	int p30	: 1;
> 	int p31	: 1;
> }port_t;
> 
> typedef union {
> 	port_t pins;
> 	unsigned int reg;
> } ioreg;
> 
> typedef struct {
> 	ioreg iopin;
> 	ioreg ioset;
> 	ioreg iodir;
> 	ioreg ioclr;
> }gpio_t;
> 
> So I declare a pinter like
> 
> 	volatile gpio_t *gpio = 0xE0028000;
> 
> If I access the registers using 
> 
> 	if( gpio->iopin.reg & 0x01 )
> 
> or 
> 
> 	gpio->ioset.reg |= 0x00008000;
> 
> Everithing works fine! But if I try a code like this:
> 
> 	gpio->ioset.pins.p15 = 1;
> 
> To set P0.15, P0.23 and P0.31 are set too! I had tried this code 
in my Linux 
> workstaion and it works just fine. The compiles setting I'm using 
are 
> 
> arm-elf-gcc -c -Wall -D GCC_ARM7 -mcpu=arm7tdmi -Tlpc2106-rom.ld -
Wcast-align 
> -O3
> 
> So I'm compiling it in ARM mode. Any clues? Is this a compiler 
issue ( I'm not 
> using the right parameters)?
> 
> Thanks a lot!
> 
> -- 
> This is Linux country.
> On a quiet night, you can hear Windows reboot.
> 
> Leonardo Pereira Santos
> Engenheiro de Projetos
> PD3 Tecnologia
> av. ParĂ¡ 330/202
> (51) 3337 1237
> 
> Today Fortune tells us:
> The most important service rendered by the press is that of 
educating
> people to approach printed matter with distrust.

Re: [lpc2000] Re: C union not working

2005-03-20 by Robert Adsett

At 05:08 PM 3/19/05 +0000, jamesasteres wrote:
>I don't believe the ARM has bit access instructions.  So when the
>compiler reads the ioset register (or a byte of it?) according to
>the datasheet you will read what was previously written.  So you
>risk setting unwanted pins (likely).

That's true, but I don't think it's relevant in this case.  IOSET is 
documented to read back the last values the port was set to

> >       gpio->ioset.reg |= 0x00008000;

Should read the current set value for the port and set the 16'th bit and 
any other bits that are already set.  While

> >       gpio->ioset.pins.p15 = 1;

should logically do the same (after logically doing the appropriate sign 
wrapping which ends up being a null operation).  Anton's earlier question 
about packed structs is probably very much to the point.  It never occurs 
to me that anyone would use packed structs on an architecture that doesn't 
support unaligned access.  Certainly accessing any of the peripheral 
registers on anything other than a word boundary could cause interesting 
results.

Perhaps Leonardo can report back the results of the investigation when it's 
finished ?

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: C union not working

2005-03-20 by Arie de Muynck

From: "Robert Adsett" <subscriptions@...>
> At 05:08 PM 3/19/05 +0000, jamesasteres wrote:
> >I don't believe the ARM has bit access instructions.  So when the
> >compiler reads the ioset register (or a byte of it?) according to
> >the datasheet you will read what was previously written.  So you
> >risk setting unwanted pins (likely).
>
> That's true, but I don't think it's relevant in this case.  IOSET is
> documented to read back the last values the port was set to
>
> > >       gpio->ioset.reg |= 0x00008000;
>
> Should read the current set value for the port and set the 16'th bit and
> any other bits that are already set.  While
>
> > >       gpio->ioset.pins.p15 = 1;
>
> should logically do the same (after logically doing the appropriate sign
> wrapping which ends up being a null operation).  Anton's earlier question
> about packed structs is probably very much to the point.  It never occurs
> to me that anyone would use packed structs on an architecture that doesn't
> support unaligned access.  Certainly accessing any of the peripheral
> registers on anything other than a word boundary could cause interesting
> results.
>
> Perhaps Leonardo can report back the results of the investigation when
it's
> finished ?
>
> Robert

The GCC compiler tries to optimize the access for bitfields. It combines
multiple sequential set and clear instruction to the same bitfield into one
AND-OR pattern, then determines the minimal necessary width. If that fits
inside one byte, it just changes that single byte, irrespective the width of
the total bitfield.
This is fine for memory (RAM) operations on most processors, even the ARM -
unfortunately  it is deadly to I/O registers that can only be read and
written 32-bits wide.

I've seen a nice example in the NetSilicon NET+ARM BSP, originally written
for ADS using bitfields for the registers, and completely rewritten for all
I/O access to be able to use the GCC compiler.

Regards,
Arie de Muynck

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.