LELEC2811 - I&S / Mbed OS LELEC2811_LISDW12_Accelerometer

Dependencies:   X_NUCLEO_IKS01A3

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

Go to the documentation of this file.
00001 /**
00002  ******************************************************************************
00003  * @file    main.cpp
00004  * @author  SRA
00005  * @version V1.0.0
00006  * @date    5-March-2019
00007  * @brief   Simple Example application for using the X_NUCLEO_IKS01A3
00008  *          MEMS Inertial & Environmental Sensor Nucleo expansion board.
00009  ******************************************************************************
00010  * @attention
00011  *
00012  * <h2><center>&copy; COPYRIGHT(c) 2019 STMicroelectronics</center></h2>
00013  *
00014  * Redistribution and use in source and binary forms, with or without modification,
00015  * are permitted provided that the following conditions are met:
00016  *   1. Redistributions of source code must retain the above copyright notice,
00017  *      this list of conditions and the following disclaimer.
00018  *   2. Redistributions in binary form must reproduce the above copyright notice,
00019  *      this list of conditions and the following disclaimer in the documentation
00020  *      and/or other materials provided with the distribution.
00021  *   3. Neither the name of STMicroelectronics nor the names of its contributors
00022  *      may be used to endorse or promote products derived from this software
00023  *      without specific prior written permission.
00024  *
00025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00028  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00029  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00030  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00031  *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00032  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00033  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00034  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  ******************************************************************************
00037 */
00038 
00039 /*
00040     LELEC2811 Accelerometer LIS2DW12 Project
00041     M. Lefebvre - 2019-2020
00042 */
00043 
00044 /* Includes */
00045 #include <stdlib.h>
00046 #include <time.h>
00047 #include "mbed.h"
00048 #include "XNucleoIKS01A3.h"
00049 #include "stm32l073xx.h"
00050 #include "stm32l0xx_hal_flash.h"
00051 
00052 /* Defines */
00053 #define FS                      12.5    // Readout frequency (Hz) - /!\ Must be below 100Hz
00054 #define FLASH_WRITE_TIME        0.00328 // Flash write time (s)
00055 
00056 // LIS2DW12 Accelerometer
00057 #define LIS2DW12_ODR            3       // Output data rate (0 power down, 1 HP 12.5Hz/LP 1.6Hz, 2 for 12.5Hz, 3 for 25Hz, 4 for 50Hz, 5 for 100Hz, 6 for 200Hz, 7 for HP 400Hz/LP 200Hz, 8 for HP 800Hz/LP 200Hz, 9 for HP 1600Hz/LP 200Hz)
00058 #define LIS2DW12_FS             16      // Full-scale +-(2, 4, 8 or 16 g)
00059 #define LIS2DW12_BW_FILT        0       // Filter bandwidth (0 for ODR/2, 1 for ODR/4, 2 for ODR/10, 3 for ODR/20)
00060 #define LIS2DW12_LP_MODE        1       // Low-power modes 1 to 4 (1 gives the max. rms noise, 4 gives the min. rms noise)
00061 #define LIS2DW12_MODE           0       // Mode (0 for low-power, 1 for high-performance, 2 for single data conversion)
00062 #define LIS2DW12_LOW_NOISE      0       // Low-noise (0 disabled, 1 enabled)
00063 #define LIS2DW12_POWER_MODE     LIS2DW12_LP_MODE + (LIS2DW12_MODE << 2) + (LIS2DW12_LOW_NOISE << 4)
00064 #define LIS2DW12_DATA_SIZE      12      // Number of bytes for LIS2DW12 accelerometer sensor data
00065 
00066 #define TS                      (1/FS)-((LIS2DW12_DATA_SIZE/4)*FLASH_WRITE_TIME)
00067 
00068 /* Functions definition */
00069 bool acquisition_task(bool verbose);
00070 void read_task();
00071 void print_flash_info();
00072 bool erase_flash(bool verbose);
00073 bool write_flash(uint32_t Flash_addr, uint32_t* Flash_wdata, int32_t n_words, bool verbose);
00074 void read_flash(uint32_t Flash_addr, uint32_t* Flash_rdata, uint32_t n_bytes);
00075 void button1_enabled_cb(void);
00076 void button1_onpressed_cb(void);
00077 static char *print_double(char *str, double v);
00078 uint32_t FloatToUint(float n);
00079 float UintToFloat(uint32_t n);
00080 
00081 /* Serial link */
00082 Serial pc(SERIAL_TX, SERIAL_RX);
00083 
00084 /* Button */
00085 InterruptIn button1(USER_BUTTON);
00086 volatile bool button1_pressed = false; // Used in the main loop
00087 volatile bool button1_enabled = true; // Used for debouncing
00088 Timeout button1_timeout; // Used for debouncing
00089 
00090 /* Instantiate the expansion board */
00091 static XNucleoIKS01A3 *mems_expansion_board = XNucleoIKS01A3::instance(D14, D15, D4, D5, A3, D6, A4);
00092 
00093 /* Retrieve the composing elements of the expansion board */
00094 static LIS2MDLSensor *magnetometer = mems_expansion_board->magnetometer;
00095 static HTS221Sensor *hum_temp = mems_expansion_board->ht_sensor;
00096 static LPS22HHSensor *press_temp = mems_expansion_board->pt_sensor;
00097 static LSM6DSOSensor *acc_gyro = mems_expansion_board->acc_gyro;
00098 static LIS2DW12Sensor *accelerometer = mems_expansion_board->accelerometer;
00099 static STTS751Sensor *temp = mems_expansion_board->t_sensor;
00100 
00101 /* Main */
00102 int main()
00103 {
00104     uint8_t id;
00105     float read_reg, read_reg_1;
00106     uint8_t read_reg_int, read_reg_int_1, read_reg_int_2;
00107     
00108     bool save_data = false;
00109     uint32_t Flash_addr = FLASH_BANK2_BASE;
00110 
00111     /* Serial link configuration */
00112     pc.baud(115200);
00113     
00114     /* Button configuration */
00115     button1.fall(callback(button1_onpressed_cb)); // Attach ISR to handle button press event
00116     
00117     /* Reset message */
00118     printf("\n\r**************************************************\n\r");
00119     printf("LELEC2811 LIS2DW12 Accelerometer Program\n\r");
00120     printf("**************************************************\n\r");
00121     
00122     /* LIS2DW12 accelerometer sensor configuration */
00123     accelerometer->enable_x();
00124     printf("/***** LIS2DW12 accelerometer sensor configuration *****/\r\n");
00125     
00126     accelerometer->read_id(&id);
00127     printf("LIS2DW12 accelerometer = 0x%X\r\n", id);
00128     
00129     accelerometer->set_x_odr(LIS2DW12_ODR);
00130     accelerometer->get_x_odr(&read_reg);
00131     printf("LIS2DW12 ODR = %1.3f [Hz]\r\n", read_reg);
00132     
00133     accelerometer->set_x_fs(LIS2DW12_FS);
00134     accelerometer->get_x_fs(&read_reg);
00135     printf("LIS2DW12 FS = %1.3f [g]\r\n", read_reg);
00136     
00137     accelerometer->set_x_bw_filt(LIS2DW12_BW_FILT);
00138     accelerometer->get_x_bw_filt(&read_reg_int);
00139     printf("LIS2DW12 BW_FILT = %1d\r\n", read_reg_int);
00140     
00141     accelerometer->set_x_power_mode(LIS2DW12_POWER_MODE);
00142     accelerometer->get_x_power_mode(&read_reg_int, &read_reg_int_1, &read_reg_int_2);
00143     printf("LIS2DW12 LP_MODE = %1d\r\n", read_reg_int);
00144     printf("LIS2DW12 MODE = %1d\r\n", read_reg_int_1);
00145     printf("LIS2DW12 LOW_NOISE = %1d\r\n", read_reg_int_2);
00146     
00147     /* Print Flash memory information */
00148     print_flash_info();
00149     
00150     /* Information for the user */
00151     printf("Press blue button to start data acquisition\r\n");
00152     printf("Press 'R' to read previously measured data\r\n");
00153     
00154     /* Acquisition loop */
00155     while(1) {
00156         // Start saving data when button is pushed
00157         if (button1_pressed) {
00158             button1_pressed = false;
00159             save_data = true;
00160             erase_flash(false);
00161             printf("Acquiring data...\r\n");
00162             printf("Press blue button to stop data acquisition\r\n");
00163             Flash_addr = FLASH_BANK2_BASE;
00164         }
00165         
00166         if (save_data) {
00167             // Acquisition task
00168             save_data = acquisition_task(false);
00169         }
00170         else {
00171             // Read task
00172             read_task();
00173         }
00174     }
00175 }
00176 
00177 /* Acquisition task */
00178 bool acquisition_task(bool verbose)
00179 {
00180     int32_t acc_axes[3];
00181     uint32_t Flash_addr = FLASH_BANK2_BASE;
00182 
00183     while (Flash_addr <= FLASH_BANK2_END-FLASH_PAGE_SIZE+1) {
00184         // Read sensors data
00185         accelerometer->get_x_axes(acc_axes);
00186         
00187         // Save data to Flash memory
00188         write_flash(Flash_addr, (uint32_t*) &acc_axes[0], 3, false);
00189         Flash_addr += LIS2DW12_DATA_SIZE;
00190         
00191         // Print data in terminal
00192         if (verbose) {
00193             printf("LIS2DW12: [acc/mg] %6d, %6d, %6d\r\n", ((uint32_t) acc_axes[0]), ((uint32_t) acc_axes[1]), ((uint32_t) acc_axes[2]));
00194         }
00195         
00196         // Wait for acquisition period
00197         wait(TS);
00198         
00199         // Stop saving data when button is pushed
00200         if (button1_pressed) {
00201             button1_pressed = false;
00202             printf("Data acquisition stopped\r\n");
00203             printf("Press 'R' to read the data\r\n");
00204             return false;
00205         }
00206     }
00207     printf("Data acquisition stopped\r\n");
00208     printf("Press 'R' to read the data\r\n");
00209     return false;
00210 }
00211 
00212 /* Read task */
00213 void read_task()
00214 {
00215     char pc_input;
00216     uint32_t Flash_rdata[3];
00217     bool flash_empty = false;
00218     
00219     // Read terminal input
00220     if (pc.readable()) {
00221         pc_input = pc.getc();
00222     }
00223     else {
00224         pc_input = ' ';
00225     }
00226     
00227     // Read Flash memory if 'R' is pressed
00228     if ((pc_input == 'r') || (pc_input == 'R')) {
00229         // Data labels
00230         printf("acc_X\tacc_Y\tacc_Z\r\n");
00231         
00232         // Read 1st Flash data
00233         uint32_t Flash_addr_temp = FLASH_BANK2_BASE;
00234         read_flash(Flash_addr_temp, &Flash_rdata[0], LIS2DW12_DATA_SIZE);
00235         
00236         // Read Flash data
00237         while ((Flash_addr_temp <= FLASH_BANK2_END-LIS2DW12_DATA_SIZE+1) && !flash_empty) {
00238             // Print read data in the terminal
00239             printf("%6d\t%6d\t%6d\r\n", Flash_rdata[0], Flash_rdata[1], Flash_rdata[2]);
00240             Flash_addr_temp += LIS2DW12_DATA_SIZE;
00241             
00242             // Check if the next address is not empty (erased Flash only contains 0)
00243             if (Flash_addr_temp <= FLASH_BANK2_END-LIS2DW12_DATA_SIZE+1) {
00244                 read_flash(Flash_addr_temp, &Flash_rdata[0], LIS2DW12_DATA_SIZE);
00245                 if ((Flash_rdata[0] == 0) && (Flash_rdata[1] == 0) && (Flash_rdata[2] == 0)) {
00246                     flash_empty = true;
00247                 }
00248             }
00249         }
00250     }
00251 }
00252 
00253 /* Print Flash memory info */
00254 void print_flash_info()
00255 {
00256     printf("**************************************************\n\r");
00257     printf("/***** Flash memory info *****/\r\n");
00258     printf("Flash size: %d [B]\r\n", FLASH_SIZE);
00259     printf("Flash page size: %d [B]\r\n", FLASH_PAGE_SIZE);
00260     printf("Flash nb of pages: %d \r\n", FLASH_SIZE/FLASH_PAGE_SIZE);
00261     printf("Flash bank 1 base address: 0x%X\r\n", FLASH_BASE);
00262     printf("Flash bank 1 end address: 0x%X\r\n", FLASH_BANK1_END);
00263     printf("Flash bank 2 base address: 0x%X\r\n", FLASH_BANK2_BASE);
00264     printf("Flash bank 2 end address: 0x%X\r\n", FLASH_BANK2_END);
00265     printf("**************************************************\n\r");
00266 }
00267 
00268 /* Erase content of Flash memory */
00269 bool erase_flash(bool verbose)
00270 {
00271     printf("Erasing Flash memory...\r\n");
00272     
00273     // Unlock Flash memory
00274     HAL_FLASH_Unlock();
00275 
00276     // Erase Flash memory
00277     FLASH_EraseInitTypeDef eraser;
00278     uint32_t Flash_addr = FLASH_BANK2_BASE;
00279     uint32_t page_error = 0;
00280     int32_t page = 1;
00281     
00282     while (Flash_addr < FLASH_BANK2_END) {
00283         eraser.TypeErase = FLASH_TYPEERASE_PAGES;
00284         eraser.PageAddress = Flash_addr;
00285         eraser.NbPages = 1;
00286         if(HAL_OK != HAL_FLASHEx_Erase(&eraser, &page_error)) {
00287             if (verbose) {printf("Flash erase failed!\r\n");}
00288             printf("Error 0x%X\r\n", page_error);
00289             HAL_FLASH_Lock();
00290             return false;
00291         }
00292         if (verbose) {printf("Erased page %d at address: 0x%X\r\n", page, Flash_addr);}
00293         Flash_addr += FLASH_PAGE_SIZE;
00294         page++;
00295     }
00296     
00297     if (verbose) {printf("Flash erase succesful!\r\n");}
00298     return true;
00299 }
00300 
00301 /* Write Flash memory */
00302 bool write_flash(uint32_t Flash_addr, uint32_t* Flash_wdata, int32_t n_words, bool verbose)
00303 {
00304     clock_t time;
00305     if (verbose) {time = clock();}
00306     
00307     // Unlock Flash memory
00308     HAL_FLASH_Unlock();
00309     
00310     // Write Flash memory
00311     for (int i=0; i<n_words; i++) {
00312         if (HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Flash_addr, Flash_wdata[i])) {
00313             if (verbose) {printf("Flash write failed!\r\n");}
00314             HAL_FLASH_Lock();
00315             return false;
00316         }
00317         Flash_addr += 4;
00318     }
00319     if (verbose) {printf("Flash write succesful!\r\n");}
00320     
00321     HAL_FLASH_Lock();
00322     
00323     if (verbose) {
00324         time = clock() - time;
00325         printf("Time to write: %1.6f [s]\r\n", (((double) time)/CLOCKS_PER_SEC));
00326     }
00327     
00328     return true;
00329 }
00330 
00331 /* Read Flash memory */
00332 void read_flash(uint32_t Flash_addr, uint32_t* Flash_rdata, uint32_t n_bytes)
00333 {
00334     memcpy(Flash_rdata, (uint32_t*) Flash_addr, n_bytes);
00335 }
00336 
00337 /* Enables button when bouncing is over */
00338 void button1_enabled_cb(void)
00339 {
00340     button1_enabled = true;
00341 }
00342 
00343 /* ISR handling button pressed event */
00344 void button1_onpressed_cb(void)
00345 {
00346     if (button1_enabled) { // Disabled while the button is bouncing
00347         button1_enabled = false;
00348         button1_pressed = true; // To be read by the main loop
00349         button1_timeout.attach(callback(button1_enabled_cb), 0.3); // Debounce time 300 ms
00350     }
00351 }
00352 
00353 /* Helper function for printing floats & doubles */
00354 static char *print_double(char *str, double v)
00355 {
00356     int decimalDigits = 6;
00357     int i = 1;
00358     int intPart, fractPart;
00359     int len;
00360     char *ptr;
00361 
00362     /* prepare decimal digits multiplicator */
00363     for (; decimalDigits != 0; i *= 10, decimalDigits--);
00364 
00365     /* calculate integer & fractinal parts */
00366     intPart = (int)v;
00367     fractPart = (int)((v - (double)(int)v) * i);
00368 
00369     /* fill in integer part */
00370     sprintf(str, "%i.", intPart);
00371 
00372     /* prepare fill in of fractional part */
00373     len = strlen(str);
00374     ptr = &str[len];
00375 
00376     /* fill in leading fractional zeros */
00377     for (i /= 10; i > 1; i /= 10, ptr++) {
00378         if (fractPart >= i) {
00379             break;
00380         }
00381         *ptr = '0';
00382     }
00383 
00384     /* fill in (rest of) fractional part */
00385     sprintf(ptr, "%i", fractPart);
00386 
00387     return str;
00388 }
00389 
00390 uint32_t FloatToUint(float n)
00391 {
00392    return (uint32_t)(*(uint32_t*)&n);
00393 }
00394  
00395 float UintToFloat(uint32_t n)
00396 {
00397    return (float)(*(float*)&n);
00398 }