Test application for the STMicroelectronics X-NUCLEO-LED61A1 LED Control Expansion Board showing several LED control modes.

Dependencies:   X_NUCLEO_LED61A1 mbed

Fork of LedDimming_LED61A1 by ST Expansion SW Team

LED Control with the X-NUCLEO-LED61A1 Expansion Board

This application provides an example of usage of the X-NUCLEO-LED61A1 LED Control Expansion Board. It shows how to control a LED stripe load connected to the board through the following control modes:

  1. Manual PWM Dimming;
  2. Manual Analog Dimming;
  3. Sinusoidal PWM Dimming;
  4. Sinusoidal Analog Dimming;
  5. Photo-based Analog Dimming.

The button of the MCU board, when available, can be used in the following ways:

  • Short Button Press [<0.5s] for Manual Dimming;
  • Medium Button Press to Switch Demo;
  • Long Button Press [>2s] to Switch Power ON/OFF.

The program starts in mode 1.

main.cpp

Committer:
Davidroid
Date:
2017-07-13
Revision:
16:2497344ba436
Parent:
15:ea1e402ce919

File content as of revision 16:2497344ba436:

/**
 ******************************************************************************
 * @file    main.cpp
 * @author  Davide Aliprandi, STMicroelectronics
 * @version V1.0.0
 * @date    February 4h, 2016
 * @brief   mbed test application for the STMicroelectronics X-NUCLEO-LED61A1
 *          LED Control Expansion Board showing several LED control modes.
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of STMicroelectronics nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 */


/* Includes ------------------------------------------------------------------*/

/* mbed specific header files. */
#include "mbed.h"

/* Component specific header files. */
#include "Led6001.h"


/* Definitions ---------------------------------------------------------------*/

/* PI. */
#ifndef M_PI
    #define M_PI                          (3.14159265358979323846f)
#endif

/* Loop period in micro-seconds. */
#define LOOP_PERIOD_us                    (1E5)

/* Sin period in micro-seconds. */
#define PWM_SIN_PERIOD_us                 (1E7)
#define ANALOG_SIN_PERIOD_us              (1E7)

/* Duration of button press in milli-seconds. */
#define SWITCH_DEMO_BUTTON_PRESS_ms       (500)
#define SWITCH_POWER_BUTTON_PRESS_ms      (2000)

/* Dimming Step. */
#define DIMMING_STEP                      (0.05f)


/* Types ---------------------------------------------------------------------*/

/* Demos. */
typedef enum
{
  MANUAL_PWM_DIMMING = 0,
  MANUAL_ANALOG_DIMMING,
  AUTOMATIC_PWM_DIMMING,
  AUTOMATIC_ANALOG_DIMMING,
  PHOTO_BASED_ANALOG_DIMMING,
  LED_DEMO_SIZE
} LED_Demo_t;

/* Actions. */
typedef enum
{
  SWITCH_POWER = 0,
  SWITCH_DEMO,
  SWITCH_STATE,
  NO_ACTION
} LED_Action_t;


/* Variables -----------------------------------------------------------------*/

/* Main loop's ticker. */
static Ticker ticker;

/* User Button's interrupt. */
static InterruptIn button(USER_BUTTON);

/* MCU Board's Led which provides the user with a visual feedback on
   the user button's status (ON = pressed, OFF = released). */
DigitalOut button_pressed_led(LED1);

/* LED Control Component. */
Led6001 *led;

/* Interrupt flags. */
static volatile bool ticker_irq_triggered = false;
static volatile bool button_irq_triggered = false;
static volatile bool xfault_irq_triggered = false;

/* Demo State. */
static volatile LED_Demo_t demo;
static volatile LED_Action_t action;
static volatile bool power_on;

/* Demos' Names. */
static char* demos[] =
{
    "Manual PWM Dimming",
    "Manual Analog Dimming",
    "Sinusoidal PWM Dimming",
    "Sinusoidal Analog Dimming",
    "Photo-based Analog Dimming"
};


