I have some code, which does not have any issues running on ESP32. If I run this on ATTiny85, it does have issues.
What happens is, I will run the program and move the "sender" (potentiometer) across its range a few times. Eventually, seemingly at random, the "gauge" (pwm) output changes. It clamps to 0 or 1.
Somehow, one of the variables (sender_min/max, or gauge_min/max) is getting changed, it seems.
I commented out all the code which can change those variables other than at program start.
This never happens if I hardcode the gauge/pwm output to a set value, so the PWM timer seems to be working fine and I am left with the variables getting changed somehow.
The program is not resetting, as the blinkLED() at the start of the program (or anywhere) is not firing.
Since there isn't a great way to Serial write with attiny85 I am having a bit of trouble debugging.
I feel like what is happening is maybe some out of bounds memory access, but I am not seeing it in the code. Maybe I am missing it.
Also attached the circuit diagram. Thanks for the help.
#include <EEPROM.h>
#define SENDER_PIN 3
#define GAUGE_PIN 4
#define SENDER_SET_PIN 0
#define LED_PIN 1
#define GAUGE_SET_PIN 2
// 100 times per second
#define EXECUTION_RATE_MS 10
typedef enum ButtonPressResult {
ButtonPressNone = 0,
ButtonPressShort = 1,
ButtonPressLong = 2
} ButtonPressResult;
typedef struct Button {
int state;
unsigned long start_time;
} Button;
Button SENDER_SET_BUTTON = { .state = HIGH, .start_time = 0 };
Button GAUGE_SET_BUTTON = { .state = HIGH, .start_time = 0 };
int sender_min = 0;
int sender_max = 1023;
int gauge_min = 0;
int gauge_max = 255;
int averageGaugeVal[80];
int averageGaugeValSorted[80];
unsigned long lastSampleTime = 0;
void blinkLED(int count) {
for (int i = 0; i < count; i++) {
digitalWrite(LED_PIN, HIGH);
delay(200);
digitalWrite(LED_PIN, LOW);
delay(200);
}
}
void writeInt(int val, int offset) {
// Serial.print("writeInt: ");
// Serial.println(val, DEC);
EEPROM.write(offset, highByte(val));
EEPROM.write(offset + 1, lowByte(val));
}
int readInt(int offset) {
byte high = EEPROM.read(offset);
byte low = EEPROM.read(offset + 1);
// Serial.print("readInt: ");
// Serial.println(word(high,low), DEC);
return word(high,low);
}
int getSender() {
return analogRead(SENDER_PIN);
}
void setGauge(int val) {
// Serial.print("setGauge: ");
// Serial.println(val);
analogWrite(GAUGE_PIN, val);
// analogWrite(GAUGE_PIN, 220);
}
void setSenderMin(int val) {
// Serial.print("setSenderMin: ");
// Serial.println(val);
sender_min = val;
writeInt(val, 0);
}
void setSenderMax(int val) {
// Serial.print("setSenderMax: ");
// Serial.println(val);
sender_max = val;
writeInt(val, 2);
}
// void setGaugeMax(int val) {
// // Serial.print("setGaugeMax: ");
// // Serial.println(val);
// gauge_max = val;
// writeInt(val, 4);
// }
void setGaugeMin(int val) {
// Serial.print("setGaugeMin: ");
// Serial.println(val);
gauge_min = val;
writeInt(val, 4);
}
int senderToGauge(int v) {
// If for some reason they get set to the same value, just return 0 since it's invalid anyways
if (sender_min == sender_max) {
return 0;
}
return (long)(v - sender_min) * (gauge_max - gauge_min) / (sender_max - sender_min) + gauge_min;
}
void setup() {
// Serial.begin(9600);
blinkLED(5);
sender_min = readInt(0);
sender_max = readInt(2);
gauge_min = readInt(4);
// Serial.print("sender_min: ");
// Serial.println(sender_min);
// Serial.print("sender_max: ");
// Serial.println(sender_max);
// Serial.print("gauge_max: ");
// Serial.println(gauge_max);
pinMode(SENDER_SET_PIN, INPUT_PULLUP);
pinMode(GAUGE_SET_PIN, INPUT_PULLUP);
pinMode(SENDER_PIN, INPUT);
pinMode(GAUGE_PIN, OUTPUT);
// Fill out avg
int senderVal = getSender();
for (int i = 0; i < 80; i++) {
averageGaugeVal[i] = senderVal;
averageGaugeValSorted[i] = senderVal;
}
setGauge(senderToGauge(senderVal));
// Sample timer
lastSampleTime = millis();
}
int sortAsc(const void *v1, const void *v2) {
return *((int *)v1) - *((int *)v2);
}
// Shift everything over
void addGaugeVal(int val) {
// Serial.print("addGaugeVal: ");
// Serial.println(val);
// Add it
for (int i = 1; i < 80; i++) {
averageGaugeVal[i - 1] = averageGaugeVal[i];
}
averageGaugeVal[79] = val;
// Copy vals to sorted version
for (int i = 0; i < 80; i++) {
averageGaugeValSorted[i] = averageGaugeVal[i];
}
// Sort it
qsort(averageGaugeValSorted, 80, sizeof(averageGaugeValSorted[0]), sortAsc);
}
// Return the median value
int getGaugeVal() {
return averageGaugeValSorted[39];
}
ButtonPressResult buttonPressed(Button *button, int newState) {
// Press down
if (button->state == HIGH && newState == LOW) {
button->state = LOW;
button->start_time = millis();
return ButtonPressNone;
}
// Press up
if (button->state == LOW && newState == HIGH) {
button->state = HIGH;
if (millis() - button->start_time >= 50) {
if (millis() - button->start_time >= 1000) {
return ButtonPressLong;
} else {
return ButtonPressShort;
}
}
}
return ButtonPressNone;
}
void loop() {
int senderVal = getSender();
unsigned long sampleTime = millis();
// Update gauge val every 100ms
if (sampleTime - lastSampleTime >= 100) {
lastSampleTime = sampleTime;
// Add it to the dampened array
addGaugeVal(senderVal);
// Update gauge with latest dampened value
int gaugeVal = senderToGauge(getGaugeVal());
setGauge(gaugeVal);
// setGauge(senderVal);
// Serial.print("s: ");
// Serial.println(senderVal);
// Serial.print("g: ");
// Serial.println(gaugeVal);
// Serial.print("gA: ");
// Serial.println(getGaugeVal());
}
// detect if any buttons are pressed which updates eeprom
// if (ButtonPressResult result = buttonPressed(&SENDER_SET_BUTTON, digitalRead(SENDER_SET_PIN))) {
// if (result == ButtonPressShort) {
// setSenderMin(senderVal);
// // blinkLED(1);
// }
// if (result == ButtonPressLong) {
// setSenderMax(senderVal);
// // blinkLED(2);
// }
// }
// if (ButtonPressResult result = buttonPressed(&GAUGE_SET_BUTTON, digitalRead(GAUGE_SET_PIN))) {
// if (result == ButtonPressShort) {
// setGaugeMin(min(240, gauge_min + 20));
// // blinkLED(3);
// }
// if (result == ButtonPressLong) {
// setGaugeMin(0);
// // blinkLED(4);
// }
// }
// Execute at 100hz by sleeping the difference between loop execution time and desired execution rate
unsigned long elapsedTime = millis() - sampleTime;
if (elapsedTime <= EXECUTION_RATE_MS) {
delay(EXECUTION_RATE_MS - elapsedTime);
}
}