Skip to content

Commit 5a8bd60

Browse files
committed
Check processor frequency, change if possible to the right value, go into failure mode if not possible signalling SOS. Provide reading the fuse values over I2C.
1 parent 1e74262 commit 5a8bd60

3 files changed

Lines changed: 79 additions & 15 deletions

File tree

firmware/ATTinyDaemon/ATTinyDaemon.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <EEPROM.h>
44
#include <limits.h>
55
#include <avr/io.h>
6+
#include <avr/boot.h>
7+
#include <avr/power.h>
68
#include <avr/sleep.h>
79
#include <avr/wdt.h>
810

@@ -118,8 +120,12 @@
118120
#define REGISTER_RESET_CONFIG 0x51
119121
#define REGISTER_RESET_PULSE_LENGTH 0x52
120122
#define REGISTER_SW_RECOVERY_DELAY 0x53
123+
#define REGISTER_FUSE_LOW 0x81
124+
#define REGISTER_FUSE_HIGH 0x82
125+
#define REGISTER_FUSE_EXTENDED 0x83
121126

122127
#define REGISTER_VERSION 0x80
128+
123129
#define REGISTER_INIT_EEPROM 0xFF
124130

125131
/*

firmware/ATTinyDaemon/ATTinyDaemon.ino

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
Our version number - used by the daemon to ensure that the major number is equal between firmware and daemon
1111
*/
1212
#define MAJOR 2L
13-
#define MINOR 4L
14-
#define PATCH 2L
13+
#define MINOR 6L
14+
#define PATCH 3L
1515

1616
const uint32_t prog_version = (MAJOR << 16) | (MINOR << 8) | PATCH;
1717

@@ -36,6 +36,15 @@ uint8_t state = UNCLEAR_STATE;
3636
*/
3737
uint8_t register_number;
3838

39+
/*
40+
These variables hold the fuse settings. If we try to read the fuse settings over I2C without
41+
this buffering then we very often get timeouts. So, until we are in dire need of memory we
42+
simply copy the fuse settings to RAM.
43+
*/
44+
uint8_t fuse_low;
45+
uint8_t fuse_high;
46+
uint8_t fuse_extended;
47+
3948
/*
4049
These are the 8 bit registers (the register numbers are defined in ATTinyDaemon.h)
4150
Important: The value 0xFF is no valid value and will be filtered on the RPi side
@@ -69,6 +78,8 @@ uint16_t sw_recovery_delay = 1000; // the pause needed between two reset puls
6978
void setup() {
7079
reset_watchdog (); // do this first in case WDT fires
7180

81+
check_fuses(); // verify that we can run with the fuse settings
82+
7283
/*
7384
If we got a reset while pulling down the switch, this might lead to short
7485
spike on switch pin. Shouldn't be a problem because we can stop the RPi
@@ -131,12 +142,7 @@ void loop() {
131142
if (state < SHUTDOWN_STATE) {
132143
if (should_shutdown > SL_INITIATED && (seconds < timeout)) {
133144
// RPi should take action, possibly shut down. Signal by blinking 5 times
134-
for (int i = 0; i < 5; i++) {
135-
delay(BLINK_TIME);
136-
ledOff_buttonOn();
137-
delay(BLINK_TIME);
138-
ledOn_buttonOff();
139-
}
145+
blink_led(5, BLINK_TIME);
140146
}
141147
}
142148

@@ -171,12 +177,7 @@ void loop() {
171177
if (seconds > timeout) {
172178
// RPi has not accessed the I2C interface for more than timeout seconds.
173179
// We restart it. Signal restart by blinking ten times
174-
for (int i = 0; i < 10; i++) {
175-
ledOn_buttonOff();
176-
delay(BLINK_TIME / 2);
177-
ledOff_buttonOn();
178-
delay(BLINK_TIME / 2);
179-
}
180+
blink_led(10, BLINK_TIME / 2);
180181
restart_raspberry();
181182
reset_counter();
182183
}
@@ -195,7 +196,7 @@ void loop() {
195196
reset_watchdog();
196197
sleep_enable();
197198
sleep_bod_disable();
198-
interrupts (); // guarantees next instruction executed
199+
interrupts (); // guarantees next instruction executed
199200
sleep_cpu ();
200201
sleep_disable();
201202
}
@@ -208,6 +209,53 @@ void reset_counter() {
208209
seconds = 0;
209210
}
210211

212+
/*
213+
check the fuse settings for clock frequency and divisor. Signal SOS in
214+
an endless loop if not correct.
215+
*/
216+
void check_fuses() {
217+
fuse_low = boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS);
218+
fuse_high = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
219+
fuse_extended = boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS);
220+
221+
if (fuse_low == 0xE2) {
222+
// everything set up perfectly, we are running at 8MHz
223+
return;
224+
}
225+
if (fuse_low == 0x62) {
226+
/*
227+
Default fuse setting, we can change the clock divisor to run with 8 MHz.
228+
We do not need to correct any other values for the arduino libraries
229+
since we only use the delay()-function which relies on a system timer
230+
*/
231+
232+
clock_prescale_set(clock_div_1);
233+
return;
234+
}
235+
// fuses have been changed, but not to the needed frequency. We send an SOS.
236+
237+
while (1) {
238+
blink_led(3, BLINK_TIME / 2);
239+
delay(BLINK_TIME / 2);
240+
blink_led(3, BLINK_TIME);
241+
delay(BLINK_TIME / 2);
242+
blink_led(3, BLINK_TIME / 2);
243+
delay(BLINK_TIME);
244+
}
245+
}
246+
247+
/*
248+
Blink the led n times for blink_length
249+
*/
250+
void blink_led(int n, int blink_length) {
251+
for (int i = 0; i < n; i++) {
252+
ledOn_buttonOff();
253+
delay(blink_length);
254+
ledOff_buttonOn();
255+
delay(blink_length);
256+
}
257+
}
258+
211259
/*
212260
Read the values stored in the EEPROM. The addresses are defined in
213261
the header file. We use the modern get()-method that determines the

firmware/ATTinyDaemon/handleI2C.ino

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,18 @@ void request_event() {
197197
case REGISTER_VERSION:
198198
write_data_crc((uint8_t *)&prog_version, sizeof(prog_version));
199199
break;
200+
case REGISTER_FUSE_LOW:
201+
write_data_crc((uint8_t *)&fuse_low, sizeof(fuse_low));
202+
break;
203+
case REGISTER_FUSE_HIGH:
204+
write_data_crc((uint8_t *)&fuse_high, sizeof(fuse_high));
205+
break;
206+
case REGISTER_FUSE_EXTENDED:
207+
write_data_crc((uint8_t *)&fuse_extended, sizeof(fuse_extended));
208+
break;
200209
}
201210

211+
202212
// we had a read operation and reset the counter
203213
reset_counter();
204214
}

0 commit comments

Comments
 (0)