Example: Fan_Control_Auto_FW_with_Alert and volatile variables

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
alro_2373731
Level 1
Level 1

I am basing an application off of this example and i am getting a lot of false positives on stall alerts which has been a headache. I am looking over this example and I am wondering why the global variables in the example are not volatile as they exist inside interrupts...  I am not the best coder in C so it may be correct...

uint16  stallStatus = 0u; uint16  speedStatus = 0u;

/*******************************************************************************

* Project Name:      FW_Fan_Control_with_Alert

*

* Version:           1.0

*

* Theory of Operation:

*

*  Fan Controller is configured into Automatic Firmware (CPU) fan control mode.

*  Speed control algorithm is implemented in firmware using PID control

*  algorithm.

*  2 Fans are supported (individual PWMs - no banks).

*

*  1st line of LCD displays Desired Speed and Actual Speed and PWM Duty Cycle

*  of Fan 1

*  2nd line of LCD displays Actual Speed and PWM Duty Cycle of Fan 2

*  SW1 decreases desired speed in RPM

*  SW2 increases desired speed in RPM

*  Fan stall/speed alert monitored - pulses GPIO, triggers interrupt which

*  sets flag

*

********************************************************************************

* Copyright 2013-2015, Cypress Semiconductor Corporation. All rights reserved.

* This software is owned by Cypress Semiconductor Corporation and is protected

* by and subject to worldwide patent and copyright laws and treaties.

* Therefore, you may use this software only as provided in the license agreement

* accompanying the software package from which you obtained this software.

* CYPRESS AND ITS SUPPLIERS MAKE NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,

* WITH REGARD TO THIS SOFTWARE, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,

* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

*******************************************************************************/

#include <project.h>

#include <stdio.h>

#if defined (__GNUC__)

    /* Add an explicit reference to the floating point printf library */

    /* to allow the usage of floating point conversion specifiers. */

    /* This is not linked in by default with the newlib-nano library. */

    asm (".global _printf_float");

#endif

/***************************************

*       Constants

***************************************/

#define MIN_RPM     (1000u)

#define MAX_RPM     (20000u)

#define INIT_RPM    (4500u)

#define RPM_STEP    (500u)

#define FAN_1       (1u)

#define FAN_2       (2u)

/***************************************

*        Function Prototypes

***************************************/

CY_ISR_PROTO(AlertInt_Isr);

/***************************************

*   Global variable declarations

***************************************/

uint16  stallStatus = 0u;

uint16  speedStatus = 0u;

/*******************************************************************************

* Function Name: main

********************************************************************************

*

* Summary:

*  main() performs following functions:

*  1: Starts the components

*  2: Checks for Fan Stall and Speed Failure.

*  3: Displays Fan actual speeds when there are no errors.

*  4: Displays PWM duty cycles for each fan.

*

* Parameters:

*  None.

*

* Return:

*  None.

*

*******************************************************************************/

int main()

