diff --git a/fw/Core/Inc/sps30.h b/fw/Core/Inc/sps30.h index 819dd5b..9b1b943 100644 --- a/fw/Core/Inc/sps30.h +++ b/fw/Core/Inc/sps30.h @@ -76,7 +76,7 @@ int8_t sps30_send_cmd(sps30_cmd_t cmd); int8_t sps30_start_measurement( void ); int8_t sps30_stop_measurement( void ); -int8_t sps30_read_measured_values(uint16_t *measured_values, uint8_t measured_values_len); +int8_t sps30_read_measured_values(sps30_data_t *measured_data); int8_t sps30_sleep( void ); int8_t sps30_wake_up( void ); diff --git a/fw/Core/Src/main.c b/fw/Core/Src/main.c index a058d38..d7a138a 100644 --- a/fw/Core/Src/main.c +++ b/fw/Core/Src/main.c @@ -71,13 +71,23 @@ const uint16_t tim21_period = 1200-1; // 6s /* Input registers memory map implementation */ enum { - REGISTER_NUM_CO2 = 30010, - REGISTER_NUM_T_SHT4x = 30011, - REGISTER_NUM_RH_SHT4x = 30012, - REGISTER_NUM_T_SCD4x = 30013, - REGISTER_NUM_RH_SCD4x = 30014, - REGISTER_NUM_T_SHT4x_SIGNED = 30015, - REGISTER_NUM_T_SCD4x_SIGNED = 30016 + REGISTER_NUM_CO2 = 30010, /* ppm */ + REGISTER_NUM_T_SHT4x = 30011, /* deg C */ + REGISTER_NUM_RH_SHT4x = 30012, /* % */ + REGISTER_NUM_T_SCD4x = 30013, /* deg C */ + REGISTER_NUM_RH_SCD4x = 30014, /* % */ + REGISTER_NUM_T_SHT4x_SIGNED = 30015, /* deg C */ + REGISTER_NUM_T_SCD4x_SIGNED = 30016, /* deg C */ + REGISTER_NUM_PMC_MASS_1_0 = 30017, /* ug / m^3 */ + REGISTER_NUM_PMC_MASS_2_5 = 30018, /* ug / m^3 */ + REGISTER_NUM_PMC_MASS_4_0 = 30019, /* ug / m^3 */ + REGISTER_NUM_PMC_MASS_10_0 = 30020, /* ug / m^3 */ + REGISTER_NUM_PMC_NUMBER_0_5 = 30021, /* 1 / m^3 */ + REGISTER_NUM_PMC_NUMBER_1_0 = 30022, /* 1 / m^3 */ + REGISTER_NUM_PMC_NUMBER_2_5 = 30023, /* 1 / m^3 */ + REGISTER_NUM_PMC_NUMBER_4_0 = 30024, /* 1 / m^3 */ + REGISTER_NUM_PMC_NUMBER_10_0 = 30025, /* 1 / m^3 */ + REGISTER_NUM_TYPICAL_PARTICLE_SIZE = 30026 /* nm */ } data_registers_numbers; enum @@ -105,7 +115,7 @@ enum /* Variables to store the measured data */ int16_t T_SCD4x, T_SHT4x; uint16_t CO2, RH_SCD4x, RH_SHT4x; -uint16_t sps30_measured_data[10]; +sps30_data_t PM_SPS30; /* Struct to store the sensor config */ config_t sensor_config; @@ -242,10 +252,6 @@ int main(void) device_id.object_name.ModelName = "Hugo"; modbus_slave_init_device_id(&device_id); - - LL_mDelay(2000); - - scd4x_start_periodic_measurement(); uint8_t scd4x_is_connected = 0; uint8_t sps30_is_connected = 0; /* USER CODE END 2 */ @@ -259,6 +265,7 @@ int main(void) /* Attempt to start SPS30 measurement and check if it's connected */ sps30_reset(); + LL_mDelay(500); // should be less than 100 ms (we have 500 just to be sure) if (sps30_start_measurement() == SPS30_OK) { sps30_is_connected = 1; @@ -345,7 +352,7 @@ int main(void) /* Read SPS30 data (if connected) */ if (sps30_is_connected == 1) { - sps30_read_measured_values(sps30_measured_data, 10); + sps30_read_measured_values(&PM_SPS30); } /* TODO: Process data and light a desired color of LED */ /* TODO: Add hystheresis */ @@ -855,6 +862,36 @@ int8_t modbus_slave_callback(modbus_transaction_t *transaction) case REGISTER_NUM_T_SCD4x_SIGNED: transaction->input_registers_signed[i] = (int16_t)T_SCD4x; break; + case REGISTER_NUM_PMC_MASS_1_0: + transaction->input_registers[i] = (uint16_t)PM_SPS30.mass_concentration[PM1_0]; + break; + case REGISTER_NUM_PMC_MASS_2_5: + transaction->input_registers[i] = (uint16_t)PM_SPS30.mass_concentration[PM2_5]; + break; + case REGISTER_NUM_PMC_MASS_4_0: + transaction->input_registers[i] = (uint16_t)PM_SPS30.mass_concentration[PM4_0]; + break; + case REGISTER_NUM_PMC_MASS_10_0: + transaction->input_registers[i] = (uint16_t)PM_SPS30.mass_concentration[PM10_0]; + break; + case REGISTER_NUM_PMC_NUMBER_0_5: + transaction->input_registers[i] = (uint16_t)PM_SPS30.number_concentration[PM0_5]; + break; + case REGISTER_NUM_PMC_NUMBER_1_0: + transaction->input_registers[i] = (uint16_t)PM_SPS30.number_concentration[PM1_0]; + break; + case REGISTER_NUM_PMC_NUMBER_2_5: + transaction->input_registers[i] = (uint16_t)PM_SPS30.number_concentration[PM2_5]; + break; + case REGISTER_NUM_PMC_NUMBER_4_0: + transaction->input_registers[i] = (uint16_t)PM_SPS30.number_concentration[PM4_0]; + break; + case REGISTER_NUM_PMC_NUMBER_10_0: + transaction->input_registers[i] = (uint16_t)PM_SPS30.number_concentration[PM10_0]; + break; + case REGISTER_NUM_TYPICAL_PARTICLE_SIZE: + transaction->input_registers[i] = (uint16_t)PM_SPS30.typical_particle_size; + break; default: return MODBUS_ERROR_FUNCTION_NOT_IMPLEMENTED; } diff --git a/fw/Core/Src/sps30.c b/fw/Core/Src/sps30.c index 52826dd..db4c115 100644 --- a/fw/Core/Src/sps30.c +++ b/fw/Core/Src/sps30.c @@ -71,8 +71,6 @@ int8_t sps30_read_measured_values(sps30_data_t *measured_data) /* check data integrity */ for (uint8_t i = 0; i < SPS30_MEASURED_VALUES_COUNT; i++) { -// measured_values[i] = (i2c_rx_buffer[j++] << 8) + i2c_rx_buffer[j++]; -// checksums[i] = i2c_rx_buffer[j++]; uint8_t checksum_calculated = crc8_calculate(buffer + 3*i, 2); uint8_t checksum_received = buffer[3*i + 2]; if (checksum_calculated != checksum_received) { @@ -80,6 +78,21 @@ int8_t sps30_read_measured_values(sps30_data_t *measured_data) } } /* copy to output struct */ + /* mass concencration [ug / m^3] */ + int pos = 0; + for (int i = 0; i < 4; i++) { + /* i + 1 because mass concentration starts at PM1.0 (there is no PM0.5) */ + measured_data->mass_concentration[i + 1] = (buffer[pos] << 8) + buffer[pos + 1]; + pos += 3; /* 2 B data, 1 B crc */ + } + /* number concentration [1 / cm^3] */ + for (int i = 0; i < 5; i++) { + measured_data->number_concentration[i] = (buffer[pos] << 8) + buffer[pos + 1]; + pos += 3; + } + /* typical particle size [nm] */ + measured_data->typical_particle_size = (buffer[pos] << 8) + buffer[pos + 1]; + return SPS30_OK; } @@ -91,7 +104,6 @@ int8_t sps30_sleep( void ) int8_t sps30_wake_up( void ) { return sps30_send_cmd(SPS30_WAKE_UP); - return sps30_send_cmd(SPS30_WAKE_UP); } int8_t sps30_start_fan_cleaning( void ) @@ -104,30 +116,25 @@ int8_t sps30_reset( void ) return sps30_send_cmd(SPS30_RESET); } - int8_t sps30_read_status_register ( void ) { - uint8_t i2c_tx_buffer[2]; - uint8_t i2c_rx_buffer[6]; + uint8_t buffer[6]; uint8_t result; // start measurement - i2c_tx_buffer[0] = SPS30_READ_DEVICE_STATUS_REGISTER >> 8; - i2c_tx_buffer[1] = SPS30_READ_DEVICE_STATUS_REGISTER & 0x00ff; - result = i2c_transmit(SPS30_I2C_ADDRESS<<1, i2c_tx_buffer, 2); - - // TODO: Proc to vraci NACK? Vyresit. - /*if (result != I2C_OK) { + buffer[0] = SPS30_READ_DEVICE_STATUS_REGISTER >> 8; + buffer[1] = SPS30_READ_DEVICE_STATUS_REGISTER & 0x00ff; + result = i2c_transmit(SPS30_I2C_ADDRESS<<1, buffer, 2); + if (result != I2C_OK) { return SPS30_ERROR; } - return SPS30_OK;*/ - - LL_mDelay(1); // 10 ms should be enough + LL_mDelay(10); // 10 ms should be enough // read out - result = i2c_receive(SPS30_I2C_ADDRESS<<1, i2c_rx_buffer, 6); + result = i2c_receive(SPS30_I2C_ADDRESS<<1, buffer, 6); + // TODO - return 0; + return SPS30_OK; } int8_t sps30_read_firmware_version ( uint8_t * fw_ver_hi, uint8_t * fw_ver_lo ) @@ -161,20 +168,3 @@ int8_t sps30_read_firmware_version ( uint8_t * fw_ver_hi, uint8_t * fw_ver_lo ) return SPS30_OK; } - -// -//uint8_t calculate_crc(uint8_t data[2]) -//{ -// uint8_t crc = 0xFF; -// for(uint8_t i = 0; i < 2; i++) { -// crc ^= data[i]; -// for(uint8_t bit = 8; bit > 0; --bit) { -// if(crc & 0x80) { -// crc = (crc << 1) ^ 0x31u; -// } else { -// crc = (crc << 1); -// } -// } -// } -// return crc; -//} diff --git a/tests/sensor.py b/tests/sensor.py index a77aad4..c001137 100644 --- a/tests/sensor.py +++ b/tests/sensor.py @@ -17,7 +17,17 @@ class Sensor(): 'T_SCD4x': 30013, \ 'RH_SCD4x': 30014, \ 'T_SHT4x_signed': 30015, \ - 'T_SCD4x_signed': 30016 } + 'T_SCD4x_signed': 30016, \ + 'PM_mass_concentration_1.0': 30017, \ + 'PM_mass_concentration_2.5': 30018, \ + 'PM_mass_concentration_4.0': 30019, \ + 'PM_mass_concentration_10.0': 30020, \ + 'PM_number_concentration_0.5': 30021, \ + 'PM_number_concentration_1.0': 30022, \ + 'PM_number_concentration_2.5': 30023, \ + 'PM_number_concentration_4.0': 30024, \ + 'PM_number_concentration_10.0': 30025, \ + 'PM_typical_particle_size': 30026 } holding_registers = { \ 'LED_on': 40001, \ 'LED_brightness': 40002, \