base code for beer_project

Dependencies:   mbed tsi_sensor FreescaleIAP MMA8451Q MPL3115A2

main.cpp

Committer:
tuscasp
Date:
2018-11-30
Revision:
3:93bc37d442df
Parent:
2:1bd31ca8a126
Child:
4:64f3383f2c43

File content as of revision 3:93bc37d442df:

/*******************************************************/ 
/**** LELEC_2811  Multiple sensors logger            ***/
/**** P. Gerard UCL     23/11/2016                   ***/
/**** M. Lefebvre UCL   09/11/2018                   ***/
/*******************************************************/ 

#include "mbed.h"
#include "FreescaleIAP.h"   // Library for Flash access
#include "MMA8451Q.h"       // Accelerometer
#include "MPL3115A2.h"      // Library for altimeter/temperature access

#define KL25Z_VDD 2.7       // !!! Value of supply voltage VDD: To be measured on board KL25Z pin 3V3 (calibration)

#define MMA8451_I2C_ADDRESS (0x1d<<1)
#define FSR                     0x02    // 0x00 for 2G, 0x01 for 4G, 0x02 for 8G
#define REG_OUT_X_MSB           0x01
#define REG_OUT_Y_MSB           0x03
#define REG_OUT_Z_MSB           0x05

#define MPL3115A2_I2C_ADDRESS (0x60<<1)
#define REG_ALTIMETER_MSB       0x01

#define DISABLE_STATE           0
#define ENABLE_STATE            1

#define NO_JUMPER               0
#define JUMPER_PRESENT          1

#define LEVEL_0                 0
#define LEVEL_1                 1

#define LED_ON                  0
#define LED_OFF                 1

#define FLASH_NO_ACQ_DONE       0
#define FLASH_ACQ_DONE          1
#define ERASE_FLASH_ERROR       -1
#define WRITE_FLASH_ERROR       -2

#define SECTOR_SIZE             1024
#define RESERVED_SECTOR         32

#define ACQ_TIMER_PERIOD        0.5   // Time between 2 acquisitions in seconds

#define N_PER_AVERAGE           8

#define BOARD_STRAIGHT          0
#define BOARD_UPSIDE_DOWN       1
#define ACCEL_MINIMUM_FOR_STORAGE   0

// Structure of sensors Data !!!!! SIZE MUST BE A MULTIPLE OF 4 bytes !!!!!
typedef struct{
    int16_t Accel_X;                // 2 bytes
    int16_t Accel_Y;                // 2 bytes
    int16_t Accel_Z;                // 2 bytes
    float Temperature;              // 4 bytes
    unsigned short Analog_PTE20;    // 2 bytes
    unsigned short Analog_PTE21;    // 2 bytes
    unsigned short Empty;           // 2 bytes
} Sensor_Data;                      // TOTAL = 16 bytes 

typedef struct{
    unsigned short Accel_Z;
    unsigned short Sallen_Key;
    unsigned short Interface;
    unsigned short Useless;
} Stored_Data;

int Number_Stored_Points;

// --- Setup I2C for MMA8451 accelerometer
// --- The last argument is the full scale range (FSR). 0x00 for 2G, 0x01 for 4G, 0x02 for 8G
MMA8451Q my8451(PTE25, PTE24, MMA8451_I2C_ADDRESS, FSR);
DigitalOut Accel_Enable(PTA13);

// --- Set temperature sensor
MPL3115A2 myMPL3115(PTE0, PTE1, MPL3115A2_I2C_ADDRESS);

// --- Set serial port (for communication with PC)
Serial Host_Comm(USBTX, USBRX);

// Analog inputs (ADCs)
AnalogIn myPTE20(PTE20);
AnalogIn myPTE21(PTE21);

// Analog output (DAC)
AnalogOut myDAC(PTE30);

// Digital outputs
DigitalOut Led_Red(LED1);           // Define I/O for LEDs
DigitalOut Led_Green(LED2);
DigitalOut Led_Blue(LED3);
DigitalOut Start_Pulse_Out(PTC9);   // Used to enter/exit acquisition mode 
DigitalIn  Start_Pulse_In(PTC11);   // Short pins J1_15 and J1_16 to enter in Acq_Mode

