This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Volatile struct members

Hi,

I would like to prevent structure members optimization. I used volatile keyword:

typedef volatile struct
{
    volatile ...
    volatile uint32_t discard;
    volatile ...
} regs_t;

I declared a member in another non-volatile struct:

typedef struct
{
    ...
    volatile regs_t *regs;
    ...
} peripheral_t;

I used an "empty" expression to just clear flags in register (the memory read access must be performed):

peripheral_t p;

p.regs = 0x12345678; /* init to register block starting address */
p.regs->discard;     /* gets optimized out when opt. is on      */

The "empty" expression gets optimized out although I thought (hoped) I prevented it via the volatile keywords.
- What is the right place to put the volatile?
- Does the whole struct have to be volatile?
- Does it make sense to define volatile type? (typedef volatile struct...)

Thanks for tips/explanations.

Regards Pavel

  • "to just clear flags in register"

    That's a fundamaentally flawed idea in a High-Level Language (HLL).

    You have no control over what instructions the compiler may generate for the source - it may do other stuff that affects flags...

    If you need specific control of specific flags, you probably should be writing in assembler!

    "the memory read access must be performed"

    IS that true?

  • According to the ARM ABI, volatile is applied recursively to all members of a struct.

    I am not sure what the C standard says about (non-volatile) composite data types containing (non-volatile) pointers to volatile types.

    It could well be the case that the compiler behavior is perfectly legal. Try qualifying peripheral_t as volatile just to see if that changes anything.

    I recommend to manage peripherals using structures placed via at-attribute or the scatter loading file (linker script). Some also use integer literals cast to pointers to structs.

    @Andy
    > you probably should be writing in assembler

    But C is "[...](the PDP-11 assembler that thinks it's a language) and C++ (the PDP-11 assembler that thinks it's an object system)[...]" (Jamie Zawinski)

    Regards
    Marcus
    http://www.doulos.com/arm/

  • Me says:
    > I am not sure what the C standard says about
    > (non-volatile) composite data types containing
    > (non-volatile) pointers to volatile types.

    I think I found it in 6.7.3 §5: If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.

    --
    Marcus

  • Andy,

    maybe it's not strict regarding ANSIC, but in most cases in embedded world and C language, volatile and register accesses through pointers are the prevailing methods for accessing peripherals, aren't they?

    I'm not expecting this behaviour in GNU/microsoft's C compilers on my PC when compiling SW, but expecting it for embedded compilers when making FW.

    -----------------------------------
    A volatile object is one that may be modified outside of program control. Memory-mapped I/O ports are a typical example. Declaring an object as volatile indicates that the compiler should always generate code to fetch the object's value from its actual memory location — it may have changed since the last access by the program. (This disallows optimizations which could load the value into a register and possibly return erroneous results.)
    -----------------------------------
    www.ericgiguere.com/.../ansi-c-summary.html
    (google first hit)

  • - Does it make sense to define volatile type? (typedef volatile struct...)

    It is possible to declare a whole structure volatile instead of its single elements, however, for the sake of intuitiveness, it makes more sense to declare the various registers of a register set as volatile, because it really is the single register that is volatile.

    You may have discovered a compiler bug here. Incorrect implementations of the volatile keyword appear to be rather common among compilers.

  • That's a fundamaentally flawed idea in a High-Level Language (HLL).

    Andy,

    I think the OP is talking about accessing peripheral registers. Using a structure with volatile members and the base address of the peripheral converted into a pointer to the appropriate structure to access peripheral registers is one of the common ways to communicate with a peripheral in C.

  • Christoph: wrote
    > You may have discovered a compiler bug here.

    As I wrote earlier, the behavior seems to be valid according to the C standard. The volatile structure is a member of a non-volatile structure, a pointer to which is used to access a register. Following my advice in previous post may solve the issue.

    --
    Marcus
    http://www.doulos.com/arm/

  • I don't know much about this.
    I don't have any experience on ATMEL MCU.

    But, maybe you can take a look at some ATMEL Example Code.

    In AT91SAM7S32.h

    #ifndef AT91SAM7S32_H
    #define AT91SAM7S32_H
    
    #ifndef __ASSEMBLY__
    typedef volatile unsigned int AT91_REG;// Hardware register definition
    #define AT91_CAST(a) (a)
    #else
    #define AT91_CAST(a)
    #endif
    
    // *****************************************************************************
    //              SOFTWARE API DEFINITION  FOR System Peripherals
    // *****************************************************************************
    #ifndef __ASSEMBLY__
    typedef struct _AT91S_SYS {
            AT91_REG         AIC_SMR[32];   // Source Mode Register
            AT91_REG         AIC_SVR[32];   // Source Vector Register
            AT91_REG         AIC_IVR;       // IRQ Vector Register
            AT91_REG         AIC_FVR;       // FIQ Vector Register
            AT91_REG         AIC_ISR;       // Interrupt Status Register
            AT91_REG         AIC_IPR;       // Interrupt Pending Register