{

    uint16 desiredSpeed = INIT_RPM;

    uint8  fanNumber;

    char   string[6];

    /* Enable interrupts to the CPU core */

    CyGlobalIntEnable;

    /* Start alert interrupt with a custom handler */

    AlertInt_StartEx(&AlertInt_Isr);

    /* Start components */

    LCD_Start();

    FanController_Start();

    /* Set desired fan speed (fan number, rpm) */

    FanController_SetDesiredSpeed(FAN_1, desiredSpeed);

    FanController_SetDesiredSpeed(FAN_2, desiredSpeed);

    FanController_EnableAlert();

    LCD_Position(0u, 0u);

    LCD_PrintNumber(desiredSpeed);

    LCD_Position(1u, 0u);

    LCD_PrintString("F/W");

    while(1u)

    {

        /* If the tachometer block has read speeds of all fans in system,

         * only then check speed/stall conditions.

         */

        if(EOC_SR_Read())

        {

            for(fanNumber = FAN_1; fanNumber <= FAN_2; fanNumber++)

            {

                LCD_Position(fanNumber - 1u, 5u);

                /* Check for Fan Stall and Speed Failure (flags set in AlertInt ISR) */

                if(stallStatus & fanNumber)

                {

                    LCD_PrintString("STALL");

                    stallStatus &= ~fanNumber;

                }

                else if(speedStatus & fanNumber)

                {

                    LCD_PrintString("SPEED");

                    speedStatus &= ~fanNumber;

                }

                else

                {

                    /* Display Fan actual speeds when there are no errors */

                    LCD_PrintNumber(FanController_GetActualSpeed(fanNumber));

                    LCD_PrintString(" ");

                }

                /* Display PWM duty cycles for each fan */

                LCD_Position(fanNumber - 1u, 11u);

                sprintf(string, "%4.1f", ((float)(FanController_GetDutyCycle(fanNumber))) / 100u);

                LCD_PrintString(string);

                LCD_PrintString("%");

            }

        }

        /* Check for Button Press to Change Speed */

        if((!SW1_Read()) || (!SW2_Read()))

        {

            /* Decrease Speed */

            if(!SW1_Read())

            {

                if(desiredSpeed > MIN_RPM)

                {

                    desiredSpeed -= RPM_STEP;

                }

            }

            /* Increase Speed */

            else

            {

                desiredSpeed += RPM_STEP;

                if(desiredSpeed > MAX_RPM)

                {

                    desiredSpeed = MAX_RPM;

                }

            }

            FanController_SetDesiredSpeed(1u, desiredSpeed);

            FanController_SetDesiredSpeed(2u, desiredSpeed);

            /* Display Updated Desired Speed */

            LCD_Position(0u, 0u);

            LCD_PrintNumber(desiredSpeed);

            LCD_PrintString(" ");

            /* Switch Debounce */

            CyDelay(250u);

        }

    }

}

/*******************************************************************************

* Function Name: AlertInt_Isr

********************************************************************************

* Summary:

*  Informs main() routine about occured alerts.

*

* Parameters:

*  None.

*

* Return:

*  None.

*

*******************************************************************************/

CY_ISR(AlertInt_Isr)

{

    uint8 alertStatus;

   

    /* Determine alert source: stall or speed regulation failure (could be both) */

    alertStatus = FanController_GetAlertSource();

   

    /* If stall alert, determine which fan(s) */

    if (alertStatus & FanController_STALL_ALERT)

  {

  stallStatus = FanController_GetFanStallStatus();

  }

    /* If speed regulation failure alert, determine which fan(s) */

    if (alertStatus & FanController_SPEED_ALERT)

    {

  speedStatus = FanController_GetFanSpeedStatus();

  }

}

/* [] END OF FILE */

0 Likes
1 Solution

No, they aren't volatile as default. An error is reproduced easily: Just use an empty while loop as

while(flag) {};

and set the flag to FALSE in an interrupt handler.

Set the optimization to something stronger than "debug".

When "flag" is not declared volatile the loop will not end.

Bob

View solution in original post

0 Likes
8 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

You are quite right, this is an engineer's bug! Probably it was not detected yet because nobody compiled the project with strong optimization.

Cypress is watching this forum, so I assume they will answer shortly.

Bob

0 Likes

After a bit of googling, I think variables in the global scope are likely to be compiled volatile.  I did see a lot of how-evers so I am still confused.

0 Likes

No, they aren't volatile as default. An error is reproduced easily: Just use an empty while loop as

while(flag) {};

and set the flag to FALSE in an interrupt handler.

Set the optimization to something stronger than "debug".

When "flag" is not declared volatile the loop will not end.

Bob

0 Likes

Hi Bob,

Can you please share the code that you had tested and the optimization level used.

Jobin GT

0 Likes
lock attach
Attachments are accessible only for community members.

Yes, of course. At first something to read, an excerpt from my script.

The Project is attached too.

Happy coding

Bob

0 Likes
JobinT_31
Employee
Employee
50 solutions authored 25 solutions authored 10 solutions authored

Yes, Bob is correct. This is a bug in code example and you need to add the volatile keyword.

We had created an internal ticket to fix this.

Why volatile is required?

At higher optimization compiler will check if the variable is modified anywhere else. Since the CYISR is not called anywhere, the compiler might optimize the global variable, thinking the variable never changed.

Thanks

Jobin GT

0 Likes
JobinT_31
Employee
Employee
50 solutions authored 25 solutions authored 10 solutions authored

Hi Bob,

Thank you very much for the code and PDF. I am able to reproduce.

I will create a KBA to help future customers.

Thanks

Jobin GT

0 Likes

Jobin,

Always at your service 😉

Bob