// Global variables
volatile bool bTimer;               // 1 means a timer tick is done
Ticker myTick_Acq;                  // Periodical timer for acquisition

int Flash_Base_Address = RESERVED_SECTOR * SECTOR_SIZE;     // Store Flash base address with 32K reserved for application code
int Nb_Sector;
uint32_t KL25_Flash_Size;

// Functions declaration
void Clear_Led(void);
int Acquisition_Flash(void);
int Read_Data_Logging(void);
bool Check_Jumper(void);
void myTimer_Acq_Task(void);
void Acquisition_Task(void);
void Read_Task(void);
extern IAPCode verify_erased(int address, unsigned int length);

int main() {
    
    uint8_t Count;                                          // Count defining the number of time the LED blinks before data acquisition
    
    // Set DAC output voltage
    float vdac;
    uint16_t dac_value;                                     // Local variable in 16 bits
     
    vdac = 0;                                               // Voltage output value
    dac_value = (uint16_t) ((vdac * 65536) / KL25Z_VDD);    // Transform desired voltage to fraction of 0xFFFF 
    myDAC.write_u16(dac_value);                             // DAC value in range 0x0000 - 0xFFFF (see mbed's AnalogOut classe ref.)
    
    Start_Pulse_In.mode(PullNone);                          // Input pin is programmed as floating
    Accel_Enable = DISABLE_STATE;                           // Turn Accel. Enable I/O to disabled state
 
// --- Baud rate setting
    Host_Comm.baud(115200);
    Clear_Led();
    
    KL25_Flash_Size = flash_size();                                 // Get size of KL25 embedded Flash
    Nb_Sector = (KL25_Flash_Size / SECTOR_SIZE) - RESERVED_SECTOR;  // Reserve max 32K for app code
    myTick_Acq.attach(&myTimer_Acq_Task, ACQ_TIMER_PERIOD);         // Initialize timer interrupt
  
    Host_Comm.printf("\n\rLELEC2811 Multiple sensors logger V2.0 UCL 2018\n\r");
    
    if ((sizeof(Sensor_Data) % 4) != 0)
    {
        Host_Comm.printf("\n\rERROR! Acquisition Data Structure size is NOT a multiple of 4!!! (%d)", sizeof(Sensor_Data));
        for(;;);        
    }
      
    myMPL3115.Oversample_Ratio(OVERSAMPLE_RATIO_4); 
    myMPL3115.Barometric_Mode();                                    // Configure MPL3115 (used for temperature and pressure measurement)
 
    for (;;)
    {
        if (Check_Jumper() == JUMPER_PRESENT)             
        {
            Clear_Led();
            
            Count = 5;
            while (Count !=0)
            {
                if (Check_Jumper() == JUMPER_PRESENT)   
                {
                    Led_Blue = LED_ON;  // Blink to alert user "Enter in Acquisition" after 5 seconds
                    wait_ms(900);
                    Led_Blue = LED_OFF;
                    wait_ms(100);
                    Count --;
                    if (Count == 0)
                    {        
                        Acquisition_Task();
                    }
                }
                else
                {
                    Count = 0;
                }
            } 
        }
        else
        {
            Read_Task();         
        }
    }
}
    
void Read_Task()
{
    char host_cmd;
    IAPCode Flash_State;
    bool bAcq_Done;
    
    Flash_State = verify_erased(Flash_Base_Address, KL25_Flash_Size - (RESERVED_SECTOR * SECTOR_SIZE)); 
    if (Flash_State == 0) // Virgin Flash ?
    {
        bAcq_Done = 0;      
    }
    else
    {
        bAcq_Done = 1;
    }     
    
    Clear_Led();
    wait_ms(500);
                
    if (bAcq_Done == 1)
    {
        Led_Green = LED_ON;
        Host_Comm.putc('1');
    }
    else
    {
        Led_Red = LED_ON;
        Host_Comm.putc('0');
    }
           
    if(Host_Comm.readable())                    // Did we receive a char from Host ?
    {
        host_cmd = Host_Comm.getc();            // Get it
                  
        if ((host_cmd == 'R') || (host_cmd == 'r')) // Read Flash Command ?
        {    
            Read_Data_Logging();                // Read and send acquisition data                   
        }
    }
    wait_ms(50);          
}

