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 #include "build/debug.h"
25 #include "drivers/1-wire.h"
26 #include "drivers/1-wire/ds_crc.h"
27 #include "drivers/1-wire/ds2482.h"
28 #include "drivers/time.h"
31 #define DS2482_STATUS_REG_ADDR 0xF0
32 #define DS2482_READ_DATA_REG_ADDR 0xE1
33 #define DS2482_CONFIG_REG_ADDR 0xC3
35 #define DS2482_CONFIG_REG_APU (1<<0) // Active pull-up
36 #define DS2482_CONFIG_REG_SPU (1<<2) // Strong pull-up
37 #define DS2482_CONFIG_REG_WS (1<<3) // 1-Wire speed
39 #define DS2482_STATUS_REG_1WB_POS 0 // 1-Wire busy
40 #define DS2482_STATUS_REG_PPD_POS 1 // Presense-pulse detect
41 #define DS2482_STATUS_REG_SD_POS 2 // Short detected
42 #define DS2482_STATUS_REG_LL_POS 3 // Logic level
43 #define DS2482_STATUS_REG_RST_POS 4 // Device reset
44 #define DS2482_STATUS_REG_SBR_POS 5 // Single bit result
45 #define DS2482_STATUS_REG_TSB_POS 6 // Triplet second bit
46 #define DS2482_STATUS_REG_DIR_POS 7 // Branch direction taken
48 #define DS2482_1WIRE_BUSY(status) (status & (1 << DS2482_STATUS_REG_1WB_POS))
49 #define DS2482_DEVICE_PRESENT(status) (status & (1 << DS2482_STATUS_REG_PPD_POS)) // True if a device have been detected on the bus after a bus reset
50 #define DS2482_RESET(status) (status & (1 << DS2482_STATUS_REG_RST_POS))
51 #define DS2482_LOGIC_LEVEL(status) (status & (1 << DS2482_STATUS_REG_LL_POS))
52 #define DS2482_SHORT_DETECTED(status) (status & (1 << DS2482_STATUS_REG_SD_POS))
53 #define DS2482_SBR_VALUE(status) ((status >> DS2482_STATUS_REG_SBR_POS) & 1) // Extract single bit read value or triplet first bit from status register value
54 #define DS2482_TSB_VALUE(status) ((status >> DS2482_STATUS_REG_TSB_POS) & 1) // Extract triplet second bit value from status register value
55 #define DS2482_DIR_VALUE(status) ((status >> DS2482_STATUS_REG_DIR_POS) & 1) // Extract triplet chosen direction bit value from status register value
57 #define DS2482_1WIRE_SINGLE_BIT_WRITE0 0
58 #define DS2482_1WIRE_SINGLE_BIT_WRITE1_READ (1<<7)
60 #define DS2482_CONFIG_WRITE_BYTE(config) (config | ((~config & 0xF) << 4)) // Config's upper nibble should be the one's complement of lower nibble when writing
62 #define DS2482_RESET_CMD 0xF0
63 #define DS2482_SET_READ_PTR_CMD 0xE1
64 #define DS2482_WRITE_CONFIG_CMD 0xD2
65 #define DS2482_1WIRE_RESET_CMD 0xB4
66 #define DS2482_1WIRE_SINGLE_BIT_CMD 0x87
67 #define DS2482_1WIRE_WRITE_BYTE_CMD 0xA5
68 #define DS2482_1WIRE_READ_BYTE_CMD 0x96
69 #define DS2482_1WIRE_TRIPLET_CMD 0x78
71 #define _1WIRE_SEARCH_ROM_CMD 0xF0
72 #define _1WIRE_READ_ROM_CMD 0x33
73 #define _1WIRE_MATCH_ROM_CMD 0x55
74 #define _1WIRE_SKIP_ROM_CMD 0xCC
77 #if defined(USE_1WIRE) && defined(USE_1WIRE_DS2482)
80 static bool ds2482Reset(owDev_t
*owDev
)
82 return busWrite(owDev
->busDev
, 0xFF, DS2482_RESET_CMD
);
85 static bool ds2482SetReadPtr(owDev_t
*owDev
, uint8_t reg
)
87 return busWrite(owDev
->busDev
, DS2482_SET_READ_PTR_CMD
, reg
);
90 static bool ds2482ReadReg(owDev_t
*owDev
, uint8_t reg
, uint8_t *byte
)
92 bool ack
= ds2482SetReadPtr(owDev
, reg
);
93 if (!ack
) return false;
94 return busRead(owDev
->busDev
, 0xFF, byte
);
97 static bool ds2482ReadByte(owDev_t
*owDev
, uint8_t *byte
)
99 return ds2482ReadReg(owDev
, DS2482_READ_DATA_REG_ADDR
, byte
);
102 static bool ds2482ReadConfig(owDev_t
*owDev
, uint8_t *config
)
104 return ds2482ReadReg(owDev
, DS2482_CONFIG_REG_ADDR
, config
);
107 static bool ds2482WriteConfig(owDev_t
*owDev
, uint8_t config
)
109 return busWrite(owDev
->busDev
, DS2482_WRITE_CONFIG_CMD
, DS2482_CONFIG_WRITE_BYTE(config
));
112 static bool ds2482ReadStatus(owDev_t
*owDev
, uint8_t *status
)
114 bool ack
= ds2482ReadReg(owDev
, DS2482_STATUS_REG_ADDR
, &owDev
->status
);
115 if (!ack
) return false;
116 *status
= owDev
->status
;
120 static uint8_t ds2482GetStatus(owDev_t
*owDev
)
122 return owDev
->status
;
125 static bool ds2482Poll(owDev_t
*owDev
, bool waitForBus
, uint8_t *status
)
128 bool ack
= busRead(owDev
->busDev
, 0xFF, &owDev
->status
);
129 if (!ack
) return false;
130 } while (waitForBus
&& DS2482_1WIRE_BUSY(owDev
->status
));
131 if (status
) *status
= owDev
->status
;
135 static bool ds2482WaitForBus(owDev_t
*owDev
)
137 return ds2482Poll(owDev
, true, NULL
);
140 static bool ds2482OwBusReady(owDev_t
*owDev
)
142 bool ack
= busRead(owDev
->busDev
, 0xFF, &owDev
->status
);
143 if (!ack
) return false;
144 return !DS2482_1WIRE_BUSY(owDev
->status
);
147 static bool ds2482OwResetCommand(owDev_t
*owDev
)
149 return busWrite(owDev
->busDev
, 0xFF, DS2482_1WIRE_RESET_CMD
);
152 static bool ds2482OwReset(owDev_t
*owDev
)
154 bool ack
= ds2482OwResetCommand(owDev
);
155 if (!ack
) return false;
156 return ds2482WaitForBus(owDev
);
159 static bool ds2482OwWriteByteCommand(owDev_t
*owDev
, uint8_t byte
)
161 return busWrite(owDev
->busDev
, DS2482_1WIRE_WRITE_BYTE_CMD
, byte
);
164 static bool ds2482OwWriteByte(owDev_t
*owDev
, uint8_t byte
)
166 bool ack
= ds2482OwWriteByteCommand(owDev
, byte
);
167 if (!ack
) return false;
168 return ds2482WaitForBus(owDev
);
171 static bool ds2482OwWriteBuf(owDev_t
*owDev
, const uint8_t *buf
, uint8_t len
)
173 for (uint8_t index
= 0; index
< len
; ++index
) {
174 bool ack
= ds2482OwWriteByte(owDev
, buf
[index
]);
175 if (!ack
) return false;
180 static bool ds2482OwReadByteCommand(owDev_t
*owDev
)
182 return busWrite(owDev
->busDev
, 0xFF, DS2482_1WIRE_READ_BYTE_CMD
);
185 static bool ds2482OwReadByte(owDev_t
*owDev
, uint8_t *result
)
187 bool ack
= ds2482OwReadByteCommand(owDev
);
188 if (!ack
) return false;
190 ack
= ds2482WaitForBus(owDev
);
191 if (!ack
) return false;
193 return ds2482ReadByte(owDev
, result
);
196 static bool ds2482OwReadBuf(owDev_t
*owDev
, uint8_t *buf
, uint8_t len
)
198 for (uint8_t index
= 0; index
< len
; ++index
) {
199 bool ack
= ds2482OwReadByte(owDev
, buf
+ index
);
200 if (!ack
) return false;
205 static bool ds2482OwSingleBitCommand(owDev_t
*owDev
, uint8_t type
)
207 return busWrite(owDev
->busDev
, DS2482_1WIRE_SINGLE_BIT_CMD
, type
);
210 static bool ds2482OwSingleBitResult(owDev_t
*owDev
)
212 return DS2482_SBR_VALUE(owDev
->status
);
215 static bool ds2482OwSingleBit(owDev_t
*owDev
, uint8_t type
, bool *result
)
217 bool ack
= ds2482OwSingleBitCommand(owDev
, type
);
219 ack
= ds2482WaitForBus(owDev
);
220 if (!ack
) return false;
222 if (result
) *result
= ds2482OwSingleBitResult(owDev
);
226 static bool ds2482OwTripletCommand(owDev_t
*owDev
, uint8_t direction
)
228 return busWrite(owDev
->busDev
, DS2482_1WIRE_TRIPLET_CMD
, direction
<< 7);
231 static uint8_t ds2482OwTripletResult(owDev_t
*owDev
)
233 return owDev
->status
>> 5;
236 static bool ds2482OwTriplet(owDev_t
*owDev
, uint8_t direction
, uint8_t *result
)
238 bool ack
= ds2482OwTripletCommand(owDev
, direction
<< 7);
239 if (!ack
) return false;
240 ack
= ds2482Poll(owDev
, true, NULL
);
241 if (!ack
) return false;
242 *result
= ds2482OwTripletResult(owDev
);
246 static bool ds2482OwSkipRomCommand(owDev_t
*owDev
)
248 return ds2482OwWriteByte(owDev
, _1WIRE_SKIP_ROM_CMD
);
251 static bool ds2482OwSkipRom(owDev_t
*owDev
)
253 bool ack
= ds2482OwReset(owDev
);
254 if (!ack
) return false;
256 ack
= ds2482OwSkipRomCommand(owDev
);
257 if (!ack
) return false;
259 return ds2482WaitForBus(owDev
);
262 static bool ds2482OwMatchRomCommand(owDev_t
*owDev
)
264 return ds2482OwWriteByteCommand(owDev
, _1WIRE_MATCH_ROM_CMD
);
267 static bool ds2482OwMatchRom(owDev_t
*owDev
, uint64_t rom
)
269 bool ack
= ds2482OwReset(owDev
);
270 if (!ack
) return false;
272 ack
= ds2482OwMatchRomCommand(owDev
);
273 if (!ack
) return false;
275 ack
= ds2482WaitForBus(owDev
);
276 if (!ack
) return false;
278 for (uint8_t romByteIndex
= 0; romByteIndex
< 8; ++romByteIndex
) {
279 ack
= ds2482OwWriteByte(owDev
, ((uint8_t *)&rom
)[romByteIndex
]);
280 if (!ack
) return false;
286 static bool ds2482OwSearchRom(owDev_t
*owDev
, uint8_t family_code
, uint64_t *rom_table
, uint8_t *rom_table_len
)
289 uint8_t last_collision_index
= 0, rom_index
= 0;
293 uint8_t rom_byte_index
= 0, rom_bit_index
= 1, rom_byte_mask
= 1;
294 uint8_t dir_zero_last_index
= 0; // Bit index where the 0 direction has been chosen after collision
295 uint8_t *rom
= (uint8_t *)&rom_table
[rom_index
];
297 ack
= ds2482OwReset(owDev
);
298 if (!ack
) goto ds2482SearchRomReturn
;
300 ack
= ds2482Poll(owDev
, true, NULL
);
301 if (!ack
) goto ds2482SearchRomReturn
;
303 if (!DS2482_DEVICE_PRESENT(owDev
->status
))
304 goto ds2482SearchRomReturn
;
306 ack
= ds2482OwWriteByte(owDev
, _1WIRE_SEARCH_ROM_CMD
);
307 if (!ack
) goto ds2482SearchRomReturn
;
312 if (family_code
&& (rom_bit_index
< 9)) {
313 direction
= (family_code
>> (rom_bit_index
- 1)) & 1;
314 } else if ((rom_index
> 0) && (rom_bit_index
< last_collision_index
)) {
315 const uint8_t *previous_rom
= (uint8_t *)&rom_table
[rom_index
-1];
316 direction
= (previous_rom
[rom_byte_index
] & rom_byte_mask
) > 0;
318 direction
= rom_bit_index
== last_collision_index
;
321 ack
= ds2482OwTripletCommand(owDev
, direction
);
322 if (!ack
) goto ds2482SearchRomReturn
;
324 ack
= ds2482Poll(owDev
, true, NULL
);
325 if (!ack
) goto ds2482SearchRomReturn
;
327 uint8_t triplet_sbr
= DS2482_SBR_VALUE(owDev
->status
);
328 uint8_t triplet_tsb
= DS2482_TSB_VALUE(owDev
->status
);
329 uint8_t triplet_dir
= DS2482_DIR_VALUE(owDev
->status
);
331 if (triplet_sbr
&& triplet_tsb
) break; // Error, the device have been disconnected during the search, restart
333 if (family_code
&& (rom_bit_index
< 9) && (triplet_dir
!= direction
))
334 goto ds2482SearchRomReturn
;
337 rom
[rom_byte_index
] |= rom_byte_mask
;
339 if (!(triplet_sbr
|| triplet_tsb
)) dir_zero_last_index
= rom_bit_index
; // Collision
340 rom
[rom_byte_index
] &= ~rom_byte_mask
;
345 if (!(rom_byte_mask
<<= 1)) {
350 } while (rom_byte_index
< 8);
352 if ((rom_bit_index
> 64) && (rom
[7] == ds_crc8(rom
, 7))) {
354 last_collision_index
= dir_zero_last_index
;
355 if (!last_collision_index
) break; // All the devices have been found
358 } while (rom_index
< *rom_table_len
);
360 ds2482SearchRomReturn
:
362 *rom_table_len
= rom_index
;
369 static bool ds2482Init(owDev_t
*owDev
)
371 return ds2482WriteConfig(owDev
, DS2482_CONFIG_REG_APU
);
374 #define DETECTION_MAX_RETRY_COUNT 5
375 static bool deviceDetect(owDev_t
*owDev
)
377 for (int retryCount
= 0; retryCount
< DETECTION_MAX_RETRY_COUNT
; retryCount
++) {
379 if (ds2482Reset(owDev
)) return true;
385 bool ds2482Detect(owDev_t
*owDev
)
387 owDev
->busDev
= busDeviceInit(BUSTYPE_I2C
, DEVHW_DS2482
, 0, OWNER_1WIRE
);
388 if (owDev
->busDev
== NULL
) {
392 if (!deviceDetect(owDev
)) {
393 busDeviceDeInit(owDev
->busDev
);
399 owDev
->reset
= ds2482Reset
;
400 owDev
->owResetCommand
= ds2482OwResetCommand
;
401 owDev
->owReset
= ds2482OwReset
;
402 owDev
->waitForBus
= ds2482WaitForBus
;
403 owDev
->readConfig
= ds2482ReadConfig
;
404 owDev
->writeConfig
= ds2482WriteConfig
;
405 owDev
->readStatus
= ds2482ReadStatus
;
406 owDev
->getStatus
= ds2482GetStatus
;
407 owDev
->poll
= ds2482Poll
;
408 owDev
->owBusReady
= ds2482OwBusReady
;
410 owDev
->owSearchRom
= ds2482OwSearchRom
;
411 owDev
->owMatchRomCommand
= ds2482OwMatchRomCommand
;
412 owDev
->owMatchRom
= ds2482OwMatchRom
;
413 owDev
->owSkipRomCommand
= ds2482OwSkipRomCommand
;
414 owDev
->owSkipRom
= ds2482OwSkipRom
;
416 owDev
->owWriteByteCommand
= ds2482OwWriteByteCommand
;
417 owDev
->owWriteByte
= ds2482OwWriteByte
;
418 owDev
->owWriteBuf
= ds2482OwWriteBuf
;
419 owDev
->owReadByteCommand
= ds2482OwReadByteCommand
;
420 owDev
->owReadByteResult
= ds2482ReadByte
;
421 owDev
->owReadByte
= ds2482OwReadByte
;
422 owDev
->owReadBuf
= ds2482OwReadBuf
;
423 owDev
->owSingleBitCommand
= ds2482OwSingleBitCommand
;
424 owDev
->owSingleBitResult
= ds2482OwSingleBitResult
;
425 owDev
->owSingleBit
= ds2482OwSingleBit
;
426 owDev
->owTripletCommand
= ds2482OwTripletCommand
;
427 owDev
->owTripletResult
= ds2482OwTripletResult
;
428 owDev
->owTriplet
= ds2482OwTriplet
;
433 #endif /* defined(USE_1WIRE) && defined(USE_1WIRE_DS2482) */