/* Functions -----------------------------------------------------------------*/

/**
 * @brief  Initializing the demo.
 * @param  None.
 * @retval None.
 */
void init_demo(void)
{
    power_on = true;
    action = SWITCH_DEMO;
    demo = (LED_Demo_t) (LED_DEMO_SIZE - 1);
}

/**
 * @brief  Handling the LED capabilities and executing several demos.
 * @param  None.
 * @retval None.
 */
void led_handler(void)
{
    static int tick = 0;
    static float pwm_dimming;
    static float analog_dimming;

    /* Handling the power switch. */
    if (action == SWITCH_POWER) {
        /* Switching the LED power ON/OFF. */
        power_on = !power_on;

        if (power_on) {
            /* Initializing PWM and Analog dimming to maximum values. */
            pwm_dimming = 1.0f;
            analog_dimming = 1.0f;
        } else {
            /* Printing to the console. */
            printf("%-56s\r", "Power OFF");

            /* Powering OFF the LED. */
            led->power_off();
        }
    }

    /* Handling the LED dimming when powered ON. */
    if (power_on) {
        /* Switching to the next demo. */
        if (action == SWITCH_DEMO) {
            pwm_dimming = 1.0f;
            analog_dimming = 1.0f;
            tick = 0;
            demo = (LED_Demo_t) ((demo + 1) % LED_DEMO_SIZE);
        }

        /* Setting the LED dimming depending on the selected demo. */
        switch (demo) {
            /* Changing PWM dimming according to the user button. */
            case MANUAL_PWM_DIMMING:
                if (action == SWITCH_STATE) {
                    pwm_dimming -= DIMMING_STEP;
                    pwm_dimming = (pwm_dimming < 0.0f ? 1.0f : pwm_dimming);
                }
                break;

            /* Changing Analog dimming according to the user button. */
            case MANUAL_ANALOG_DIMMING:
                if (action == SWITCH_STATE) {
                    analog_dimming -= DIMMING_STEP;
                    analog_dimming = (analog_dimming < 0.0f ? 1.0f : analog_dimming);
                }
                break;

            /* Changing PWM dimming continuously. */
            case AUTOMATIC_PWM_DIMMING:
                pwm_dimming = 0.5f * sin(2 * M_PI * (tick++ * LOOP_PERIOD_us) / PWM_SIN_PERIOD_us) + 0.5f;
                tick %= (int) (PWM_SIN_PERIOD_us / LOOP_PERIOD_us);
                action = SWITCH_STATE;
                break;

            /* Changing Analog dimming continuously. */
            case AUTOMATIC_ANALOG_DIMMING:
                analog_dimming = 0.5f * sin(2 * M_PI * (tick++ * LOOP_PERIOD_us) / ANALOG_SIN_PERIOD_us) + 0.5f;
                tick %= (int) (ANALOG_SIN_PERIOD_us / LOOP_PERIOD_us);
                action = SWITCH_STATE;
                break;

            /* Setting Analog dimming according to the photo sensor. */
            case PHOTO_BASED_ANALOG_DIMMING:
                analog_dimming = 1.0f - led->get_current();
                action = SWITCH_STATE;
                break;
        }

        /* Writing PWM and Analog dimming values to the LED. */
        if (action != NO_ACTION) {
            /* Printing to the console. */
            printf("%d) %-26s --> Dimming: %0.2f\r", demo + 1, demos[demo], demo == MANUAL_PWM_DIMMING || demo == AUTOMATIC_PWM_DIMMING ? pwm_dimming : analog_dimming);

            /* Writing PWM and Analog dimming values to the LED. */
            led->set_pwm_dimming(pwm_dimming);
            led->set_analog_dimming(analog_dimming);
        }
    }
    
    /* Resetting the action. */
    action = NO_ACTION;
}

/**
 * @brief  Interrupt Request for the main loop's ticker related interrupt.
 * @param  None.
 * @retval None.
 */
void ticker_irq(void)
{
    ticker_irq_triggered = true;
}

