From 6b61bdbca74f12def23fc5f7099cc633aba420b3 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Thu, 10 May 2018 20:58:29 +0100 Subject: [PATCH] Poll temperature on a 10s basis Rather than polling the temperature sensor when the host requests it use a timer to poll every 10s and store the result. This means we can reply quicker when requests, reducing the number of errors we see on the host due to USB issues. Fixes interaction with the double request python-temperusb does for every check. --- Makefile | 2 +- main.c | 25 +++++++------ timer.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ timer.h | 8 +++++ 4 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 timer.c create mode 100644 timer.h diff --git a/Makefile b/Makefile index 2a0028f..db8e4a5 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 w1.o + libs-device/osccalASM.o main.o timer.o w1.o all: main.hex diff --git a/main.c b/main.c index 4e3d72c..ee6b1a1 100644 --- a/main.c +++ b/main.c @@ -30,6 +30,7 @@ #include "usbdrv.h" #include "libs-device/osccal.h" +#include "timer.h" #include "w1.h" typedef struct { @@ -40,6 +41,8 @@ typedef struct { keyboard_report_t keyboard_report; uint8_t temp_state = 0; +uint16_t last_temp = 0xFFFD; +#define TEMP_INTERVAL (10 * 1000) uint8_t temp_report[8]; bool have_temp_int = false; @@ -335,9 +338,11 @@ usbMsgLen_t usbFunctionWrite(uint8_t * data, uchar len) if (data[1] == 0x80 && data[2] == 0x33 && data[3] == 1) { /* Temperature query */ memset(temp_report, 0, 8); - temp_state = 1; + have_temp_int = true; temp_report[0] = 0x80; temp_report[1] = 2; + temp_report[2] = last_temp >> 8; + temp_report[3] = last_temp & 0xFF; } else if (data[1] == 0x82 && data[2] == 0x77 && data[3] == 1) { /* Initialisation Query #1 */ @@ -369,11 +374,13 @@ int main(void) { unsigned char i; uint8_t buf[9]; + unsigned long last_temp_time = 0; wdt_enable(WDTO_1S); w1_setup(); set_serial(); + timer_init(); usbDeviceDisconnect(); i = 0; @@ -413,9 +420,6 @@ int main(void) if (w1_reset()) { temp_state = 2; } else { - temp_report[2] = 0xFF; - temp_report[3] = 0xFF; - have_temp_int = true; temp_state = 0; } } else if (temp_state == 2) { @@ -431,9 +435,6 @@ int main(void) if (w1_reset()) { temp_state = 6; } else { - temp_report[2] = 0xFF; - temp_report[3] = 0xFE; - have_temp_int = true; temp_state = 0; } } else if (temp_state == 6) { @@ -446,10 +447,14 @@ int main(void) buf[temp_state - 8] = w1_read_byte(); temp_state++; } else if (temp_state == 17) { - temp_report[2] = buf[1] << 4 | buf[0] >> 4; - temp_report[3] = buf[0] << 4; - have_temp_int = true; + last_temp = buf[1] << 12 | buf[0] << 4; temp_state = 0; + last_temp_time = millis(); + } + + if (temp_state == 0 && + (millis() - last_temp_time) > TEMP_INTERVAL) { + temp_state = 1; } } } diff --git a/timer.c b/timer.c new file mode 100644 index 0000000..421d763 --- /dev/null +++ b/timer.c @@ -0,0 +1,106 @@ +/* + * Timer1 functions for ATTiny85 + * + * Heavily based on code from Ardunio: + * https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring.c + * + * Copyright (c) 2005-2006 David A. Mellis + * 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 + +#include + +#include "timer.h" + +#define clockCyclesPerMicrosecond() (F_CPU / 1000000L) +/* Prescaler of 64 from CPU_CLK */ +#define MICROSECONDS_PER_TIMER1_OVERFLOW (64 * 256 / clockCyclesPerMicrosecond()) +#define MILLIS_INC (MICROSECONDS_PER_TIMER1_OVERFLOW / 1000) +#define FRACT_INC ((MICROSECONDS_PER_TIMER1_OVERFLOW % 1000) >> 3) +#define FRACT_MAX (1000 >> 3) + +volatile unsigned long timer1_overflow_count = 0; +volatile unsigned long timer1_millis = 0; +static unsigned char timer1_fract = 0; + +void timer_init(void) +{ + /* + * bit 7: 0 (CTC1: Disabled CTC) + * bit 6/5: 00 (COM1A1/COM1A0: Disconnect counter from OC1A output) + * bit 3-0: 0111 (CS13/CS12/CS11/CS10: CPU_CK/64) + */ + TCCR1 = (1 << CS12) | (1 << CS11) | (1 << CS10); + + /* Initialise counter */ + TCNT1 = 0; + + /* Disable Timer 1 output compare match interrupt */ + TIMSK &= ~(OCIE1A | OCIE1B); + /* Enable Timer 1 overflow interrupt */ + TIMSK |= _BV(TOIE1); +} + +unsigned long micros(void) +{ + unsigned long m; + uint8_t oldSREG = SREG, t; + + cli(); + m = timer1_overflow_count; + t = TCNT1; + + if ((TIFR & _BV(TOV1)) & (t < 255)) + m++; + + SREG = oldSREG; + + return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); +} + +unsigned long millis(void) +{ + unsigned long m; + uint8_t oldSREG = SREG; + + cli(); + m = timer1_millis; + SREG = oldSREG; + + return m; +} + +SIGNAL(TIMER1_OVF_vect) +{ + unsigned long m = timer1_millis; + unsigned char f = timer1_fract; + + m += MILLIS_INC; + f += FRACT_INC; + if (f >= FRACT_MAX) { + f -= FRACT_MAX; + m++; + } + + timer1_fract = f; + timer1_millis = m; + timer1_overflow_count++; +} diff --git a/timer.h b/timer.h new file mode 100644 index 0000000..65647f5 --- /dev/null +++ b/timer.h @@ -0,0 +1,8 @@ +#ifndef __TIMER_H_ +#define __TIMER_H_ + +void timer_init(void); +unsigned long micros(void); +unsigned long millis(void); + +#endif /* __TIMER_H_ */ -- 2.39.2