2019-2020 LPS22HH Altimeter Project

Dependencies:   X_NUCLEO_IKS01A3

main.cpp

Committer:
martlefebvre94
Date:
2019-09-05
Revision:
7:4a3b6202963e
Parent:
6:b2e247935342
Child:
8:fa346d946e7e

File content as of revision 7:4a3b6202963e:

/**
 ******************************************************************************
 * @file    main.cpp
 * @author  SRA
 * @version V1.0.0
 * @date    5-March-2019
 * @brief   Simple Example application for using the X_NUCLEO_IKS01A3
 *          MEMS Inertial & Environmental Sensor Nucleo expansion board.
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2019 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.
 *
 ******************************************************************************
*/

/*
    LELEC2811 Magnetometer LIS2MDL Project
    M. Lefebvre - 2019
*/

/* Includes */
#include <stdlib.h>
#include "mbed.h"
#include "XNucleoIKS01A3.h"
#include "stm32l073xx.h"
#include "stm32l0xx_hal_flash.h"

/* Defines */
#define LIS2MDL_ODR             50.0    // Output data rate (10, 20, 50 or 100 Hz)
#define LIS2MDL_LP              0       // Power mode (0 for high-resolution mode, 1 for low-power mode)
#define LIS2MDL_LPF             0       // Bandwidth (0 for ODR/2, 1 for ODR/4)
#define LIS2MDL_COMP_TEMP_EN    1       // Temperature compensation (0 disabled, 1 enabled)
#define LIS2MDL_OFF_CANC        1       // Offset cancellation (0 for no offset cancellation, 1 for offset cancellation, 2 for set pulse only at power-on)
#define FS                      12.5    // Sampling frequency (Hz)      

/* Serial link */
Serial pc(SERIAL_TX, SERIAL_RX);

/* Button */
InterruptIn button1(USER_BUTTON);
volatile bool button1_pressed = false; // Used in the main loop
volatile bool button1_enabled = true; // Used for debouncing
Timeout button1_timeout; // Used for debouncing

/* Instantiate the expansion board */
static XNucleoIKS01A3 *mems_expansion_board = XNucleoIKS01A3::instance(D14, D15, D4, D5, A3, D6, A4);

/* Retrieve the composing elements of the expansion board */
static LIS2MDLSensor *magnetometer = mems_expansion_board->magnetometer;
static HTS221Sensor *hum_temp = mems_expansion_board->ht_sensor;
static LPS22HHSensor *press_temp = mems_expansion_board->pt_sensor;
static LSM6DSOSensor *acc_gyro = mems_expansion_board->acc_gyro;
static LIS2DW12Sensor *accelerometer = mems_expansion_board->accelerometer;
static STTS751Sensor *temp = mems_expansion_board->t_sensor;

/* Erase content of Flash memory */
bool erase_flash(bool verbose)
{
    printf("Erasing Flash memory...\r\n");
    
    // Unlock Flash memory
    HAL_FLASH_Unlock();

    // Erase Flash memory
    FLASH_EraseInitTypeDef eraser;
    uint32_t Flash_addr = FLASH_BANK2_BASE;
    uint32_t page_error = 0;
    int32_t page = 1;
    
    while (Flash_addr < FLASH_BANK2_END) {
        eraser.TypeErase = FLASH_TYPEERASE_PAGES;
        eraser.PageAddress = Flash_addr;
        eraser.NbPages = 1;
        if(HAL_OK != HAL_FLASHEx_Erase(&eraser, &page_error)) {
            if (verbose) {printf("Flash erase failed!\r\n");}
            printf("Error 0x%X\r\n", page_error);
            HAL_FLASH_Lock();
            return false;
        }
        if (verbose) {printf("Erased page %d at address: 0x%X\r\n", page, Flash_addr);}
        Flash_addr += FLASH_PAGE_SIZE;
        page++;
    }
    
    if (verbose) {printf("Flash erase succesful!\r\n");}
    return true;
}

/* Write Flash memory */
bool write_flash(uint32_t Flash_addr, uint32_t Flash_wdata, bool verbose)
{
    // Unlock Flash memory
    HAL_FLASH_Unlock();
    
    // Write Flash memory
    if (HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Flash_addr, Flash_wdata)) {
        if (verbose) {printf("Flash write failed!\r\n");}
        HAL_FLASH_Lock();
        return false;
    }
    if (verbose) {printf("Flash write succesful!\r\n");}
    HAL_FLASH_Lock();
    return true;
}

/* Read Flash memory */
void read_flash(uint32_t Flash_addr, uint32_t* Flash_rdata, uint32_t n_bytes)
{
    memcpy(Flash_rdata, (uint32_t*) Flash_addr, n_bytes);
}

/* Print Flash memory info */
void print_flash_info()
{
    printf("**************************************************\n\r");
    printf("/***** Flash memory info *****/\r\n");
    printf("Flash size: %d [B]\r\n", FLASH_SIZE);
    printf("Flash page size: %d [B]\r\n", FLASH_PAGE_SIZE);
    printf("Flash nb of pages: %d \r\n", FLASH_SIZE/FLASH_PAGE_SIZE);
    printf("Flash bank 1 base address: 0x%X\r\n", FLASH_BASE);
    printf("Flash bank 1 end address: 0x%X\r\n", FLASH_BANK1_END);
    printf("Flash bank 2 base address: 0x%X\r\n", FLASH_BANK2_BASE);
    printf("Flash bank 2 end address: 0x%X\r\n", FLASH_BANK2_END);
    printf("**************************************************\n\r");
}