/**
 * @brief  Interrupt Request for the user button's interrupt.
 * @param  None.
 * @retval None.
 */
void button_irq(void)
{
    button_irq_triggered = true;
    button.disable_irq();
}

/**
 * @brief  Interrupt Request for the component's XFAULT interrupt.
 * @param  None.
 * @retval None.
 */
void xfault_irq(void)
{
    xfault_irq_triggered = true;
    led->disable_xfault_irq();
}

/**
 * @brief  Interrupt Handler for the user button's interrupt.
 * @param  None.
 * @retval None.
 */
void button_handler(void)
{
    /* User Button's timer to measure the time the button remains pressed. */
    static Timer button_pressed_timer;

    bool button_pressed_flag = (button.read() == 0 ? true : false);

    if (button_pressed_flag) {
        button_pressed_led = 1;
        button_pressed_timer.start();
    } else {
        button_pressed_led = 0;
        button_pressed_timer.stop();

        /* Either changing current demo's state or switching to the next demo. */
        int time_pressed = button_pressed_timer.read_ms();
        if (time_pressed < SWITCH_DEMO_BUTTON_PRESS_ms) {
            action = SWITCH_STATE;
        } else if (time_pressed < SWITCH_POWER_BUTTON_PRESS_ms) {
            action = SWITCH_DEMO;
        } else {
            action = SWITCH_POWER;
        }

        button_pressed_timer.reset();
    }

    button.enable_irq();
}

/**
 * @brief  Interrupt Handler for the component's XFAULT interrupt.
 * @param  None.
 * @retval None.
 */
void xfault_handler(void)
{
    /* Printing to the console. */
    printf("XFAULT Interrupt detected! Re-initializing LED driver...");

    /* Re-starting-up LED Control Component. */
    led->start_up();

    /* Printing to the console. */
    printf("Done.\r\n\n");

    /* Re-initializing the demo. */
    init_demo();

    led->enable_xfault_irq();
}


/* Main ----------------------------------------------------------------------*/

int main()
{
    /*----- Initialization. -----*/

    /* Printing to the console. */
    printf("LED Control Application Example\r\n\n" \
           "Demos:\r\n");
    int demo = 0;
    for (demo = 0; demo < LED_DEMO_SIZE; demo++) {
        printf("%d) %-26s\r\n", demo + 1, demos[demo]);
    }
    printf("\r\nActions:\r\n" \
           "+ Short Button Press [<%.1fs]  --> Manual Dimming\r\n" \
           "+ Medium Button Press         --> Switch Demo\r\n" \
           "+ Long Button Press  [>%.1fs]  --> Switch Power ON/OFF\r\n\n" \
           , SWITCH_DEMO_BUTTON_PRESS_ms / 1000.0f, SWITCH_POWER_BUTTON_PRESS_ms / 1000.0f);

    /* Initializing LED Control Component. */
    led = new Led6001(D4, A3, D6, D5);
    if (led->init() != COMPONENT_OK) {
        exit(EXIT_FAILURE);
    }

    /* Attaching interrupt request functions. */
    button.fall(button_irq);
    button.rise(button_irq);
    led->attach_xfault_irq(&xfault_irq);
    led->enable_xfault_irq();
    ticker.attach_us(ticker_irq, LOOP_PERIOD_us);

    /* Starting-up LED Control Component. */
    led->start_up();

    /* Initializing the demo. */
    init_demo();


    /*----- LED Control. -----*/

    /* Either performing the component handler, interrupt handlers, or waiting for events. */
    while (true) {
        if (ticker_irq_triggered) {
            ticker_irq_triggered = false;
            led_handler();
        } else if (button_irq_triggered) {
            button_irq_triggered = false;
            button_handler();
        } else if (xfault_irq_triggered) {
            xfault_irq_triggered = false;
            xfault_handler();
        } else {
            /* It is recommended that SEVONPEND in the System Control Register is NOT set. */
            __WFE();
        }
    }
}