Wednesday, 15 July 2020

Application of volatile in C

A variable should be declared volatile when its value could be changed unexpectedly. In practice, you must declare a variable as volatile whenever you are:

  1. Accessing the memory-mapped peripherals register.
  2. Sharing the global variables or buffers between the multiple threads.
  3. Accessing the global variables in an interrupt routine or signal handler.
Interrupt service routine (ISR)

In the case of Interrupt service routine for a key press interrupt, often a global variable is shared between ISR and main function. In this scenario value of global variable set or check by either the ISR or main function, for example, I am taking a sample code.

void KeyDataISR(void) 
{ 
  keyFlag = 1; 
} 

int key_task(void) 
{ 
   
  while (!keyFlag)
  {
      //copy key data via I2C to some variable then reset this flag.
  }

  return 0;
}
In the above code, the global flag is the monitor in the key_task function, When we have turned on the optimization level of the compiler then might be this code work fine because the compiler is unaware of the value changed of the global variable in ISR, so it assumes that while loop is always true and it never exits from the loop.

A solution of this problem is to make the global keyFlag volatile, this technique prevents the compiler from applying any optimization on the global flag and tells the compiler that value of this flag can change by external event at any time without any action being taken the by code.

volatile int keyFlag = 0;

KeyDataISR(void) 
{ 
  keyFlag = 1; 
} 

int key_task(void) 
{ 
   
  while (!keyFlag)
  {
      //copy key data via I2C to some variable then reset this flag.
} return 0; }

Application of volatile and const keywords in C

To read the status of the register, address of the register is 0x00020000. To access the value of the status register, we need to map the address of register with a pointer.
#define NEW_STATUS_BIT  0x00000006
uint32_t const volatile * const StatusReg = (uint32_t*)0x00020000;
unit32_t GetRecvData()
{
  //recv data
           RecvData = readRegister(uint8_t i2cAddr, uint8_t regAddr); 
  while (((*StatusReg)  & NEW_STATUS_BIT) == 0)
  {
    // Wait until flag does not set
  }
  
  return RecvData;
}
If any object qualifies by both volatile and const, the value of the object could not be altered by its own program, but could be altered by another process.

Unions in C programming

Union is a data type in C programming that allows different data types to be stored in the same memory locations. Union provides an efficient way of reusing the memory location, as only one of its members can be accessed at a time.

typedef union
{
  struct
  {
    unsigned char bit1 : 1;
    unsigned char bit2 : 1;
    unsigned char bit3 : 1;
    unsigned char bit4 : 1;
    unsigned char bit5 : 1;
    unsigned char bit6 : 1;
    unsigned char bit7 : 1;
    unsigned char bit8 : 1;
  }u;
  unsigned char status;
}DeviceStatus;

int main()
{
    DeviceStatus bb;
    bb.status=1;
    
    printf("Access single bit %d",bb.u.bit1);

    return 0;
}
 

This structure would allow a control register to be accessed as a control_byte or via the individual bits. It would be important to ensure the bits map on to the correct register bits for a given endianness..

typedef union {
    unsigned char control_byte;
    struct {
        unsigned int nibble  : 4;
        unsigned int nmi     : 1;
        unsigned int enabled : 1;
        unsigned int fired   : 1;
        unsigned int control : 1;
    };
} ControlRegister;

No comments:

Post a Comment

Application of volatile in C A variable should be declared volatile when its value could be changed unexpectedly. In practice, you must decl...