/* * ulp_main.c * * Created on: Feb 17, 2023 * Author: Partha */ #include #include #include "ulp_riscv.h" #include "ulp_riscv_utils.h" #include "ulp_riscv_gpio.h" #include "sensors_registers.h" #include "ulp_riscv_i2c_ulp_core.h" #include "sdkconfig.h" #define I2C_MASTER_NUM 0 #define ULP_CLOCK_CYCLE_IN_MS 8500 volatile uint32_t server_time = 0; volatile uint32_t is_sleep = 0; /*Settings structure*/ volatile settings settings_structure; /*Sensor variables*/ //Sensor Data float ulp_temperature; float ulp_humidity; float ulp_thermocoupleTemp; //Sensor previous Data float ulp_prev_temperature; float ulp_prev_humidity; float ulp_prev_thermocoupleTemp; /*Sensor flags and triggers*/ uint16_t ulp_triggersThatCanWakeTheHost; uint16_t ulp_strobedHumidityFlags; uint16_t ulp_strobedMiscFlags; uint16_t ulp_strobedMotionFlags; uint16_t ulp_strobedTemperatureFlags; uint16_t ulp_strobedThermocoupleFlags; uint32_t wakeup_type = 0; uint32_t ens_dev_id = 0; uint32_t mcp9600_dev_id = 0; uint32_t temp_needed = 0; //Temp, Humi, Thermo raw_thresholds uint32_t humidity_raw_max_thr = 0; uint32_t humidity_raw_min_thr = 0; uint32_t temperature_raw_max_thr = 0; uint32_t temperature_raw_min_thr = 0; uint32_t thermo_raw_max_thr = 0; int32_t thermo_raw_min_thr = 0; //Sensor Raw values uint32_t humidity_raw = 0; uint32_t prev_humidity_raw = 0; uint32_t thermo_temp_raw = 0; //need to be signed uint32_t prev_thermo_temp_raw = 0; //need to be signed uint32_t ens_temp_raw = 0; uint32_t prev_ens_temp_raw = 0; uint8_t data[8]; uint32_t ens_dev_id; uint32_t opt_dev_id; uint32_t opt_manf_id; uint32_t config_reg = 0; uint32_t result_reg = 0; uint32_t light_exponent = 0; uint32_t light_data_opt = 0; uint32_t prev_light_data_opt = 0; static uint8_t buff[8]; /****************************************************************************************/ /********************************** General ULP-Functions *******************************/ static void ulp_initialize_variables(void) { server_time = 0; //Sensor Data ulp_temperature = 0; ulp_humidity = 0; ulp_thermocoupleTemp = 0; //Sensor previous Data ulp_prev_temperature = 0; ulp_prev_humidity = 0; ulp_prev_thermocoupleTemp = 0; //Strobes and triggers variables ulp_triggersThatCanWakeTheHost = 0; ulp_strobedHumidityFlags = 0; ulp_strobedMiscFlags = 0; ulp_strobedMotionFlags = 0; ulp_strobedTemperatureFlags = 0; ulp_strobedThermocoupleFlags = 0; //Settings structure settings_structure.accelerometerInterval = 0; settings_structure.accelerometerLevel = 0; settings_structure.accelerometerLockoutInSeconds = 0; settings_structure.accelerometerMode = 0; //settings_structure.accelerometerTokens = 0; settings_structure.alertInterval = 0; settings_structure.historyIndex = 0; } /****************************************************************************************/ /******************************** MCP9600-Thermocouple Sensor ***************************/ static void set_thermocouple_type(uint8_t type) { uint8_t tempThermocoupleType; tempThermocoupleType = type; tempThermocoupleType &= 0x70; /*Start new conversion */ buff[0] = tempThermocoupleType; ulp_riscv_i2c_master_set_slave_addr(0x60); ulp_riscv_i2c_master_set_slave_reg_addr(0x05); ulp_riscv_i2c_master_write_to_device(buff, 1); ulp_riscv_delay_cycles(500 * ULP_CLOCK_CYCLE_IN_MS); ulp_riscv_delay_cycles(500 * ULP_CLOCK_CYCLE_IN_MS); } static void get_thermocouple_dev_id(void) { memset(buff, 0, 2); ulp_riscv_i2c_master_set_slave_addr(0x60); ulp_riscv_i2c_master_set_slave_reg_addr(0x20); ulp_riscv_i2c_master_read_from_device(buff, 1); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); mcp9600_dev_id = buff[0];//buff[1] | (buff[0] << 8); } #if 1 static void mcp_set_burst_mode(void) { //printf("Setting Burst mode\n"); ulp_riscv_i2c_master_set_slave_addr(0x60); ulp_riscv_i2c_master_set_slave_reg_addr(0x06); buff[0] = 0xA2; ulp_riscv_i2c_master_write_to_device(buff, 1); ulp_riscv_delay_cycles(1000 * ULP_CLOCK_CYCLE_IN_MS); } static void mcp_start_conversion(void) { memset(buff, 0, 2); //printf("Starting thermocouple conversion\n"); ulp_riscv_i2c_master_set_slave_addr(0x60); ulp_riscv_i2c_master_set_slave_reg_addr(0x04); buff[0] = 0xC0; ulp_riscv_i2c_master_write_to_device(buff, 1); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); mcp_set_burst_mode(); } static void mcp_get_temp(void) { uint16_t temp = 0; uint8_t counter = 0; uint8_t err = 1; memset(buff, 0, 6); mcp_start_conversion(); do { //ulp_riscv_i2c_master_set_slave_addr(0x60); ulp_riscv_i2c_master_set_slave_reg_addr(0x04); ulp_riscv_i2c_master_read_from_device(buff, 1); if(counter > 3) { //printf("Timeout for getting thermocouple temp\n"); err = 0; break; } counter++; ulp_riscv_delay_cycles(111 * ULP_CLOCK_CYCLE_IN_MS); } while (!(buff[0] & 0x40)); if(err && !(buff[0] & 0x10)) { memset(buff, 0, 6); //ulp_riscv_i2c_master_set_slave_addr(0x60); ulp_riscv_i2c_master_set_slave_reg_addr(0x00); ulp_riscv_i2c_master_read_from_device(buff, 1); ulp_riscv_i2c_master_set_slave_reg_addr(0x00); //ulp_riscv_i2c_master_read_from_device(buff + 1, 1); ulp_riscv_i2c_master_read_from_device(buff + 1, 2); ulp_riscv_delay_cycles(10 * ULP_CLOCK_CYCLE_IN_MS); prev_thermo_temp_raw = thermo_temp_raw; temp = buff[1] | (buff[0] << 8); thermo_temp_raw = temp; thermo_temp_raw /= 16; if(temp & 0x8000) // Adjust for sign bit thermo_temp_raw -= 4096; } ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); } #endif /****************************************************************************************/ /************************** ENS210-Temperature & Humidity Sensor ************************/ static void ens_set_active(void) { //ESN Setting to active mode //printf("ESN Setting to active mode\n"); ulp_riscv_i2c_master_set_slave_reg_addr(0x10); buff[0] = 0; ulp_riscv_i2c_master_write_to_device(buff, 1); } static void ens_init(void) { ulp_riscv_i2c_master_set_slave_addr(0x43); ens_set_active(); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); ens_set_active(); ulp_riscv_delay_cycles(500 * ULP_CLOCK_CYCLE_IN_MS); //ESN Reading sys stat //("ESN Reading sys stat\n"); ulp_riscv_i2c_master_set_slave_reg_addr(0x11); buff[0] = 0; ulp_riscv_i2c_master_read_from_device(buff, 1); //("ENS Sys stat: %d\n", buff[0]); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); //Reading device id //("ESN Reading device id\n"); memset(buff, 0, 2); ulp_riscv_i2c_master_set_slave_reg_addr(0x00); ulp_riscv_i2c_master_read_from_device(buff, 1); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); ulp_riscv_i2c_master_set_slave_reg_addr(0x01); ulp_riscv_i2c_master_read_from_device(buff + 1, 1); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); ens_dev_id = buff[0] | (buff[1] << 8); } static void ens_start(void) { ulp_riscv_i2c_master_set_slave_addr(0x43); //Sens Run ulp_riscv_i2c_master_set_slave_reg_addr(0x21); buff[0] = 3; ulp_riscv_i2c_master_write_to_device(buff, 1); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); //Sens Start ulp_riscv_i2c_master_set_slave_reg_addr(0x22); buff[0] = 3; ulp_riscv_i2c_master_write_to_device(buff, 1); ulp_riscv_delay_cycles(500 * ULP_CLOCK_CYCLE_IN_MS); } static void ens_read_temp(void) { uint8_t index = 0; memset(buff, 0, 6); ulp_riscv_i2c_master_set_slave_addr(0x43); ulp_riscv_i2c_master_set_slave_reg_addr(0x30); ulp_riscv_i2c_master_read_from_device(buff, 1); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); ulp_riscv_i2c_master_set_slave_reg_addr(0x31); ulp_riscv_i2c_master_read_from_device(buff + 1, 1); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); ulp_riscv_i2c_master_set_slave_reg_addr(0x32); ulp_riscv_i2c_master_read_from_device(buff + 2, 1); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); ulp_riscv_i2c_master_set_slave_reg_addr(0x33); ulp_riscv_i2c_master_read_from_device(buff + 3, 1); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); ulp_riscv_i2c_master_set_slave_reg_addr(0x34); ulp_riscv_i2c_master_read_from_device(buff + 4, 1); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); ulp_riscv_i2c_master_set_slave_reg_addr(0x35); ulp_riscv_i2c_master_read_from_device(buff + 5, 1); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); if(buff[2] & 0x01) { prev_ens_temp_raw = ens_temp_raw; ens_temp_raw = buff[0] | (buff[1] << 8); //tempC = temp/64.0; //tempC -= 273.15; } if(buff[5] & 0x01) { prev_humidity_raw = humidity_raw; humidity_raw = buff[3] | (buff[4] << 8); //hum = hum/512.0; } } uint8_t ulp_data_process_tempHumi_thresholds(uint32_t raw_data, uint32_t prev_raw_data, ulpSensorType_t sensor) { uint8_t useTokens = 0; uint8_t wakeHostForStrobedTrigger = 0; switch(sensor) { case ULP_LIGHT_SENSOR: break; case ULP_ACCELEROMETER_SENSOR: break; case ULP_POWER_MONITOR_SENSOR: break; case ULP_TEMPERATURE_SENSOR: /* Process thresholds for ENS210-TempData*/ if((raw_data > temperature_raw_max_thr) && (prev_raw_data < temperature_raw_max_thr)) { (ulp_strobedTemperatureFlags) |= STROBED_SENSOR_MEASUREMENT_EXCEEDED_UPPER_THRESHOLD; wakeup_type |= (1<<3); wakeHostForStrobedTrigger = 1; } else if((raw_data < temperature_raw_min_thr) && (prev_raw_data > temperature_raw_min_thr)) { (ulp_strobedTemperatureFlags) |= STROBED_SENSOR_MEASUREMENT_FELL_BELOW_LOWER_THRESHOLD; wakeup_type |= (1<<4); wakeHostForStrobedTrigger = 1; } break; case ULP_HUMIDITY_SENSOR: /* Process thresholds for ENS210-HumiData*/ if((raw_data > humidity_raw_max_thr) && (prev_raw_data < humidity_raw_max_thr)) { (ulp_strobedHumidityFlags) |= STROBED_SENSOR_MEASUREMENT_EXCEEDED_UPPER_THRESHOLD; wakeup_type |= (1<<5); wakeHostForStrobedTrigger = 1; } else if((raw_data < humidity_raw_min_thr) && (prev_raw_data > humidity_raw_min_thr)) { (ulp_strobedHumidityFlags) |= STROBED_SENSOR_MEASUREMENT_FELL_BELOW_LOWER_THRESHOLD; wakeup_type |= (1<<6); wakeHostForStrobedTrigger = 1; } break; case ULP_THERMOCOUPLE_SENSOR: if((ulp_triggersThatCanWakeTheHost & WAKE_HOST_WHEN_THERMOCOUPLE_CROSSES_LIMITS)) { /* Process thresholds for MCP9600-TcData*/ if((raw_data > thermo_raw_max_thr) && (prev_raw_data < thermo_raw_max_thr)) { (ulp_strobedThermocoupleFlags) |= STROBED_SENSOR_MEASUREMENT_EXCEEDED_UPPER_THRESHOLD; wakeup_type |= (1<<7); wakeHostForStrobedTrigger = 1; } else if((raw_data < thermo_raw_min_thr) && (prev_raw_data > thermo_raw_min_thr)) { (ulp_strobedThermocoupleFlags) |= STROBED_SENSOR_MEASUREMENT_FELL_BELOW_LOWER_THRESHOLD; wakeup_type |= (1<<8); wakeHostForStrobedTrigger = 1; } break; } break; } return wakeHostForStrobedTrigger; } uint8_t ulp_data_process_tempHumi_thresholds2(uint32_t raw_data, uint32_t prev_raw_data, uint8_t sensor) { //uint8_t enable_thsProcess = 1; uint8_t useTokens = 0; uint8_t wakeHostForStrobedTrigger = 0; uint32_t thr = 0; uint32_t thr2 = 0; switch(sensor) { case 1: /* Set the tokens register to be ThermoCouple token-registers */ //tokenregister = &(esp_settings->temperatureTokens); thr = ((26.6+273.15)*64); thr2 = ((-1.1+273.15)*64); /* Process thresholds for ENS210-TempData*/ if((raw_data > thr) && (prev_raw_data < thr)) { wakeup_type |= (1<<3); wakeHostForStrobedTrigger = 1; } else if((raw_data < thr2) && (prev_raw_data > thr2)) { wakeup_type |= (1<<4); wakeHostForStrobedTrigger = 1; } break; case 2: /* Set the tokens register to be Humidity token registers */ //tokenregister = &(esp_settings->humidityTokens); /* Process thresholds for ENS210-HumiData*/ if((raw_data > (512*80)) && (prev_raw_data < (512*80))) { wakeup_type |= (1<<5); wakeHostForStrobedTrigger = 1; } else if((raw_data < (512*10)) && (prev_raw_data > (512*10))) { wakeup_type |= (1<<6); wakeHostForStrobedTrigger = 1; } break; case 3: { /* Set the tokens register to be ThermoCouple token-registers */ //tokenregister = &(esp_settings->thermocoupleTokens); /* Process thresholds for MCP9600-TcData*/ if((raw_data > 50) && (prev_raw_data < 50)) { wakeup_type |= (1<<7); wakeHostForStrobedTrigger = 1; } else if((raw_data < -100) && (prev_raw_data > -100)) { wakeup_type |= (1<<8); wakeHostForStrobedTrigger = 1; } break; } break; } return wakeHostForStrobedTrigger; } /**********************************************************************/ /************************Light sensor**********************************/ /**********************************************************************/ void opt_init(void) { /* Fetch manufacturer ID */ data[0] = 0; data[1] = 0; ulp_riscv_i2c_master_set_slave_addr(0x44); ulp_riscv_i2c_master_set_slave_reg_addr(0x7E); ulp_riscv_i2c_master_read_from_device(data, 2); ulp_riscv_delay_cycles(500 * ULP_CLOCK_CYCLE_IN_MS); opt_manf_id = (data[0]<<8)|(data[1]); /* Fetch Device ID */ data[0] = 0; data[1] = 0; ulp_riscv_i2c_master_set_slave_addr(0x44); ulp_riscv_i2c_master_set_slave_reg_addr(0x7F); ulp_riscv_i2c_master_read_from_device(data, 2); ulp_riscv_delay_cycles(500 * ULP_CLOCK_CYCLE_IN_MS); opt_dev_id = (data[0]<<8)|(data[1]); } void opt_read_reg(void) { uint8_t data[8]; uint8_t exponent = 0; uint16_t result =1 ; uint32_t result_reg2 = 0; /* Fetch Configuration register */ data[0] = 0; data[1] = 0; ulp_riscv_i2c_master_set_slave_addr(0x44); ulp_riscv_i2c_master_set_slave_reg_addr(0x01); ulp_riscv_i2c_master_read_from_device(data, 1); ulp_riscv_i2c_master_read_from_device(data+1, 2); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); config_reg = (data[0]<<8)|(data[1]); /* Set the single shot mode */ config_reg = config_reg | (1<<9); config_reg = config_reg & (~(1<<10)); /* Send the new value of the configuration register */ data[0] = config_reg>>8; data[1] = config_reg&255; ulp_riscv_i2c_master_set_slave_reg_addr(0x01); ulp_riscv_i2c_master_write_to_device(data, 2); ulp_riscv_delay_cycles(800 * ULP_CLOCK_CYCLE_IN_MS); /* Wait for the CRF from the opt3001 sensor */ while(config_reg & (1<<9)) { ulp_riscv_i2c_master_set_slave_addr(0x44); ulp_riscv_i2c_master_set_slave_reg_addr(0x01); ulp_riscv_i2c_master_read_from_device(data, 1); ulp_riscv_i2c_master_read_from_device(data+1, 2); ulp_riscv_delay_cycles(100 * ULP_CLOCK_CYCLE_IN_MS); config_reg = (data[0]<<8)|(data[1]); } /* Fetch Light sensor result register */ data[0] = 0; data[1] = 0; ulp_riscv_i2c_master_set_slave_addr(0x44); ulp_riscv_i2c_master_set_slave_reg_addr(0x00); ulp_riscv_i2c_master_read_from_device(data, 1); ulp_riscv_i2c_master_read_from_device(data+1, 2); result_reg = (data[0]<<8)|(data[1]); result_reg2 = result_reg & 0xFFF; for(int i=1; i<=light_exponent; i++) result *=2; prev_light_data_opt = light_data_opt; light_data_opt = 0.01*result*result_reg2; //light_data_opt = 0.16 * result_reg2; } uint8_t ulp_data_process_lightSen_thresholds(uint32_t prev_raw_data, uint32_t raw_data) { uint8_t wakeHostForStrobedTrigger = 0; #if 0 /* Check if light now has been detected and in the previous state there were no light*/ /* (Current_data > Threshold_GP) && (Previous_data < Threshold_GN)*/ if((raw_data > settings_structure.lightSensorLevelGP) && (prev_raw_data < settings_structure.lightSensorLevelGN)) { /* Check if we should do check-in when changing from dark to light*/ if(ulp_triggersThatCanWakeTheHost & WAKE_HOST_ON_DARK_TO_LIGHT) { ulp_strobedMiscFlags |= STROBED_MISC_CHANGE_FROM_DARK_TO_LIGHT; /* Reduce light tokens by 1*/ if(settings_structure.lightSensorTokens) { settings_structure.lightSensorTokens--; wakeHostForStrobedTrigger = 1; } } }/* (Current_data < Threshold_GN) && (Previous_data > Threshold_GP)*/ else if((raw_data < settings_structure.lightSensorLevelGN) && (prev_raw_data > settings_structure.lightSensorLevelGP)) { /* Check if we should do check-in when changing from light to dark*/ if(ulp_triggersThatCanWakeTheHost & WAKE_HOST_ON_LIGHT_TO_DARK) { ulp_strobedMiscFlags |= STROBED_MISC_CHANGE_FROM_LIGHT_TO_DARK; /* Reduce light tokens by 1*/ if(settings_structure.lightSensorTokens) { settings_structure.lightSensorTokens--; wakeHostForStrobedTrigger = 1; } } } else { } #endif /* Check if light now has been detected and in the previous state there were no light*/ if((raw_data > settings_structure.lightSensorLevel) && (prev_raw_data < settings_structure.lightSensorLevel)) { /* Check if we should do check-in when changing from dark to light*/ if(ulp_triggersThatCanWakeTheHost & WAKE_HOST_ON_DARK_TO_LIGHT) { ulp_strobedMiscFlags |= STROBED_MISC_CHANGE_FROM_DARK_TO_LIGHT; wakeHostForStrobedTrigger = 1; wakeup_type |= (1<<1); } } else if((raw_data < settings_structure.lightSensorLevel) && (prev_raw_data > settings_structure.lightSensorLevel)) { /* Check if we should do check-in when changing from light to dark*/ if(ulp_triggersThatCanWakeTheHost & WAKE_HOST_ON_LIGHT_TO_DARK) { ulp_strobedMiscFlags |= STROBED_MISC_CHANGE_FROM_LIGHT_TO_DARK; wakeHostForStrobedTrigger = 1; wakeup_type |= (1<<2); } } return wakeHostForStrobedTrigger; } int main(void) { int cycle_count = 0; int wakeHostForStrobedTrigger = 0; ulp_initialize_variables(); ens_init(); set_thermocouple_type(0); get_thermocouple_dev_id(); mcp_start_conversion(); ens_start(); for(;;) { /*if(temp_needed) { ens_read_temp(); mcp_get_temp(); }*/ if(is_sleep) { server_time += 2; ens_read_temp(); //wakeHostForStrobedTrigger += ulp_data_process_tempHumi_thresholds2(ens_temp_raw, prev_ens_temp_raw, 1); wakeHostForStrobedTrigger += ulp_data_process_tempHumi_thresholds(ens_temp_raw, prev_ens_temp_raw, ULP_TEMPERATURE_SENSOR); //wakeHostForStrobedTrigger += ulp_data_process_tempHumi_thresholds2(humidity_raw, prev_humidity_raw, 2); wakeHostForStrobedTrigger += ulp_data_process_tempHumi_thresholds(humidity_raw, prev_humidity_raw, ULP_HUMIDITY_SENSOR); if((ulp_triggersThatCanWakeTheHost & WAKE_HOST_WHEN_THERMOCOUPLE_CROSSES_LIMITS)) { mcp_get_temp(); //wakeHostForStrobedTrigger += ulp_data_process_tempHumi_thresholds2(thermo_temp_raw, prev_thermo_temp_raw, 3); wakeHostForStrobedTrigger += ulp_data_process_tempHumi_thresholds(thermo_temp_raw, prev_thermo_temp_raw, ULP_THERMOCOUPLE_SENSOR); } if(ulp_triggersThatCanWakeTheHost & (WAKE_HOST_ON_DARK_TO_LIGHT|WAKE_HOST_ON_LIGHT_TO_DARK)) { opt_read_reg(); wakeHostForStrobedTrigger += ulp_data_process_lightSen_thresholds(prev_light_data_opt,light_data_opt); } if(wakeHostForStrobedTrigger > 0) { wakeHostForStrobedTrigger = 0; is_sleep = 0; ulp_riscv_wakeup_main_processor(); } #if 0 //if(tempC > 50.0) (tempC > (threshold+273.15)*64) if(ens_temp_raw > 20681) { wakeup_type |= 1; } if(thermo_temp_raw > 800) { wakeup_type |= 2; } /*if(thermoTemp > 50.0) { is_sleep = 0; temp_needed = 0; wakeup_type = 2; ulp_riscv_wakeup_main_processor(); }*/ if(wakeup_type) { is_sleep = 0; temp_needed = 0; ulp_riscv_wakeup_main_processor(); } #endif } ulp_riscv_delay_cycles(1000 * ULP_CLOCK_CYCLE_IN_MS); } return 0; }