]> the.earth.li Git - temper-clone.git/blob - w1.c
Add initial 1-Wire support and use it for the USB serial #
[temper-clone.git] / w1.c
1 /*
2  * Basic routines to bit-bang standard 1-Wire via a GPIO pin
3  *
4  * Copyright 2018 Jonathan McDowell <noodles@earth.li>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <stdbool.h>
20 #include <avr/io.h>
21 #include <util/atomic.h>
22 #include <util/delay.h>
23
24 #include "w1.h"
25
26 uint8_t w1_crc(uint8_t *buf, uint8_t len)
27 {
28         uint8_t i, j, crc;
29
30         crc = 0;
31         for (i = 0; i < len; i++)
32         {
33                 crc ^= buf[i];
34                 for (j = 0; j < 8; j++)
35                 {
36                         crc = crc >> 1 ^ ((crc & 1) ? 0x8c : 0);
37                 }
38         }
39
40         return crc;
41 }
42
43 void w1_write(uint8_t val)
44 {
45         uint8_t i;
46
47         for (i = 0; i < 8; i++) {
48                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
49                 {
50                         /* Pull low for 6µs for 1, 60µs for 0 */
51                         DDRB |= 1 << W1_PIN;
52                         if (val & 1)
53                                 _delay_us(6);
54                         else
55                                 _delay_us(60);
56                         /* Release to make up to 70µs total */
57                         DDRB &= ~(1 << W1_PIN);
58                         if (val & 1)
59                                 _delay_us(64);
60                         else
61                                 _delay_us(10);
62                 }
63
64                 val >>= 1;
65         }
66 }
67
68 uint8_t w1_read_byte()
69 {
70         uint8_t i, val;
71
72         val = 0;
73         for (i = 0; i < 8; i++) {
74                 ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
75                 {
76                         /* Pull low for 6µs */
77                         DDRB |= 1 << W1_PIN;
78                         _delay_us(6);
79                         /* Release for 9µs */
80                         DDRB &= ~(1 << W1_PIN);
81                         _delay_us(9);
82
83                         /* Read the line state */
84                         val |= ((PINB >> W1_PIN) & 1) << i;
85                 }
86
87                 _delay_us(55);
88         }
89
90         return val;
91 }
92
93 void w1_read(uint8_t *buf, uint8_t len)
94 {
95         uint8_t i;
96
97         for (i = 0; i < len; i++) {
98                 buf[i] = w1_read_byte();
99         }
100 }
101
102 bool w1_reset(void)
103 {
104         bool present;
105
106         /* Pull low for 480µs */
107         DDRB |= 1 << W1_PIN;
108         _delay_us(480);
109         /* Release for 70µs */
110         DDRB &= ~(1 << W1_PIN);
111         _delay_us(70);
112
113         /* If there's a device present it'll have pulled the line low */
114         present = !((PINB >> W1_PIN) & 1);
115
116         /* Wait for reset to complete */
117         _delay_us(410);
118
119         return present;
120 }
121
122 void w1_setup(void)
123 {
124         /* Set 1w pin to low */
125         PORTB &= (1 << W1_PIN);
126 }