Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
sps30.cpp
00001 #include "mbed.h" 00002 #include "sps30.h" 00003 00004 //----------------------------------------------------------------------------- 00005 // Constructor 00006 00007 Sps30::Sps30(PinName sda, PinName scl, int i2c_frequency) : _i2c(sda, scl) { 00008 _i2c.frequency(i2c_frequency); 00009 00010 sensor_data_name.push_back("PM1.0 Mass"); 00011 sensor_data_name.push_back("PM2.5 Mass"); 00012 sensor_data_name.push_back("PM4.0 Mass"); 00013 sensor_data_name.push_back("PM10.0 Mass"); 00014 sensor_data_name.push_back("PM0.5 Num"); 00015 sensor_data_name.push_back("PM1.0 Num"); 00016 sensor_data_name.push_back("PM2.5 Num"); 00017 sensor_data_name.push_back("PM4.0 Num"); 00018 sensor_data_name.push_back("PM10.0 Num"); 00019 sensor_data_name.push_back("Typical Particle Size"); 00020 } 00021 00022 //----------------------------------------------------------------------------- 00023 // Destructor 00024 00025 Sps30::~Sps30() { 00026 } 00027 00028 //----------------------------------------------------------------------------- 00029 // start auto-measurement 00030 // 00031 00032 uint8_t Sps30::StartMeasurement() 00033 { 00034 i2cbuff[0] = SPS30_CMMD_STRT_MEAS >> 8; 00035 i2cbuff[1] = SPS30_CMMD_STRT_MEAS & 255; 00036 i2cbuff[2] = SPS30_STRT_MEAS_WRITE_DATA >> 8; 00037 i2cbuff[3] = SPS30_STRT_MEAS_WRITE_DATA & 255; 00038 i2cbuff[4] = Sps30::CalcCrc2b(SPS30_STRT_MEAS_WRITE_DATA); 00039 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 5, false); 00040 if(res) return SPSNOACKERROR; 00041 return SPSNOERROR; 00042 } 00043 00044 //----------------------------------------------------------------------------- 00045 // Stop auto-measurement 00046 00047 uint8_t Sps30::StopMeasurement() 00048 { 00049 i2cbuff[0] = SPS30_CMMD_STOP_MEAS >> 8; 00050 i2cbuff[1] = SPS30_CMMD_STOP_MEAS & 255; 00051 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00052 if(res) return SPSNOACKERROR; 00053 return SPSNOERROR; 00054 } 00055 00056 //----------------------------------------------------------------------------- 00057 // Get Sps30 serial number 00058 00059 int Sps30::GetSerialNumber() 00060 { 00061 i2cbuff[0] = SPS30_CMMD_READ_SERIALNBR >> 8; 00062 i2cbuff[1] = SPS30_CMMD_READ_SERIALNBR & 255; 00063 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00064 if(res) return SPSNOACKERROR; 00065 00066 int i = 0; 00067 for(i = 0; i < sizeof(sn); i++) sn[i] = 0; 00068 for(i = 0; i < sizeof(i2cbuff); i++) i2cbuff[i] = 0; 00069 00070 _i2c.read(SPS30_I2C_ADDR | 1, i2cbuff, SPS30_SN_SIZE, false); 00071 int t = 0; 00072 for(i = 0; i < SPS30_SN_SIZE; i +=3) 00073 { 00074 uint16_t stat = (i2cbuff[i] << 8) | i2cbuff[i + 1]; 00075 sn[i - t] = stat >> 8; 00076 sn[i - t + 1] = stat & 255; 00077 uint8_t dat = Sps30::CheckCrc2b(stat, i2cbuff[i + 2]); 00078 t++; 00079 if(dat == SPSCRCERROR) return SPSCRCERROR; 00080 if(stat == 0) break; 00081 } 00082 00083 return SPSNOERROR; 00084 } 00085 00086 //----------------------------------------------------------------------------- 00087 // Get ready status value 00088 00089 uint8_t Sps30::GetReadyStatus() 00090 { 00091 i2cbuff[0] = SPS30_CMMD_GET_READY_STAT >> 8; 00092 i2cbuff[1] = SPS30_CMMD_GET_READY_STAT & 255; 00093 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00094 if(res) return SPSNOACKERROR; 00095 00096 _i2c.read(SPS30_I2C_ADDR | 1, i2cbuff, 3, false); 00097 uint16_t stat = (i2cbuff[0] << 8) | i2cbuff[1]; 00098 sps_ready = stat; 00099 uint8_t dat = Sps30::CheckCrc2b(stat, i2cbuff[2]); 00100 00101 if(dat == SPSCRCERROR) return SPSCRCERROR; 00102 return SPSNOERROR; 00103 } 00104 00105 //----------------------------------------------------------------------------- 00106 // Get all the measurement values, stick them into the array 00107 00108 uint8_t Sps30::ReadMeasurement() 00109 { 00110 i2cbuff[0] = SPS30_CMMD_READ_MEAS >> 8; 00111 i2cbuff[1] = SPS30_CMMD_READ_MEAS & 255; 00112 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00113 if(res) return SPSNOACKERROR; 00114 00115 _i2c.read(SPS30_I2C_ADDR | 1, i2cbuff, 60, false); 00116 00117 uint16_t stat = (i2cbuff[0] << 8) | i2cbuff[1]; 00118 mass_1p0_m = stat; 00119 uint8_t dat = Sps30::CheckCrc2b(stat, i2cbuff[2]); 00120 if(dat == SPSCRCERROR) return SPSCRCERROR; 00121 00122 stat = (i2cbuff[3] << 8) | i2cbuff[4]; 00123 mass_1p0_l = stat; 00124 dat = Sps30::CheckCrc2b(stat, i2cbuff[5]); 00125 if(dat == SPSCRCERROR) return SPSCRCERROR; 00126 00127 00128 00129 stat = (i2cbuff[6] << 8) | i2cbuff[7]; 00130 mass_2p5_m = stat; 00131 dat = Sps30::CheckCrc2b(stat, i2cbuff[8]); 00132 if(dat == SPSCRCERROR) return SPSCRCERROR; 00133 00134 stat = (i2cbuff[9] << 8) | i2cbuff[10]; 00135 mass_2p5_l = stat; 00136 dat = Sps30::CheckCrc2b(stat, i2cbuff[11]); 00137 if(dat == SPSCRCERROR) return SPSCRCERROR; 00138 00139 00140 00141 stat = (i2cbuff[12] << 8) | i2cbuff[13]; 00142 mass_4p0_m = stat; 00143 dat = Sps30::CheckCrc2b(stat, i2cbuff[14]); 00144 if(dat == SPSCRCERROR) return SPSCRCERROR; 00145 00146 stat = (i2cbuff[15] << 8) | i2cbuff[16]; 00147 mass_4p0_l = stat; 00148 dat = Sps30::CheckCrc2b(stat, i2cbuff[17]); 00149 if(dat == SPSCRCERROR) return SPSCRCERROR; 00150 00151 00152 00153 stat = (i2cbuff[18] << 8) | i2cbuff[19]; 00154 mass_10p0_m = stat; 00155 dat = Sps30::CheckCrc2b(stat, i2cbuff[20]); 00156 if(dat == SPSCRCERROR) return SPSCRCERROR; 00157 00158 stat = (i2cbuff[21] << 8) | i2cbuff[22]; 00159 mass_10p0_l = stat; 00160 dat = Sps30::CheckCrc2b(stat, i2cbuff[23]); 00161 if(dat == SPSCRCERROR) return SPSCRCERROR; 00162 00163 00164 00165 stat = (i2cbuff[24] << 8) | i2cbuff[25]; 00166 num_0p5_m = stat; 00167 dat = Sps30::CheckCrc2b(stat, i2cbuff[26]); 00168 if(dat == SPSCRCERROR) return SPSCRCERROR; 00169 00170 stat = (i2cbuff[27] << 8) | i2cbuff[28]; 00171 num_0p5_l = stat; 00172 dat = Sps30::CheckCrc2b(stat, i2cbuff[29]); 00173 if(dat == SPSCRCERROR) return SPSCRCERROR; 00174 00175 00176 stat = (i2cbuff[30] << 8) | i2cbuff[31]; 00177 num_1p0_m = stat; 00178 dat = Sps30::CheckCrc2b(stat, i2cbuff[32]); 00179 if(dat == SPSCRCERROR) return SPSCRCERROR; 00180 00181 stat = (i2cbuff[33] << 8) | i2cbuff[34]; 00182 num_1p0_l = stat; 00183 dat = Sps30::CheckCrc2b(stat, i2cbuff[35]); 00184 if(dat == SPSCRCERROR) return SPSCRCERROR; 00185 00186 00187 00188 stat = (i2cbuff[36] << 8) | i2cbuff[37]; 00189 num_2p5_m = stat; 00190 dat = Sps30::CheckCrc2b(stat, i2cbuff[38]); 00191 if(dat == SPSCRCERROR) return SPSCRCERROR; 00192 00193 stat = (i2cbuff[39] << 8) | i2cbuff[40]; 00194 num_2p5_l = stat; 00195 dat = Sps30::CheckCrc2b(stat, i2cbuff[41]); 00196 if(dat == SPSCRCERROR) return SPSCRCERROR; 00197 00198 00199 00200 stat = (i2cbuff[42] << 8) | i2cbuff[43]; 00201 num_4p0_m = stat; 00202 dat = Sps30::CheckCrc2b(stat, i2cbuff[44]); 00203 if(dat == SPSCRCERROR) return SPSCRCERROR; 00204 00205 stat = (i2cbuff[45] << 8) | i2cbuff[46]; 00206 num_4p0_l = stat; 00207 dat = Sps30::CheckCrc2b(stat, i2cbuff[47]); 00208 if(dat == SPSCRCERROR) return SPSCRCERROR; 00209 00210 00211 stat = (i2cbuff[48] << 8) | i2cbuff[49]; 00212 num_10p0_m = stat; 00213 dat = Sps30::CheckCrc2b(stat, i2cbuff[50]); 00214 if(dat == SPSCRCERROR) return SPSCRCERROR; 00215 00216 stat = (i2cbuff[51] << 8) | i2cbuff[52]; 00217 num_10p0_l = stat; 00218 dat = Sps30::CheckCrc2b(stat, i2cbuff[53]); 00219 if(dat == SPSCRCERROR) return SPSCRCERROR; 00220 00221 00222 stat = (i2cbuff[54] << 8) | i2cbuff[55]; 00223 typ_pm_size_m = stat; 00224 dat = Sps30::CheckCrc2b(stat, i2cbuff[56]); 00225 if(dat == SPSCRCERROR) return SPSCRCERROR; 00226 00227 stat = (i2cbuff[57] << 8) | i2cbuff[58]; 00228 typ_pm_size_l = stat; 00229 dat = Sps30::CheckCrc2b(stat, i2cbuff[59]); 00230 if(dat == SPSCRCERROR) return SPSCRCERROR; 00231 00232 mass_1p0_i = (mass_1p0_m << 16) | mass_1p0_l; 00233 mass_2p5_i = (mass_2p5_m << 16) | mass_2p5_l; 00234 mass_4p0_i = (mass_4p0_m << 16) | mass_4p0_l; 00235 mass_10p0_i = (mass_10p0_m << 16) | mass_10p0_l; 00236 00237 num_0p5_i = (num_0p5_m << 16) | num_0p5_l; 00238 num_1p0_i = (num_1p0_m << 16) | num_1p0_l; 00239 num_2p5_i = (num_2p5_m << 16) | num_2p5_l; 00240 num_4p0_i = (num_4p0_m << 16) | num_4p0_l; 00241 num_10p0_i = (num_10p0_m << 16) | num_10p0_l; 00242 00243 typ_pm_size_i = (typ_pm_size_m << 16) | typ_pm_size_l; 00244 00245 mass_1p0_f = *(float*)&mass_1p0_i; 00246 mass_2p5_f = *(float*)&mass_2p5_i; 00247 mass_4p0_f = *(float*)&mass_4p0_i; 00248 mass_10p0_f = *(float*)&mass_10p0_i; 00249 00250 num_0p5_f = *(float*)&num_0p5_i; 00251 num_1p0_f = *(float*)&num_1p0_i; 00252 num_2p5_f = *(float*)&num_2p5_i; 00253 num_4p0_f = *(float*)&num_4p0_i; 00254 num_10p0_f = *(float*)&num_10p0_i; 00255 00256 typ_pm_size_f = *(float*)&typ_pm_size_i; 00257 00258 return SPSNOERROR; 00259 } 00260 00261 //----------------------------------------------------------------------------- 00262 // Calculate the CRC of a 2 byte value using the SPS30 CRC polynomial 00263 00264 uint8_t Sps30::CalcCrc2b(uint16_t seed) 00265 { 00266 uint8_t bit; // bit mask 00267 uint8_t crc = SPS30_CRC_INIT; // calculated checksum 00268 00269 // calculates 8-Bit checksum with given polynomial 00270 00271 crc ^= (seed >> 8) & 255; 00272 for(bit = 8; bit > 0; --bit) 00273 { 00274 if(crc & 0x80) crc = (crc << 1) ^ SPS30_POLYNOMIAL; 00275 else crc = (crc << 1); 00276 } 00277 00278 crc ^= seed & 255; 00279 for(bit = 8; bit > 0; --bit) 00280 { 00281 if(crc & 0x80) crc = (crc << 1) ^ SPS30_POLYNOMIAL; 00282 else crc = (crc << 1); 00283 } 00284 00285 return crc; 00286 } 00287 00288 //----------------------------------------------------------------------------- 00289 // Compare the CRC values 00290 00291 uint8_t Sps30::CheckCrc2b(uint16_t seed, uint8_t crc_in) 00292 { 00293 uint8_t crc_calc = Sps30::CalcCrc2b(seed); 00294 if(crc_calc != crc_in) return SPSCRCERROR; 00295 return SPSNOERROR; 00296 } 00297 00298 //----------------------------------------------------------------------------- 00299 // Read Auto Cleaning Interval on the SPS30 00300 00301 uint8_t Sps30::ReadAutoCleanInterval() 00302 { 00303 i2cbuff[0] = SPS30_CMMD_AUTO_CLEAN_INTV >> 8; 00304 i2cbuff[1] = SPS30_CMMD_AUTO_CLEAN_INTV & 255; 00305 00306 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00307 if(res) return SPSNOACKERROR; 00308 00309 _i2c.read(SPS30_I2C_ADDR | 1, i2cbuff, 6, false); 00310 00311 uint16_t stat = (i2cbuff[0] << 8) | i2cbuff[1]; 00312 clean_interval_m = stat; 00313 uint8_t dat = Sps30::CheckCrc2b(stat, i2cbuff[2]); 00314 if(dat == SPSCRCERROR) return SPSCRCERROR; 00315 00316 stat = (i2cbuff[3] << 8) | i2cbuff[4]; 00317 clean_interval_l = stat; 00318 dat = Sps30::CheckCrc2b(stat, i2cbuff[5]); 00319 if(dat == SPSCRCERROR) return SPSCRCERROR; 00320 00321 clean_interval_i = (clean_interval_m << 16) | clean_interval_l; 00322 00323 return SPSNOERROR; 00324 } 00325 00326 //----------------------------------------------------------------------------- 00327 // Set Auto Cleaning Interval on the SPS30 00328 00329 uint8_t Sps30::SetAutoCleanInterval(uint32_t set_interval) 00330 { 00331 uint16_t set_interval_m = set_interval >> 16; 00332 uint16_t set_interval_l = set_interval & 65535; 00333 00334 i2cbuff[0] = SPS30_CMMD_AUTO_CLEAN_INTV >> 8; 00335 i2cbuff[1] = SPS30_CMMD_AUTO_CLEAN_INTV & 255; 00336 00337 i2cbuff[2] = set_interval_m >> 8; 00338 i2cbuff[3] = set_interval_m & 255; 00339 i2cbuff[4] = Sps30::CalcCrc2b(set_interval_m); 00340 00341 i2cbuff[5] = set_interval_l >> 8; 00342 i2cbuff[6] = set_interval_l & 255; 00343 i2cbuff[7] = Sps30::CalcCrc2b(set_interval_l); 00344 00345 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 8, false); 00346 if(res) return SPSNOACKERROR; 00347 00348 _i2c.read(SPS30_I2C_ADDR | 1, i2cbuff, 6, false); 00349 00350 uint16_t stat = (i2cbuff[0] << 8) | i2cbuff[1]; 00351 clean_interval_m = stat; 00352 uint8_t dat = Sps30::CheckCrc2b(stat, i2cbuff[2]); 00353 if(dat == SPSCRCERROR) return SPSCRCERROR; 00354 00355 stat = (i2cbuff[3] << 8) | i2cbuff[4]; 00356 clean_interval_l = stat; 00357 dat = Sps30::CheckCrc2b(stat, i2cbuff[5]); 00358 if(dat == SPSCRCERROR) return SPSCRCERROR; 00359 00360 clean_interval_i = (clean_interval_m << 16) | clean_interval_l; 00361 00362 return SPSNOERROR; 00363 } 00364 00365 //----------------------------------------------------------------------------- 00366 // Perform manual fan cleaning 00367 00368 uint8_t Sps30::StartFanClean() 00369 { 00370 i2cbuff[0] = SPS30_CMMD_START_FAN_CLEAN >> 8; 00371 i2cbuff[1] = SPS30_CMMD_START_FAN_CLEAN & 255; 00372 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00373 if(res) return SPSNOACKERROR; 00374 return SPSNOERROR; 00375 } 00376 00377 //----------------------------------------------------------------------------- 00378 // Perform a soft reset on the SPS30 00379 00380 uint8_t Sps30::SoftReset() 00381 { 00382 i2cbuff[0] = SPS30_CMMD_SOFT_RESET >> 8; 00383 i2cbuff[1] = SPS30_CMMD_SOFT_RESET & 255; 00384 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00385 if(res) return SPSNOACKERROR; 00386 return SPSNOERROR; 00387 } 00388 00389 //----------------------------------------------------------------------------- 00390 // Fill up the sensor data vector to be read in Sensor Thread 00391 00392 void Sps30::GetDataArray() 00393 { 00394 sensor_float_data.clear(); 00395 00396 sensor_float_data.push_back(mass_1p0_f); 00397 sensor_float_data.push_back(mass_2p5_f); 00398 sensor_float_data.push_back(mass_4p0_f); 00399 sensor_float_data.push_back(mass_10p0_f); 00400 00401 sensor_float_data.push_back(num_0p5_f); 00402 sensor_float_data.push_back(num_1p0_f); 00403 sensor_float_data.push_back(num_2p5_f); 00404 sensor_float_data.push_back(num_4p0_f); 00405 sensor_float_data.push_back(num_10p0_f); 00406 00407 sensor_float_data.push_back(typ_pm_size_f); 00408 00409 int i = 0; 00410 for (i = 0; i < sensor_float_data.size(); i++) 00411 { 00412 std::string sensor_string_data = ConvertDataToString(sensor_float_data[i]); 00413 sensor_data.push_back( make_pair(sensor_data_name[i],sensor_string_data) ); 00414 00415 int val_data; 00416 if (i < 4) 00417 { 00418 // sensor_float_data[i] = 99999.00; // test use case 3c; expected output: EmTrace for sensor data out-of-range with data value 00419 val_data = ValidateData(sensor_float_data[i], MASS_MIN, MASS_MAX); 00420 } 00421 else if (i < 9) 00422 { 00423 // sensor_float_data[i] = 99999.00; // test use case 3c; expected output: EmTrace for sensor data out-of-range with data value 00424 val_data = ValidateData(sensor_float_data[i], NUM_MIN, NUM_MAX); 00425 } 00426 00427 if (val_data == SENSOR_DATAOOR) 00428 { 00429 std::string oor_string = sensor_data_name[i] + " is out-of-range: " + sensor_string_data; 00430 SendSensorEmTrace(SENSOR_DATAOOR, oor_string); 00431 } 00432 } 00433 return; 00434 } 00435 00436 /************************** PUBLIC METHODS **********************************/ 00437 00438 //----------------------------------------------------------------------------- 00439 // Initialise SPS30 00440 00441 void Sps30::InitSensor() 00442 { 00443 uint8_t dat = Sps30::GetSerialNumber(); 00444 if (dat == SPSNOACKERROR) 00445 { 00446 SendSensorEmTrace(SENSOR_DCN); 00447 sps_status = 0; 00448 } 00449 00450 dat = Sps30::StartMeasurement(); 00451 if (dat == SPSNOACKERROR) 00452 { 00453 SendSensorEmTrace(SENSOR_DCN); 00454 sps_status = 0; 00455 } 00456 00457 SendSensorEmTrace(SENSOR_CN); 00458 sensor_serial = ConvertSerialNumber(sn); 00459 sps_status = 1; 00460 t_count = 0; 00461 00462 return; 00463 } 00464 00465 //----------------------------------------------------------------------------- 00466 // Poll SPS30 00467 00468 int Sps30::PollSensor() 00469 { 00470 sensor_data.clear(); 00471 uint8_t dat = Sps30::GetReadyStatus(); 00472 if (dat == SPSNOACKERROR) 00473 { 00474 if (sps_status == 1) SendSensorEmTrace(SENSOR_DCN); 00475 sps_status = 0; 00476 return SENSOR_DCN; 00477 } 00478 00479 if (sps_status == 0) 00480 { 00481 Sps30::InitSensor(); // If was disconnected, reinitialise 00482 Sps30::GetReadyStatus(); 00483 } 00484 // sps_ready = 0; // test use case 3b; expeced output: EMTrace for sensor data not ready 00485 if (sps_ready == SPSISREADY) 00486 { 00487 uint8_t crcc = Sps30::ReadMeasurement(); 00488 // crcc = SPSCRCERROR; // test use case 3b; expeced output: EMTrace for sensor data not ready 00489 if (crcc == SPSNOERROR) 00490 { 00491 Sps30::GetDataArray(); 00492 return SENSOR_DATAOK; 00493 } 00494 else if (crcc == SPSNOACKERROR) 00495 { 00496 SendSensorEmTrace(SENSOR_DCN); 00497 sps_status = 0; 00498 return SENSOR_DCN; 00499 } 00500 else 00501 { 00502 SendSensorEmTrace(SENSOR_DATAERR); 00503 return SENSOR_DATAERR; 00504 } 00505 } 00506 else 00507 { 00508 if (t_count == TIMEOUT_COUNT) // timeout counter for data not ready 00509 { 00510 SendSensorEmTrace(SENSOR_DATAERR); 00511 Sps30::SoftReset(); 00512 t_count = 0; 00513 } 00514 t_count++; 00515 00516 return SENSOR_DATAERR; 00517 } 00518 }
Generated on Sun Jul 31 2022 16:29:41 by
1.7.2