Contiki 3.x
onewire.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Eistec AB.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * This file is part of the Mulle platform port of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * 1-wire driver using hardware UART as a bus master.
36  *
37  * \author
38  * Joakim Gebart <joakim.gebart@eistec.se>
39  *
40  * \note
41  * This is heavily based on Maxim document TUTORIAL 214
42  * "Using a UART to Implement a 1-Wire Bus Master"
43  *
44  * \note Nothing in this driver is thread safe, make sure to call all ow_*
45  * functions from a single thread or things will break.
46  *
47  * \todo Use FIFO if UART supports it (UART0, UART1).
48  * \todo Low power wait/stop during sends in 1-wire driver.
49  */
50 
51 #include "onewire.h"
52 #include "onewire-crc-table.h"
53 #include "interrupt.h"
54 #include "K60.h"
55 #include "uart.h"
56 #include "config-clocks.h"
57 #include <stdio.h>
58 #include <stdint.h>
59 
60 #define ONEWIRE_UART_NUM 4
61 #define ONEWIRE_UART UART[ONEWIRE_UART_NUM]
62 #define ONEWIRE_ISR_FUNC _isr_uart4_status
63 #define ONEWIRE_IRQn UART4_RX_TX_IRQn
64 #define ONEWIRE_UART_MODULE_FREQUENCY F_BUS
65 #define ONEWIRE_RXPIN_PCR PORTE->PCR[25]
66 #define ONEWIRE_TXPIN_PCR PORTE->PCR[24]
67 
68 /* TX pin port clock gate mask */
69 #define ONEWIRE_TXPIN_PORT_CG SIM_SCGC5_PORTE_MASK
70 /* RX pin port clock gate mask */
71 #define ONEWIRE_RXPIN_PORT_CG SIM_SCGC5_PORTE_MASK
72 
73 /* Data bytes used in the UART to generate the correct 1-wire waveforms. */
74 #define ONEWIRE_D_RESET (0xF0)
75 #define ONEWIRE_D_READ (0xFF)
76 #define ONEWIRE_D_WRITE_0 (0x00)
77 #define ONEWIRE_D_WRITE_1 (0xFF)
78 
79 /* Length in bytes of the 1-wire ROM code */
80 #define OW_ROM_ID_LENGTH (8)
81 
82 static volatile const uint8_t *ow_write_bytes_buf;
83 static volatile uint8_t ow_write_bytes_count;
84 static volatile uint8_t *ow_read_bytes_buf;
85 static volatile uint8_t ow_read_bytes_count;
86 static volatile uint8_t ow_write_bits;
87 static volatile uint8_t ow_read_bits;
88 static volatile uint8_t ow_isr_scratch;
89 
90 #define OW_TIMING_FAST() \
91  ONEWIRE_UART->BDH = UART_BDH_SBR(UART_SBR(ONEWIRE_UART_MODULE_FREQUENCY, ONEWIRE_UART_BAUD_FAST) / 256); \
92  ONEWIRE_UART->BDL = UART_BDL_SBR(UART_SBR(ONEWIRE_UART_MODULE_FREQUENCY, ONEWIRE_UART_BAUD_FAST) % 256); \
93  ONEWIRE_UART->C4 = UART_C4_BRFA(UART_BRFA(ONEWIRE_UART_MODULE_FREQUENCY, ONEWIRE_UART_BAUD_FAST))
94 
95 #define OW_TIMING_SLOW() \
96  ONEWIRE_UART->BDH = UART_BDH_SBR(UART_SBR(ONEWIRE_UART_MODULE_FREQUENCY, ONEWIRE_UART_BAUD_SLOW) / 256); \
97  ONEWIRE_UART->BDL = UART_BDL_SBR(UART_SBR(ONEWIRE_UART_MODULE_FREQUENCY, ONEWIRE_UART_BAUD_SLOW) % 256); \
98  ONEWIRE_UART->C4 = UART_C4_BRFA(UART_BRFA(ONEWIRE_UART_MODULE_FREQUENCY, ONEWIRE_UART_BAUD_SLOW))
99 
100 #define OW_WAIT_WRITE() \
101  /* Wait until the 1-wire bus is idle */ \
102  while(ow_write_bytes_count > 0 || ow_read_bytes_count > 0 || ow_write_bits > 0 || ow_read_bits > 0)
103 
104 #define OW_WAIT_READ() \
105  /* Wait until there are no reads queued */ \
106  while(ow_read_bytes_count > 0 || ow_read_bits > 0 /*|| ow_write_bytes_count > 0 || ow_write_bits > 0*/)
107 
108 #define OW_BUSY_WAIT() \
109  /* Wait until the last bit of the previous transmission has been transferred */ \
110  while(ow_write_bytes_count > 0 || ow_read_bytes_count > 0 || ow_write_bits > 0 || ow_read_bits > 0 || !(ONEWIRE_UART->S1 & UART_S1_TC_MASK) || (ONEWIRE_UART->S2 & UART_S2_RAF_MASK))
111 
112 /**
113  * Used by the ISR handler to queue the next byte for transmission on the bus.
114  */
115 void
117 {
118  static volatile uint8_t dummy;
119  /* Shut up GCC warnings about set but not used variable [-Wunused-but-set-variable] */
120  (void)dummy;
121  if(ow_write_bytes_count > 0) {
122  /* Queue next byte */
123  OW_TIMING_FAST();
124  /* Enable transmitter */
125  ONEWIRE_UART->C2 |= UART_C2_TE_MASK;
126  /* Disable receiver */
127  ONEWIRE_UART->C2 &= ~UART_C2_RE_MASK;
128  ow_isr_scratch = (*ow_write_bytes_buf);
129  ow_write_bits = 8;
130  /* Move source buffer location forward */
131  --ow_write_bytes_count;
132  ++ow_write_bytes_buf;
133  /* Disable RX interrupts */
134  ONEWIRE_UART->C2 &= ~(UART_C2_RIE_MASK);
135  /* Enable TX interrupts */
136  ONEWIRE_UART->C2 |= UART_C2_TCIE_MASK;
137  } else if(ow_read_bytes_count > 0) {
138  /* Set up reading */
139  OW_TIMING_FAST();
140  /* Enable transmitter and receiver */
141  ONEWIRE_UART->C2 |= UART_C2_TE_MASK | UART_C2_RE_MASK;
142  ow_read_bits = 8;
143  --ow_read_bytes_count;
144  ow_isr_scratch = 0x00;
145 
146  /* Dummy read to clear out any crap left in the data buffer */
147  dummy = ONEWIRE_UART->D;
148  /* Flush the RX buffer before we begin */
149  ONEWIRE_UART->CFIFO |= UART_CFIFO_RXFLUSH_MASK;
150 
151  /* Disable TX interrupts */
152  ONEWIRE_UART->C2 &= ~(UART_C2_TIE_MASK | UART_C2_TCIE_MASK);
153  /* Trigger a read slot */
154  ONEWIRE_UART->D = ONEWIRE_D_READ;
155  /* Enable RX interrupts */
156  ONEWIRE_UART->C2 |= UART_C2_RIE_MASK;
157  } else {
158  /* All done! */
159  /* disable interrupts */
160  ONEWIRE_UART->C2 &= ~(UART_C2_TIE_MASK | UART_C2_TCIE_MASK | UART_C2_RIE_MASK);
161  /* Disable transmitter and receiver */
162  ONEWIRE_UART->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK);
163 
164  /** \todo Trigger an event after reading 1-wire stuff */
165  }
166 }
167 /**
168  * This ISR handles most of the business interacting with the 1-wire bus.
169  *
170  * \note The implementation depends on the fact that no writes are queued before
171  * any preceding reads have completed.
172  */
173 
174 void __attribute__((interrupt))
175 ONEWIRE_ISR_FUNC(void)
176 {
177  static volatile uint8_t data;
178  static volatile uint8_t status;
179  status = ONEWIRE_UART->S1;
180 
181  if(ow_write_bits > 0) {
182  if(status & (UART_S1_TDRE_MASK | UART_S1_TC_MASK)) {
183  ONEWIRE_UART->D = ((ow_isr_scratch & 0x01) ? ONEWIRE_D_WRITE_1 : ONEWIRE_D_WRITE_0);
184  ow_isr_scratch >>= 1;
185  --ow_write_bits;
186  }
187  } else if(ow_read_bits > 0) {
188  /* Check if we got something yet */
189  /* We can end up here without anything received when being called from a TX
190  * interrupt in the transition from a 1-wire write to a 1-wire read */
191  if(ONEWIRE_UART->RCFIFO > 0 || (status & UART_S1_RDRF_MASK)) {
192  --ow_read_bits;
193  ow_isr_scratch >>= 1;
194  data = ONEWIRE_UART->D;
195  if(data == ONEWIRE_D_READ) {
196  /* We read a 1 */
197  ow_isr_scratch |= (1 << 7);
198  }
199 
200  if(ow_read_bits == 0) {
201  /* Place output in destination buffer */
202  (*ow_read_bytes_buf) = ow_isr_scratch;
203  ++ow_read_bytes_buf;
205  } else {
206  /* Trigger next read slot */
207  ONEWIRE_UART->D = ONEWIRE_D_READ;
208  }
209  }
210  } else {
212  }
213 }
214 /**
215  * Initialize the 1-wire driver.
216  *
217  * This will set up the clocks, interrupts and I/O pins.
218  */
219 void
220 ow_init(void)
221 {
222 
223  /* initialize counters */
224  ow_read_bytes_buf = 0;
225  ow_read_bytes_count = 0;
226  ow_write_bytes_buf = 0;
227  ow_write_bytes_count = 0;
228  ow_isr_scratch = 0x00;
229  ow_write_bits = 0;
230  ow_read_bits = 0;
231 
232  /* Enable clock gate on I/O pins */
233  SIM->SCGC5 |= ONEWIRE_TXPIN_PORT_CG | ONEWIRE_RXPIN_PORT_CG;
234  /* Choose UART in pin mux */
235  ONEWIRE_RXPIN_PCR = PORT_PCR_MUX(3);
236 
237  /* Use open drain on UART TX pin */
238  /* The built in pull-up in the I/O pin is too weak (20k-50k Ohm) on TX pin,
239  * you should add an external pull up of circa 5k Ohm. */
240  ONEWIRE_TXPIN_PCR = PORT_PCR_MUX(3) | PORT_PCR_ODE_MASK;
241 
242  /* Enable clock gate on UART module */
243  uart_module_enable(ONEWIRE_UART_NUM);
244 
245  /* Make sure MSBF bit is not set */
246  ONEWIRE_UART->S2 = 0;
247 
248  /* Disable transmitter and receiver */
249  ONEWIRE_UART->C2 = 0;
250 
251  /* Set up UART for two wire operation. */
252  /* The reason we are not using single wire mode (LOOPS=1, RSRC=1) is that
253  * because of limitations in the MCU, we are reduced to half duplex and can
254  * not see when the slave is pulling the line low after we release it */
255  ONEWIRE_UART->C1 = 0;
256 
257  /* Disable FIFO (set buffer depth to 1) */
258  ONEWIRE_UART->PFIFO = 0;
259 
260  /* Set up interrupt controller */
261  NVIC_EnableIRQ(ONEWIRE_IRQn);
262 }
263 /**
264  * Reset the 1-wire bus.
265  *
266  * A reset is always the first step in communicating with the bus slaves.
267  */
268 void
269 ow_reset(void)
270 {
271  uint8_t dummy;
272  /* Shut up GCC warnings about set but not used variable [-Wunused-but-set-variable] */
273  (void)dummy;
274 
275  OW_BUSY_WAIT();
276 
277  MK60_ENTER_CRITICAL_REGION();
278 
279  /*
280  * The reset pulse must be a long zero, switch to slow timing to allow the reset
281  * byte to stretch on for long enough.
282  * ISR will switch back to fast timing when sending other stuff.
283  */
284  OW_TIMING_SLOW();
285  /* Enable transmitter */
286  ONEWIRE_UART->C2 |= UART_C2_TE_MASK;
287  /* Disable receiver */
288  ONEWIRE_UART->C2 &= ~UART_C2_RE_MASK;
289 
290  /* Read whatever crap was left in the data buffer */
291  dummy = ONEWIRE_UART->D;
292  /* Flush the RX buffer before we begin */
293  ONEWIRE_UART->CFIFO |= UART_CFIFO_RXFLUSH_MASK;
294  /* Send a reset pulse */
295  ONEWIRE_UART->D = ONEWIRE_D_RESET;
296  MK60_LEAVE_CRITICAL_REGION();
297 
298  /* Wait until the byte has been transferred to the shift register */
299  while(!(ONEWIRE_UART->S1 & UART_S1_TC_MASK));
300 
301  /*
302  * Queue up an IDLE character (all 1's, no start bit or stop bit) by disabling
303  * the transmitter and then reenabling it in order to let the reset pulse
304  * finish before we switch baud rates.
305  */
306 
307  ONEWIRE_UART->C2 &= ~(UART_C2_TE_MASK);
308 
309  ONEWIRE_UART->C2 |= UART_C2_TE_MASK;
310 
311  /* Wait until the byte has been transferred to the shift register */
312  while(!(ONEWIRE_UART->S1 & UART_S1_TC_MASK));
313 
314  /* We don't check for presence pulses */
315 }
316 /**
317  * Write a sequence of bytes to the 1-wire bus.
318  *
319  * The transmission to the 1-wire bus is asynchronous, which means this function
320  * will return before all bits have gone out the wire.
321  *
322  * \note As src is not copied to a local buffer and the transmission is
323  * asynchronous, be careful when using stack-allocated buffers for src.
324  *
325  * \param src the source buffer.
326  * \param count number of bytes to write to the bus.
327  */
328 void
329 ow_write_bytes(const uint8_t *src, const uint8_t count)
330 {
331  OW_WAIT_WRITE();
332 
333  /* Place the byte in the tx buffer */
334  MK60_ENTER_CRITICAL_REGION();
335  ow_write_bytes_count = count;
336  ow_write_bytes_buf = src;
337  MK60_LEAVE_CRITICAL_REGION();
338 
339  /* Enable TX interrupts, all bits will be pushed by the ISR */
340  ONEWIRE_UART->C2 |= (UART_C2_TCIE_MASK);
341 }
342 /**
343  * Shorthand function to write a single byte to the 1-wire bus.
344  *
345  * \param data the data byte to write.
346  */
347 void
348 ow_write_byte(const uint8_t data)
349 {
350  static uint8_t buf;
351  buf = data;
352  ow_write_bytes(&buf, 1);
353 }
354 /**
355  * Read a sequence of bytes from the 1-wire bus.
356  *
357  * Contrary to the ow_write_bytes function, this function is synchronous and
358  * will do a busy wait until all bits have been read. This is not really
359  * desirable but is so only because of laziness and lack of time.
360  *
361  * \param dest the destination buffer.
362  * \param count number of bytes to read from the bus.
363  */
364 void
365 ow_read_bytes(uint8_t *dest, const uint8_t count)
366 {
367  OW_WAIT_READ();
368 
369  /* Compute where the received byte will be at */
370  MK60_ENTER_CRITICAL_REGION();
371  ow_read_bytes_count = count;
372  ow_read_bytes_buf = dest;
373  MK60_LEAVE_CRITICAL_REGION();
374 
375  /* Enable TX interrupts, all bits will be pushed by the ISR */
376  ONEWIRE_UART->C2 |= (UART_C2_TCIE_MASK);
377 
378  /** \todo sleep while waiting for rx bits on 1-wire bus. */
379  while(ow_read_bits > 0 || ow_read_bytes_count > 0);
380 }
381 /**
382  * Compute a 1-wire 8-bit CRC.
383  *
384  * This function uses a lookup table method of computing the CRC one byte at a
385  * time, instead of bit per bit. The table is found in ow_crc_table in
386  * onewire-crc-table.h.
387  *
388  * The polynomial used by the 1-wire bus is x^8 + x^5 + x^4 + x^0, or 0x31.
389  * But take care when computing the CRC (or producing a lookup table) that the
390  * CRC is computed LSB first and using the reversed polynomial 0x8C instead.
391  *
392  * \note Because of the mathematics of the CRC, if passed a message where the
393  * last byte is the CRC, the return value will be 0 if the CRC is correct
394  * for the message.
395  *
396  * \param data The message.
397  * \param count Number of bytes in the message.
398  * \return The CRC
399  */
400 uint8_t
401 ow_compute_crc(const uint8_t *data, const uint8_t count)
402 {
403  uint8_t i;
404  uint8_t crc = 0;
405  uint8_t index;
406  for(i = 0; i < count; ++i) {
407  index = data[i] ^ crc;
408  crc = ow_crc_table[index];
409  }
410 
411  return crc;
412 }
413 /**
414  * Issue a 1-wire READ ROM command
415  *
416  * The value will be returned in the order it arrives on the bus, i.e. 8 bit
417  * family code first, then 48 bit serial number, last 8 bit CRC.
418  *
419  * On a little endian machine this will be the exact same representation as in
420  * the 1-wire data sheets, LSB first.
421  *
422  * \note Use ow_compute_crc(rom_code, 8) to verify the ROM code, return value
423  * should be 0x00.
424  *
425  * \return 64 bit ROM CODE from the bus, including CRC.
426  */
427 ow_rom_code_t
429 {
430  uint16_t buf;
431  uint8_t rom[ONEWIRE_ROM_CODE_LENGTH];
432  uint8_t i;
433  ow_rom_code_t rom_code;
434  static const ow_rom_cmd_t cmd = ONEWIRE_CMD_READ_ROM;
435  printf("READ ROM: ");
436  ow_reset();
437  ow_write_bytes((const uint8_t *)(&cmd), 1);
438  ow_read_bytes(rom, ONEWIRE_ROM_CODE_LENGTH);
439  /* Little endian */
440  rom_code = *((uint64_t *)rom);
441  /* For non-Little endian machines */
442  /*rom_code = (((ow_rom_code_t)rom[0]) |
443  (((ow_rom_code_t)rom[1]) << 8) |
444  (((ow_rom_code_t)rom[2]) << 16) |
445  (((ow_rom_code_t)rom[3]) << 24) |
446  (((ow_rom_code_t)rom[4]) << 32) |
447  (((ow_rom_code_t)rom[5]) << 40) |
448  (((ow_rom_code_t)rom[6]) << 48) |
449  (((ow_rom_code_t)rom[7]) << 56));
450  */
451 
452  for(i = 0; i < sizeof(rom) / 2; ++i) {
453  buf = (rom[2 * i] << 8) | (rom[2 * i + 1]);
454  printf("%x", buf);
455  }
456  printf("\n");
457  printf("CRC: 0x%x\n", ow_compute_crc(rom, ONEWIRE_ROM_CODE_LENGTH));
458  return rom_code;
459 }
460 /**
461  * Issue a 1-wire SKIP ROM command.
462  *
463  * The SKIP ROM command is used to issue commands to all devices on the bus.
464  */
465 void
467 {
468  static const ow_rom_cmd_t cmd = ONEWIRE_CMD_SKIP_ROM;
469  printf("SKIP ROM\n");
470  ow_reset();
471  ow_write_bytes((const uint8_t *)(&cmd), 1);
472 }
473 /**
474  * Issue a 1-wire MATCH ROM command.
475  *
476  * The MATCH ROM command is used to single out a specific device using its ROM
477  * code as identifier.
478  *
479  * \param id The ROM code of the selected device.
480  */
481 void
482 ow_match_rom(const ow_rom_code_t id)
483 {
484  static ow_rom_code_t rom_code;
485  static const ow_rom_cmd_t cmd = ONEWIRE_CMD_MATCH_ROM;
486  printf("MATCH ROM\n");
487  ow_reset();
488  ow_write_bytes((const uint8_t *)(&cmd), 1);
489  /* Copy from stack to a static variable to avoid messing up the buffer when
490  * returning from this function before all bytes have gone out on the wire. */
491  rom_code = id;
492  ow_write_bytes((const uint8_t *)(&rom_code), ONEWIRE_ROM_CODE_LENGTH);
493 }
494 /**
495  * Shorthand function for MATCH ROM or SKIP ROM if id is zero.
496  *
497  * \param id The ROM code of the selected device, or 0 for all devices.
498  */
499 void
500 ow_skip_or_match_rom(const ow_rom_code_t id)
501 {
502 #if ONEWIRE_ALWAYS_SKIP_ROM
503  ow_skip_rom();
504 #else
505  if(id == 0) {
506  /* SKIP ROM */
507  ow_skip_rom();
508  } else {
509  /* MATCH ROM */
510  ow_match_rom(id);
511  }
512 #endif /* ONEWIRE_ALWAYS_SKIP_ROM */
513 }
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
Enable External Interrupt.
Definition: core_cm0.h:535
K60 clock configuration defines.
void ow_init(void)
Initialize the 1-wire driver.
Definition: onewire.c:220
One wire CRC lookup table.
void ow_match_rom(const ow_rom_code_t id)
Issue a 1-wire MATCH ROM command.
Definition: onewire.c:482
void __attribute__((interrupt))
This ISR handles most of the business interacting with the 1-wire bus.
Definition: onewire.c:174
#define SIM
Peripheral SIM base pointer.
Definition: MK60D10.h:7650
void uart_module_enable(const unsigned int uart_num)
Enable the clock gate to an UART module.
Definition: uart.c:115
void ow_skip_or_match_rom(const ow_rom_code_t id)
Shorthand function for MATCH ROM or SKIP ROM if id is zero.
Definition: onewire.c:500
K60 hardware register header wrapper.
One wire driver using hardware UART as a bus master.
void ow_read_bytes(uint8_t *dest, const uint8_t count)
Read a sequence of bytes from the 1-wire bus.
Definition: onewire.c:365
void ow_reset(void)
Reset the 1-wire bus.
Definition: onewire.c:269
void ow_begin_next_byte(void)
Used by the ISR handler to queue the next byte for transmission on the bus.
Definition: onewire.c:116
void ow_write_byte(const uint8_t data)
Shorthand function to write a single byte to the 1-wire bus.
Definition: onewire.c:348
void ow_skip_rom(void)
Issue a 1-wire SKIP ROM command.
Definition: onewire.c:466
Provide common UART routines for MK60DZ10.
K60 interrupt save/restore macros.
ow_rom_code_t ow_read_rom(void)
Issue a 1-wire READ ROM command.
Definition: onewire.c:428
void ow_write_bytes(const uint8_t *src, const uint8_t count)
Write a sequence of bytes to the 1-wire bus.
Definition: onewire.c:329
uint8_t ow_compute_crc(const uint8_t *data, const uint8_t count)
Compute a 1-wire 8-bit CRC.
Definition: onewire.c:401