EmbeddedRelated.com
Forums

Cortex-M0 GPIO shadow registers

Started by Unknown March 29, 2012
Il 30/03/2012 11:50, Phil Young ha scritto:
>
>
> You completely missed the point here.
> In the masked operation preparing the value to be written using the masked
> register access can take millions of cycles without causing a problem.
> There is no hazard since the updating of the GPIO using the masked write
> interface involves a single access to the GPIO register.
>
> So for the purposes of hazard analysis this is an atomic operation.
>
> Using a read modify write approach is not.
>
I wasn't very clear. I told about bit-banding that permit atomic
operations; when I say 32bit registers I mean in this context 32bit i/o
registers so using them with mask registers, another form of atomic
operations to access i/o registers.

So to be more clear: when you need to set or clear more then 1 bit on a
register it is better to use 32bit registers using properly mask
registers, when you need to set or clear 1 bit only you can use bit-banding.

Technically speaking, CMSIS as imposed by ARM to silicon vendors doesn't
make possible to optimize too much i/o access.

If you search i/o definition files for ARM7 or ARM9 microcontrollers as
LPC2148 you could see that i/o registers are defined in a different way
using #defines with the address embedded on them. The main difference is
when the compiler computes the destination address. If you wish lowest
access time you should write a define with the destination address
embedded on it so there is no need to calculate it at run time.