void Acquisition_Task()
{
    int Acq_Status;
               
    Clear_Led();
        
    Acq_Status = Acquisition_Flash();

    Clear_Led();
    
    while (Check_Jumper() == JUMPER_PRESENT)
    {     
        if (Acq_Status != FLASH_ACQ_DONE)
        {
            Led_Red = !Led_Red;
        }
        else
        {
           Led_Green = !Led_Green;            
        }
        wait_ms(100);
    }
}

void Clear_Led(void)
{
    Led_Red = LED_OFF;
    Led_Green = LED_OFF;
    Led_Blue = LED_OFF;     // Bug on board : Turning on the blue LED decreases consumption...
}

bool Check_Jumper()         // If J1_15 and J1_16 connected together -> return JUMPER_PRESENT
{
    uint8_t i;
    
    for (i = 0 ; i < 2 ; i ++)
    {
        Start_Pulse_Out = LEVEL_1;
        wait_ms(1);
        if (Start_Pulse_In != LEVEL_1)
        {
            return NO_JUMPER;
        }
    
        Start_Pulse_Out = LEVEL_0;
        wait_ms(1);
        if (Start_Pulse_In != LEVEL_0)
        {
            return NO_JUMPER;
        }
    }
    return JUMPER_PRESENT;
}

int Acquisition_Flash(void)
{
    int Status;  
    int Flash_Ptr ;
    int Led_Counter;
    Sensor_Data myData;
    int Board_Position;
    int Count_Measurements;
    Stored_Data myStoredData;
    
    
/*** Erase all Flash Page **/          
    for (Flash_Ptr = Flash_Base_Address ; Flash_Ptr < KL25_Flash_Size ; Flash_Ptr += 0x400)
    {
        Status = erase_sector(Flash_Ptr);   // Erase sector
                 
        if (Status !=0)
        { 
            return ERASE_FLASH_ERROR;
        }    
    }
  
    Flash_Ptr = Flash_Base_Address;         // Begin of Storage Area in Flash
    
    Led_Blue = LED_ON;
    Led_Counter = 0;

/*** Reset new variables **/          

    myStoredData.Accel_Z= 0;
    myStoredData.Interface = 0;
    myStoredData.Sallen_Key = 0;
    
    Board_Position = BOARD_STRAIGHT;
    
    Number_Stored_Points = 0;
    
    
/***** Begin of Loop Acquisition - Write in Flash ***/      
    
    while (Flash_Ptr < (KL25_Flash_Size - sizeof(Sensor_Data)) )    // Acq Loop
    {              
        while (bTimer == 0)                                         // Wait Acq Tick Timer Done
        {
  
        }
        bTimer = 0;
                   
        if ((float) Led_Counter * ACQ_TIMER_PERIOD == 1.0)          // Blink at 1Hz
        { 
            Led_Counter = 0;
            Led_Blue = !Led_Blue;
        }
        
        Led_Counter++; 
        
        // Get accelerometer data        
        Accel_Enable = ENABLE_STATE;                                // Rising edge -> Start accelerometer measurement
  
        // myData.Accel_X = my8451.getAccAxis(REG_OUT_X_MSB);
        // myData.Accel_Y = my8451.getAccAxis(REG_OUT_Y_MSB);
        myData.Accel_Z = my8451.getAccAxis(REG_OUT_Z_MSB);       
        
        Accel_Enable = DISABLE_STATE;
        
        
 /*** verify if it is upside down ***/           
        if (myData.Accel_Z < ACCEL_MINIMUM_FOR_STORAGE)
            Board_Position = BOARD_UPSIDE_DOWN;

        if (Board_Position == BOARD_UPSIDE_DOWN){
            
            Count_Measurements ++;

            // Get ADC values
            myData.Analog_PTE20 = myPTE20.read_u16(); 
            myData.Analog_PTE21 = myPTE21.read_u16();
            
            // add data to stored variable
            myStoredData.Accel_Z    = myData.Accel_Z;
            
            myStoredData.Sallen_Key += myData.Analog_PTE20;
            myStoredData.Interface += myData.Analog_PTE21;
            
            Host_Comm.printf("\n\r%d %d", Count_Measurements, myStoredData.Accel_Z);
            
            // after N_PER_AVERAGE measurements, take average and store
            if (Count_Measurements >= N_PER_AVERAGE){
                
                Count_Measurements = 0;
                
                myStoredData.Sallen_Key = myStoredData.Sallen_Key / N_PER_AVERAGE;
                myStoredData.Interface = myStoredData.Interface / N_PER_AVERAGE;

 /*** Save Data in Flash ***/
                Number_Stored_Points ++;
                Status = program_flash(Flash_Ptr, (char *) &myStoredData, sizeof(Stored_Data));   // Write in the Flash
                if (Status != 0) 
                {
                     Host_Comm.printf("\n\rFlash_Write Error = %d", Status); 
                     return WRITE_FLASH_ERROR;
                }
                Flash_Ptr += sizeof(Stored_Data); 
                
                // verifies if system comes back straight orientation
                if (myData.Accel_Z > ACCEL_MINIMUM_FOR_STORAGE)
                    Board_Position = BOARD_STRAIGHT; 
        
                if (Check_Jumper() != JUMPER_PRESENT)                       // If jumper removed -> Stop acquisition
                {
                    return FLASH_ACQ_DONE ;   
                }
            }
            
        }
        
        else {
            if (Check_Jumper() != JUMPER_PRESENT)                       // If jumper removed -> Stop acquisition
                return FLASH_ACQ_DONE ;   
        }       
        
    }
    
    return FLASH_ACQ_DONE ;
}

