printid and get_temp implementation
[cortex-from-scratch] / drivers / tsensor.c
1 /* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
2  * 
3  * $LOG$
4  * 2019/8/28 - ROBIN KRENS      
5  * Initial version 
6  * 
7  * $DESCRIPTION$
8  * DS18B20 temperature sensor implementation
9  * Uses the 1-wire protocol. You will need to setup the temperature sensor
10  * with an external pull up resistor. High is the idle state of the chip.  
11  * This implementation does not use parasite power. Uses busy waits. 
12  * The chip doesn't require too accurate timings. Busy waits are between 15
13  * and 240 microseconds.
14  *
15  * The temperature conversion on the chip it takes a lot longer (up to 700ms).
16  * In case temperature is often read, implementing this with interrupts might be
17  * worthwile.
18  *
19  * Each series of commands is initiated with a long reset and prescence pulse.
20  * Implemented:
21  *      - Read ID of Chip
22  *      - Convert and read temperature
23  *
24  * TODO:
25  *      - Scratchpad copy functionality (+EEPROM)
26  *      - Alarm functionality
27  *
28  * */
29
30 #include <stdbool.h>
31 #include <stddef.h>
32 #include <stdint.h>
33
34 #include <sys/mmap.h>
35 #include <sys/robsys.h>
36
37 #include <lib/regfunc.h>
38 #include <lib/string.h>
39 #include <lib/tinyprintf.h>
40
41 #include <drivers/tsensor.h>
42
43 /* Commands */
44 #define READ_ROM        0x33
45 #define SKIP_ROM        0xCC
46 #define READ_SCRATCH    0xBE
47 #define CONVERT_T       0x44
48
49 /* Basic GPIO settings for output pulses and input */
50 static void in_conf() {
51         rwrite(GPIOB_CRL, 0x44444444);
52 }
53
54 static void out_conf() {
55         rwrite(GPIOB_CRL, 0x46444444); // open drain (with external pullup resistor)
56 }
57
58 /* Send command cmd over data wire. Each write slot should be
59  * at least 60ms.   */
60 static void send_cmd(unsigned char cmd) {
61
62         int pos = 0;
63
64         for (int i = 0; i < 8; i++) {
65                 // initiate write slot
66                 out_conf();
67                 rclrbit(GPIOB_ODR, 6); // pull low
68
69                 // writing a logical 1 or 0 
70                 if ((cmd >> pos) & 0x01) {
71                         _block(5);
72                         in_conf();
73                         _block(60);
74                 }
75                 else {
76                         _block(60);
77                         in_conf();
78                 }
79                 pos++;
80         }
81 }
82
83 /* Read reply of sensor. Depending on the command, the sensor
84  * can send back up to 9 bytes */
85 static char get_byte() {
86
87         char c = 0x00;
88
89         for (int i = 0; i < 8; i++) {
90                 /* Initate write slot*/
91                 out_conf();
92                 rclrbit(GPIOB_ODR, 6);
93                 _block(3);
94                 /* Listen for reply */
95                 in_conf();
96                 if (rchkbit(GPIOB_IDR,6)) {
97                         c = c | (0x1 << i);
98                 }
99                 else {
100                         c = c | (0x0 << i);
101                 }
102                 /* Each read slot should be at least 60 microseconds
103                  * before the next one is initiated */
104                 _block(60);
105         }
106         return c;
107 }
108
109
110 /* Initiate the sensor, send a reset pulse and wait consequently for 
111  * presence pulse. Slots should be at least 450 and 240 microseconds.  
112  * */
113 static int tsensor_init() {
114
115         rsetbit(RCC_APB2ENR, 3); // GPIOB enable
116         
117         /* send presence pulse */
118         out_conf();     
119         rclrbit(GPIOB_ODR, 6); // pull low
120         _block(450);    
121         /* wait for the chips reply */
122         in_conf();
123         _block(60);
124         if (!rchkbit(GPIOB_IDR, 6)) {
125                 //printf("Info: sensor detected\n");
126                 //get_id();
127         }
128         else {
129                 printf("Error: no temperature sensor found!");
130                 return -1;
131         }
132         _block(240); // finish intialization slot
133         
134         return 0;
135
136
137
138
139
140
141 /* Wait for the chip to convert the temperature */
142 static void wait_tconvert() {
143
144         printf("Info: Converting temp\n");
145         /* initiate write slot */
146         out_conf();
147         rclrbit(GPIOB_ODR, 6);
148         _block(3);
149         in_conf();
150         while (!rchkbit(GPIOB_IDR, 6)) {
151                 //printf(".");
152                 _block(60);
153                 out_conf();
154                 rclrbit(GPIOB_ODR, 6);
155                 _block(3);
156                 in_conf();
157         }
158 }
159
160 /* Print some serial and CRC information about the chip */
161 void tsensor_printid() {
162
163         tsensor_init();
164         send_cmd(READ_ROM);
165
166         // replies with 8 bytes
167         int nbytes = 8;
168
169         char scratchbuf[nbytes];
170         memset(&scratchbuf, 0, sizeof(char) * nbytes);
171         scratchbuf[nbytes+1] = '\n';
172         
173         for (int i = 0; i < nbytes; i++) {
174                 scratchbuf[i] = get_byte();
175         }
176
177         
178         printf("Family Code: %#x\n", scratchbuf[0]);
179         printf("Serial Number: 0x");
180         for (int i = 1; i < 7; i++) {
181                 printf("%x", scratchbuf[i]);
182         }
183         printf("\n");
184         printf("CRC Code: %#x\n", scratchbuf[7]);
185
186 }
187
188 /* Convert and read temperature of chip. Sensor has to be initialized twice
189  * since there are two series of commands (see datasheet flowchart) */
190 uint16_t tsensor_get_temp() {
191
192         /* initialize sensor and send commands */
193         tsensor_init();
194         send_cmd(SKIP_ROM);
195         send_cmd(CONVERT_T);
196         wait_tconvert();
197
198         tsensor_init();
199         send_cmd(SKIP_ROM);
200         send_cmd(READ_SCRATCH);
201
202         /* Scratchpad is 9 bytes, but we are only interested in 
203          * the first two bytes, since they contain the LSB and 
204          * MSB of temperature  */
205         int nbytes = 2;
206
207         char scratchbuf[nbytes];
208         memset(&scratchbuf, 0, sizeof(char) * nbytes);
209         scratchbuf[nbytes+1] = '\n';
210         
211         for (int i = 0; i < nbytes; i++) {
212                 scratchbuf[i] = get_byte();
213         }
214
215         // LSB first four bits are after floating point
216         // uint8_t lsb_afltp = scratchbuf[0] & 0xF;
217         
218         int8_t lsb_bfltp = (scratchbuf[0] >> 4) & 0xF;
219         // MSB only the first three bits are used
220         uint8_t msb = scratchbuf[1] & 0x7;
221         
222         return  (msb << 4) + lsb_bfltp;
223         
224 }
225
226 /* 
227 void test() {
228
229         //get_id();
230         uint16_t temp = get_temp();
231         printf("Current temperature: %d\n", temp);
232
233 } */