Actually CMSIS compliant i/o definition for Cortex-M microcontrollers
require use of union of structs and arrays, so the destination address
have to be calculated at run time.
> Regards
>
> Phil.
>
> -----Original Message-----
> From: l...
> [mailto:l... ] On
> Behalf Of
> M. Manca
> Sent: 30 March 2012 10:21
> To: l...
> Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers
>
> Il 30/03/2012 05:56, AndrRairan ha scritto:
> > Ok, now I got it.
> >
> > There are 4096 registers because they are the masks! pretty obvious...
> > I was thinking that you have to write in a mask for after using it, but
> they are the mask already.
> > Thats right?
> >
> > But my second questions stays.
> > What's the difference between:
> >
> > LPC_GPIO3->MASKED_ACCESS[ 0x01 ] = 0x01; and LPC_GPIO3->DATA |= 0x01;
> >
> > They both aren't single cycle?
> Both AREN'T single cycle, they are a sequence of movs, lsls, (orrs
> only for
> the second with |=) and str.
> str that is the last instruction performs the write to the register.
>
> In general ARM architectures have no particular feeling with i/o
> management.
> In Cortex-M series there is the possibility for the silicon vendors to
> implement a bit-banding region that permits to access real single bits as
> they were bytes so we can say that bit-banding is a memory region
> devoted to
> bit access "shadowing" them as bytes so Cortex-M processor don't need bit
> access special instructions.
>
> This may be an advantage if you have to access just 1 bit but if you
> need to
> access more bits it is better to access the 32bit registers because to set
> bits performance of C compiler is the same, for toggling, oring and anding
> there is always one more instruction.
> >
> >
> > AndrRairan.
> >
> >
> > On Mar 29, 2012, at 11:54 PM, Phil Young wrote:
> >
> >> Hi Andr
> >>
> >> The whole point of masked access is to avoid conflicts with
> >> interrupts, and it's really easy to use in most cases.
> >>
> >> I use the following macros for setting and clearing bits.
> >>
> >> #define SET_GPIO(Port,Bits)(Port->MASKED_ACCESS[(Bits)] = (Bits))
> >> #define CLR_GPIO(Port,Bits)(Port->MASKED_ACCESS[(Bits)] = (0))
> >>
> >> Then I define macro's for the ports to make the code more portable,
> e.g.
> >> #define ISR_LED_ON SET_GPIO(LPC_GPIO3,0x1) // P3.0 #define
> >> ISR_LED_OFF CLR_GPIO(LPC_GPIO3,0x1)
> >>
> >> Of course if you change multiple bits you can simply clear the
> >> inverse using another SW mask then set the bits required ( a slightly
> >> more complex macro ).
> >> e.g.
> >>
> >> #define
> >> PUT_GPIO(Port,Value,Mask)(CLR_GPIO(Port,(Mask));SET_GPIO(Port,(Value)
> >> ))
> >>
> >> Or slightly better but probably a CPU cycle longer
> >>
> >> #define PUT_GPIO(Port,Value,Mask)(CLR_GPIO(Port,(Mask) &
> >> ~(Value));SET_GPIO(Port,(Value)))
> >>
> >> This will of course lead to a couple of CPU cycles when the bits are
> >> neither the old or new value, but for most cases that doesn't matter.
> >>
> >> If you need to change multiple bits and they must transition
> >> "simultaneously" then you have to do as Olivier suggested but then
> >> also you need to disable interrupts before the sequence and re-enable
> >> them immediately afterwards.
> >>
> >> Also using the masked approach if you change bits in multiple threads
> >> you need to restore the mask in anything but the lowest priority
> >> thread, though this can be done after re-enabling interrupts so that
> >> you don't affect interrupt latency too much.
> >>
> >> Regards
> >>
> >> Phil.
> >>
> >> -----Original Message-----
> >> From: l...
> [mailto:l... ] On
> >> Behalf Of Olivier Gautherot
> >> Sent: 30 March 2012 02:15
> >> To: l...
> >> Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers
> >>
> >> Hi Andr
> >>
> >> the mask register defines the bits that your operation is allowed to
> modify.
> >> This way, you don't need read-modify-write cycles in software but
> >> simply set the mask and write your value.
> >>
> >> I would suggest you use the following sequence on ***ALL*** accesses
> >> (more on "***ALL***" below):
> >> - backup the mask register
> >> - set the mask to the value you want
> >> - write your value to the port (note that masked bits are not
> >> relevant, so you may simplify your code)
> >> - restore the mask
> >>
> >> By doing this on all accesses, you're likely not to worry about
> >> interrupts, except if your sequence needs to need a precise timing or
> >> if the interrupt may change the sequence. Likewise, you have a SET
> >> and CLEAR registers that can simplify single bits operations. It's
> actually a nice feature.
> >>
> >> Hope it helps
> >> Cheers
> >> Olivier
> >>
> >> AndrRairan wrote:
> >>> Hello guys,
> >>>
> >>> I just can't figure out how the shadow registers works on Cortex-M0,
> >>> i'm
> >> using LPC11C14.
> >>> I'm doing this way now, using CMSIS:
> >>> LPC_GPIO0->DATA |= (0x1<< bit);
> >>> or
> >>> LPC_GPIO0->DATA&= ~(0x1<< bit);
> >>>
> >>> writing directly on GPIOnDATA register... As I could understand
> >>> writing
> >> directly to this register set all mask bits to 1 allowing directly
> access.
> >>> This way of doing is wrong or unsafe?
> >>> Why use masked access?
> >>>
> >>>
> >>> following...
> >>> this in on CMSIS file:
> >>>
> >>> union {
> >>> __IO uint32_t MASKED_ACCESS[4096]; /*!< Offset: 0x0000 to 0x3FFC
> >> Port data Register for pins PIOn_0 to PIOn_11 (R/W) */
> >>> struct {
> >>> uint32_t RESERVED0[4095];
> >>> __IO uint32_t DATA; /*!< Offset: 0x3FFC Port data
> >> Register (R/W) */
> >>> };
> >>>
> >>>
> >>> I read the pages 185 to 187, but I really can't understand it.
> >>>
> >>> How do I use the masks?
> >>> Wich one should I use?
> >>> Should I make some think like this:
> >>>
> >>> LPC_GPIO0->MASKED_ACCESS[ 0 ] = 0x01<< 2; LPC_GPIO0->DATA = 0xFF;
> >>>
> >>> This would set just the first bit?
> >>>
> >>>
> >>> Thanks,
> >>> AndrRairan.
> >>>
> >>>
> >>>
> >>>

An Engineer's Guide to the LPC2100 Series

Il 30/03/2012 12:18, Wouter van Ooijen ha scritto:
>
>
> > In the masked operation preparing the value to be written using the
> masked
> > register access can take millions of cycles without causing a problem.
> > There is no hazard since the updating of the GPIO using the masked write
> > interface involves a single access to the GPIO register.
> >
> > So for the purposes of hazard analysis this is an atomic operation.
>
> Only when there the mask register is used by just one thread!
>
First of all dividing tasks or threads operations is not a trivial thing
and it is a not recommended practice to have 2 concurrent threads to
set/clear bits on the same i/o register and I should say that different
tasks/threads shouldn't access the same peripheral. It is a lot better
introduce a 3rd task to manage only the peripheral having the 2 older
tasks to communicate to the 3rd via messages or mailboxes. When 2
tasks/threads needs both to set/clear the same bit or the same byteflag
is a signal that you have to use an o.s. data struct to do this or
better you have to redesign what the 2 tasks have to do.

Any way it may be a problem. In this case the correct solution is use
bit-banding (bit by bit) but this means you need just 1 bit or that
using more bits you accept the possibility to have interruptions between
bit writing operations.
>
> --
>
> Wouter van Ooijen
>
> -- -------
> Van Ooijen Technische Informatica: www.voti.nl
> consultancy, development, PICmicro products
> docent Hogeschool van Utrecht: www.voti.nl/hvu
> C++ on uC blog: http://www.voti.nl/erblog



Phil, Wouter,

you are both right. I think Wouter meant that if thread A sets the mask
register and then writes to the port and, in between thread B sets the
mask to a different value and does not restore it, thread A will not
have the expected effect. In this sense, the sequence "write mask",
"write port" is not atomic. That's why I recommended to save the mask
and restore it - in most cases it will waste cycles but it's for the
sake of safety.

Cheers
Olivier
Phil Young wrote:
>
> Again, you missed the point.
>
> With the LPC1114 the masked register write is an atomic operation.
>
> The lower address bits are used as the mask, so a single write operation
> performs a masked update of the register.
>
> There is no physical mask register involved, it's a virtual mask.
>
> It IS ALWAYS atomic.
>
> Regards
>
> Phil.
>
> From: l...
> [mailto:l... ] On
> Behalf Of
> Wouter van Ooijen
> Sent: 30 March 2012 11:18
> To: l...
> Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers
>
> > In the masked operation preparing the value to be written using the
> masked
> > register access can take millions of cycles without causing a problem.
> > There is no hazard since the updating of the GPIO using the masked write
> > interface involves a single access to the GPIO register.
> >
> > So for the purposes of hazard analysis this is an atomic operation.
>
> Only when there the mask register is used by just one thread!
>
> --
>
> Wouter van Ooijen
>
> -- -------
> Van Ooijen Technische Informatica: www.voti.nl
> consultancy, development, PICmicro products
> docent Hogeschool van Utrecht: www.voti.nl/hvu
> C++ on uC blog: http://www.voti.nl/erblog
>
>
--

Olivier Gautherot
*Email:* o...@gautherot.net
*Cel:* +56 98 730 9361
*Web:* www.gautherot.net
*LinkedIn:* http://www.linkedin.com/in/ogautherot



Hi Wouter,

It's quite common to have multiple tasks needing to set / clear bits on the
same IO register, particularly when using standard parts since you have to
work within the constraints of pin multiplexing.

Whenever I design a SOC I define suitable IO port mappings to avoid this,
but that's not possible with a generic device.

The traditional way to handle this is by disabling interrupts to perform the
port update, but that's not ideal, so NXP provided an excellent mechanism to
overcome this by providing the virtual mask mechanism, i.e using the address
bits as a mask for bits to modify in the port. It's a very elegant solution.

Using inter task communication for handling low level IO is extremely
inefficient and non-deterministic, for example I have to bit-bash the RMII
interface to the Ethernet PHY on an LPC1758 and using inter-task
communication for this would be coimpletely inappropriate.

So I completely disagree with you in this case, the correct solution is to
use the hardware in the way that it was designed, use the masked IO
operations rather than bit-banding.

Bit Banding is a comparatively poor solution designed to enable the ARM to
emulate this behaviour on platform where the hardware does not support these
masked operations, it should always be the second choice when HW exists for
the purpose.

Regards

Phil.

From: l... [mailto:l...] On Behalf Of
M. Manca
Sent: 30 March 2012 11:46
To: l...
Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers

Il 30/03/2012 12:18, Wouter van Ooijen ha scritto:
> > In the masked operation preparing the value to be written using the
> masked
> > register access can take millions of cycles without causing a problem.
> > There is no hazard since the updating of the GPIO using the masked write
> > interface involves a single access to the GPIO register.
> >
> > So for the purposes of hazard analysis this is an atomic operation.
>
> Only when there the mask register is used by just one thread!
>
First of all dividing tasks or threads operations is not a trivial thing
and it is a not recommended practice to have 2 concurrent threads to
set/clear bits on the same i/o register and I should say that different
tasks/threads shouldn't access the same peripheral. It is a lot better
introduce a 3rd task to manage only the peripheral having the 2 older
tasks to communicate to the 3rd via messages or mailboxes. When 2
tasks/threads needs both to set/clear the same bit or the same byteflag
is a signal that you have to use an o.s. data struct to do this or
better you have to redesign what the 2 tasks have to do.

Any way it may be a problem. In this case the correct solution is use
bit-banding (bit by bit) but this means you need just 1 bit or that
using more bits you accept the possibility to have interruptions between
bit writing operations.
>
> --
>
> Wouter van Ooijen
>
> -- -------
> Van Ooijen Technische Informatica: www.voti.nl
> consultancy, development, PICmicro products
> docent Hogeschool van Utrecht: www.voti.nl/hvu
> C++ on uC blog: http://www.voti.nl/erblog





Il 30/03/2012 12:31, Phil Young ha scritto:
>
>
> Again, you missed the point.
>
> With the LPC1114 the masked register write is an atomic operation.
>
> The lower address bits are used as the mask, so a single write operation
> performs a masked update of the register.
>
> There is no physical mask register involved, it's a virtual mask.
>
This is absolutely not true. If you look with attention to GPIO
structure of LPC11U14 for instance you will see that the 2 i/o ports
(PORT0 and PORT1) have both 32bit i/o bytes in the bit-banding region
from 0x50000000 to 0x5000003f and then you will find that P0MASK and
P1MASK at 0x50002080 and 0x50002084 to be used with P0SET/P0CLR and
P1SET/P1CLR. So to use the mask feature you have to write before to the
mask register and after to the set or clear register. This last write
will change the i/o pin status. So it is an atomic operation made
possible by the hardware registers but it is not a full atomic operation
at all. The demonstration is simple; take a task that interrupts your
operation after writing to the mask register and before writing to the
data register and think what happen if that task alters the mask
register. As I said in a previous post this is not a good way to
programming but demonstrates that it is not a full atomic operation,
they are 2 atomic operations 1 to write to the mask register and the 2nd
to write the data using the set or the clr register.
> It IS ALWAYS atomic.
>
> Regards
>
> Phil.
>
> From: l...
> [mailto:l... ] On
> Behalf Of
> Wouter van Ooijen
> Sent: 30 March 2012 11:18
> To: l...
> Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers
>
> > In the masked operation preparing the value to be written using the
> masked
> > register access can take millions of cycles without causing a problem.
> > There is no hazard since the updating of the GPIO using the masked write
> > interface involves a single access to the GPIO register.
> >
> > So for the purposes of hazard analysis this is an atomic operation.
>
> Only when there the mask register is used by just one thread!
>
> --
>
> Wouter van Ooijen
>
> -- -------
> Van Ooijen Technische Informatica: www.voti.nl
> consultancy, development, PICmicro products
> docent Hogeschool van Utrecht: www.voti.nl/hvu
> C++ on uC blog: http://www.voti.nl/erblog
>
>



I know that stelaris family from texas have it.
Does NXP implemented it also?
On Mar 30, 2012, at 6:21 AM, M. Manca wrote:

> Il 30/03/2012 05:56, André Rairan ha scritto:
>> Ok, now I got it.
>>
>> There are 4096 registers because they are the masks! pretty obvious...
>> I was thinking that you have to write in a mask for after using it, but they are the mask already.
>> Thats right?
>>
>> But my second questions stays.
>> What's the difference between:
>>
>> LPC_GPIO3->MASKED_ACCESS[ 0x01 ] = 0x01;
>> and
>> LPC_GPIO3->DATA |= 0x01;
>>
>> They both aren't single cycle?
> Both AREN'T single cycle, they are a sequence of movs, lsls, (orrs only
> for the second with |=) and str.
> str that is the last instruction performs the write to the register.
>
> In general ARM architectures have no particular feeling with i/o
> management. In Cortex-M series there is the possibility for the silicon
> vendors to implement a bit-banding region that permits to access real
> single bits as they were bytes so we can say that bit-banding is a
> memory region devoted to bit access "shadowing" them as bytes so
> Cortex-M processor don't need bit access special instructions.
>
> This may be an advantage if you have to access just 1 bit but if you
> need to access more bits it is better to access the 32bit registers
> because to set bits performance of C compiler is the same, for toggling,
> oring and anding there is always one more instruction.
>>
>>
>> André Rairan.
>>
>>
>> On Mar 29, 2012, at 11:54 PM, Phil Young wrote:
>>
>>> Hi André,
>>>
>>> The whole point of masked access is to avoid conflicts with interrupts, and
>>> it's really easy to use in most cases.
>>>
>>> I use the following macros for setting and clearing bits.
>>>
>>> #define SET_GPIO(Port,Bits)(Port->MASKED_ACCESS[(Bits)] = (Bits))
>>> #define CLR_GPIO(Port,Bits)(Port->MASKED_ACCESS[(Bits)] = (0))
>>>
>>> Then I define macro's for the ports to make the code more portable, e.g.
>>> #define ISR_LED_ON SET_GPIO(LPC_GPIO3,0x1) // P3.0
>>> #define ISR_LED_OFF CLR_GPIO(LPC_GPIO3,0x1)
>>>
>>> Of course if you change multiple bits you can simply clear the inverse using
>>> another SW mask then set the bits required ( a slightly more complex macro
>>> ).
>>> e.g.
>>>
>>> #define
>>> PUT_GPIO(Port,Value,Mask)(CLR_GPIO(Port,(Mask));SET_GPIO(Port,(Value)))
>>>
>>> Or slightly better but probably a CPU cycle longer
>>>
>>> #define PUT_GPIO(Port,Value,Mask)(CLR_GPIO(Port,(Mask) &
>>> ~(Value));SET_GPIO(Port,(Value)))
>>>
>>> This will of course lead to a couple of CPU cycles when the bits are neither
>>> the old or new value, but for most cases that doesn't matter.
>>>
>>> If you need to change multiple bits and they must transition
>>> "simultaneously" then you have to do as Olivier suggested but then also you
>>> need to disable interrupts before the sequence and re-enable them
>>> immediately afterwards.
>>>
>>> Also using the masked approach if you change bits in multiple threads you
>>> need to restore the mask in anything but the lowest priority thread, though
>>> this can be done after re-enabling interrupts so that you don't affect
>>> interrupt latency too much.
>>>
>>> Regards
>>>
>>> Phil.
>>>
>>> -----Original Message-----
>>> From: l... [mailto:l...] On Behalf Of
>>> Olivier Gautherot
>>> Sent: 30 March 2012 02:15
>>> To: l...
>>> Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers
>>>
>>> Hi André,
>>>
>>> the mask register defines the bits that your operation is allowed to modify.
>>> This way, you don't need read-modify-write cycles in software but simply set
>>> the mask and write your value.
>>>
>>> I would suggest you use the following sequence on ***ALL*** accesses (more
>>> on "***ALL***" below):
>>> - backup the mask register
>>> - set the mask to the value you want
>>> - write your value to the port (note that masked bits are not relevant, so
>>> you may simplify your code)
>>> - restore the mask
>>>
>>> By doing this on all accesses, you're likely not to worry about interrupts,
>>> except if your sequence needs to need a precise timing or if the interrupt
>>> may change the sequence. Likewise, you have a SET and CLEAR registers that
>>> can simplify single bits operations. It's actually a nice feature.
>>>
>>> Hope it helps
>>> Cheers
>>> Olivier
>>>
>>> André Rairan wrote:
>>>> Hello guys,
>>>>
>>>> I just can't figure out how the shadow registers works on Cortex-M0, i'm
>>> using LPC11C14.
>>>> I'm doing this way now, using CMSIS:
>>>> LPC_GPIO0->DATA |= (0x1<< bit);
>>>> or
>>>> LPC_GPIO0->DATA&= ~(0x1<< bit);
>>>>
>>>> writing directly on GPIOnDATA register∑ As I could understand writing
>>> directly to this register set all mask bits to 1 allowing directly access.
>>>> This way of doing is wrong or unsafe?
>>>> Why use masked access?
>>>>
>>>>
>>>> following...
>>>> this in on CMSIS file:
>>>>
>>>> union {
>>>> __IO uint32_t MASKED_ACCESS[4096]; /*!< Offset: 0x0000 to 0x3FFC
>>> Port data Register for pins PIOn_0 to PIOn_11 (R/W) */
>>>> struct {
>>>> uint32_t RESERVED0[4095];
>>>> __IO uint32_t DATA; /*!< Offset: 0x3FFC Port data
>>> Register (R/W) */
>>>> };
>>>>
>>>>
>>>> I read the pages 185 to 187, but I really can't understand it.
>>>>
>>>> How do I use the masks?
>>>> Wich one should I use?
>>>> Should I make some think like this:
>>>>
>>>> LPC_GPIO0->MASKED_ACCESS[ 0 ] = 0x01<< 2; LPC_GPIO0->DATA = 0xFF;
>>>>
>>>> This would set just the first bit?
>>>>
>>>>
>>>> Thanks,
>>>> André Rairan.
>>>>
>>>>
>>>>
>>>>
Why are you writing to the mask register?.

You should study the user manual again, it's not necessary.

See the compiler output below, there is NO write to the mask register.

51: ISR_LED_ON; // defined to null when LED's disabled

52:

53: //~~~~~~~~~~~~ ensure LCD reset is held long enough if LCD
enabled

0x00000F02 4BFF LDR r3,[pc,#1020] ; // get address of register
into R3

0x00000F04 B08E SUB sp,sp,#0x38 //This is not part of the
operation, but optimization enables instruction re-ordering

0x00000F06 2101 MOVS r1,#0x01 // get bit to be set

0x00000F08 6059 STR r1,[r3,#0x04] // perform masked IO port update

Taken from the user manual, this is dedicated HW for the GPIO ports, it does
NOT use the bit-banding mechanism.

Write/read data operation

In order for software to be able to set GPIO bits without affecting any
other pins in a single

write operation, bits [13:2] of a 14-bit wide address bus are used to create
a 12-bit wide

mask for write and read operations on the 12 GPIO pins for each port. Only
GPIOnDATA

bits masked by 1 are affected by read and write operations. The masked
GPIOnDATA

register can be located anywhere between address offsets 0x0000 to 0x3FFC in
the

GPIOn address space. Reading and writing to the GPIOnDATA register at
address

0x3FFC sets all masking bits to 1.

Regards

Phil.

From: l... [mailto:l...] On Behalf Of
M. Manca
Sent: 30 March 2012 12:03
To: l...
Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers

Il 30/03/2012 12:31, Phil Young ha scritto:
> Again, you missed the point.
>
> With the LPC1114 the masked register write is an atomic operation.
>
> The lower address bits are used as the mask, so a single write operation
> performs a masked update of the register.
>
> There is no physical mask register involved, it's a virtual mask.
>
This is absolutely not true. If you look with attention to GPIO
structure of LPC11U14 for instance you will see that the 2 i/o ports
(PORT0 and PORT1) have both 32bit i/o bytes in the bit-banding region
from 0x50000000 to 0x5000003f and then you will find that P0MASK and
P1MASK at 0x50002080 and 0x50002084 to be used with P0SET/P0CLR and
P1SET/P1CLR. So to use the mask feature you have to write before to the
mask register and after to the set or clear register. This last write
will change the i/o pin status. So it is an atomic operation made
possible by the hardware registers but it is not a full atomic operation
at all. The demonstration is simple; take a task that interrupts your
operation after writing to the mask register and before writing to the
data register and think what happen if that task alters the mask
register. As I said in a previous post this is not a good way to
programming but demonstrates that it is not a full atomic operation,
they are 2 atomic operations 1 to write to the mask register and the 2nd
to write the data using the set or the clr register.
> It IS ALWAYS atomic.
>
> Regards
>
> Phil.
>
> From: l...

> [mailto:l...
] On
> Behalf Of
> Wouter van Ooijen
> Sent: 30 March 2012 11:18
> To: l...

> Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers
>
> > In the masked operation preparing the value to be written using the
> masked
> > register access can take millions of cycles without causing a problem.
> > There is no hazard since the updating of the GPIO using the masked write
> > interface involves a single access to the GPIO register.
> >
> > So for the purposes of hazard analysis this is an atomic operation.
>
> Only when there the mask register is used by just one thread!
>
> --
>
> Wouter van Ooijen
>
> -- -------
> Van Ooijen Technische Informatica: www.voti.nl
> consultancy, development, PICmicro products
> docent Hogeschool van Utrecht: www.voti.nl/hvu
> C++ on uC blog: http://www.voti.nl/erblog
>
>





A couple of important points.

I use CMSIS where it makes sense, but CMSIS does not IMPOSE anything, its
just there to make life a little easier.



The CMSIS files provided by a vendor for their HW must follow certain
guidelines, but they are free to provide whatever functions they like.



The NXP provided CMSIS header include register definitions providing full
support of the masked write operations, I use these register definitions.



See the following from the NXP provided CMSIS compliant headers for the
LPC1114.



/*------------- General Purpose Input/Output (GPIO)
--------------------------*/

/** @addtogroup LPC11xx_GPIO LPC11xx General Purpose Input/Output

@{

*/

typedef struct

{

union {

__IO uint32_t MASKED_ACCESS[4096]; /*!< Offset: 0x0000 to 0x3FFC Port
data Register for pins PIOn_0 to PIOn_11 (R/W) */

struct {

uint32_t RESERVED0[4095];

__IO uint32_t DATA; /*!< Offset: 0x3FFC Port data
Register (R/W) */

};

};

uint32_t RESERVED1[4096];

__IO uint32_t DIR; /*!< Offset: 0x8000 Data direction
Register (R/W) */

__IO uint32_t IS; /*!< Offset: 0x8004 Interrupt sense
Register (R/W) */

__IO uint32_t IBE; /*!< Offset: 0x8008 Interrupt both
edges Register (R/W) */

__IO uint32_t IEV; /*!< Offset: 0x800C Interrupt event
Register (R/W) */

__IO uint32_t IE; /*!< Offset: 0x8010 Interrupt mask
Register (R/W) */

__IO uint32_t RIS; /*!< Offset: 0x8014 Raw interrupt
status Register (R/ ) */

__IO uint32_t MIS; /*!< Offset: 0x8018 Masked interrupt
status Register (R/ ) */

__IO uint32_t IC; /*!< Offset: 0x801C Interrupt clear
Register (R/W) */

} LPC_GPIO_TypeDef;

/*@}*/ /* end of group LPC11xx_GPIO */



Regards



Phil.



From: l... [mailto:l...] On Behalf Of
M. Manca
Sent: 30 March 2012 11:36
To: l...
Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers





Il 30/03/2012 11:50, Phil Young ha scritto:
>
>
> You completely missed the point here.
> In the masked operation preparing the value to be written using the masked
> register access can take millions of cycles without causing a problem.
> There is no hazard since the updating of the GPIO using the masked write
> interface involves a single access to the GPIO register.
>
> So for the purposes of hazard analysis this is an atomic operation.
>
> Using a read modify write approach is not.
>
I wasn't very clear. I told about bit-banding that permit atomic
operations; when I say 32bit registers I mean in this context 32bit i/o
registers so using them with mask registers, another form of atomic
operations to access i/o registers.

So to be more clear: when you need to set or clear more then 1 bit on a
register it is better to use 32bit registers using properly mask
registers, when you need to set or clear 1 bit only you can use bit-banding.

Technically speaking, CMSIS as imposed by ARM to silicon vendors doesn't
make possible to optimize too much i/o access.

If you search i/o definition files for ARM7 or ARM9 microcontrollers as
LPC2148 you could see that i/o registers are defined in a different way
using #defines with the address embedded on them. The main difference is
when the compiler computes the destination address. If you wish lowest
access time you should write a define with the destination address
embedded on it so there is no need to calculate it at run time.

Actually CMSIS compliant i/o definition for Cortex-M microcontrollers
require use of union of structs and arrays, so the destination address
have to be calculated at run time.
> Regards
>
> Phil.
>
> -----Original Message-----
> From: l...

> [mailto:l...
] On
> Behalf Of
> M. Manca
> Sent: 30 March 2012 10:21
> To: l...

> Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers
>
> Il 30/03/2012 05:56, AndrRairan ha scritto:
> > Ok, now I got it.
> >
> > There are 4096 registers because they are the masks! pretty obvious...
> > I was thinking that you have to write in a mask for after using it, but
> they are the mask already.
> > Thats right?
> >
> > But my second questions stays.
> > What's the difference between:
> >
> > LPC_GPIO3->MASKED_ACCESS[ 0x01 ] = 0x01; and LPC_GPIO3->DATA |= 0x01;
> >
> > They both aren't single cycle?
> Both AREN'T single cycle, they are a sequence of movs, lsls, (orrs
> only for
> the second with |=) and str.
> str that is the last instruction performs the write to the register.
>
> In general ARM architectures have no particular feeling with i/o
> management.
> In Cortex-M series there is the possibility for the silicon vendors to
> implement a bit-banding region that permits to access real single bits as
> they were bytes so we can say that bit-banding is a memory region
> devoted to
> bit access "shadowing" them as bytes so Cortex-M processor don't need bit
> access special instructions.
>
> This may be an advantage if you have to access just 1 bit but if you
> need to
> access more bits it is better to access the 32bit registers because to set
> bits performance of C compiler is the same, for toggling, oring and anding
> there is always one more instruction.
> >
> >
> > AndrRairan.
> >
> >
> > On Mar 29, 2012, at 11:54 PM, Phil Young wrote:
> >
> >> Hi Andr
> >>
> >> The whole point of masked access is to avoid conflicts with
> >> interrupts, and it's really easy to use in most cases.
> >>
> >> I use the following macros for setting and clearing bits.
> >>
> >> #define SET_GPIO(Port,Bits)(Port->MASKED_ACCESS[(Bits)] = (Bits))
> >> #define CLR_GPIO(Port,Bits)(Port->MASKED_ACCESS[(Bits)] = (0))
> >>
> >> Then I define macro's for the ports to make the code more portable,
> e.g.
> >> #define ISR_LED_ON SET_GPIO(LPC_GPIO3,0x1) // P3.0 #define
> >> ISR_LED_OFF CLR_GPIO(LPC_GPIO3,0x1)
> >>
> >> Of course if you change multiple bits you can simply clear the
> >> inverse using another SW mask then set the bits required ( a slightly
> >> more complex macro ).
> >> e.g.
> >>
> >> #define
> >> PUT_GPIO(Port,Value,Mask)(CLR_GPIO(Port,(Mask));SET_GPIO(Port,(Value)
> >> ))
> >>
> >> Or slightly better but probably a CPU cycle longer
> >>
> >> #define PUT_GPIO(Port,Value,Mask)(CLR_GPIO(Port,(Mask) &
> >> ~(Value));SET_GPIO(Port,(Value)))
> >>
> >> This will of course lead to a couple of CPU cycles when the bits are
> >> neither the old or new value, but for most cases that doesn't matter.
> >>
> >> If you need to change multiple bits and they must transition
> >> "simultaneously" then you have to do as Olivier suggested but then
> >> also you need to disable interrupts before the sequence and re-enable
> >> them immediately afterwards.
> >>
> >> Also using the masked approach if you change bits in multiple threads
> >> you need to restore the mask in anything but the lowest priority
> >> thread, though this can be done after re-enabling interrupts so that
> >> you don't affect interrupt latency too much.
> >>
> >> Regards
> >>
> >> Phil.
> >>
> >> -----Original Message-----
> >> From: l...

