forked from ToyKeeper/anduril
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added "emisar-2ch-fet-joined" build, for D4S w/ lighted switch
(it's an odd case with a 2 channel driver which only uses 1 set of LEDs)
- Loading branch information
Showing
6 changed files
with
512 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Emisar 2-channel driver connected to only 1 set of LEDs | ||
|
||
The default Emisar D4S driver doesn't support a lighted switch, so for lights | ||
built with one of those, Hank puts in a 2-channel driver instead... but he only | ||
connects 1 set of LEDs. | ||
|
||
This is an odd hardware configuration used only for special orders, I think. | ||
|
||
The driver itself has 3 power channels: | ||
|
||
1. Linear regulator 1 | ||
2. Linear regulator 2 | ||
3. Direct-drive FET | ||
|
||
Channels 1 and 3 are connected to the main LEDs, while channel 2 is not | ||
physically wired up to anything. | ||
|
||
Two channel modes are included: | ||
|
||
1. Linear only | ||
2. Linear + DD FET | ||
|
||
Channel mode 2 is default, and the only mode enabled after a factory reset. | ||
Channel mode 1 is included in case anyone wants to turn off the DD FET. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// Anduril config for Emisar 2ch+FET-joined-into-1-channel | ||
// Copyright (C) 2024 Selene ToyKeeper | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
#pragma once | ||
|
||
// This is mostly just used on the Emisar D4S w/ lighted switch, | ||
// which uses a 2-channel driver but only actually uses 1 set of LEDs | ||
// (so instead of the usual 2ch or 2ch-fet firmware, it needs something else) | ||
|
||
#define HWDEF_H hank/emisar-2ch/fet/joined/hwdef.h | ||
#include "hank/anduril.h" | ||
|
||
// this light has three aux LED channels: R, G, B | ||
#define USE_AUX_RGB_LEDS | ||
// the aux LEDs are front-facing, so turn them off while main LEDs are on | ||
// it also has an independent LED in the button | ||
#define USE_BUTTON_LED | ||
// enabling this option breaks the button LED | ||
#ifdef USE_INDICATOR_LED_WHILE_RAMPING | ||
#undef USE_INDICATOR_LED_WHILE_RAMPING | ||
#endif | ||
|
||
// channel modes... | ||
// CM_CH1 -- linear ch1 only | ||
// CM_CH1_FET -- linear ch1 + DD FET | ||
#define DEFAULT_CHANNEL_MODE CM_CH1_FET | ||
|
||
#define USE_CONFIG_COLORS | ||
|
||
// strobes on this light should use the same channel as the ramp | ||
#undef USE_CHANNEL_PER_STROBE | ||
|
||
// blink numbers on the main LEDs by default (but allow user to change it) | ||
#define DEFAULT_BLINK_CHANNEL CM_CH1_FET | ||
|
||
#define POLICE_COLOR_STROBE_CH1 CM_AUXRED | ||
#define POLICE_COLOR_STROBE_CH2 CM_AUXBLU | ||
|
||
#define RAMP_SIZE 150 | ||
|
||
// Output estimates: | ||
// - linear ch1 only: 2500 lm | ||
// - ch1 + DD FET: 3500 lm | ||
// (tested on a D4S with Osram W2 LEDs, with a mediocre battery at 3.7V) | ||
// (LuxWad estimated 6000 lm (uncalibrated) on a full high-amp cell) | ||
// (I picked 4500 lm as a rough realistic estimate) | ||
// - linear ch2 only: 0 (not connected) | ||
// - moon: 0.7 lm at PWM 1/4096, 0.15 lm at DSM 0/32640 | ||
|
||
// delta-sigma modulated PWM (0b0HHHHHHHHLLLLLLL = 0, 8xHigh, 7xLow bits) | ||
// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) | ||
// | ||
// linear ch1 only (copied from noctigon-m44 ramp) | ||
// level_calc.py 5.01 1 150 7135 0 0.2 2000 --pwm 32640 | ||
#define PWM1_LEVELS 0,1,2,3,4,5,6,7,9,10,12,14,17,19,22,25,28,32,36,41,45,50,56,62,69,76,84,92,101,110,121,132,143,156,169,184,199,215,232,251,270,291,313,336,360,386,414,442,473,505,539,574,612,651,693,736,782,829,880,932,987,1045,1105,1168,1233,1302,1374,1449,1527,1608,1693,1781,1873,1969,2068,2172,2279,2391,2507,2628,2753,2883,3018,3158,3303,3454,3609,3771,3938,4111,4289,4475,4666,4864,5068,5280,5498,5724,5957,6197,6445,6701,6965,7237,7518,7808,8106,8413,8730,9056,9392,9737,10093,10459,10835,11223,11621,12031,12452,12884,13329,13786,14255,14737,15232,15741,16262,16798,17347,17911,18489,19082,19691,20314,20954,21609,22281,22969,23674,24397,25137,25895,26671,27465,28279,29111,29963,30835,31727,32640 | ||
// | ||
// linear+FET linear ch1 segment | ||
// level_calc.py 4.85 2 150 7135 0 0.5 2500 FET 1 10 4500 --pwm 32640 | ||
#define PWM2_LEVELS 0,2,3,5,7,9,11,14,17,20,24,28,33,38,44,50,57,64,72,81,91,101,112,125,138,152,167,184,201,220,241,263,286,311,337,365,395,427,461,497,535,575,618,663,711,761,814,870,929,992,1057,1126,1198,1274,1353,1437,1524,1616,1712,1812,1917,2027,2141,2261,2386,2516,2652,2794,2941,3095,3255,3422,3595,3775,3962,4156,4358,4568,4785,5011,5245,5487,5738,5999,6268,6548,6837,7135,7445,7764,8095,8437,8790,9154,9531,9919,10321,10735,11162,11602,12056,12524,13006,13503,14015,14542,15085,15643,16218,16810,17419,18045,18688,19350,20031,20730,21448,22186,22944,23722,24521,25342,26184,27048,27935,28844,29777,30733,31714,32640,32640,32640,32640,32640,32640,32640,32640,32640,32640,32640,32640,32640,32640,32640,32640,32640,32640,32640,32640,0 | ||
// | ||
// linear+FET DD FET segment | ||
// level_calc.py 4.85 2 150 7135 0 0.5 2500 FET 1 10 4500 --pwm 255 | ||
#define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,20,31,42,53,65,76,88,101,113,126,139,152,166,180,194,209,224,239,255 | ||
|
||
#define DEFAULT_LEVEL 70 | ||
#define MIN_THERM_STEPDOWN 50 | ||
#define MAX_REGULATED 130 | ||
#define MAX_1x7135 MAX_REGULATED | ||
#define MAX_Nx7135 MAX_REGULATED | ||
#define HALFSPEED_LEVEL 20 | ||
#define QUARTERSPEED_LEVEL 10 | ||
|
||
#define RAMP_SMOOTH_FLOOR 1 | ||
#define RAMP_SMOOTH_CEIL 150 | ||
// 10, 30, 50, [70], 90, 110, [130] | ||
#define RAMP_DISCRETE_FLOOR 10 | ||
#define RAMP_DISCRETE_CEIL MAX_REGULATED | ||
#define RAMP_DISCRETE_STEPS 7 | ||
|
||
// safe limit highest regulated power (no FET or turbo) | ||
// 10, 40, [70], 100, [130] | ||
#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR | ||
#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL | ||
#define SIMPLE_UI_STEPS 5 | ||
|
||
// stop panicking at ~2500 lm | ||
#define THERM_FASTER_LEVEL MAX_REGULATED | ||
|
||
#define USE_POLICE_COLOR_STROBE_MODE | ||
#undef TACTICAL_LEVELS | ||
#define TACTICAL_LEVELS MAX_REGULATED,30,(RAMP_SIZE+3) // high, low, police strobe | ||
|
||
// use the brightest setting for strobe | ||
#define STROBE_BRIGHTNESS MAX_LEVEL | ||
// slow down party strobe; this driver can't pulse for less than 1ms | ||
// (in linear-only mode ... but FET mode can pulse a much shorter time) | ||
#define PARTY_STROBE_ONTIME 1 | ||
|
||
// the default of 26 looks a bit flat, so increase it | ||
#define CANDLE_AMPLITUDE 33 | ||
|
||
// the power regulator is a bit slow, so push it harder for a quick response from off | ||
#define DEFAULT_JUMP_START_LEVEL 22 | ||
#define BLINK_BRIGHTNESS 45 | ||
#define BLINK_ONCE_TIME 12 // longer blink, since main LEDs are slow | ||
|
||
#define THERM_CAL_OFFSET 5 | ||
|
||
// don't blink while ramping | ||
#ifdef BLINK_AT_RAMP_MIDDLE | ||
#undef BLINK_AT_RAMP_MIDDLE | ||
#endif | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
// Emisar 2-channel-plus-FET-joined-into-1-channel | ||
// Copyright (C) 2024 Selene ToyKeeper | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
#pragma once | ||
|
||
#include "fsm/chan-rgbaux.c" | ||
|
||
|
||
void set_level_zero(); | ||
|
||
void set_level_ch1(uint8_t level); | ||
void set_level_ch1_fet(uint8_t level); | ||
|
||
bool gradual_tick_ch1(uint8_t gt); | ||
bool gradual_tick_ch1_fet(uint8_t gt); | ||
|
||
|
||
Channel channels[] = { | ||
{ // channel 1 only | ||
.set_level = set_level_ch1, | ||
.gradual_tick = gradual_tick_ch1, | ||
// .has_args = 0 | ||
}, | ||
{ // channel 1 + DD FET | ||
.set_level = set_level_ch1_fet, | ||
.gradual_tick = gradual_tick_ch1_fet, | ||
// .has_args = 0 | ||
}, | ||
RGB_AUX_CHANNELS | ||
}; | ||
|
||
|
||
void set_level_zero() { | ||
// disable timer overflow interrupt | ||
// (helps improve button press handling from Off state) | ||
DSM_INTCTRL &= ~DSM_OVF_bm; | ||
|
||
// turn off all LEDs | ||
ch1_dsm_lvl = 0; | ||
//ch2_dsm_lvl = 0; | ||
CH1_PWM = 0; | ||
CH2_PWM = 0; | ||
CH3_PWM = 0; | ||
PWM_CNT = 0; // reset phase | ||
CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp | ||
CH2_ENABLE_PORT &= ~(1 << CH2_ENABLE_PIN); // disable opamp | ||
} | ||
|
||
|
||
// wrap setting the dsm vars, to get a faster response | ||
// (just setting *_dsm_lvl doesn't work well for strobes) | ||
// set new values for both channels, | ||
// handling any possible combination | ||
// and any before/after state | ||
void set_hw_levels(PWM1_DATATYPE ch1, | ||
//PWM2_DATATYPE ch2, | ||
PWM3_DATATYPE ch3 | ||
//, bool ch1_on, bool ch2_on | ||
) { | ||
|
||
//bool was_on = (CH1_PWM>0) || (CH2_PWM>0) | ||
// || ( CH1_ENABLE_PORT & (1 << CH1_ENABLE_PIN) ) | ||
// || ( CH2_ENABLE_PORT & (1 << CH2_ENABLE_PIN) ); | ||
|
||
//if (ch1 || ch1_on) | ||
CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable opamp | ||
//else | ||
// CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp | ||
|
||
//if (ch2 || ch2_on) | ||
// CH2_ENABLE_PORT |= (1 << CH2_ENABLE_PIN); // enable opamp | ||
//else | ||
// CH2_ENABLE_PORT &= ~(1 << CH2_ENABLE_PIN); // disable opamp | ||
|
||
// set delta-sigma soft levels | ||
ch1_dsm_lvl = ch1; | ||
//ch2_dsm_lvl = ch2; | ||
|
||
// set hardware PWM levels and init dsm loop | ||
CH1_PWM = ch1_pwm = ch1 >> 7; | ||
//CH2_PWM = ch2_pwm = ch2 >> 7; | ||
CH3_PWM = ch3; | ||
|
||
// enable timer overflow interrupt so DSM can work | ||
DSM_INTCTRL |= DSM_OVF_bm; | ||
|
||
// reset phase when turning on | ||
if (! prev_level) PWM_CNT = 0; | ||
|
||
} | ||
|
||
// delta-sigma modulation of PWM outputs | ||
// happens on each Timer overflow (every 512 cpu clock cycles) | ||
// uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD) | ||
ISR(DSM_vect) { | ||
// set new hardware values first, | ||
// for best timing (reduce effect of interrupt jitter) | ||
CH1_PWM = ch1_pwm; | ||
//CH2_PWM = ch2_pwm; | ||
|
||
// calculate next values, now that timing matters less | ||
|
||
// accumulate error | ||
ch1_dsm += (ch1_dsm_lvl & 0x007f); | ||
// next PWM = base PWM value + carry bit | ||
ch1_pwm = (ch1_dsm_lvl >> 7) + (ch1_dsm > 0x7f); | ||
// clear carry bit | ||
ch1_dsm &= 0x7f; | ||
|
||
// repeat for other channels | ||
|
||
//ch2_dsm += (ch2_dsm_lvl & 0x007f); | ||
//ch2_pwm = (ch2_dsm_lvl >> 7) + (ch2_dsm > 0x7f); | ||
//ch2_dsm &= 0x7f; | ||
} | ||
|
||
|
||
void set_level_ch1(uint8_t level) { | ||
PWM1_DATATYPE pwm1 = PWM1_GET(level); | ||
set_hw_levels(pwm1, 0); | ||
} | ||
|
||
void set_level_ch1_fet(uint8_t level) { | ||
PWM2_DATATYPE pwm2 = PWM2_GET(level); | ||
PWM3_DATATYPE pwm3 = PWM3_GET(level); | ||
set_hw_levels(pwm2, pwm3); | ||
} | ||
|
||
|
||
///// bump each channel toward a target value ///// | ||
bool gradual_adjust(PWM1_DATATYPE ch1, | ||
//PWM2_DATATYPE ch2, | ||
PWM3_DATATYPE ch3) { | ||
|
||
// instant 0 to TOP change, and TOP to 0 | ||
if (((DSM_TOP == ch1_dsm_lvl) && (0 == ch1)) || | ||
((DSM_TOP == ch1) && (0 == ch1_dsm_lvl))) | ||
ch1_dsm_lvl = ch1; | ||
|
||
// bump the DD FET multiple steps | ||
// (it only has 255 steps, but the effect is small | ||
// compared to the linear channel it's stacked on, | ||
// so smaller steps tend to overheat on turbo) | ||
for (uint8_t i=0; i<4; i++) | ||
GRADUAL_ADJUST_SIMPLE(ch3, CH3_PWM); | ||
|
||
// if DSM changed by less than 100%, | ||
// adjust multiple times based on current brightness | ||
// (so it adjusts faster/coarser when bright, slower/finer when dim) | ||
|
||
// higher shift = slower/finer adjustments | ||
const uint8_t shift = 9; // ((255 << 7) >> 9) = 63 max | ||
uint8_t steps; | ||
|
||
steps = ch1_dsm_lvl >> shift; | ||
for (uint8_t i=0; i<=steps; i++) | ||
GRADUAL_ADJUST_SIMPLE(ch1, ch1_dsm_lvl); | ||
|
||
//steps = ch2_dsm_lvl >> shift; | ||
////for (uint8_t i=0; i<=steps; i++) | ||
//// GRADUAL_ADJUST_SIMPLE(ch2, ch2_dsm_lvl); | ||
|
||
if ((ch1 == ch1_dsm_lvl) | ||
//&& (ch2 == ch2_dsm_lvl) | ||
&& (ch3 == CH3_PWM) ) { | ||
return true; // done | ||
} | ||
return false; // not done yet | ||
} | ||
|
||
bool gradual_tick_ch1(uint8_t gt) { | ||
PWM1_DATATYPE pwm1 = PWM1_GET(gt); | ||
return gradual_adjust(pwm1, 0); | ||
} | ||
|
||
bool gradual_tick_ch1_fet(uint8_t gt) { | ||
PWM2_DATATYPE pwm2 = PWM2_GET(gt); | ||
PWM3_DATATYPE pwm3 = PWM3_GET(gt); | ||
return gradual_adjust(pwm2, pwm3); | ||
} | ||
|
Oops, something went wrong.