aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios-contrib/os/hal/src/hal_onewire.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios-contrib/os/hal/src/hal_onewire.c')
-rw-r--r--lib/chibios-contrib/os/hal/src/hal_onewire.c889
1 files changed, 889 insertions, 0 deletions
diff --git a/lib/chibios-contrib/os/hal/src/hal_onewire.c b/lib/chibios-contrib/os/hal/src/hal_onewire.c
new file mode 100644
index 000000000..06e63e68d
--- /dev/null
+++ b/lib/chibios-contrib/os/hal/src/hal_onewire.c
@@ -0,0 +1,889 @@
1/*
2 ChibiOS/RT - Copyright (C) 2014 Uladzimir Pylinsky aka barthess
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/*===========================================================================*/
18/* Main ideas: */
19/*===========================================================================
20
211) switch PWM output pin to open drain mode.
222) start 2 channels _simultaneously_. First (master channel) generates
23 pulses (read time slots) second (sample channel) generates interrupts
24 from where read pin function will be called.
25
26- --------------------------------------- master channel generates pulses
27 | / .
28 --............................. <---------- slave (not)pulls down bus here
29- -------------------------------- sample channel reads pad state
30 | |
31 -------------
32 ^
33 | read interrupt fires here
34
35For data write it is only master channel needed. Data bit width updates
36on every timer overflow event.
37*/
38
39/*===========================================================================*/
40/* General recommendations for strong pull usage */
41/*===========================================================================
42 * 1) Use separate power rail instead of strong pull up whenever possible.
43 * Driver's strong pull up feature is very sensible to interrupt jitter.
44 * 2) Use specialized 1-wire bus master (DS2484 for example) if you are
45 * forced to handle bus requiring strong pull up feature.
46 */
47
48/**
49 * @file hal_onewire.c
50 * @brief 1-wire Driver code.
51 *
52 * @addtogroup onewire
53 * @{
54 */
55
56#include "hal.h"
57
58#if (HAL_USE_ONEWIRE == TRUE) || defined(__DOXYGEN__)
59
60#include <string.h>
61#include <limits.h>
62
63/*===========================================================================*/
64/* Driver local definitions. */
65/*===========================================================================*/
66/**
67 * @brief 1MHz clock for PWM driver.
68 */
69#define ONEWIRE_PWM_FREQUENCY 1000000
70
71/**
72 * @brief Pulse width constants in microseconds.
73 * @details Inspired by Microchip's AN1199
74 * "1-Wire® Communication with PIC® Microcontroller"
75 */
76#define ONEWIRE_ZERO_WIDTH 60
77#define ONEWIRE_ONE_WIDTH 6
78#define ONEWIRE_SAMPLE_WIDTH 15
79#define ONEWIRE_RECOVERY_WIDTH 10
80#define ONEWIRE_RESET_LOW_WIDTH 480
81#define ONEWIRE_RESET_SAMPLE_WIDTH 550
82#define ONEWIRE_RESET_TOTAL_WIDTH 960
83
84/**
85 * @brief Local function declarations.
86 */
87static void ow_reset_cb(PWMDriver *pwmp, onewireDriver *owp);
88static void pwm_reset_cb(PWMDriver *pwmp);
89static void ow_read_bit_cb(PWMDriver *pwmp, onewireDriver *owp);
90static void pwm_read_bit_cb(PWMDriver *pwmp);
91static void ow_write_bit_cb(PWMDriver *pwmp, onewireDriver *owp);
92static void pwm_write_bit_cb(PWMDriver *pwmp);
93#if ONEWIRE_USE_SEARCH_ROM
94static void ow_search_rom_cb(PWMDriver *pwmp, onewireDriver *owp);
95static void pwm_search_rom_cb(PWMDriver *pwmp);
96#endif
97
98/*===========================================================================*/
99/* Driver exported variables. */
100/*===========================================================================*/
101/**
102 * @brief 1-wire driver identifier.
103 */
104onewireDriver OWD1;
105
106/*===========================================================================*/
107/* Driver local variables and types. */
108/*===========================================================================*/
109/**
110 * @brief Look up table for fast 1-wire CRC calculation
111 */
112static const uint8_t onewire_crc_table[256] = {
113 0x0, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83,
114 0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41,
115 0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e,
116 0x5f, 0x1, 0xe3, 0xbd, 0x3e, 0x60, 0x82, 0xdc,
117 0x23, 0x7d, 0x9f, 0xc1, 0x42, 0x1c, 0xfe, 0xa0,
118 0xe1, 0xbf, 0x5d, 0x3, 0x80, 0xde, 0x3c, 0x62,
119 0xbe, 0xe0, 0x2, 0x5c, 0xdf, 0x81, 0x63, 0x3d,
120 0x7c, 0x22, 0xc0, 0x9e, 0x1d, 0x43, 0xa1, 0xff,
121 0x46, 0x18, 0xfa, 0xa4, 0x27, 0x79, 0x9b, 0xc5,
122 0x84, 0xda, 0x38, 0x66, 0xe5, 0xbb, 0x59, 0x7,
123 0xdb, 0x85, 0x67, 0x39, 0xba, 0xe4, 0x6, 0x58,
124 0x19, 0x47, 0xa5, 0xfb, 0x78, 0x26, 0xc4, 0x9a,
125 0x65, 0x3b, 0xd9, 0x87, 0x4, 0x5a, 0xb8, 0xe6,
126 0xa7, 0xf9, 0x1b, 0x45, 0xc6, 0x98, 0x7a, 0x24,
127 0xf8, 0xa6, 0x44, 0x1a, 0x99, 0xc7, 0x25, 0x7b,
128 0x3a, 0x64, 0x86, 0xd8, 0x5b, 0x5, 0xe7, 0xb9,
129 0x8c, 0xd2, 0x30, 0x6e, 0xed, 0xb3, 0x51, 0xf,
130 0x4e, 0x10, 0xf2, 0xac, 0x2f, 0x71, 0x93, 0xcd,
131 0x11, 0x4f, 0xad, 0xf3, 0x70, 0x2e, 0xcc, 0x92,
132 0xd3, 0x8d, 0x6f, 0x31, 0xb2, 0xec, 0xe, 0x50,
133 0xaf, 0xf1, 0x13, 0x4d, 0xce, 0x90, 0x72, 0x2c,
134 0x6d, 0x33, 0xd1, 0x8f, 0xc, 0x52, 0xb0, 0xee,
135 0x32, 0x6c, 0x8e, 0xd0, 0x53, 0xd, 0xef, 0xb1,
136 0xf0, 0xae, 0x4c, 0x12, 0x91, 0xcf, 0x2d, 0x73,
137 0xca, 0x94, 0x76, 0x28, 0xab, 0xf5, 0x17, 0x49,
138 0x8, 0x56, 0xb4, 0xea, 0x69, 0x37, 0xd5, 0x8b,
139 0x57, 0x9, 0xeb, 0xb5, 0x36, 0x68, 0x8a, 0xd4,
140 0x95, 0xcb, 0x29, 0x77, 0xf4, 0xaa, 0x48, 0x16,
141 0xe9, 0xb7, 0x55, 0xb, 0x88, 0xd6, 0x34, 0x6a,
142 0x2b, 0x75, 0x97, 0xc9, 0x4a, 0x14, 0xf6, 0xa8,
143 0x74, 0x2a, 0xc8, 0x96, 0x15, 0x4b, 0xa9, 0xf7,
144 0xb6, 0xe8, 0xa, 0x54, 0xd7, 0x89, 0x6b, 0x35
145};
146
147/*===========================================================================*/
148/* Driver local functions. */
149/*===========================================================================*/
150/**
151 * @brief Put bus in idle mode.
152 */
153static void ow_bus_idle(onewireDriver *owp) {
154#if defined(STM32F1XX)
155 palSetPadMode(owp->config->port, owp->config->pad,
156 owp->config->pad_mode_idle);
157#endif
158 pwmStop(owp->config->pwmd);
159}
160
161/**
162 * @brief Put bus in active mode.
163 */
164static void ow_bus_active(onewireDriver *owp) {
165 pwmStart(owp->config->pwmd, owp->config->pwmcfg);
166#if defined(STM32F1XX)
167 palSetPadMode(owp->config->port, owp->config->pad,
168 owp->config->pad_mode_active);
169#endif
170}
171
172/**
173 * @brief Function performing read of single bit.
174 * @note It must be callable from any context.
175 */
176static ioline_t ow_read_bit(onewireDriver *owp) {
177#if ONEWIRE_SYNTH_SEARCH_TEST
178 (void)owp;
179 return _synth_ow_read_bit();
180#else
181 return palReadPad(owp->config->port, owp->config->pad);
182#endif
183}
184
185/**
186 * @brief PWM adapter
187 */
188static void pwm_reset_cb(PWMDriver *pwmp) {
189 ow_reset_cb(pwmp, &OWD1);
190}
191
192/**
193 * @brief PWM adapter
194 */
195static void pwm_read_bit_cb(PWMDriver *pwmp) {
196 ow_read_bit_cb(pwmp, &OWD1);
197}
198
199/**
200 * @brief PWM adapter
201 */
202static void pwm_write_bit_cb(PWMDriver *pwmp) {
203 ow_write_bit_cb(pwmp, &OWD1);
204}
205
206#if ONEWIRE_USE_SEARCH_ROM
207/**
208 * @brief PWM adapter
209 */
210static void pwm_search_rom_cb(PWMDriver *pwmp) {
211 ow_search_rom_cb(pwmp, &OWD1);
212}
213#endif /* ONEWIRE_USE_SEARCH_ROM */
214
215/**
216 * @brief Write bit routine.
217 * @details Switch PWM channel to 'width' or 'narrow' pulse depending
218 * on value of bit need to be transmitted.
219 *
220 * @param[in] owp pointer to the @p onewireDriver object
221 * @param[in] bit value to be written
222 *
223 * @notapi
224 */
225static void ow_write_bit_I(onewireDriver *owp, ioline_t bit) {
226#if ONEWIRE_SYNTH_SEARCH_TEST
227 _synth_ow_write_bit(owp, bit);
228#else
229 osalSysLockFromISR();
230 if (0 == bit) {
231 pwmEnableChannelI(owp->config->pwmd, owp->config->master_channel,
232 ONEWIRE_ZERO_WIDTH);
233 }
234 else {
235 pwmEnableChannelI(owp->config->pwmd, owp->config->master_channel,
236 ONEWIRE_ONE_WIDTH);
237 }
238 osalSysUnlockFromISR();
239#endif
240}
241
242/**
243 * @brief 1-wire reset pulse callback.
244 * @note Must be called from PWM's ISR.
245 *
246 * @param[in] pwmp pointer to the @p PWMDriver object
247 * @param[in] owp pointer to the @p onewireDriver object
248 *
249 * @notapi
250 */
251static void ow_reset_cb(PWMDriver *pwmp, onewireDriver *owp) {
252
253 owp->reg.slave_present = (PAL_LOW == ow_read_bit(owp));
254 osalSysLockFromISR();
255 pwmDisableChannelI(pwmp, owp->config->sample_channel);
256 osalThreadResumeI(&owp->thread, MSG_OK);
257 osalSysUnlockFromISR();
258}
259
260/**
261 * @brief 1-wire read bit callback.
262 * @note Must be called from PWM's ISR.
263 *
264 * @param[in] pwmp pointer to the @p PWMDriver object
265 * @param[in] owp pointer to the @p onewireDriver object
266 *
267 * @notapi
268 */
269static void ow_read_bit_cb(PWMDriver *pwmp, onewireDriver *owp) {
270
271 if (true == owp->reg.final_timeslot) {
272 osalSysLockFromISR();
273 pwmDisableChannelI(pwmp, owp->config->sample_channel);
274 osalThreadResumeI(&owp->thread, MSG_OK);
275 osalSysUnlockFromISR();
276 return;
277 }
278 else {
279 *owp->buf |= ow_read_bit(owp) << owp->reg.bit;
280 owp->reg.bit++;
281 if (8 == owp->reg.bit) {
282 owp->reg.bit = 0;
283 owp->buf++;
284 owp->reg.bytes--;
285 if (0 == owp->reg.bytes) {
286 owp->reg.final_timeslot = true;
287 osalSysLockFromISR();
288 /* Only master channel must be stopped here.
289 Sample channel will be stopped in next ISR call.
290 It is still needed to generate final interrupt. */
291 pwmDisableChannelI(pwmp, owp->config->master_channel);
292 osalSysUnlockFromISR();
293 }
294 }
295 }
296}
297
298/**
299 * @brief 1-wire bit transmission callback.
300 * @note Must be called from PWM's ISR.
301 *
302 * @param[in] pwmp pointer to the @p PWMDriver object
303 * @param[in] owp pointer to the @p onewireDriver object
304 *
305 * @notapi
306 */
307static void ow_write_bit_cb(PWMDriver *pwmp, onewireDriver *owp) {
308
309 if (8 == owp->reg.bit) {
310 owp->buf++;
311 owp->reg.bit = 0;
312 owp->reg.bytes--;
313
314 if (0 == owp->reg.bytes) {
315 osalSysLockFromISR();
316 pwmDisableChannelI(pwmp, owp->config->master_channel);
317 osalSysUnlockFromISR();
318 /* used to prevent premature timer stop from userspace */
319 owp->reg.final_timeslot = true;
320 return;
321 }
322 }
323
324 /* wait until timer generate last pulse */
325 if (true == owp->reg.final_timeslot) {
326 #if ONEWIRE_USE_STRONG_PULLUP
327 if (owp->reg.need_pullup) {
328 owp->reg.state = ONEWIRE_PULL_UP;
329 owp->config->pullup_assert();
330 owp->reg.need_pullup = false;
331 }
332 #endif
333
334 osalSysLockFromISR();
335 osalThreadResumeI(&owp->thread, MSG_OK);
336 osalSysUnlockFromISR();
337 return;
338 }
339
340 ow_write_bit_I(owp, (*owp->buf >> owp->reg.bit) & 1);
341 owp->reg.bit++;
342}
343
344#if ONEWIRE_USE_SEARCH_ROM
345/**
346 * @brief Helper function for collision handler
347 *
348 * @param[in] sr pointer to the @p onewire_search_rom_t helper structure
349 * @param[in] bit discovered bit to be stored in helper structure
350 */
351static void store_bit(onewire_search_rom_t *sr, uint8_t bit) {
352
353 size_t rb = sr->reg.rombit;
354
355 sr->retbuf[rb / CHAR_BIT] |= bit << (rb % CHAR_BIT);
356 sr->reg.rombit++;
357}
358
359/**
360 * @brief Helper function for collision handler
361 * @details Extract bit from previous search path.
362 *
363 * @param[in] path pointer to the array with previous path stored in
364 * 'search ROM' helper structure
365 * @param[in] bit number of bit [0..63]
366 */
367static uint8_t extract_path_bit(const uint8_t *path, size_t bit) {
368
369 return (path[bit / CHAR_BIT] >> (bit % CHAR_BIT)) & 1;
370}
371
372/**
373 * @brief Collision handler for 'search ROM' procedure.
374 * @details You can find algorithm details in APPNOTE 187
375 * "1-Wire Search Algorithm" from Maxim
376 *
377 * @param[in,out] sr pointer to the @p onewire_search_rom_t helper structure
378 */
379static uint8_t collision_handler(onewire_search_rom_t *sr) {
380
381 uint8_t bit;
382
383 switch(sr->reg.search_iter) {
384 case ONEWIRE_SEARCH_ROM_NEXT:
385 if ((int)sr->reg.rombit < sr->last_zero_branch) {
386 bit = extract_path_bit(sr->prev_path, sr->reg.rombit);
387 if (0 == bit) {
388 sr->prev_zero_branch = sr->reg.rombit;
389 sr->reg.result = ONEWIRE_SEARCH_ROM_SUCCESS;
390 }
391 store_bit(sr, bit);
392 return bit;
393 }
394 else if ((int)sr->reg.rombit == sr->last_zero_branch) {
395 sr->last_zero_branch = sr->prev_zero_branch;
396 store_bit(sr, 1);
397 return 1;
398 }
399 else {
400 /* found next branch some levels deeper */
401 sr->prev_zero_branch = sr->last_zero_branch;
402 sr->last_zero_branch = sr->reg.rombit;
403 store_bit(sr, 0);
404 sr->reg.result = ONEWIRE_SEARCH_ROM_SUCCESS;
405 return 0;
406 }
407 break;
408
409 case ONEWIRE_SEARCH_ROM_FIRST:
410 /* always take 0-branch */
411 sr->prev_zero_branch = sr->last_zero_branch;
412 sr->last_zero_branch = sr->reg.rombit;
413 store_bit(sr, 0);
414 sr->reg.result = ONEWIRE_SEARCH_ROM_SUCCESS;
415 return 0;
416 break;
417
418 default:
419 osalSysHalt("Unhandled case");
420 return 0; /* warning supressor */
421 break;
422 }
423}
424
425/**
426 * @brief 1-wire search ROM callback.
427 * @note Must be called from PWM's ISR.
428 *
429 * @param[in] pwmp pointer to the @p PWMDriver object
430 * @param[in] owp pointer to the @p onewireDriver object
431 *
432 * @notapi
433 */
434static void ow_search_rom_cb(PWMDriver *pwmp, onewireDriver *owp) {
435
436 onewire_search_rom_t *sr = &owp->search_rom;
437
438 if (0 == sr->reg.bit_step) { /* read direct bit */
439 sr->reg.bit_buf |= ow_read_bit(owp);
440 sr->reg.bit_step++;
441 }
442 else if (1 == sr->reg.bit_step) { /* read complement bit */
443 sr->reg.bit_buf |= ow_read_bit(owp) << 1;
444 sr->reg.bit_step++;
445 switch(sr->reg.bit_buf){
446 case 0b11:
447 /* no one device on bus or any other fail happened */
448 sr->reg.result = ONEWIRE_SEARCH_ROM_ERROR;
449 goto THE_END;
450 break;
451 case 0b01:
452 /* all slaves have 1 in this position */
453 store_bit(sr, 1);
454 ow_write_bit_I(owp, 1);
455 break;
456 case 0b10:
457 /* all slaves have 0 in this position */
458 store_bit(sr, 0);
459 ow_write_bit_I(owp, 0);
460 break;
461 case 0b00:
462 /* collision */
463 sr->reg.single_device = false;
464 ow_write_bit_I(owp, collision_handler(sr));
465 break;
466 }
467 }
468 else { /* start next step */
469 #if !ONEWIRE_SYNTH_SEARCH_TEST
470 ow_write_bit_I(owp, 1);
471 #endif
472 sr->reg.bit_step = 0;
473 sr->reg.bit_buf = 0;
474 }
475
476 /* one ROM successfully discovered */
477 if (64 == sr->reg.rombit) {
478 sr->reg.devices_found++;
479 sr->reg.search_iter = ONEWIRE_SEARCH_ROM_NEXT;
480 if (true == sr->reg.single_device)
481 sr->reg.result = ONEWIRE_SEARCH_ROM_LAST;
482 goto THE_END;
483 }
484 return; /* next search bit iteration */
485
486THE_END:
487#if ONEWIRE_SYNTH_SEARCH_TEST
488 (void)pwmp;
489 return;
490#else
491 osalSysLockFromISR();
492 pwmDisableChannelI(pwmp, owp->config->master_channel);
493 pwmDisableChannelI(pwmp, owp->config->sample_channel);
494 osalThreadResumeI(&(owp)->thread, MSG_OK);
495 osalSysUnlockFromISR();
496#endif
497}
498
499/**
500 * @brief Helper function. Initialize structures required by 'search ROM'.
501 * @details Early reset. Call it once before 'search ROM' routine.
502 *
503 * @param[in] sr pointer to the @p onewire_search_rom_t helper structure
504 */
505static void search_clean_start(onewire_search_rom_t *sr) {
506
507 sr->reg.single_device = true; /* presume simplest way at beginning */
508 sr->reg.result = ONEWIRE_SEARCH_ROM_LAST;
509 sr->reg.search_iter = ONEWIRE_SEARCH_ROM_FIRST;
510 sr->retbuf = NULL;
511 sr->reg.devices_found = 0;
512 memset(sr->prev_path, 0, 8);
513
514 sr->reg.rombit = 0;
515 sr->reg.bit_step = 0;
516 sr->reg.bit_buf = 0;
517 sr->last_zero_branch = -1;
518 sr->prev_zero_branch = -1;
519}
520
521/**
522 * @brief Helper function. Prepare structures required by 'search ROM'.
523 *
524 * @param[in] sr pointer to the @p onewire_search_rom_t helper structure
525 */
526static void search_clean_iteration(onewire_search_rom_t *sr) {
527
528 sr->reg.rombit = 0;
529 sr->reg.bit_step = 0;
530 sr->reg.bit_buf = 0;
531 sr->reg.result = ONEWIRE_SEARCH_ROM_LAST;
532}
533#endif /* ONEWIRE_USE_SEARCH_ROM */
534
535/*===========================================================================*/
536/* Driver exported functions. */
537/*===========================================================================*/
538
539/**
540 * @brief Calculates 1-wire CRC.
541 *
542 * @param[in] buf pointer to the data buffer
543 * @param[in] len lenght of data buffer
544 *
545 * @init
546 */
547uint8_t onewireCRC(const uint8_t *buf, size_t len) {
548 uint8_t ret = 0;
549 size_t i;
550
551 for (i=0; i<len; i++)
552 ret = onewire_crc_table[ret ^ buf[i]];
553
554 return ret;
555}
556
557/**
558 * @brief Initializes @p onewireDriver structure.
559 *
560 * @param[out] owp pointer to the @p onewireDriver object
561 *
562 * @init
563 */
564void onewireObjectInit(onewireDriver *owp) {
565
566 osalDbgCheck(NULL != owp);
567
568 owp->config = NULL;
569 owp->reg.slave_present = false;
570 owp->reg.state = ONEWIRE_STOP;
571 owp->thread = NULL;
572
573 owp->reg.bytes = 0;
574 owp->reg.bit = 0;
575 owp->reg.final_timeslot = false;
576 owp->buf = NULL;
577
578#if ONEWIRE_USE_STRONG_PULLUP
579 owp->reg.need_pullup = false;
580#endif
581}
582
583/**
584 * @brief Configures and activates the 1-wire driver.
585 *
586 * @param[in] owp pointer to the @p onewireDriver object
587 * @param[in] config pointer to the @p onewireConfig object
588 *
589 * @api
590 */
591void onewireStart(onewireDriver *owp, const onewireConfig *config) {
592
593 osalDbgCheck((NULL != owp) && (NULL != config));
594 osalDbgAssert(PWM_STOP == config->pwmd->state,
595 "PWM will be started by onewire driver internally");
596 osalDbgAssert(ONEWIRE_STOP == owp->reg.state, "Invalid state");
597#if ONEWIRE_USE_STRONG_PULLUP
598 osalDbgCheck((NULL != config->pullup_assert) &&
599 (NULL != config->pullup_release));
600#endif
601
602 owp->config = config;
603 owp->config->pwmcfg->frequency = ONEWIRE_PWM_FREQUENCY;
604 owp->config->pwmcfg->period = ONEWIRE_RESET_TOTAL_WIDTH;
605
606#if !defined(STM32F1XX)
607 palSetPadMode(owp->config->port, owp->config->pad,
608 owp->config->pad_mode_active);
609#endif
610 ow_bus_idle(owp);
611 owp->reg.state = ONEWIRE_READY;
612}
613
614/**
615 * @brief Deactivates the UART peripheral.
616 *
617 * @param[in] owp pointer to the @p onewireDriver object
618 *
619 * @api
620 */
621void onewireStop(onewireDriver *owp) {
622 osalDbgCheck(NULL != owp);
623#if ONEWIRE_USE_STRONG_PULLUP
624 owp->config->pullup_release();
625#endif
626 ow_bus_idle(owp);
627 pwmStop(owp->config->pwmd);
628 owp->config = NULL;
629 owp->reg.state = ONEWIRE_STOP;
630}
631
632/**
633 * @brief Generate reset pulse on bus.
634 *
635 * @param[in] owp pointer to the @p onewireDriver object
636 *
637 * @return Bool flag denoting device presence.
638 * @retval true There is at least one device on bus.
639 */
640bool onewireReset(onewireDriver *owp) {
641 PWMDriver *pwmd;
642 PWMConfig *pwmcfg;
643 size_t mch, sch;
644
645 osalDbgCheck(NULL != owp);
646 osalDbgAssert(owp->reg.state == ONEWIRE_READY, "Invalid state");
647
648 /* short circuit on bus or any other device transmit data */
649 if (PAL_LOW == ow_read_bit(owp))
650 return false;
651
652 pwmd = owp->config->pwmd;
653 pwmcfg = owp->config->pwmcfg;
654 mch = owp->config->master_channel;
655 sch = owp->config->sample_channel;
656
657
658 pwmcfg->period = ONEWIRE_RESET_LOW_WIDTH + ONEWIRE_RESET_SAMPLE_WIDTH;
659 pwmcfg->callback = NULL;
660 pwmcfg->channels[mch].callback = NULL;
661 pwmcfg->channels[mch].mode = owp->config->pwmmode;
662 pwmcfg->channels[sch].callback = pwm_reset_cb;
663 pwmcfg->channels[sch].mode = PWM_OUTPUT_DISABLED;
664
665 ow_bus_active(owp);
666
667 osalSysLock();
668 pwmEnableChannelI(pwmd, mch, ONEWIRE_RESET_LOW_WIDTH);
669 pwmEnableChannelI(pwmd, sch, ONEWIRE_RESET_SAMPLE_WIDTH);
670 pwmEnableChannelNotificationI(pwmd, sch);
671 osalThreadSuspendS(&owp->thread);
672 osalSysUnlock();
673
674 ow_bus_idle(owp);
675
676 /* wait until slave release bus to discriminate short circuit condition */
677 osalThreadSleepMicroseconds(500);
678 return (PAL_HIGH == ow_read_bit(owp)) && (true == owp->reg.slave_present);
679}
680
681/**
682 * @brief Read some bytes from slave device.
683 *
684 * @param[in] owp pointer to the @p onewireDriver object
685 * @param[out] rxbuf pointer to the buffer for read data
686 * @param[in] rxbytes amount of data to be received
687 */
688void onewireRead(onewireDriver *owp, uint8_t *rxbuf, size_t rxbytes) {
689 PWMDriver *pwmd;
690 PWMConfig *pwmcfg;
691 size_t mch, sch;
692
693 osalDbgCheck((NULL != owp) && (NULL != rxbuf));
694 osalDbgCheck((rxbytes > 0) && (rxbytes <= ONEWIRE_MAX_TRANSACTION_LEN));
695 osalDbgAssert(owp->reg.state == ONEWIRE_READY, "Invalid state");
696
697 /* Buffer zeroing. This is important because of driver collects
698 bits using |= operation.*/
699 memset(rxbuf, 0, rxbytes);
700
701 pwmd = owp->config->pwmd;
702 pwmcfg = owp->config->pwmcfg;
703 mch = owp->config->master_channel;
704 sch = owp->config->sample_channel;
705
706 owp->reg.bit = 0;
707 owp->reg.final_timeslot = false;
708 owp->buf = rxbuf;
709 owp->reg.bytes = rxbytes;
710
711 pwmcfg->period = ONEWIRE_ZERO_WIDTH + ONEWIRE_RECOVERY_WIDTH;
712 pwmcfg->callback = NULL;
713 pwmcfg->channels[mch].callback = NULL;
714 pwmcfg->channels[mch].mode = owp->config->pwmmode;
715 pwmcfg->channels[sch].callback = pwm_read_bit_cb;
716 pwmcfg->channels[sch].mode = PWM_OUTPUT_DISABLED;
717
718 ow_bus_active(owp);
719 osalSysLock();
720 pwmEnableChannelI(pwmd, mch, ONEWIRE_ONE_WIDTH);
721 pwmEnableChannelI(pwmd, sch, ONEWIRE_SAMPLE_WIDTH);
722 pwmEnableChannelNotificationI(pwmd, sch);
723 osalThreadSuspendS(&owp->thread);
724 osalSysUnlock();
725
726 ow_bus_idle(owp);
727}
728
729/**
730 * @brief Write some bytes to slave device.
731 *
732 * @param[in] owp pointer to the @p onewireDriver object
733 * @param[in] txbuf pointer to the buffer with data to be written
734 * @param[in] txbytes amount of data to be written
735 * @param[in] pullup_time how long strong pull up must be activated. Set
736 * it to 0 if not needed.
737 */
738void onewireWrite(onewireDriver *owp, uint8_t *txbuf,
739 size_t txbytes, systime_t pullup_time) {
740 PWMDriver *pwmd;
741 PWMConfig *pwmcfg;
742 size_t mch, sch;
743
744 osalDbgCheck((NULL != owp) && (NULL != txbuf));
745 osalDbgCheck((txbytes > 0) && (txbytes <= ONEWIRE_MAX_TRANSACTION_LEN));
746 osalDbgAssert(owp->reg.state == ONEWIRE_READY, "Invalid state");
747#if !ONEWIRE_USE_STRONG_PULLUP
748 osalDbgAssert(0 == pullup_time,
749 "Non zero time is valid only when strong pull enabled");
750#endif
751
752 pwmd = owp->config->pwmd;
753 pwmcfg = owp->config->pwmcfg;
754 mch = owp->config->master_channel;
755 sch = owp->config->sample_channel;
756
757 owp->buf = txbuf;
758 owp->reg.bit = 0;
759 owp->reg.final_timeslot = false;
760 owp->reg.bytes = txbytes;
761
762 pwmcfg->period = ONEWIRE_ZERO_WIDTH + ONEWIRE_RECOVERY_WIDTH;
763 pwmcfg->callback = pwm_write_bit_cb;
764 pwmcfg->channels[mch].callback = NULL;
765 pwmcfg->channels[mch].mode = owp->config->pwmmode;
766 pwmcfg->channels[sch].callback = NULL;
767 pwmcfg->channels[sch].mode = PWM_OUTPUT_DISABLED;
768
769#if ONEWIRE_USE_STRONG_PULLUP
770 if (pullup_time > 0) {
771 owp->reg.state = ONEWIRE_PULL_UP;
772 owp->reg.need_pullup = true;
773 }
774#endif
775
776 ow_bus_active(owp);
777 osalSysLock();
778 pwmEnablePeriodicNotificationI(pwmd);
779 osalThreadSuspendS(&owp->thread);
780 osalSysUnlock();
781
782 pwmDisablePeriodicNotification(pwmd);
783 ow_bus_idle(owp);
784
785#if ONEWIRE_USE_STRONG_PULLUP
786 if (pullup_time > 0) {
787 osalThreadSleep(pullup_time);
788 owp->config->pullup_release();
789 owp->reg.state = ONEWIRE_READY;
790 }
791#endif
792}
793
794#if ONEWIRE_USE_SEARCH_ROM
795/**
796 * @brief Performs tree search on bus.
797 * @note This function does internal 1-wire reset calls every search
798 * iteration.
799 *
800 * @param[in] owp pointer to a @p OWDriver object
801 * @param[out] result pointer to buffer for discovered ROMs
802 * @param[in] max_rom_cnt buffer size in ROMs count for overflow prevention
803 *
804 * @return Count of discovered ROMs. May be more than max_rom_cnt.
805 * @retval 0 no ROMs found or communication error occurred.
806 */
807size_t onewireSearchRom(onewireDriver *owp, uint8_t *result,
808 size_t max_rom_cnt) {
809 PWMDriver *pwmd;
810 PWMConfig *pwmcfg;
811 uint8_t cmd;
812 size_t mch, sch;
813
814 osalDbgCheck(NULL != owp);
815 osalDbgAssert(ONEWIRE_READY == owp->reg.state, "Invalid state");
816 osalDbgCheck((max_rom_cnt <= 256) && (max_rom_cnt > 0));
817
818 pwmd = owp->config->pwmd;
819 pwmcfg = owp->config->pwmcfg;
820 cmd = ONEWIRE_CMD_SEARCH_ROM;
821 mch = owp->config->master_channel;
822 sch = owp->config->sample_channel;
823
824 search_clean_start(&owp->search_rom);
825
826 do {
827 /* every search must be started from reset pulse */
828 if (false == onewireReset(owp))
829 return 0;
830
831 /* initialize buffer to store result */
832 if (owp->search_rom.reg.devices_found >= max_rom_cnt)
833 owp->search_rom.retbuf = result + 8*(max_rom_cnt-1);
834 else
835 owp->search_rom.retbuf = result + 8*owp->search_rom.reg.devices_found;
836 memset(owp->search_rom.retbuf, 0, 8);
837
838 /* clean iteration state */
839 search_clean_iteration(&owp->search_rom);
840
841 /**/
842 onewireWrite(&OWD1, &cmd, 1, 0);
843
844 /* Reconfiguration always needed because of previous call onewireWrite.*/
845 pwmcfg->period = ONEWIRE_ZERO_WIDTH + ONEWIRE_RECOVERY_WIDTH;
846 pwmcfg->callback = NULL;
847 pwmcfg->channels[mch].callback = NULL;
848 pwmcfg->channels[mch].mode = owp->config->pwmmode;
849 pwmcfg->channels[sch].callback = pwm_search_rom_cb;
850 pwmcfg->channels[sch].mode = PWM_OUTPUT_DISABLED;
851
852 ow_bus_active(owp);
853 osalSysLock();
854 pwmEnableChannelI(pwmd, mch, ONEWIRE_ONE_WIDTH);
855 pwmEnableChannelI(pwmd, sch, ONEWIRE_SAMPLE_WIDTH);
856 pwmEnableChannelNotificationI(pwmd, sch);
857 osalThreadSuspendS(&owp->thread);
858 osalSysUnlock();
859
860 ow_bus_idle(owp);
861
862 if (ONEWIRE_SEARCH_ROM_ERROR != owp->search_rom.reg.result) {
863 /* check CRC and return 0 (0 == error) if mismatch */
864 if (owp->search_rom.retbuf[7] != onewireCRC(owp->search_rom.retbuf, 7))
865 return 0;
866 /* store cached result for usage in next iteration */
867 memcpy(owp->search_rom.prev_path, owp->search_rom.retbuf, 8);
868 }
869 }
870 while (ONEWIRE_SEARCH_ROM_SUCCESS == owp->search_rom.reg.result);
871
872 /**/
873 if (ONEWIRE_SEARCH_ROM_ERROR == owp->search_rom.reg.result)
874 return 0;
875 else
876 return owp->search_rom.reg.devices_found;
877}
878#endif /* ONEWIRE_USE_SEARCH_ROM */
879
880/*
881 * Include test code (if enabled).
882 */
883#if ONEWIRE_SYNTH_SEARCH_TEST
884#include "synth_searchrom.c"
885#endif
886
887#endif /* HAL_USE_ONEWIRE */
888
889/** @} */