2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
23 #if defined(USE_RANGEFINDER) && defined(USE_RANGEFINDER_US42)
25 #include "build/build_config.h"
27 #include "drivers/time.h"
28 #include "drivers/bus_i2c.h"
30 #include "drivers/rangefinder/rangefinder.h"
31 #include "drivers/rangefinder/rangefinder_us42.h"
33 #include "build/debug.h"
35 // GY-US42(v2) Ultrasonic Range Sensor
36 #define US42_MAX_RANGE_CM 400 // vcc=3.3v -> 500cm; vcc=5v -> 700cm; Ardupilot recommends a maximum of 400cm
37 #define US42_DETECTION_CONE_DECIDEGREES 250
38 #define US42_DETECTION_CONE_EXTENDED_DECIDEGREES 300
39 #define US42_MIN_PROBE_INTERVAL 50
41 #define US42_I2C_ADDRESS 0x70
42 #define US42_I2C_REGISTRY_BASE 0x00
43 #define US42_I2C_REGISTRY_PROBE 0x51
44 #define US42_I2C_REGISTRY_STATUS_OK 0x00
45 #define US42_I2C_REGISTRY_DISTANCE_HIGH 0x00
46 #define US42_I2C_REGISTRY_DISTANCE_LOW 0x01
48 volatile int32_t us42MeasurementCm
= RANGEFINDER_OUT_OF_RANGE
;
49 static int16_t minimumReadingIntervalMs
= US42_MIN_PROBE_INTERVAL
;
50 static uint32_t timeOfLastMeasurementMs
;
51 uint8_t nullProbeCommandValue
[0];
52 static bool isUs42Responding
= false;
54 static void us42Init(rangefinderDev_t
*rangefinder
)
56 busWriteBuf(rangefinder
->busDev
, US42_I2C_REGISTRY_PROBE
, nullProbeCommandValue
, 0);
59 void us42Update(rangefinderDev_t
*rangefinder
)
62 isUs42Responding
= busReadBuf(rangefinder
->busDev
, US42_I2C_REGISTRY_PROBE
, data
, 2);
64 if (isUs42Responding
) {
65 us42MeasurementCm
= (int32_t)data
[0] << 8 | (int32_t)data
[1];
67 if (us42MeasurementCm
> US42_MAX_RANGE_CM
) {
68 us42MeasurementCm
= RANGEFINDER_OUT_OF_RANGE
;
72 us42MeasurementCm
= RANGEFINDER_HARDWARE_FAILURE
;
75 const timeMs_t timeNowMs
= millis();
76 if (timeNowMs
> timeOfLastMeasurementMs
+ minimumReadingIntervalMs
) {
77 // measurement repeat interval should be greater than minimumReadingIntervalMs
78 // to avoid interference between connective measurements.
79 timeOfLastMeasurementMs
= timeNowMs
;
80 busWriteBuf(rangefinder
->busDev
, US42_I2C_REGISTRY_PROBE
, nullProbeCommandValue
, 0);
85 * Get the distance that was measured by the last pulse, in centimeters.
87 int32_t us42GetDistance(rangefinderDev_t
*rangefinder
)
90 return us42MeasurementCm
;
93 static bool deviceDetect(busDevice_t
* busDev
)
95 for (int retry
= 0; retry
< 5; retry
++) {
96 uint8_t inquiryResult
;
100 bool ack
= busRead(busDev
, US42_I2C_REGISTRY_BASE
, &inquiryResult
);
101 if (ack
&& inquiryResult
== US42_I2C_REGISTRY_STATUS_OK
) {
109 bool us42Detect(rangefinderDev_t
*rangefinder
)
111 rangefinder
->busDev
= busDeviceInit(BUSTYPE_I2C
, DEVHW_US42
, 0, OWNER_RANGEFINDER
);
112 if (rangefinder
->busDev
== NULL
) {
116 if (!deviceDetect(rangefinder
->busDev
)) {
117 busDeviceDeInit(rangefinder
->busDev
);
121 rangefinder
->delayMs
= RANGEFINDER_US42_TASK_PERIOD_MS
;
122 rangefinder
->maxRangeCm
= US42_MAX_RANGE_CM
;
123 rangefinder
->detectionConeDeciDegrees
= US42_DETECTION_CONE_DECIDEGREES
;
124 rangefinder
->detectionConeExtendedDeciDegrees
= US42_DETECTION_CONE_EXTENDED_DECIDEGREES
;
126 rangefinder
->init
= &us42Init
;
127 rangefinder
->update
= &us42Update
;
128 rangefinder
->read
= &us42GetDistance
;