int Read_Data_Logging()
{  
    Stored_Data * data = (Stored_Data * )Flash_Base_Address;    // Sensor_Data pointer of data stored in Flash
    int Flash_Record_Ptr;
    char cmd;
    int Record_Counter;
    int Max_Record;
    Stored_Data myRead_Data;                                    // Data Structure used to retrieve saved value from Flash
    
    float Ethanol_Sallen_Key;
    float Ethanol_Interface;
    
    Clear_Led(); 
  
    Max_Record = (Nb_Sector * SECTOR_SIZE) / sizeof(Sensor_Data);
    Record_Counter = 0;
    Flash_Record_Ptr = 0;
    
    Host_Comm.printf("\n\r# AccZ Eth_SK Eth_Int");  
     
    while (Record_Counter < Number_Stored_Points && Record_Counter < Max_Record) 
    {         
        Led_Green = !Led_Green;
        Led_Blue = !Led_Green;
        
        if(Host_Comm.readable()) 
        {
            cmd = Host_Comm.getc();
            if ((cmd == 'S') || (cmd == 's'))   // Receiving 'S' or 's' means stop Read Flash
            {
                Clear_Led(); 
                return 0;    
            }
        }
        
        myRead_Data = data[Flash_Record_Ptr];
        
        Flash_Record_Ptr ++;
                       
        if (myRead_Data.Accel_Z == -1)  // Valid data ? (!= 0xFFFFFFFF from empty Flash sector)
        {
        }
        else
        {
            Ethanol_Sallen_Key  = ((float) myRead_Data.Sallen_Key / 0XFFFF) * KL25Z_VDD;    // Convert to voltage
            Ethanol_Interface   = ((float) myRead_Data.Interface / 0XFFFF) * KL25Z_VDD;                          
            
            Host_Comm.printf("\n\r%d ", Record_Counter);
            Host_Comm.printf("%d ", myRead_Data.Accel_Z);
            Host_Comm.printf("%1.3f %1.3f ", Ethanol_Sallen_Key, Ethanol_Interface);               
        }
        
        Record_Counter ++;
    }
    Clear_Led();
    return 0;
}

/* Interrupt Task */
void myTimer_Acq_Task() 
{   
    bTimer = 1;
}