> [mailto:l...
] On
> >> Behalf Of Olivier Gautherot
> >> Sent: 30 March 2012 02:15
> >> To: l...

> >> Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers
> >>
> >> Hi Andr
> >>
> >> the mask register defines the bits that your operation is allowed to
> modify.
> >> This way, you don't need read-modify-write cycles in software but
> >> simply set the mask and write your value.
> >>
> >> I would suggest you use the following sequence on ***ALL*** accesses
> >> (more on "***ALL***" below):
> >> - backup the mask register
> >> - set the mask to the value you want
> >> - write your value to the port (note that masked bits are not
> >> relevant, so you may simplify your code)
> >> - restore the mask
> >>
> >> By doing this on all accesses, you're likely not to worry about
> >> interrupts, except if your sequence needs to need a precise timing or
> >> if the interrupt may change the sequence. Likewise, you have a SET
> >> and CLEAR registers that can simplify single bits operations. It's
> actually a nice feature.
> >>
> >> Hope it helps
> >> Cheers
> >> Olivier
> >>
> >> AndrRairan wrote:
> >>> Hello guys,
> >>>
> >>> I just can't figure out how the shadow registers works on Cortex-M0,
> >>> i'm
> >> using LPC11C14.
> >>> I'm doing this way now, using CMSIS:
> >>> LPC_GPIO0->DATA |= (0x1<< bit);
> >>> or
> >>> LPC_GPIO0->DATA&= ~(0x1<< bit);
> >>>
> >>> writing directly on GPIOnDATA register... As I could understand
> >>> writing
> >> directly to this register set all mask bits to 1 allowing directly
> access.
> >>> This way of doing is wrong or unsafe?
> >>> Why use masked access?
> >>>
> >>>
> >>> following...
> >>> this in on CMSIS file:
> >>>
> >>> union {
> >>> __IO uint32_t MASKED_ACCESS[4096]; /*!< Offset: 0x0000 to 0x3FFC
> >> Port data Register for pins PIOn_0 to PIOn_11 (R/W) */
> >>> struct {
> >>> uint32_t RESERVED0[4095];
> >>> __IO uint32_t DATA; /*!< Offset: 0x3FFC Port data
> >> Register (R/W) */
> >>> };
> >>>
> >>>
> >>> I read the pages 185 to 187, but I really can't understand it.
> >>>
> >>> How do I use the masks?
> >>> Wich one should I use?
> >>> Should I make some think like this:
> >>>
> >>> LPC_GPIO0->MASKED_ACCESS[ 0 ] = 0x01<< 2; LPC_GPIO0->DATA = 0xFF;
> >>>
> >>> This would set just the first bit?
> >>>
> >>>
> >>> Thanks,
> >>> AndrRairan.
> >>>
> >>>
> >>>
> >>>
OK, now I got it! It make sense and I agree that it's a very elegant solution.

Either if I use the same make operation inside and outside an interrupt it will be safe.

On Mar 30, 2012, at 8:30 AM, Phil Young wrote:

> Why are you writing to the mask register?.
>
> You should study the user manual again, it's not necessary.
>
> See the compiler output below, there is NO write to the mask register.
>
> 51: ISR_LED_ON; // defined to null when LED's disabled
>
> 52:
>
> 53: //~~~~~~~~~~~~ ensure LCD reset is held long enough if LCD
> enabled
>
> 0x00000F02 4BFF LDR r3,[pc,#1020] ; // get address of register
> into R3
>
> 0x00000F04 B08E SUB sp,sp,#0x38 //This is not part of the
> operation, but optimization enables instruction re-ordering
>
> 0x00000F06 2101 MOVS r1,#0x01 // get bit to be set
>
> 0x00000F08 6059 STR r1,[r3,#0x04] // perform masked IO port update
>
> Taken from the user manual, this is dedicated HW for the GPIO ports, it does
> NOT use the bit-banding mechanism.
>
> Write/read data operation
>
> In order for software to be able to set GPIO bits without affecting any
> other pins in a single
>
> write operation, bits [13:2] of a 14-bit wide address bus are used to create
> a 12-bit wide
>
> mask for write and read operations on the 12 GPIO pins for each port. Only
> GPIOnDATA
>
> bits masked by 1 are affected by read and write operations. The masked
> GPIOnDATA
>
> register can be located anywhere between address offsets 0x0000 to 0x3FFC in
> the
>
> GPIOn address space. Reading and writing to the GPIOnDATA register at
> address
>
> 0x3FFC sets all masking bits to 1.
>
> Regards
>
> Phil.
>
> From: l... [mailto:l...] On Behalf Of
> M. Manca
> Sent: 30 March 2012 12:03
> To: l...
> Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers
>
> Il 30/03/2012 12:31, Phil Young ha scritto:
> >
> >
> > Again, you missed the point.
> >
> > With the LPC1114 the masked register write is an atomic operation.
> >
> > The lower address bits are used as the mask, so a single write operation
> > performs a masked update of the register.
> >
> > There is no physical mask register involved, it's a virtual mask.
> >
> This is absolutely not true. If you look with attention to GPIO
> structure of LPC11U14 for instance you will see that the 2 i/o ports
> (PORT0 and PORT1) have both 32bit i/o bytes in the bit-banding region
> from 0x50000000 to 0x5000003f and then you will find that P0MASK and
> P1MASK at 0x50002080 and 0x50002084 to be used with P0SET/P0CLR and
> P1SET/P1CLR. So to use the mask feature you have to write before to the
> mask register and after to the set or clear register. This last write
> will change the i/o pin status. So it is an atomic operation made
> possible by the hardware registers but it is not a full atomic operation
> at all. The demonstration is simple; take a task that interrupts your
> operation after writing to the mask register and before writing to the
> data register and think what happen if that task alters the mask
> register. As I said in a previous post this is not a good way to
> programming but demonstrates that it is not a full atomic operation,
> they are 2 atomic operations 1 to write to the mask register and the 2nd
> to write the data using the set or the clr register.
> >
> >
> > It IS ALWAYS atomic.
> >
> > Regards
> >
> > Phil.
> >
> > From: l...
>
> > [mailto:l...
> ] On
> > Behalf Of
> > Wouter van Ooijen
> > Sent: 30 March 2012 11:18
> > To: l...
>
> > Subject: Re: [lpc2000] Cortex-M0 GPIO shadow registers
> >
> > > In the masked operation preparing the value to be written using the
> > masked
> > > register access can take millions of cycles without causing a problem.
> > > There is no hazard since the updating of the GPIO using the masked write
> > > interface involves a single access to the GPIO register.
> > >
> > > So for the purposes of hazard analysis this is an atomic operation.
> >
> > Only when there the mask register is used by just one thread!
> >
> > --
> >
> > Wouter van Ooijen
> >
> > -- -------
> > Van Ooijen Technische Informatica: www.voti.nl
> > consultancy, development, PICmicro products
> > docent Hogeschool van Utrecht: www.voti.nl/hvu
> > C++ on uC blog: http://www.voti.nl/erblog
> >
> >
> >
> >
>
>



> Hi Wouter,
> It's quite common to have multiple tasks needing to set / clear bits on the
> same IO register, particularly when using standard parts since you have to
> work within the constraints of pin multiplexing.

Take care who you are addressing: you are responding to a response to my
post, not to my post itself!

--

Wouter van Ooijen

-- -------
Van Ooijen Technische Informatica: www.voti.nl
consultancy, development, PICmicro products
docent Hogeschool van Utrecht: www.voti.nl/hvu
C++ on uC blog: http://www.voti.nl/erblog