From 7c4eb3db5ea3142d014582ce68424541ab2d7cfb Mon Sep 17 00:00:00 2001 From: Mark van Renswoude Date: Sun, 27 Aug 2017 11:18:51 +0200 Subject: [PATCH] Initial commit, working version --- .gitignore | 2 + TinyDimmer.sublime-project | 9 +++ build.ps1 | 1 + platformio.ini | 19 ++++++ src/ledpwmcurve.c | 66 ++++++++++++++++++ src/ledpwmcurve.h | 6 ++ src/main.c | 133 +++++++++++++++++++++++++++++++++++++ upload.ps1 | 1 + 8 files changed, 237 insertions(+) create mode 100644 .gitignore create mode 100644 TinyDimmer.sublime-project create mode 100644 build.ps1 create mode 100644 platformio.ini create mode 100644 src/ledpwmcurve.c create mode 100644 src/ledpwmcurve.h create mode 100644 src/main.c create mode 100644 upload.ps1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c0e7901 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.sublime-workspace +.pioenvs/ diff --git a/TinyDimmer.sublime-project b/TinyDimmer.sublime-project new file mode 100644 index 0000000..b01586b --- /dev/null +++ b/TinyDimmer.sublime-project @@ -0,0 +1,9 @@ +{ + "folders": + [ + { + "path": ".", + "file_exclude_patterns": ["*.sublime-project"] + } + ] +} \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..c2fb43d --- /dev/null +++ b/build.ps1 @@ -0,0 +1 @@ +& platformio run \ No newline at end of file diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..f3886d0 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,19 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; http://docs.platformio.org/page/projectconf.html + +[env:attiny85] +platform = atmelavr +board = attiny85 +upload_protocol = stk500v1 +upload_flags = -P$UPLOAD_PORT -b$UPLOAD_SPEED +board_f_cpu = 8000000L + +upload_port = COM7 +upload_speed = 19200 \ No newline at end of file diff --git a/src/ledpwmcurve.c b/src/ledpwmcurve.c new file mode 100644 index 0000000..b355501 --- /dev/null +++ b/src/ledpwmcurve.c @@ -0,0 +1,66 @@ +#include +#include + +#include "ledpwmcurve.h" + +// Source: https://electronics.stackexchange.com/a/118120 + +// Anti-Log (reverse) lookup table +// y = 0-255 (pwm output), y_range=256 +// x = 0-1023 (10-bit ADC input); +// assuming lower/higher end of ADC out values cannot be used +// discarding first 32 and last 32 values. +// min_x = 32, max_x = 1023-min_x, x_range=1024-2*min_x +// ANTI_LOG[y] = round( x_range*log(y, base=y_range) + min_x ) +// given a value of x, perform a binary lookup on below table +// takes about 28uS for Attiny85 @8MHz clock +const uint16_t ANTI_LOG[] PROGMEM = +{ + 0x0000, 0x0020, 0x0098, 0x00de, 0x0110, 0x0137, 0x0156, 0x0171, 0x0188, 0x019c, 0x01af, 0x01bf, 0x01ce, 0x01dc, 0x01e9, 0x01f5, + 0x0200, 0x020a, 0x0214, 0x021e, 0x0227, 0x022f, 0x0237, 0x023f, 0x0246, 0x024d, 0x0254, 0x025b, 0x0261, 0x0267, 0x026d, 0x0273, + 0x0278, 0x027d, 0x0282, 0x0288, 0x028c, 0x0291, 0x0296, 0x029a, 0x029f, 0x02a3, 0x02a7, 0x02ab, 0x02af, 0x02b3, 0x02b7, 0x02bb, + 0x02be, 0x02c2, 0x02c5, 0x02c9, 0x02cc, 0x02cf, 0x02d3, 0x02d6, 0x02d9, 0x02dc, 0x02df, 0x02e2, 0x02e5, 0x02e8, 0x02eb, 0x02ed, + 0x02f0, 0x02f3, 0x02f5, 0x02f8, 0x02fa, 0x02fd, 0x0300, 0x0302, 0x0304, 0x0307, 0x0309, 0x030b, 0x030e, 0x0310, 0x0312, 0x0314, + 0x0317, 0x0319, 0x031b, 0x031d, 0x031f, 0x0321, 0x0323, 0x0325, 0x0327, 0x0329, 0x032b, 0x032d, 0x032f, 0x0331, 0x0333, 0x0334, + 0x0336, 0x0338, 0x033a, 0x033c, 0x033d, 0x033f, 0x0341, 0x0342, 0x0344, 0x0346, 0x0347, 0x0349, 0x034b, 0x034c, 0x034e, 0x034f, + 0x0351, 0x0352, 0x0354, 0x0355, 0x0357, 0x0358, 0x035a, 0x035b, 0x035d, 0x035e, 0x0360, 0x0361, 0x0363, 0x0364, 0x0365, 0x0367, + 0x0368, 0x0369, 0x036b, 0x036c, 0x036d, 0x036f, 0x0370, 0x0371, 0x0372, 0x0374, 0x0375, 0x0376, 0x0378, 0x0379, 0x037a, 0x037b, + 0x037c, 0x037e, 0x037f, 0x0380, 0x0381, 0x0382, 0x0383, 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038a, 0x038b, 0x038c, 0x038e, + 0x038f, 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, + 0x039f, 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ab, 0x03ac, 0x03ad, + 0x03ae, 0x03af, 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03ba, 0x03bb, + 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03bf, 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c7, 0x03c8, + 0x03c9, 0x03ca, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03cd, 0x03ce, 0x03cf, 0x03d0, 0x03d0, 0x03d1, 0x03d2, 0x03d3, 0x03d3, 0x03d4, + 0x03d5, 0x03d6, 0x03d6, 0x03d7, 0x03d8, 0x03d8, 0x03d9, 0x03da, 0x03db, 0x03db, 0x03dc, 0x03dd, 0x03dd, 0x03de, 0x03df, 0x03df +}; + +// Binary lookup using above table +uint8_t antilog(uint16_t value) +{ + uint8_t result = 0x80; + uint16_t lookupValue; + + for(uint16_t jumpOffset = 0x40; jumpOffset > 0; jumpOffset >>= 1) + { + lookupValue = pgm_read_word_near(ANTI_LOG + result); + if (lookupValue > value) + { + result -= jumpOffset; + } + else if (lookupValue < value) + { + result |= jumpOffset; + } + else + { + return result; + } + } + + if (pgm_read_word_near(ANTI_LOG + result) > value) + { + result -= 1; + } + + return result; +} diff --git a/src/ledpwmcurve.h b/src/ledpwmcurve.h new file mode 100644 index 0000000..c75a33e --- /dev/null +++ b/src/ledpwmcurve.h @@ -0,0 +1,6 @@ +#ifndef __LEDPWMCurve +#define __LEDPWMCurve + +extern uint8_t antilog(uint16_t value); + +#endif \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..a94529d --- /dev/null +++ b/src/main.c @@ -0,0 +1,133 @@ +#include +#include +#include +#include + +#include "ledpwmcurve.h" + +/* + Pin 2: 10k potentiometer input + When turned all the way to the left (off), resistance should be 0 + Pin 5: PWM output +*/ + + +// Forward declarations +inline void initPWM(); +inline void initADC(); +inline uint16_t readADC(); +inline void sleep(uint8_t prescale); + + + +int main() +{ + // Set pin B0 (physical pin 5) to output mode, pin B2 (ADC1) to input + DDRB = (DDRB | _BV(DDB0)) & ~_BV(DDB3); + + initPWM(); + OCR0A = 255; + + initADC(); + + while (1) + { + uint8_t value = 255 - antilog(readADC()); + OCR0A = value; + + if (value == 255) + { + // Off, go to sleep for 0.25s + sleep(_BV(WDP2)); + } + } + + return 0; +} + + + +inline void initPWM() +{ + // Set timer to Fast PWM mode, clear OC0A on compare-match and set OC0A on top. + // This inverts the PWM, but allows the LEDs to turn off completely. + TCCR0A = _BV(COM0A1) | _BV(COM0A0) | _BV(WGM01) | _BV(WGM00); + + // Leave WGM02 empty for Fast PWM mode, and set clock select to no prescaling + TCCR0B = _BV(CS00); + + // Disable timer 1 + TCCR1 = 0; +} + + +inline void initADC() +{ + // Use VCC as voltage reference and right adjust result, + // set to single-ended input on ADC1 + ADMUX = (ADMUX | _BV(MUX0) | _BV(MUX1)) + & ~(_BV(MUX2) | _BV(MUX3) | _BV(REFS1) | _BV(REFS0) | _BV(ADLAR)); + + // Disable digital input on the analog pin to save power + DIDR0 |= _BV(ADC3D); + + // Enable the ADC + ADCSRA |= _BV(ADEN) | _BV(ADPS1) | _BV(ADPS0); +} + + +inline uint16_t readADC() +{ + // Start conversion + ADCSRA |= _BV(ADSC); + + // Wait for result + loop_until_bit_is_clear(ADCSRA, ADSC); + + // ADCL must be read first + uint8_t low = ADCL; + return (ADCH<<8) | low; +} + + +inline void sleep(uint8_t prescaler) +{ + // Disable watchdog reset flag + MCUSR &= ~_BV(WDRF); + + // Enable watchdog + WDTCR |= _BV(WDCE) | _BV(WDE); + + // Set timeout value and enable interrupt mode + WDTCR = prescaler | _BV(WDIE); + + + // Turn ADC off + ADCSRA &= ~_BV(ADEN); + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + + // Set sleep bit and halt the CPU + sleep_enable(); + sei(); + sleep_cpu(); + + // ...goooood morning! + cli(); + + + // Disable watchdog (need to write a logic one first, see datasheet) + WDTCR |= _BV(WDCE) | _BV(WDE); + WDTCR = 0; + + + sleep_disable(); + ADCSRA |= _BV(ADEN); + + sei(); +} + + +// Interrupt for watchdog timer +ISR(WDT_vect) +{ +} \ No newline at end of file diff --git a/upload.ps1 b/upload.ps1 new file mode 100644 index 0000000..9b3c625 --- /dev/null +++ b/upload.ps1 @@ -0,0 +1 @@ +& platformio run --target upload \ No newline at end of file