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 00011 //----------------------------------------------------------------------------- 00012 // Destructor 00013 00014 Sps30::~Sps30() { 00015 } 00016 00017 //----------------------------------------------------------------------------- 00018 // start auto-measurement 00019 // 00020 00021 uint8_t Sps30::StartMeasurement() 00022 { 00023 i2cbuff[0] = SPS30_CMMD_STRT_MEAS >> 8; 00024 i2cbuff[1] = SPS30_CMMD_STRT_MEAS & 255; 00025 i2cbuff[2] = SPS30_STRT_MEAS_WRITE_DATA >> 8; 00026 i2cbuff[3] = SPS30_STRT_MEAS_WRITE_DATA & 255; 00027 i2cbuff[4] = Sps30::CalcCrc2b(SPS30_STRT_MEAS_WRITE_DATA); 00028 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 5, false); 00029 if(res) return SPSNOACKERROR; 00030 return SPSNOERROR; 00031 } 00032 00033 //----------------------------------------------------------------------------- 00034 // Stop auto-measurement 00035 00036 uint8_t Sps30::StopMeasurement() 00037 { 00038 i2cbuff[0] = SPS30_CMMD_STOP_MEAS >> 8; 00039 i2cbuff[1] = SPS30_CMMD_STOP_MEAS & 255; 00040 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00041 if(res) return SPSNOACKERROR; 00042 return SPSNOERROR; 00043 } 00044 00045 //----------------------------------------------------------------------------- 00046 // Get ready status value 00047 00048 uint8_t Sps30::GetReadyStatus() 00049 { 00050 i2cbuff[0] = SPS30_CMMD_GET_READY_STAT >> 8; 00051 i2cbuff[1] = SPS30_CMMD_GET_READY_STAT & 255; 00052 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00053 if(res) return SPSNOACKERROR; 00054 00055 _i2c.read(SPS30_I2C_ADDR | 1, i2cbuff, 3, false); 00056 uint16_t stat = (i2cbuff[0] << 8) | i2cbuff[1]; 00057 sps_ready = stat; 00058 uint8_t dat = Sps30::CheckCrc2b(stat, i2cbuff[2]); 00059 00060 if(dat == SPSCRCERROR) return SPSCRCERROR; 00061 return SPSNOERROR; 00062 } 00063 00064 //----------------------------------------------------------------------------- 00065 // Get all the measurement values, stick them into the array 00066 00067 uint8_t Sps30::ReadMeasurement() 00068 { 00069 i2cbuff[0] = SPS30_CMMD_READ_MEAS >> 8; 00070 i2cbuff[1] = SPS30_CMMD_READ_MEAS & 255; 00071 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00072 if(res) return SPSNOACKERROR; 00073 00074 _i2c.read(SPS30_I2C_ADDR | 1, i2cbuff, 60, false); 00075 00076 uint16_t stat = (i2cbuff[0] << 8) | i2cbuff[1]; 00077 mass_1p0_m = stat; 00078 uint8_t dat = Sps30::CheckCrc2b(stat, i2cbuff[2]); 00079 if(dat == SPSCRCERROR) return SPSCRCERROR; 00080 00081 stat = (i2cbuff[3] << 8) | i2cbuff[4]; 00082 mass_1p0_l = stat; 00083 dat = Sps30::CheckCrc2b(stat, i2cbuff[5]); 00084 if(dat == SPSCRCERROR) return SPSCRCERROR; 00085 00086 00087 00088 stat = (i2cbuff[6] << 8) | i2cbuff[7]; 00089 mass_2p5_m = stat; 00090 dat = Sps30::CheckCrc2b(stat, i2cbuff[8]); 00091 if(dat == SPSCRCERROR) return SPSCRCERROR; 00092 00093 stat = (i2cbuff[9] << 8) | i2cbuff[10]; 00094 mass_2p5_l = stat; 00095 dat = Sps30::CheckCrc2b(stat, i2cbuff[11]); 00096 if(dat == SPSCRCERROR) return SPSCRCERROR; 00097 00098 00099 00100 stat = (i2cbuff[12] << 8) | i2cbuff[13]; 00101 mass_4p0_m = stat; 00102 dat = Sps30::CheckCrc2b(stat, i2cbuff[14]); 00103 if(dat == SPSCRCERROR) return SPSCRCERROR; 00104 00105 stat = (i2cbuff[15] << 8) | i2cbuff[16]; 00106 mass_4p0_l = stat; 00107 dat = Sps30::CheckCrc2b(stat, i2cbuff[17]); 00108 if(dat == SPSCRCERROR) return SPSCRCERROR; 00109 00110 00111 00112 stat = (i2cbuff[18] << 8) | i2cbuff[19]; 00113 mass_10p0_m = stat; 00114 dat = Sps30::CheckCrc2b(stat, i2cbuff[20]); 00115 if(dat == SPSCRCERROR) return SPSCRCERROR; 00116 00117 stat = (i2cbuff[21] << 8) | i2cbuff[22]; 00118 mass_10p0_l = stat; 00119 dat = Sps30::CheckCrc2b(stat, i2cbuff[23]); 00120 if(dat == SPSCRCERROR) return SPSCRCERROR; 00121 00122 00123 00124 stat = (i2cbuff[24] << 8) | i2cbuff[25]; 00125 num_0p5_m = stat; 00126 dat = Sps30::CheckCrc2b(stat, i2cbuff[26]); 00127 if(dat == SPSCRCERROR) return SPSCRCERROR; 00128 00129 stat = (i2cbuff[27] << 8) | i2cbuff[28]; 00130 num_0p5_l = stat; 00131 dat = Sps30::CheckCrc2b(stat, i2cbuff[29]); 00132 if(dat == SPSCRCERROR) return SPSCRCERROR; 00133 00134 00135 stat = (i2cbuff[30] << 8) | i2cbuff[31]; 00136 num_1p0_m = stat; 00137 dat = Sps30::CheckCrc2b(stat, i2cbuff[32]); 00138 if(dat == SPSCRCERROR) return SPSCRCERROR; 00139 00140 stat = (i2cbuff[33] << 8) | i2cbuff[34]; 00141 num_1p0_l = stat; 00142 dat = Sps30::CheckCrc2b(stat, i2cbuff[35]); 00143 if(dat == SPSCRCERROR) return SPSCRCERROR; 00144 00145 00146 00147 stat = (i2cbuff[36] << 8) | i2cbuff[37]; 00148 num_2p5_m = stat; 00149 dat = Sps30::CheckCrc2b(stat, i2cbuff[38]); 00150 if(dat == SPSCRCERROR) return SPSCRCERROR; 00151 00152 stat = (i2cbuff[39] << 8) | i2cbuff[40]; 00153 num_2p5_l = stat; 00154 dat = Sps30::CheckCrc2b(stat, i2cbuff[41]); 00155 if(dat == SPSCRCERROR) return SPSCRCERROR; 00156 00157 00158 00159 stat = (i2cbuff[42] << 8) | i2cbuff[43]; 00160 num_4p0_m = stat; 00161 dat = Sps30::CheckCrc2b(stat, i2cbuff[44]); 00162 if(dat == SPSCRCERROR) return SPSCRCERROR; 00163 00164 stat = (i2cbuff[45] << 8) | i2cbuff[46]; 00165 num_4p0_l = stat; 00166 dat = Sps30::CheckCrc2b(stat, i2cbuff[47]); 00167 if(dat == SPSCRCERROR) return SPSCRCERROR; 00168 00169 00170 stat = (i2cbuff[48] << 8) | i2cbuff[49]; 00171 num_10p0_m = stat; 00172 dat = Sps30::CheckCrc2b(stat, i2cbuff[50]); 00173 if(dat == SPSCRCERROR) return SPSCRCERROR; 00174 00175 stat = (i2cbuff[51] << 8) | i2cbuff[52]; 00176 num_10p0_l = stat; 00177 dat = Sps30::CheckCrc2b(stat, i2cbuff[53]); 00178 if(dat == SPSCRCERROR) return SPSCRCERROR; 00179 00180 00181 stat = (i2cbuff[54] << 8) | i2cbuff[55]; 00182 typ_pm_size_m = stat; 00183 dat = Sps30::CheckCrc2b(stat, i2cbuff[56]); 00184 if(dat == SPSCRCERROR) return SPSCRCERROR; 00185 00186 stat = (i2cbuff[57] << 8) | i2cbuff[58]; 00187 typ_pm_size_l = stat; 00188 dat = Sps30::CheckCrc2b(stat, i2cbuff[59]); 00189 if(dat == SPSCRCERROR) return SPSCRCERROR; 00190 00191 mass_1p0_i = (mass_1p0_m << 16) | mass_1p0_l; 00192 mass_2p5_i = (mass_2p5_m << 16) | mass_2p5_l; 00193 mass_4p0_i = (mass_4p0_m << 16) | mass_4p0_l; 00194 mass_10p0_i = (mass_10p0_m << 16) | mass_10p0_l; 00195 00196 num_0p5_i = (num_0p5_m << 16) | num_0p5_l; 00197 num_1p0_i = (num_1p0_m << 16) | num_1p0_l; 00198 num_2p5_i = (num_2p5_m << 16) | num_2p5_l; 00199 num_4p0_i = (num_4p0_m << 16) | num_4p0_l; 00200 num_10p0_i = (num_10p0_m << 16) | num_10p0_l; 00201 00202 typ_pm_size_i = (typ_pm_size_m << 16) | typ_pm_size_l; 00203 00204 mass_1p0_f = *(float*)&mass_1p0_i; 00205 mass_2p5_f = *(float*)&mass_2p5_i; 00206 mass_4p0_f = *(float*)&mass_4p0_i; 00207 mass_10p0_f = *(float*)&mass_10p0_i; 00208 00209 num_0p5_f = *(float*)&num_0p5_i; 00210 num_1p0_f = *(float*)&num_1p0_i; 00211 num_2p5_f = *(float*)&num_2p5_i; 00212 num_4p0_f = *(float*)&num_4p0_i; 00213 num_10p0_f = *(float*)&num_10p0_i; 00214 00215 typ_pm_size_f = *(float*)&typ_pm_size_i; 00216 00217 return SPSNOERROR; 00218 } 00219 00220 //----------------------------------------------------------------------------- 00221 // Calculate the CRC of a 2 byte value using the SPS30 CRC polynomial 00222 00223 uint8_t Sps30::CalcCrc2b(uint16_t seed) 00224 { 00225 uint8_t bit; // bit mask 00226 uint8_t crc = SPS30_CRC_INIT; // calculated checksum 00227 00228 // calculates 8-Bit checksum with given polynomial 00229 00230 crc ^= (seed >> 8) & 255; 00231 for(bit = 8; bit > 0; --bit) 00232 { 00233 if(crc & 0x80) crc = (crc << 1) ^ SPS30_POLYNOMIAL; 00234 else crc = (crc << 1); 00235 } 00236 00237 crc ^= seed & 255; 00238 for(bit = 8; bit > 0; --bit) 00239 { 00240 if(crc & 0x80) crc = (crc << 1) ^ SPS30_POLYNOMIAL; 00241 else crc = (crc << 1); 00242 } 00243 00244 return crc; 00245 } 00246 00247 //----------------------------------------------------------------------------- 00248 // Compare the CRC values 00249 00250 uint8_t Sps30::CheckCrc2b(uint16_t seed, uint8_t crc_in) 00251 { 00252 uint8_t crc_calc = Sps30::CalcCrc2b(seed); 00253 if(crc_calc != crc_in) return SPSCRCERROR; 00254 return SPSNOERROR; 00255 } 00256 00257 //----------------------------------------------------------------------------- 00258 // Get Sps30 serial number 00259 00260 uint8_t Sps30::GetSerialNumber() 00261 { 00262 i2cbuff[0] = SPS30_CMMD_READ_SERIALNBR >> 8; 00263 i2cbuff[1] = SPS30_CMMD_READ_SERIALNBR & 255; 00264 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00265 if(res) return SPSNOACKERROR; 00266 00267 int i = 0; 00268 for(i = 0; i < sizeof(sn); i++) sn[i] = 0; 00269 for(i = 0; i < sizeof(i2cbuff); i++) i2cbuff[i] = 0; 00270 00271 _i2c.read(SPS30_I2C_ADDR | 1, i2cbuff, SPS30_SN_SIZE, false); 00272 int t = 0; 00273 for(i = 0; i < SPS30_SN_SIZE; i +=3) { 00274 uint16_t stat = (i2cbuff[i] << 8) | i2cbuff[i + 1]; 00275 sn[i - t] = stat >> 8; 00276 sn[i - t + 1] = stat & 255; 00277 uint8_t dat = Sps30::CheckCrc2b(stat, i2cbuff[i + 2]); 00278 t++; 00279 if(dat == SPSCRCERROR) return SPSCRCERROR; 00280 if(stat == 0) break; 00281 } 00282 00283 return SPSNOERROR; 00284 } 00285 00286 //----------------------------------------------------------------------------- 00287 // Read Auto Cleaning Interval on the SPS30 00288 00289 uint8_t Sps30::ReadAutoCleanInterval() 00290 { 00291 i2cbuff[0] = SPS30_CMMD_AUTO_CLEAN_INTV >> 8; 00292 i2cbuff[1] = SPS30_CMMD_AUTO_CLEAN_INTV & 255; 00293 00294 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00295 if(res) return SPSNOACKERROR; 00296 00297 _i2c.read(SPS30_I2C_ADDR | 1, i2cbuff, 6, false); 00298 00299 uint16_t stat = (i2cbuff[0] << 8) | i2cbuff[1]; 00300 clean_interval_m = stat; 00301 uint8_t dat = Sps30::CheckCrc2b(stat, i2cbuff[2]); 00302 if(dat == SPSCRCERROR) return SPSCRCERROR; 00303 00304 stat = (i2cbuff[3] << 8) | i2cbuff[4]; 00305 clean_interval_l = stat; 00306 dat = Sps30::CheckCrc2b(stat, i2cbuff[5]); 00307 if(dat == SPSCRCERROR) return SPSCRCERROR; 00308 00309 clean_interval_i = (clean_interval_m << 16) | clean_interval_l; 00310 00311 return SPSNOERROR; 00312 } 00313 00314 //----------------------------------------------------------------------------- 00315 // Set Auto Cleaning Interval on the SPS30 00316 00317 uint8_t Sps30::SetAutoCleanInterval(uint32_t set_interval) 00318 { 00319 uint16_t set_interval_m = set_interval >> 16; 00320 uint16_t set_interval_l = set_interval & 65535; 00321 00322 i2cbuff[0] = SPS30_CMMD_AUTO_CLEAN_INTV >> 8; 00323 i2cbuff[1] = SPS30_CMMD_AUTO_CLEAN_INTV & 255; 00324 00325 i2cbuff[2] = set_interval_m >> 8; 00326 i2cbuff[3] = set_interval_m & 255; 00327 i2cbuff[4] = Sps30::CalcCrc2b(set_interval_m); 00328 00329 i2cbuff[5] = set_interval_l >> 8; 00330 i2cbuff[6] = set_interval_l & 255; 00331 i2cbuff[7] = Sps30::CalcCrc2b(set_interval_l); 00332 00333 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 8, false); 00334 if(res) return SPSNOACKERROR; 00335 00336 _i2c.read(SPS30_I2C_ADDR | 1, i2cbuff, 6, false); 00337 00338 uint16_t stat = (i2cbuff[0] << 8) | i2cbuff[1]; 00339 clean_interval_m = stat; 00340 uint8_t dat = Sps30::CheckCrc2b(stat, i2cbuff[2]); 00341 if(dat == SPSCRCERROR) return SPSCRCERROR; 00342 00343 stat = (i2cbuff[3] << 8) | i2cbuff[4]; 00344 clean_interval_l = stat; 00345 dat = Sps30::CheckCrc2b(stat, i2cbuff[5]); 00346 if(dat == SPSCRCERROR) return SPSCRCERROR; 00347 00348 clean_interval_i = (clean_interval_m << 16) | clean_interval_l; 00349 00350 return SPSNOERROR; 00351 } 00352 00353 //----------------------------------------------------------------------------- 00354 // Perform manual fan cleaning 00355 00356 uint8_t Sps30::StartFanClean() 00357 { 00358 i2cbuff[0] = SPS30_CMMD_START_FAN_CLEAN >> 8; 00359 i2cbuff[1] = SPS30_CMMD_START_FAN_CLEAN & 255; 00360 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00361 if(res) return SPSNOACKERROR; 00362 return SPSNOERROR; 00363 } 00364 00365 //----------------------------------------------------------------------------- 00366 // Perform a soft reset on the SPS30 00367 00368 uint8_t Sps30::SoftReset() 00369 { 00370 i2cbuff[0] = SPS30_CMMD_SOFT_RESET >> 8; 00371 i2cbuff[1] = SPS30_CMMD_SOFT_RESET & 255; 00372 int res = _i2c.write(SPS30_I2C_ADDR, i2cbuff, 2, false); 00373 if(res) return SPSNOACKERROR; 00374 return SPSNOERROR; 00375 } 00376 00377 /************************** PUBLIC METHODS **********************************/ 00378 00379 //----------------------------------------------------------------------------- 00380 // Initialise SPS30 00381 00382 uint8_t Sps30::InitSPS30() 00383 { 00384 uint8_t dat = Sps30::GetSerialNumber(); 00385 if (dat == SPSNOACKERROR) return DISCONNECTED; 00386 00387 dat = Sps30::StartMeasurement(); 00388 if (dat == SPSNOACKERROR) return DISCONNECTED; 00389 00390 return CONNECTED; 00391 } 00392 00393 //----------------------------------------------------------------------------- 00394 // Poll SPS30 00395 00396 uint8_t Sps30::PollSPS30() 00397 { 00398 uint8_t dat = Sps30::GetReadyStatus(); 00399 if (dat == SPSNOACKERROR) return DISCONNECTED; 00400 00401 if (sps_ready == SPSISREADY) 00402 { 00403 uint8_t crcc = Sps30::ReadMeasurement(); 00404 if (crcc == SPSNOERROR) 00405 { 00406 return DATAREADY; 00407 } 00408 else if (crcc == SPSNOACKERROR) 00409 { 00410 return DISCONNECTED; 00411 } 00412 else 00413 { 00414 return DATAERROR; 00415 } 00416 } 00417 else 00418 { 00419 return DATANOTREADY; 00420 } 00421 }
Generated on Mon Jul 18 2022 10:44:22 by
1.7.2