From: Jonathan McDowell Date: Thu, 3 May 2018 21:26:36 +0000 (+0100) Subject: Add initial 1-Wire support and use it for the USB serial # X-Git-Url: https://the.earth.li/gitweb/?p=temper-clone.git;a=commitdiff_plain;h=0949ba3935c9c2ec778adc94eb25cdd65e3cba4e Add initial 1-Wire support and use it for the USB serial # Introduce some basic bit-banging 1-Wire functions and use them to detect if there is a 1-Wire device present and if so use its ROM ID as the USB serial number. --- diff --git a/Makefile b/Makefile index 7f25592..2a0028f 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CFLAGS = -Iusbdrv -Ilibs-device -I. AVRCC = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o \ - libs-device/osccalASM.o main.o + libs-device/osccalASM.o main.o w1.o all: main.hex diff --git a/main.c b/main.c index fff2ae8..9899cb9 100644 --- a/main.c +++ b/main.c @@ -30,6 +30,8 @@ #include "usbdrv.h" #include "libs-device/osccal.h" +#include "w1.h" + typedef struct { uint8_t modifier; uint8_t reserved; @@ -190,6 +192,30 @@ PROGMEM const char usbDescriptorConfiguration[] = { USB_CFG_INTR_POLL_INTERVAL, /* in ms */ }; +inline char hexdigit(unsigned int i) +{ + return (i < 10) ? ('0' + i) : ('A' - 10 + i); +} + +/* Look for a 1-Wire device and use its ROMID to set the serial ID */ +void set_serial(void) +{ + uint8_t buf[8]; + uint8_t i; + + if (!w1_reset()) { + return; + } + + w1_write(0x33); /* READ ROM */ + w1_read(buf, 8); + + for (i = 0; i < 8; i++) { + serno_str[i * 2 + 1] = hexdigit(buf[i] >> 4); + serno_str[i * 2 + 2] = hexdigit(buf[i] & 0xF); + } +} + usbMsgLen_t usbFunctionDescriptor(usbRequest_t *rq) { if (rq->wValue.bytes[1] == USBDESCR_STRING && @@ -308,6 +334,9 @@ int main(void) wdt_enable(WDTO_1S); + w1_setup(); + set_serial(); + usbInit(); usbDeviceDisconnect(); diff --git a/w1.c b/w1.c new file mode 100644 index 0000000..8217602 --- /dev/null +++ b/w1.c @@ -0,0 +1,126 @@ +/* + * Basic routines to bit-bang standard 1-Wire via a GPIO pin + * + * Copyright 2018 Jonathan McDowell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include + +#include "w1.h" + +uint8_t w1_crc(uint8_t *buf, uint8_t len) +{ + uint8_t i, j, crc; + + crc = 0; + for (i = 0; i < len; i++) + { + crc ^= buf[i]; + for (j = 0; j < 8; j++) + { + crc = crc >> 1 ^ ((crc & 1) ? 0x8c : 0); + } + } + + return crc; +} + +void w1_write(uint8_t val) +{ + uint8_t i; + + for (i = 0; i < 8; i++) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + /* Pull low for 6µs for 1, 60µs for 0 */ + DDRB |= 1 << W1_PIN; + if (val & 1) + _delay_us(6); + else + _delay_us(60); + /* Release to make up to 70µs total */ + DDRB &= ~(1 << W1_PIN); + if (val & 1) + _delay_us(64); + else + _delay_us(10); + } + + val >>= 1; + } +} + +uint8_t w1_read_byte() +{ + uint8_t i, val; + + val = 0; + for (i = 0; i < 8; i++) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + /* Pull low for 6µs */ + DDRB |= 1 << W1_PIN; + _delay_us(6); + /* Release for 9µs */ + DDRB &= ~(1 << W1_PIN); + _delay_us(9); + + /* Read the line state */ + val |= ((PINB >> W1_PIN) & 1) << i; + } + + _delay_us(55); + } + + return val; +} + +void w1_read(uint8_t *buf, uint8_t len) +{ + uint8_t i; + + for (i = 0; i < len; i++) { + buf[i] = w1_read_byte(); + } +} + +bool w1_reset(void) +{ + bool present; + + /* Pull low for 480µs */ + DDRB |= 1 << W1_PIN; + _delay_us(480); + /* Release for 70µs */ + DDRB &= ~(1 << W1_PIN); + _delay_us(70); + + /* If there's a device present it'll have pulled the line low */ + present = !((PINB >> W1_PIN) & 1); + + /* Wait for reset to complete */ + _delay_us(410); + + return present; +} + +void w1_setup(void) +{ + /* Set 1w pin to low */ + PORTB &= (1 << W1_PIN); +} diff --git a/w1.h b/w1.h new file mode 100644 index 0000000..54c9f5b --- /dev/null +++ b/w1.h @@ -0,0 +1,13 @@ +#ifndef __W1_H__ +#define __W1_H__ + +#define W1_PIN 0 /* Pin 0 on Port B */ + +uint8_t w1_crc(uint8_t *buf, uint8_t len); +void w1_write(uint8_t val); +uint8_t w1_read_byte(); +void w1_read(uint8_t *buf, uint8_t len); +bool w1_reset(void); +void w1_setup(void); + +#endif /* __W1_H__ */