From 295c9e80075351088d873c5565041193f173d02d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 8 Nov 2015 15:01:39 -0700 Subject: Different tiny25 fuses: No brownout detection, and slower startup. (am trying to reduce power use and hopefully prevent accidental resets) --- bin/flash-25.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bin') diff --git a/bin/flash-25.sh b/bin/flash-25.sh index bb5dd34..8913892 100755 --- a/bin/flash-25.sh +++ b/bin/flash-25.sh @@ -1,4 +1,4 @@ #/bin/sh FIRMWARE=$1 -avrdude -c usbasp -p t25 -u -Uflash:w:$FIRMWARE -U lfuse:w:0xd2:m -U hfuse:w:0xde:m -U efuse:w:0xff:m +avrdude -c usbasp -p t25 -u -Uflash:w:$FIRMWARE -U lfuse:w:0xe2:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m # http://www.engbedded.com/cgi-bin/fcx.cgi?P_PREV=ATtiny25&P=ATtiny25&M_LOW_0x3F=0x12&M_HIGH_0x07=0x06&M_HIGH_0x20=0x00&B_SPIEN=P&B_SUT0=P&B_CKSEL3=P&B_CKSEL2=P&B_CKSEL0=P&B_BODLEVEL0=P&V_LOW=E2&V_HIGH=DE&V_EXTENDED=FF -- cgit v1.2.3 From 4b794fa1566ed670e185f4045472ad75406c2a9a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 22 May 2016 18:42:01 -0600 Subject: Made level_calc.py work with any number of power channels. Results are slightly different than before, and I'm not sure if I broke something or fixed something. Hard to tell. Regardless, it seems to work fine. --- bin/level_calc.py | 192 +++++++++++++++++++++++++++--------------------------- 1 file changed, 96 insertions(+), 96 deletions(-) (limited to 'bin') diff --git a/bin/level_calc.py b/bin/level_calc.py index 63926ba..6a82563 100755 --- a/bin/level_calc.py +++ b/bin/level_calc.py @@ -4,115 +4,112 @@ import math interactive = False + def main(args): """Calculates PWM levels for visually-linear steps. """ # Get parameters from the user - v = dict(pwm_max=255, pwm2_max=255) - questions = [ + questions_main = [ + (int, 'num_channels', 1, 'How many power channels?'), (int, 'num_levels', 4, 'How many total levels do you want?'), - (int, 'pwm_min', 6, 'Lowest visible PWM level, for moon mode:'), - (float, 'lm_min', 0.25, 'How bright is moon mode, in lumens?'), + ] + questions_per_channel = [ + (int, 'pwm_min', 6, 'Lowest visible PWM level:'), + (float, 'lm_min', 0.25, 'How bright is the lowest level, in lumens?'), #(int, 'pwm_max', 255, 'Highest PWM level:'), (float, 'lm_max', 1000, 'How bright is the highest level, in lumens?'), - (str, 'dual_pwm', 'n', 'Use dual PWM? [y/n]'), - (float, 'pwm2_min', 6, 'Second channel, lowest visible PWM level:'), - (float, 'lm2_min', 0.25, 'Second channel, how bright is the lowest mode, in lumens?'), - #(float, 'pwm2_max', 255, 'Second channel, highest PWM level:'), - (float, 'lm2_max', 140, 'Second channel, how bright is maximum, in lumens?'), ] - for typ, name, default, text in questions: - value = get_value(text, default, args) - if not value: - value = default - else: - value = typ(value) - v[name] = value - if (name == 'dual_pwm' and value == 'n'): - # skip remaining questions if not using dual PWM - break - - if v['dual_pwm'] == 'y': - dual_pwm(v) - else: - single_pwm(v) + + def ask(questions, ans): + for typ, name, default, text in questions: + value = get_value(text, default, args) + if not value: + value = default + else: + value = typ(value) + setattr(ans, name, value) + + answers = Empty() + ask(questions_main, answers) + channels = [] + if not args: + print('Describe the channels in order of lowest to highest power.') + for chan_num in range(answers.num_channels): + if not args: + print('===== Channel %s =====' % (chan_num+1)) + chan = Empty() + chan.pwm_max = 255 + ask(questions_per_channel, chan) + channels.append(chan) + + multi_pwm(answers, channels) if interactive: # Wait on exit, in case user invoked us by clicking an icon print 'Press Enter to exit:' raw_input() -def single_pwm(v): - """Estimate the PWM levels for a one-channel driver.""" - visual_min = invpower(v['lm_min']) - visual_max = invpower(v['lm_max']) - step_size = (visual_max - visual_min) / (v['num_levels']-1) - modes = [] - goal = visual_min - for i in range(v['num_levels']): - goal_lm = power(goal) - #pwm_float = ((goal_lm / v['lm_max']) * (256-v['pwm_min'])) + v['pwm_min'] - 1 - pwm_float = (((goal_lm-v['lm_min']) / (v['lm_max']-v['lm_min'])) \ - * (255-v['pwm_min'])) \ - + v['pwm_min'] - pwm = int(round(pwm_float)) - pwm = max(min(pwm,v['pwm_max']),v['pwm_min']) - modes.append(pwm) - print '%i: visually %.2f (%.2f lm): %.2f/255' % (i+1, goal, goal_lm, pwm_float) - goal += step_size - - print 'PWM values:', ','.join([str(i) for i in modes]) - -def dual_pwm(v): - """Estimate the PWM levels for a two-channel driver. - Assume the first channel is the brighter one, and second will be used for moon/low modes. - """ - #visual_min = math.pow(v['lm2_min'], 1.0/power) - #visual_max = math.pow(v['lm_max'], 1.0/power) - visual_min = invpower(v['lm2_min']) - visual_max = invpower(v['lm_max']) - step_size = (visual_max - visual_min) / (v['num_levels']-1) - modes = [] - goal = visual_min - for i in range(v['num_levels']): - goal_lm = power(goal) - # Up to the second channel's limit, calculate things just like a - # single-channel driver (first channel will be zero) - if goal_lm <= v['lm2_max']: - pwm1_float = 0.0 - #pwm2_float = ((goal_lm / v['lm2_max']) * (256-v['pwm2_min'])) + v['pwm2_min'] - 1 - pwm2_float = (((goal_lm-v['lm2_min']) / (v['lm2_max']-v['lm2_min'])) \ - * (255-v['pwm2_min'])) \ - + v['pwm2_min'] - pwm1 = int(round(pwm1_float)) - pwm2 = int(round(pwm2_float)) - pwm2 = max(min(pwm2,v['pwm2_max']),v['pwm2_min']) - modes.append((int(pwm1),int(pwm2))) - # Above the second channel's limit, things get a little more - # complicated (second channel will be 255, first channel will be - # adjusted down by the max output of the second channel) - else: - if len(modes) == v['num_levels'] -1: # turbo is special - #pwm1_float = ((goal_lm / v['lm_max']) * (256-v['pwm_min'])) + v['pwm_min'] - 1 - pwm1_float = float(v['pwm_max']) - # on a FET+7135 driver, turbo works better without the 7135 - # (we're assuming FET+7135 here) - pwm2_float = 0.0 - else: # not the highest mode yet - #pwm1_float = (((goal_lm-v['lm2_max']) / v['lm_max']) * (256-v['pwm_min'])) + v['pwm_min'] - 1 - pwm1_float = (((goal_lm-v['lm_min']-v['lm2_max']) / (v['lm_max']-v['lm_min'])) \ - * (255-v['pwm_min'])) \ - + v['pwm_min'] - pwm2_float = 255.0 - pwm1 = int(round(pwm1_float)) - pwm2 = int(round(pwm2_float)) - pwm1 = max(min(pwm1,v['pwm_max']),v['pwm_min']) - modes.append((int(pwm1),int(pwm2))) - print '%i: visually %.2f (%.2f lm): %.2f/255, %.2f/255' % (i+1, goal, goal_lm, pwm1_float, pwm2_float) - goal += step_size - - print 'PWM1/FET values:', ','.join([str(i[0]) for i in modes]) - print 'PWM2/7135 values:', ','.join([str(i[1]) for i in modes]) - print 'On a non-FET driver, the last mode should be 255 on both channels.' + +class Empty: + pass + + +def multi_pwm(answers, channels): + lm_min = channels[0].lm_min + lm_max = channels[-1].lm_max + visual_min = invpower(lm_min) + visual_max = invpower(lm_max) + step_size = (visual_max - visual_min) / (answers.num_levels-1) + + # Determine ideal lumen levels + goals = [] + goal_vis = visual_min + for i in range(answers.num_levels): + goal_lm = power(goal_vis) + goals.append((goal_vis, goal_lm)) + goal_vis += step_size + + # Calculate each channel's output for each level + for cnum, channel in enumerate(channels): + prev_channel = Empty() ; prev_channel.lm_max = 0.0 + if cnum > 0: + prev_channel = channels[cnum-1] + channel.modes = [] + for i in range(answers.num_levels): + goal_vis, goal_lm = goals[i] + # This channel already is maxed out + if goal_lm >= channel.lm_max: + # Handle turbo specially, enable only biggest channel + if (i == (answers.num_levels - 1)) and (cnum < (len(channels)-1)): + channel.modes.append(0.0) + else: + channel.modes.append(channel.pwm_max) + # This channel's active ramp-up range + elif goal_lm > prev_channel.lm_max: + # FIXME: This produces somewhat different values than the + # dual_pwm() algorithm, and I'm not sure which one is "right" + diff = channel.lm_max - prev_channel.lm_max + needed = goal_lm - prev_channel.lm_max + ratio = needed / diff * (channel.pwm_max-channel.pwm_min) + channel.modes.append(ratio + channel.pwm_min) + # This channel isn't active yet, output too low + else: + channel.modes.append(0) + + # Show individual levels in detail + for i in range(answers.num_levels): + goal_vis, goal_lm = goals[i] + pwms = [] + for channel in channels: + pwms.append('%.2f/%i' % (channel.modes[i], channel.pwm_max)) + print('%i: visually %.2f (%.2f lm): %s' % + (i+1, goal_vis, goal_lm, ', '.join(pwms))) + + # Show values we can paste into source code + for cnum, channel in enumerate(channels): + print('PWM%s values: %s' % + (cnum+1, + ','.join([str(int(round(i))) for i in channel.modes]))) + def get_value(text, default, args): """Get input from the user, or from the command line args.""" @@ -127,6 +124,7 @@ def get_value(text, default, args): result = result.strip() return result + def power(x): #return x**5 return x**3 @@ -134,6 +132,7 @@ def power(x): #return math.e**x #return 2.0**x + def invpower(x): #return math.pow(x, 1/5.0) return math.pow(x, 1/3.0) @@ -141,6 +140,7 @@ def invpower(x): #return math.log(x, math.e) #return math.log(x, 2.0) + if __name__ == "__main__": import sys main(sys.argv[1:]) -- cgit v1.2.3 From c4cc2bb4d128eed9a1990d9a12b5ac84e5c2336e Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 22 May 2016 19:51:03 -0600 Subject: Fixed level_calc N-channel calculations to fix all errors I could find. Fixed the case with multiple 7135 channels (they should add up). Fixed the calculation of moon mode. Fixed boundary cases, including below-zero PWM. Had to ask the user for the type (FET/7135) of each channel. --- bin/level_calc.py | 56 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 13 deletions(-) (limited to 'bin') diff --git a/bin/level_calc.py b/bin/level_calc.py index 6a82563..ee1f1eb 100755 --- a/bin/level_calc.py +++ b/bin/level_calc.py @@ -14,6 +14,7 @@ def main(args): (int, 'num_levels', 4, 'How many total levels do you want?'), ] questions_per_channel = [ + (str, 'type', '7135', 'Type of channel: ["7135"] or "FET":'), (int, 'pwm_min', 6, 'Lowest visible PWM level:'), (float, 'lm_min', 0.25, 'How bright is the lowest level, in lumens?'), #(int, 'pwm_max', 255, 'Highest PWM level:'), @@ -42,6 +43,14 @@ def main(args): ask(questions_per_channel, chan) channels.append(chan) + # calculate total output of all previous channels + for i, channel in enumerate(channels): + channel.prev_lm = 0.0 + for j in range(i): + if channels[j].type == '7135': + channel.prev_lm += channels[j].lm_max + + # figure out the desired PWM values multi_pwm(answers, channels) if interactive: # Wait on exit, in case user invoked us by clicking an icon @@ -55,7 +64,16 @@ class Empty: def multi_pwm(answers, channels): lm_min = channels[0].lm_min - lm_max = channels[-1].lm_max + # figure out the highest mode + lm_max = max([(c.lm_max+c.prev_lm) for c in channels]) + if channels[-1].type == 'FET': + if channels[-1].lm_max > channels[-1].prev_lm: + # assume the highest output is with only the FET enabled + lm_max = channels[-1].lm_max + else: + # this would be a stupid driver design + raise ValueError, "FET channel isn't the most powerful?" + visual_min = invpower(lm_min) visual_max = invpower(lm_max) step_size = (visual_max - visual_min) / (answers.num_levels-1) @@ -70,27 +88,39 @@ def multi_pwm(answers, channels): # Calculate each channel's output for each level for cnum, channel in enumerate(channels): - prev_channel = Empty() ; prev_channel.lm_max = 0.0 - if cnum > 0: - prev_channel = channels[cnum-1] channel.modes = [] for i in range(answers.num_levels): goal_vis, goal_lm = goals[i] # This channel already is maxed out - if goal_lm >= channel.lm_max: - # Handle turbo specially, enable only biggest channel - if (i == (answers.num_levels - 1)) and (cnum < (len(channels)-1)): + if goal_lm >= (channel.lm_max + channel.prev_lm): + # This shouldn't happen, the FET is assumed to be the highest channel + if channel.type == 'FET': + # this would be a stupid driver design + raise ValueError, "FET channel isn't the most powerful?" + + # Handle FET turbo specially + if (i == (answers.num_levels - 1)) \ + and (cnum < (len(channels)-1)) \ + and (channels[-1].type == 'FET'): channel.modes.append(0.0) + # Normal non-turbo mode or non-FET turbo else: channel.modes.append(channel.pwm_max) # This channel's active ramp-up range - elif goal_lm > prev_channel.lm_max: - # FIXME: This produces somewhat different values than the - # dual_pwm() algorithm, and I'm not sure which one is "right" - diff = channel.lm_max - prev_channel.lm_max - needed = goal_lm - prev_channel.lm_max + #elif goal_lm > (channel.prev_lm + channel.lm_min): + elif goal_lm > channel.prev_lm: + # assume 7135 channels all add together + if channel.type == '7135': + diff = channel.lm_max - channel.lm_min + # assume FET channel gets higher output on its own + elif channel.type == 'FET': + diff = channel.lm_max - channel.prev_lm - channel.lm_min + + needed = goal_lm - channel.prev_lm - channel.lm_min + ratio = needed / diff * (channel.pwm_max-channel.pwm_min) - channel.modes.append(ratio + channel.pwm_min) + pwm = max(0, ratio + channel.pwm_min) + channel.modes.append(pwm) # This channel isn't active yet, output too low else: channel.modes.append(0) -- cgit v1.2.3 From 6cd6943a2f2ffb70d8ad3963bfbb80efe344a308 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 9 Sep 2016 14:38:03 -0600 Subject: Add more parents to include path. --- bin/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bin') diff --git a/bin/build.sh b/bin/build.sh index 0d53b57..68f981d 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -8,7 +8,7 @@ export ATTINY=13 export MCU=attiny$ATTINY export CC=avr-gcc export OBJCOPY=avr-objcopy -export CFLAGS="-Wall -g -Os -mmcu=$MCU -c -std=gnu99 -DATTINY=$ATTINY -I.." +export CFLAGS="-Wall -g -Os -mmcu=$MCU -c -std=gnu99 -DATTINY=$ATTINY -I.. -I../.. -I../../.." export OFLAGS="-Wall -g -Os -mmcu=$MCU" export LDFLAGS= export OBJCOPYFLAGS='--set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex' -- cgit v1.2.3 From e1ed706a9da273521ff10d3b3cda0b53058f1a49 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 9 Sep 2016 14:38:41 -0600 Subject: Flash ROM last, set fuses first. Switched from low=0xe2 to low=0xd2. --- bin/flash-25.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bin') diff --git a/bin/flash-25.sh b/bin/flash-25.sh index 8913892..0b24bb2 100755 --- a/bin/flash-25.sh +++ b/bin/flash-25.sh @@ -1,4 +1,4 @@ #/bin/sh FIRMWARE=$1 -avrdude -c usbasp -p t25 -u -Uflash:w:$FIRMWARE -U lfuse:w:0xe2:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m -# http://www.engbedded.com/cgi-bin/fcx.cgi?P_PREV=ATtiny25&P=ATtiny25&M_LOW_0x3F=0x12&M_HIGH_0x07=0x06&M_HIGH_0x20=0x00&B_SPIEN=P&B_SUT0=P&B_CKSEL3=P&B_CKSEL2=P&B_CKSEL0=P&B_BODLEVEL0=P&V_LOW=E2&V_HIGH=DE&V_EXTENDED=FF +avrdude -c usbasp -p t25 -u -U lfuse:w:0xd2:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m -Uflash:w:$FIRMWARE +# http://www.engbedded.com/cgi-bin/fcx.cgi?P_PREV=ATtiny25&P=ATtiny25&M_LOW_0x3F=0x22&M_HIGH_0x07=0x07&M_HIGH_0x20=0x00&B_SUT1=P&B_SPIEN=P&B_CKSEL3=P&B_CKSEL2=P&B_CKSEL0=P&V_LOW=D2&V_HIGH=DF&V_EXTENDED=FF -- cgit v1.2.3 From 0b64fad1bbac00989853567dd363bcfed408f374 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 9 Sep 2016 14:39:06 -0600 Subject: level_calc minor formatting fix --- bin/level_calc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bin') diff --git a/bin/level_calc.py b/bin/level_calc.py index ee1f1eb..de52998 100755 --- a/bin/level_calc.py +++ b/bin/level_calc.py @@ -14,7 +14,7 @@ def main(args): (int, 'num_levels', 4, 'How many total levels do you want?'), ] questions_per_channel = [ - (str, 'type', '7135', 'Type of channel: ["7135"] or "FET":'), + (str, 'type', '7135', 'Type of channel - 7135 or FET:'), (int, 'pwm_min', 6, 'Lowest visible PWM level:'), (float, 'lm_min', 0.25, 'How bright is the lowest level, in lumens?'), #(int, 'pwm_max', 255, 'Highest PWM level:'), -- cgit v1.2.3