/* Enables button when bouncing is over */
void button1_enabled_cb(void)
{
    button1_enabled = true;
}

/* ISR handling button pressed event */
void button1_onpressed_cb(void)
{
    if (button1_enabled) { // Disabled while the button is bouncing
        button1_enabled = false;
        button1_pressed = true; // To be read by the main loop
        button1_timeout.attach(callback(button1_enabled_cb), 0.3); // Debounce time 300 ms
    }
}

/* Acquisition task */
bool acquisition_task(uint32_t* Flash_addr)
{
    int32_t m_axes[3];
    
    while (*Flash_addr < FLASH_BANK2_END) {
        // Read magnetometer data
        magnetometer->get_m_axes(m_axes);
        
        // Save data to Flash memory
        for (int i=0; i<3; i++) {
            //printf("Writing to address: 0x%X\r\n", *Flash_addr);
            write_flash(*Flash_addr, (uint32_t) m_axes[i], false);
            *Flash_addr += 4;
        }
        
        // Print data in terminal
        //printf("LIS2MDL [mag/mgauss]:  %6d, %6d, %6d\r\n", ((uint32_t) m_axes[0]), ((uint32_t) m_axes[1]), ((uint32_t) m_axes[2]));
        
        // Wait for acquisition period
        wait(1/FS);
        
        // Stop saving data when button is pushed
        if (button1_pressed) {
            button1_pressed = false;
            printf("Data acquisition stopped\r\n");
            printf("Press 'R' to read the data\r\n");
            
            // Save last address in Flash memory
            write_flash(FLASH_BANK2_BASE, *Flash_addr, false);
            return false;
        }
    }
    return false;
}

/* Read task */
void read_task()
{
    char pc_input;
    uint32_t Flash_rdata[3];
    uint32_t Flash_addr;
    
    // Read terminal input
    if (pc.readable()) {
        pc_input = pc.getc();
        //printf("Read character: %c\r\n", pc_input);
    }
    else {
        pc_input = 'a';
    }
    
    // Read Flash memory if 'R' is pressed
    if ((pc_input == 'r') || (pc_input == 'R')) {
        // Read last written Flash address in Flash memory
        read_flash(FLASH_BANK2_BASE, &Flash_addr, 4);
        
        // Data names
        printf("mag_X\tmag_Y\tmag_Z\r\n");
        
        // Read Flash data
        uint32_t Flash_addr_temp = FLASH_BANK2_BASE + 4;
        while (Flash_addr_temp < Flash_addr) {
            //printf("Reading from address: 0x%X\r\n", Flash_addr_temp);
            read_flash(Flash_addr_temp, &Flash_rdata[0], 12);
            Flash_addr_temp += 12;
            printf("%6d\t%6d\t%6d\r\n", Flash_rdata[0], Flash_rdata[1], Flash_rdata[2]);
        }
    }
}

/* Main */
int main()
{
    uint8_t id;
    float read_reg;
    uint8_t read_reg_int;
    
    bool save_data = false;
    uint32_t Flash_addr = FLASH_BANK2_BASE;

    /* Serial link configuration */
    pc.baud(115200);
    
    /* Button configuration */
    button1.fall(callback(button1_onpressed_cb)); // Attach ISR to handle button press event
    
    // Reset message
    printf("\n\r**************************************************\n\r");
    printf("LELEC2811 LIS2MDL Magnetometer Program\n\r");
    printf("**************************************************\n\r");

    /* Enable LIS2MDL magnetometer sensor */
    magnetometer->enable();
    
    /* LIS2MDL magnetometer sensor configuration */
    printf("/***** LIS2MDL magnetometer configuration *****/\r\n");
    
    magnetometer->read_id(&id);
    printf("LIS2MDL magnetometer = 0x%X\r\n", id);
    
    magnetometer->set_m_odr(LIS2MDL_ODR);
    magnetometer->get_m_odr(&read_reg);
    printf("LIS2MDL ODR = %1.1f [Hz]\r\n", read_reg);
    
    magnetometer->set_m_lp(LIS2MDL_LP);
    magnetometer->get_m_lp(&read_reg_int);
    printf("LIS2MDL LP = %1d\r\n", read_reg_int);
    
    magnetometer->set_m_lpf(LIS2MDL_LPF);
    magnetometer->get_m_lpf(&read_reg_int);
    printf("LIS2MDL LPF = %1d\r\n", read_reg_int);
    
    magnetometer->set_m_comp_temp_en(LIS2MDL_COMP_TEMP_EN);
    magnetometer->get_m_comp_temp_en(&read_reg_int);
    printf("LIS2MDL COMP_TEMP_EN = %1d\r\n", read_reg_int);
    
    magnetometer->set_m_off_canc(LIS2MDL_OFF_CANC);
    magnetometer->get_m_off_canc(&read_reg_int);
    printf("LIS2MDL OFF_CANC = %1d\r\n", read_reg_int);
    
    /* Print Flash memory information */
    print_flash_info();
    
    /* Information for the user */
    printf("Press blue button to start data acquisition\r\n");
    printf("Press 'R' to read previously measured data\r\n");
    
    /* Acquisition loop */
    while(1) {
        // Start saving data when button is pushed
        if (button1_pressed) {
            button1_pressed = false;
            save_data = true;
            erase_flash(false);
            printf("Acquiring data...\r\n");
            printf("Press blue button to stop data acquisition\r\n");
            Flash_addr = FLASH_BANK2_BASE + 4;
        }
        
        if (save_data) {
            // Acquisition task
            save_data = acquisition_task(&Flash_addr);
        }
        else {
            // Read task
            read_task();
        }
    }
}