diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 57d049c4..2ba771fc 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -1,10 +1,13 @@ name: build all on: - push: - branches: [ "trunk" ] - pull_request: - branches: [ "trunk" ] + # all branches: + [ push, pull_request ] + # trunk only: + #push: + # branches: [ "trunk" ] + #pull_request: + # branches: [ "trunk" ] jobs: compile: @@ -14,6 +17,14 @@ jobs: - name: Checkout uses: actions/checkout@master + # allow 'git describe' to work, by fetching tags and history + with: + fetch-depth: 0 + fetch-tags: true + + - name: Stop committing version.h + # reject commit if version.h was changed + run: grep 1969-07-20 ui/anduril/version.h - name: Requirements run: | diff --git a/.gitignore b/.gitignore index 1b82302a..d420e340 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,15 @@ +.build/ +.env/ +.venv/ +.*.swo +.*.swp arch/dfp/ env/ hex/ ignore/ old/ +releases/ +venv/ *~ *.cpp *.elf @@ -11,5 +18,3 @@ old/ *.o *.old *.otl -.*.swo -.*.swp diff --git a/ChangeLog.md b/ChangeLog.md index 0aaa392d..a70a3989 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -10,10 +10,75 @@ formats: - Removed - Changed - Documented - - @brand-model: Hardware-specific change (NNNN, NNNN, ...) + - &brand-model: Hardware-specific change (NNNN, NNNN, ...) # Next +# 2023-12-03 + +This release is somewhat higher risk than usual, because so many large things +changed deep in the code. I did major restructuring and refactoring across the +entire project. It should work fine, but be on the lookout for any weird +problems. + +General: + +- Moved from Bzr + Launchpad to **Git + GitHub**, by popular request. +- **Completely reorganized the project** files. Really, a *massive* amount of + restructuring. The flashlight end-user interface is still the same, but + expect to have to learn the code layout from scratch. Read the [README.md] + for info about getting started with the new project layout. +- Added support for AVR DD MCUs like **avr32dd20**. This is the recommended + MCU to use in new flashlights. +- Added ability to use turbo in momentary mode. +- Upgraded **battery voltage resolution** from 0.1V steps to **0.025V** steps. + Battery check has an extra digit which can be 0, 2, 5, or 7 (for example, for + 3.70V, 3.725V, .3.75V, and 3.775V). +- Made Battery Check more consistent, so it's less likely to give different + values on the 1st and 2nd readout. +- Re-calibrated timing on each MCU type, so a 1-second beacon flasher should be + closer to 1 actual second now... mostly. Timing still varies significantly + from one light to another. +- Fixed default bike flasher brightness on some builds. It was sometimes way + too high. +- Fixed RGB aux turning on during momentary mode sometimes. +- Converted documentation to markdown format, and rewrote a lot of it. +- Fixed some build issues with specific compile-time options. +- Changed the format of **version numbers**. It now uses the most recent + release tag instead of the build date, and **may have additional numbers at + the end** to indicate distance from the last official release, and whether + the repo was clean or dirty. Today's release is `MODEL-2023-12-03`. A + derivative built 52 commits later in a dirty repo would look like + `MODEL-2023-12-03-52-1`. + +New lights: + +- Added &thefreeman-avr32dd20-devkit. It's only used for development purposes, + but otherwise it's pretty neat. It'll be the basis for many new lights in + the future. (model 1632dd20) + +Hardware-specific changes: + +- Improved idle efficiency on attiny1616, which was spending entirely too much + time doing math it didn't actually need. +- &hank-\*-boost: Fixed flicker while holding button at moon level. Reduced + ripple on low modes. (0216, 0253, 0273) +- &lumintop-blf-gt: Added smooth steps. Removed a couple other things to make + room. (0321) +- &lumintop-fw3x: Multiple fixes and upgrades... (0314, 0315) + - Fixed thermal regulation. Also fixed the external temperature sensor. + - Made moon much lower, and made ramp much smoother, by upgrading to DSM. + - Fixed the aux RGB pinouts because Lumintop got the wiring backward. + - Added a second build target for people who fixed the wires manually. + - Added red/blue police color strobe. + - Made low modes more efficient with underclocking. Moon should run at least + 4X as long as it did before. + - Fixed party strobe being blurry. + - Added documentation for the FW3X's multiple, uh, quirks. +- &sofirn-lt1s-pro: Disabled manual memory, memory timer, and extended simple + UI by default. Simple mode is simpler, and the factory settings should be + more consistent with other lights now. (0623) + # 2023-10-31 General: @@ -37,30 +102,30 @@ General: New lights: -- @thefreeman-boost21-6a: Added. (1631) +- &thefreeman-boost21-6a: Added. (1631) (very nice HDR boost driver which fits into a FW3A) -- @thefreeman-boost-fwaa: Added. (1632) +- &thefreeman-boost-fwaa: Added. (1632) (very nice AA/li-ion HDR boost driver which fits into a FWAA) Hardware-specific changes: - Upgraded several builds to use delta-sigma modulation (DSM), for lower lows and smoother ramping with less flicker or ripple: - - @blf-lt1 (0621) - - @blf-lt1-t1616 (0622) - - @emisar-d4k-3ch (0151) + - &blf-lt1 (0621) + - &blf-lt1-t1616 (0622) + - &emisar-d4k-3ch (0151) (**dramatically** improves resolution and low modes on its 8-bit channel) - - @noctigon-dm11-boost (0273) - - @noctigon-kr4-boost (0216) - - @noctigon-k1-boost (0253) - - @noctigon-m44 (0143) + - &noctigon-dm11-boost (0273) + - &noctigon-kr4-boost (0216) + - &noctigon-k1-boost (0253) + - &noctigon-m44 (0143) - Upgraded some builds to use dynamic PWM, for lower lows and smoother ramping: - - @blf-q8-t1616, @sofirn-sp36-t1616 (0613, 0614) - - @gchart-fet1-t1616 (1618) - - @noctigon-k1-sbt90 (0252) + - &blf-q8-t1616, &sofirn-sp36-t1616 (0613, 0614) + - &gchart-fet1-t1616 (1618) + - &noctigon-k1-sbt90 (0252) -- @wurkkos-ts10, @wurkkos-ts10-rgbaux: Fixed too-high default ceiling. (0713, 0714) +- &wurkkos-ts10, &wurkkos-ts10-rgbaux: Fixed too-high default ceiling. (0713, 0714) # 2023-10-01 @@ -75,42 +140,42 @@ General: - Fixed some minor post-off voltage display bugs. - Made RGB button brightness update faster in blinky modes. - Fixed bug: Wrong channel after colored factory reset. -- @attiny1616, @attiny1634: Partially fixed oscillating aux LED voltage +- &attiny1616, &attiny1634: Partially fixed oscillating aux LED voltage colors while off. Better than before, but can still happen in some cases. -- @attiny1616: Fixed spurious voltage warnings in sleep mode. (it could +- &attiny1616: Fixed spurious voltage warnings in sleep mode. (it could sometimes go from Lockout mode to Off mode by itself) - Lots of internal refactoring. New lights: -- @emisar-2ch-fet: Added. (0136) -- @emisar-d4k-3ch: Added. (0151) -- @noctigon-m44: Added. (0143) -- @wurkkos-ts10-rgbaux: Added. (0713) +- &emisar-2ch-fet: Added. (0136) +- &emisar-d4k-3ch: Added. (0151) +- &noctigon-m44: Added. (0143) +- &wurkkos-ts10-rgbaux: Added. (0713) Hardware-specific changes: -- @ff-e01, @ff-pl47, @ff-pl47g2: Enabled smooth steps instead of SOS mode. +- &ff-e01, &ff-pl47, &ff-pl47g2: Enabled smooth steps instead of SOS mode. (0421, 0422, 0423, 0441) -- @emisar-2ch, @noctigon-m44: Added RGB aux channel modes. (0135, 0143) -- @emisar-2ch-fet, @noctigon-k9.3: New ramps with better-calibrated shape. +- &emisar-2ch, &noctigon-m44: Added RGB aux channel modes. (0135, 0143) +- &emisar-2ch-fet, &noctigon-k9.3: New ramps with better-calibrated shape. (0136, 0261) -- @emisar-d4v2-nofet: New ramp table. (0115) -- @emisar-d4sv2-tintramp: Removed / renamed. (0135, 0136) -- @noctigon-k9.3: Fixed years-old mess. Merged builds, converted to +- &emisar-d4v2-nofet: New ramp table. (0115) +- &emisar-d4sv2-tintramp: Removed / renamed. (0135, 0136) +- &noctigon-k9.3: Fixed years-old mess. Merged builds, converted to multi-channel, removed old builds, generally got K9.3 working quite a bit better. (0261, 0262, 0263, 0265, 0266, 0267) -- @noctigon-m44: Lower moon, and greatly reduced flicker. (0143) -- @sofirn-lt1s-pro: Allow configuring the blink channel. (0623) -- @wurkkos: Raised default temperature limit to 50 C. (07xx) -- @wurkkos-ts10: Better / smoother ramp. (0713, 0714) +- &noctigon-m44: Lower moon, and greatly reduced flicker. (0143) +- &sofirn-lt1s-pro: Allow configuring the blink channel. (0623) +- &wurkkos: Raised default temperature limit to 50 C. (07xx) +- &wurkkos-ts10: Better / smoother ramp. (0713, 0714) # 2023-06-29 - Fixed red aux blink on 1st frame of post-off voltage display - Removed Harry Potter references because its author (J.K. Rowling) spreads hate -- @noctigon-kr4: Fixed thermal regulation (0211, 0212, 0213, 0214, 0215, 0216) +- &noctigon-kr4: Fixed thermal regulation (0211, 0212, 0213, 0214, 0215, 0216) # 2023-05-30 @@ -126,18 +191,18 @@ Hardware-specific changes: help ensure it works on all lights. - Minor code changes with no runtime impact - Documented new version check format -- @wurkkos: Added red+blue police strobe (0715, 0716, 0717) -- @noctigon-kr4: Broke thermal regulation (oops) (0211, 0212, 0213, 0214, +- &wurkkos: Added red+blue police strobe (0715, 0716, 0717) +- &noctigon-kr4: Broke thermal regulation (oops) (0211, 0212, 0213, 0214, 0215, 0216) -- @noctigon-kr4: Use 7 aux channel modes instead of 3 (0211, 0212, 0213, 0214, +- &noctigon-kr4: Use 7 aux channel modes instead of 3 (0211, 0212, 0213, 0214, 0215, 0216) -- @emisar-d4v2: Changed number blinks from aux to main LEDs by default (0113, +- &emisar-d4v2: Changed number blinks from aux to main LEDs by default (0113, 0114, 0115, 0123) # 2023-05-17 -- @noctigon-dm11-12v: Renamed to noctigon-dm11-boost (0273) -- @noctigon-dm11-boost: Now supported in multi-channel branch (0273) +- &noctigon-dm11-12v: Renamed to noctigon-dm11-boost (0273) +- &noctigon-dm11-boost: Now supported in multi-channel branch (0273) # 2023-05-02 @@ -160,14 +225,14 @@ Hardware-specific changes: it to the value it saved, which was wrong) - Documented ramp 6C, ramp 4C, ramp 4H, lockout 3H, battcheck 3C, and post-off voltage display config -- @emisar-d4v2: Added the rest of the aux RGB colors as channel modes, and set +- &emisar-d4v2: Added the rest of the aux RGB colors as channel modes, and set aux "white" as the mode it uses to blink out numbers (0113, 0114, 0115, 0123) -- @wurkkos-ts10: Converted to multi-channel, and gave it a new ramp with +- &wurkkos-ts10: Converted to multi-channel, and gave it a new ramp with better low modes (0714) -- @wurkkos-ts25: Converted to multi-channel, and gave it a smoother ramp +- &wurkkos-ts25: Converted to multi-channel, and gave it a smoother ramp (0715) -- @wurkkos: Added Wurkkos FC13 and TS11 (0716, 0717) +- &wurkkos: Added Wurkkos FC13 and TS11 (0716, 0717) # 2023-04-29 @@ -178,13 +243,13 @@ Hardware-specific changes: - Made 3H+ use mem level instead of lowest moon (this is needed for making the channel discernible, and also helps make aux LED controls stand out more) -- @emisar, @noctigon: Added Extended Simple UI to Hank's config, so a few more +- &emisar, &noctigon: Added Extended Simple UI to Hank's config, so a few more features are allowed in simple mode -- @emisar-d4v2, @noctigon-kr4: Slightly smaller ROM size -- @emisar-d4sv2: Converted to multi-channel, and updated it to use dynamic PWM +- &emisar-d4v2, &noctigon-kr4: Slightly smaller ROM size +- &emisar-d4sv2: Converted to multi-channel, and updated it to use dynamic PWM for a smoother ramp with lower lows (0133, 0134) -- @noctigon-kr4: Converted to multi-channel (0211, 0212, 0213, 0214) -- @noctigon-kr4: Don't blink at top of regulated power (0211, 0213, 0214) +- &noctigon-kr4: Converted to multi-channel (0211, 0212, 0213, 0214) +- &noctigon-kr4: Don't blink at top of regulated power (0211, 0213, 0214) # 2023-04-28 @@ -196,8 +261,8 @@ Hardware-specific changes: default) - Changed tactical mode default config: only use 2-color strobe if it's on main LEDs, not aux LEDs -- @emisar-d4v2: Smoother ramp (0113, 0114) -- @emisar-d4v2: Added hidden channel modes for RGB aux LEDs (0113, 0114, 0115) +- &emisar-d4v2: Smoother ramp (0113, 0114) +- &emisar-d4v2: Added hidden channel modes for RGB aux LEDs (0113, 0114, 0115) # 2023-04-27 @@ -207,7 +272,7 @@ Hardware-specific changes: - Fixed unnecessary flickering when changing channel modes from/to the same value - Fixed sleep voltage measurement on attiny1616 -- @noctigon-kr4-tintramp: Converted to multi-channel, renamed to +- &noctigon-kr4-tintramp: Converted to multi-channel, renamed to noctigon-kr4-2ch (0215) # 2023-04-25 @@ -226,15 +291,15 @@ Hardware-specific changes: (this change was obsoleted soon by a better post-off voltage display) - Broke sleep voltage measurement on attiny1616 (oops) - Changed internal details for how gradual ramping works -- @emisar-d4sv2-tintramp: Converted to multi-channel, renamed to emisar-2ch. +- &emisar-d4sv2-tintramp: Converted to multi-channel, renamed to emisar-2ch. (0135) -- @sofirn-lt1s-pro: Updated to use today's new code internals (0623) +- &sofirn-lt1s-pro: Updated to use today's new code internals (0623) # 2023-04-19 - Added stepped tint ramping - Documented new channel modes system -- @sofirn-lt1s-pro: Added white-only auto-tint mode (0623) +- &sofirn-lt1s-pro: Added white-only auto-tint mode (0623) # Older: TODO diff --git a/MODELS b/MODELS index 87987dd8..a77b178f 100644 --- a/MODELS +++ b/MODELS @@ -1,80 +1,82 @@ -Models: 70 +Models: 72 -Model Name MCU ------ ---- --- -0111 hank-emisar-d4 attiny85 -0112 hank-emisar-d4-219 attiny85 -0113 hank-emisar-d4v2 attiny1634 -0114 hank-emisar-d4v2-219 attiny1634 -0115 hank-emisar-d4v2-nofet attiny1634 -0121 hank-emisar-d1 attiny85 -0122 hank-emisar-d1s attiny85 -0123 hank-emisar-d1v2-7135-fet attiny1634 -0124 hank-emisar-d1v2-linear-fet attiny1634 -0125 hank-emisar-d1v2-nofet attiny1634 -0131 hank-emisar-d4s attiny85 -0132 hank-emisar-d4s-219 attiny85 -0133 hank-emisar-d4sv2 attiny1634 -0134 hank-emisar-d4sv2-219 attiny1634 -0135 hank-emisar-2ch attiny1634 -0136 hank-emisar-2ch-fet attiny1634 -0141 hank-emisar-d18 attiny85 -0142 hank-emisar-d18-219 attiny85 -0143 hank-noctigon-m44 attiny1634 -0151 hank-emisar-d4k-3ch attiny1634 -0211 hank-noctigon-kr4 attiny1634 -0212 hank-noctigon-kr4-nofet attiny1634 -0213 hank-noctigon-kr4-219 attiny1634 -0214 hank-noctigon-kr4-219b attiny1634 -0215 hank-noctigon-kr4-2ch attiny1634 -0216 hank-noctigon-kr4-boost attiny1634 -0251 hank-noctigon-k1 attiny1634 -0252 hank-noctigon-k1-sbt90 attiny1634 -0253 hank-noctigon-k1-boost attiny1634 -0261 hank-noctigon-k9.3 attiny1634 -0262 hank-noctigon-k9.3-nofet attiny1634 -0263 hank-noctigon-k9.3-219 attiny1634 -0265 noctigon-k9.3-tintramp-nofet attiny1634 (old, use 0262) -0266 noctigon-k9.3-tintramp-fet attiny1634 (old, use 0261) -0267 noctigon-k9.3-tintramp-219 attiny1634 (old, use 0263) -0271 hank-noctigon-dm11 attiny1634 -0272 hank-noctigon-dm11-nofet attiny1634 -0273 hank-noctigon-dm11-boost attiny1634 -0274 hank-noctigon-dm11-sbt90 attiny1634 -0311 lumintop-fw3a attiny85 -0312 lumintop-fw3a-219 attiny85 -0313 lumintop-fw3a-nofet attiny85 -0314 lumintop-fw3x-lume1 attiny1634 -0321 lumintop-blf-gt attiny85 -0322 lumintop-blf-gt-mini attiny85 -0411 fireflies-rot66 attiny85 -0412 fireflies-rot66-219 attiny85 -0413 fireflies-rot66g2 attiny85 -0421 fireflies-pl47 attiny85 -0422 fireflies-pl47-219 attiny85 -0423 fireflies-pl47g2 attiny85 -0441 fireflies-e01 attiny85 -0511 mateminco-mf01s attiny85 -0521 mateminco-mf01-mini attiny85 -0531 mateminco-mt35-mini attiny85 -0611 sofirn-blf-q8 attiny85 -0612 sofirn-sp36 attiny85 -0613 sofirn-blf-q8-t1616 attiny1616 -0614 sofirn-sp36-t1616 attiny1616 -0621 sofirn-blf-lt1 attiny85 -0622 sofirn-blf-lt1-t1616 attiny1616 -0623 sofirn-lt1s-pro attiny1616 -0631 sofirn-sp10-pro attiny1616 -0632 sofirn-sc21-pro attiny1616 -0713 wurkkos-ts10-rgbaux attiny1616 -0714 wurkkos-ts10 attiny1616 -0715 wurkkos-ts25 attiny1616 -0716 wurkkos-fc13 attiny1616 -0717 wurkkos-ts11 attiny1616 -1618 gchart-fet1-t1616 attiny1616 -1630 thefreeman-lin16dac attiny1616 -1631 thefreeman-boost21-6a attiny1616 -1632 thefreeman-boost-fwaa attiny1616 +Model MCU Name +----- --- ---- +0111 attiny85 hank-emisar-d4 +0112 attiny85 hank-emisar-d4-219 +0113 attiny1634 hank-emisar-d4v2 +0114 attiny1634 hank-emisar-d4v2-219 +0115 attiny1634 hank-emisar-d4v2-nofet +0121 attiny85 hank-emisar-d1 +0122 attiny85 hank-emisar-d1s +0123 attiny1634 hank-emisar-d1v2-7135-fet +0124 attiny1634 hank-emisar-d1v2-linear-fet +0125 attiny1634 hank-emisar-d1v2-nofet +0131 attiny85 hank-emisar-d4s +0132 attiny85 hank-emisar-d4s-219 +0133 attiny1634 hank-emisar-d4sv2 +0134 attiny1634 hank-emisar-d4sv2-219 +0135 attiny1634 hank-emisar-2ch +0136 attiny1634 hank-emisar-2ch-fet +0141 attiny85 hank-emisar-d18 +0142 attiny85 hank-emisar-d18-219 +0143 attiny1634 hank-noctigon-m44 +0151 attiny1634 hank-emisar-d4k-3ch +0211 attiny1634 hank-noctigon-kr4 +0212 attiny1634 hank-noctigon-kr4-nofet +0213 attiny1634 hank-noctigon-kr4-219 +0214 attiny1634 hank-noctigon-kr4-219b +0215 attiny1634 hank-noctigon-kr4-2ch +0216 attiny1634 hank-noctigon-kr4-boost +0251 attiny1634 hank-noctigon-k1 +0252 attiny1634 hank-noctigon-k1-sbt90 +0253 attiny1634 hank-noctigon-k1-boost +0261 attiny1634 hank-noctigon-k9.3 +0262 attiny1634 hank-noctigon-k9.3-nofet +0263 attiny1634 hank-noctigon-k9.3-219 +0265 attiny1634 noctigon-k9.3-tintramp-nofet (old, use 0262) +0266 attiny1634 noctigon-k9.3-tintramp-fet (old, use 0261) +0267 attiny1634 noctigon-k9.3-tintramp-219 (old, use 0263) +0271 attiny1634 hank-noctigon-dm11 +0272 attiny1634 hank-noctigon-dm11-nofet +0273 attiny1634 hank-noctigon-dm11-boost +0274 attiny1634 hank-noctigon-dm11-sbt90 +0311 attiny85 lumintop-fw3a +0312 attiny85 lumintop-fw3a-219 +0313 attiny85 lumintop-fw3a-nofet +0314 attiny1634 lumintop-fw3x-lume1 +0315 attiny1634 lumintop-fw3x-lume1-rgbswap +0321 attiny85 lumintop-blf-gt +0322 attiny85 lumintop-blf-gt-mini +0411 attiny85 fireflies-rot66 +0412 attiny85 fireflies-rot66-219 +0413 attiny85 fireflies-rot66g2 +0421 attiny85 fireflies-pl47 +0422 attiny85 fireflies-pl47-219 +0423 attiny85 fireflies-pl47g2 +0441 attiny85 fireflies-e01 +0511 attiny85 mateminco-mf01s +0521 attiny85 mateminco-mf01-mini +0531 attiny85 mateminco-mt35-mini +0611 attiny85 sofirn-blf-q8 +0612 attiny85 sofirn-sp36 +0613 attiny1616 sofirn-blf-q8-t1616 +0614 attiny1616 sofirn-sp36-t1616 +0621 attiny85 sofirn-blf-lt1 +0622 attiny1616 sofirn-blf-lt1-t1616 +0623 attiny1616 sofirn-lt1s-pro +0631 attiny1616 sofirn-sp10-pro +0632 attiny1616 sofirn-sc21-pro +0713 attiny1616 wurkkos-ts10-rgbaux +0714 attiny1616 wurkkos-ts10 +0715 attiny1616 wurkkos-ts25 (may need 0716 / 0717 on some models) +0716 attiny1616 wurkkos-fc13 (may ship with 0715) (also, TS30S Pro) +0717 attiny1616 wurkkos-ts11 (may ship with 0715) +1618 attiny1616 gchart-fet1-t1616 +1630 attiny1616 thefreeman-lin16dac +1631 attiny1616 thefreeman-boost21-mp3431-hdr-dac-argb +1632 attiny1616 thefreeman-boost-fwaa-mp3432-hdr-dac-rgb +1632dd20 avr32dd20 thefreeman-avr32dd20-devkit Duplicates: diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..2f3aaedb --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +# Tiny Makefile to simply "exec ./make $*" +# Copyright (C) 2023 Selene ToyKeeper +# SPDX-License-Identifier: GPL-3.0-or-later + +# Note: Does not pass args in the form "-a", "--arg", or "VAR=value" +# because 'make' does not put those into $MAKECMDGOALS +# but this is still helpful in case the user forgets the './' before 'make' + +# for 'make foo bar baz', don't run 3 times +# (generate no-op rules for args 2+) +ARGS := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS)) +$(eval $(ARGS):;@:) + +# handle the case with no args +all: + @./make + +# catch everything else and parse the command line ourselves +.PHONY: % +%: + @./make $(MAKECMDGOALS) + +# handle targets with the same name as a dir, +# because 'make' skips those otherwise +.PHONY: docs +docs: + @./make docs + diff --git a/README.md b/README.md index ba0786e5..3690cb30 100644 --- a/README.md +++ b/README.md @@ -117,12 +117,12 @@ If you use `pymcuprog` to flash firmware, a few extras are needed: ```sh sudo apt install python3 python3-pip python3-venv -python3 -m venv env -source env/bin/activate +python3 -m venv .venv +source .venv/bin/activate pip install pymcuprog ``` -You'll need to `source env/bin/activate` every time you start a fresh shell, +You'll need to `source .venv/bin/activate` every time you start a fresh shell, if you want to use pymcuprog. The activation lasts until the shell is closed or until you run `deactivate`. diff --git a/arch/attiny1616.c b/arch/attiny1616.c new file mode 100644 index 00000000..c5499ddc --- /dev/null +++ b/arch/attiny1616.c @@ -0,0 +1,225 @@ +// arch/attiny1616.c: attiny1616 support functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "arch/attiny1616.h" + +////////// clock speed / delay stuff ////////// + +inline void mcu_clock_speed() { + // TODO: allow hwdef to define a base clock speed + // set up the system clock to run at 10 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, + CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); +} + +///// clock dividers +// this should work, but needs further validation +inline void clock_prescale_set(uint8_t n) { + cli(); + _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, n); // Set the prescaler + while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) {} // wait for clock change to finish + sei(); +} + + +////////// ADC voltage / temperature ////////// + +inline void mcu_set_admux_therm() { + // put the ADC in temperature mode + // attiny1616 datasheet section 30.3.2.6 + mcu_set_adc0_vref(VREF_ADC0REFSEL_1V1_gc); // Set Vbg ref to 1.1V + ADC0.MUXPOS = ADC_MUXPOS_TEMPSENSE_gc; // read temperature + ADC0.CTRLB = ADC_SAMPNUM_ACC4_gc; // 10-bit result + 4x oversampling + ADC0.CTRLC = ADC_SAMPCAP_bm + | ADC_PRESC_DIV16_gc + | ADC_REFSEL_INTREF_gc; // Internal ADC reference +} + +inline void mcu_set_admux_voltage() { + // Enabled, free-running (aka, auto-retrigger), run in standby + ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm | ADC_RUNSTBY_bm; + // set a INITDLY value because the AVR manual says so (section 30.3.5) + // (delay 1st reading until Vref is stable) + ADC0.CTRLD |= ADC_INITDLY_DLY16_gc; + #ifdef USE_VOLTAGE_DIVIDER // measure an arbitrary pin + // result = resolution * Vdiv / 1.1V + mcu_set_adc0_vref(VREF_ADC0REFSEL_1V1_gc); // Set Vbg ref to 1.1V + ADC0.MUXPOS = ADMUX_VOLTAGE_DIVIDER; // read the requested ADC pin + ADC0.CTRLB = ADC_SAMPNUM_ACC4_gc; // 12-bit result, 4x oversampling + ADC0.CTRLC = ADC_SAMPCAP_bm + | ADC_PRESC_DIV16_gc + | ADC_REFSEL_INTREF_gc; // Use internal ADC reference + #else // measure VDD pin + // result = resolution * 1.5V / Vbat + mcu_set_adc0_vref(VREF_ADC0REFSEL_1V5_gc); // Set Vbg ref to 1.5V + ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc; // read internal reference + ADC0.CTRLB = ADC_SAMPNUM_ACC4_gc; // 12-bit result, 4x oversampling + ADC0.CTRLC = ADC_SAMPCAP_bm + | ADC_PRESC_DIV16_gc + | ADC_REFSEL_VDDREF_gc; // Vdd (Vcc) be ADC reference + #endif +} + +inline void mcu_adc_sleep_mode() { + set_sleep_mode(SLEEP_MODE_STANDBY); +} + +inline void mcu_adc_start_measurement() { + ADC0.INTCTRL |= ADC_RESRDY_bm; // enable interrupt + ADC0.COMMAND |= ADC_STCONV_bm; // actually start measuring +} + +/* +inline void mcu_adc_on() { + VREF.CTRLA |= VREF_ADC0REFSEL_1V1_gc; // Set Vbg ref to 1.1V + // Enabled, free-running (aka, auto-retrigger), run in standby + ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm | ADC_RUNSTBY_bm; + // set a INITDLY value because the AVR manual says so (section 30.3.5) + // (delay 1st reading until Vref is stable) + ADC0.CTRLD |= ADC_INITDLY_DLY16_gc; + hwdef_set_admux_voltage(); +} +*/ + +inline void mcu_adc_off() { + ADC0.CTRLA &= ~(ADC_ENABLE_bm); // disable the ADC +} + +inline void mcu_adc_vect_clear() { + ADC0.INTFLAGS = ADC_RESRDY_bm; // clear the interrupt +} + +inline uint16_t mcu_adc_result_temp() { + // just return left-aligned ADC result, don't convert to calibrated units + //return ADC0.RES << 6; + return ADC0.RES << 4; +} + +inline uint16_t mcu_adc_result_volts() { + // ADC has no left-aligned mode, so left-align it manually + return ADC0.RES << 4; +} + +inline uint8_t mcu_vdd_raw2cooked(uint16_t measurement) { + // In : 65535 * 1.5 / Vbat + // Out: uint8_t: Vbat * 40 + // 1.5 = ADC Vref + #if 0 + // 1024 = how much ADC resolution we're using (10 bits) + // (12 bits available, but it costs an extra 84 bytes of ROM to calculate) + uint8_t vbat40 = (uint16_t)(40 * 1.5 * 1024) / (measurement >> 6); + #else + // ... spend the extra 84 bytes of ROM for better precision + // 4096 = how much ADC resolution we're using (12 bits) + uint8_t vbat40 = (uint32_t)(40 * 1.5 * 4096) / (measurement >> 4); + #endif + return vbat40; +} + +#if 0 // fine voltage, 0 to 10.24V in 1/6400th V steps +inline uint16_t mcu_vdd_raw2fine(uint16_t measurement) { + // In : 65535 * 1.5 / Vbat + // Out: 65535 * (Vbat / 10) / 1.024V + uint16_t voltage = ((uint32_t)(1.5 * 4096 * 100 * 64 * 16) / measurement; + return voltage; +} +#endif + +#ifdef USE_VOLTAGE_DIVIDER +inline uint8_t mcu_vdivider_raw2cooked(uint16_t measurement) { + // In : 4095 * Vdiv / 1.1V + // Out: uint8_t: Vbat * 40 + // Vdiv = Vbat / 4.3 (typically) + // 1.1 = ADC Vref + const uint16_t adc_per_volt = + (((uint16_t)ADC_44 << 4) - ((uint16_t)ADC_22 << 4)) + / (4 * (44-22)); + uint8_t result = measurement / adc_per_volt; + return result; +} +#endif + +inline uint16_t mcu_temp_raw2cooked(uint16_t measurement) { + // convert raw ADC values to calibrated temperature + // In: ADC raw temperature (16-bit, or 12-bit left-aligned) + // Out: Kelvin << 6 + // Precision: 1/64th Kelvin (but noisy) + // attiny1616 datasheet section 30.3.2.6 + uint8_t sigrow_gain = SIGROW.TEMPSENSE0; // factory calibration data + int8_t sigrow_offset = SIGROW.TEMPSENSE1; + const uint32_t scaling_factor = 65536; // use all 16 bits of ADC data + uint32_t temp = measurement - (sigrow_offset << 6); + temp *= sigrow_gain; // 24-bit result + temp += scaling_factor / 8; // Add 1/8th K to get correct rounding on later divisions + temp = temp >> 8; // change (K << 14) to (K << 6) + return temp; // left-aligned uint16_t, 0 to 1023.98 Kelvin +} + +inline uint8_t mcu_adc_lsb() { + //return (ADCL >> 6) + (ADCH << 2); + return ADC0.RESL; // right aligned, not left... so should be equivalent? +} + + +////////// WDT ////////// + +inline void mcu_wdt_active() { + RTC.PITINTCTRL = RTC_PI_bm; // enable the Periodic Interrupt + while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated + // Period = 16ms (64 Hz), enable the PI Timer + RTC.PITCTRLA = RTC_PERIOD_CYC512_gc | RTC_PITEN_bm; +} + +inline void mcu_wdt_standby() { + RTC.PITINTCTRL = RTC_PI_bm; // enable the Periodic Interrupt + while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated + // Set period (64 Hz / STANDBY_TICK_SPEED = 8 Hz), enable the PI Timer + RTC.PITCTRLA = (1<<6) | (STANDBY_TICK_SPEED<<3) | RTC_PITEN_bm; +} + +inline void mcu_wdt_stop() { + while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated + RTC.PITCTRLA = 0; // Disable the PI Timer +} + +inline void mcu_wdt_vect_clear() { + RTC.PITINTFLAGS = RTC_PI_bm; // clear the PIT interrupt flag +} + + +////////// PCINT - pin change interrupt (e-switch) ////////// + +inline void mcu_switch_vect_clear() { + // Write a '1' to clear the interrupt flag + SWITCH_INTFLG |= (1 << SWITCH_PIN); +} + +inline void mcu_pcint_on() { + SWITCH_ISC_REG |= PORT_ISC_BOTHEDGES_gc; +} + +inline void mcu_pcint_off() { + SWITCH_ISC_REG &= ~(PORT_ISC_gm); +} + + +////////// misc ////////// + +void reboot() { + // put the WDT in hard reset mode, then trigger it + cli(); + // Enable, timeout 8ms + _PROTECTED_WRITE(WDT.CTRLA, WDT_PERIOD_8CLK_gc); + sei(); + wdt_reset(); + while (1) {} +} + +inline void prevent_reboot_loop() { + // prevent WDT from rebooting MCU again + RSTCTRL.RSTFR &= ~(RSTCTRL_WDRF_bm); // reset status flag + wdt_disable(); // from avr/wdt.h +} + diff --git a/arch/attiny1616.h b/arch/attiny1616.h new file mode 100644 index 00000000..940973ee --- /dev/null +++ b/arch/attiny1616.h @@ -0,0 +1,134 @@ +// arch/attiny1616.h: attiny1616 support header +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// FIXME: remove this +#define AVRXMEGA3 + +////////// clock speed / delay stuff ////////// + +#define F_CPU 10000000UL +#define BOGOMIPS (F_CPU/4350) +#define DELAY_ZERO_TIME 1020 + +inline void mcu_clock_speed(); + +///// clock dividers +// this should work, but needs further validation +inline void clock_prescale_set(uint8_t n); + +// TODO: allow hwdef to define a base clock speed, +// and adjust these values accordingly +typedef enum +{ + // Actual clock is 20 MHz, but assume that 10 MHz is the top speed and work from there + // TODO: measure PWM speed and power use at 1.25/2.5/5/10 MHz, to determine which speeds are optimal + clock_div_1 = (CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm), // 10 MHz + clock_div_2 = (CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm), // 5 MHz + clock_div_4 = (CLKCTRL_PDIV_8X_gc | CLKCTRL_PEN_bm), // 2.5 MHz + clock_div_8 = (CLKCTRL_PDIV_16X_gc | CLKCTRL_PEN_bm), // 1.25 MHz + clock_div_16 = (CLKCTRL_PDIV_32X_gc | CLKCTRL_PEN_bm), // 625 kHz + clock_div_32 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 312 kHz, max without changing to the 32 kHz ULP + clock_div_64 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 312 kHz + clock_div_128 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 312 kHz + clock_div_256 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm) // 312 kHz +} clock_div_t; + + +////////// DAC controls ////////// + +#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref +#define DAC_VREF VREF.CTRLA // 0.55V, 1.1V, 1.5V, 2.5V, or 4.3V + +// set only the relevant bits of the Vref register +#define mcu_set_dac_vref(x) \ + VREF.CTRLA = x | (VREF.CTRLA & (~VREF_DAC0REFSEL_gm)); + +// Vref values +// (for the DAC bits, not the ADC bits) +#define V05 V055 +#define V055 VREF_DAC0REFSEL_0V55_gc +#define V11 VREF_DAC0REFSEL_1V1_gc +#define V25 VREF_DAC0REFSEL_2V5_gc +#define V43 VREF_DAC0REFSEL_4V34_gc +#define V15 VREF_DAC0REFSEL_1V5_gc + +////////// ADC voltage / temperature ////////// + +// set only the relevant bits of the Vref register +#define mcu_set_adc0_vref(x) \ + VREF.CTRLA = x | (VREF.CTRLA & (~VREF_ADC0REFSEL_gm)); + +#define hwdef_set_admux_therm mcu_set_admux_therm +inline void mcu_set_admux_therm(); + +#define hwdef_set_admux_voltage mcu_set_admux_voltage +inline void mcu_set_admux_voltage(); + +inline void mcu_adc_sleep_mode(); + +inline void mcu_adc_start_measurement(); + +//inline void mcu_adc_on(); + +inline void mcu_adc_off(); + +#define ADC_vect ADC0_RESRDY_vect +inline void mcu_adc_vect_clear(); + +//// both readings are left-aligned +//inline uint16_t mcu_adc_result(); + +// read ADC differently for temperature and voltage +#define MCU_ADC_RESULT_PER_TYPE +inline uint16_t mcu_adc_result_temp(); +inline uint16_t mcu_adc_result_volts(); + +// return Volts * 40, range 0 to 6.375V +#define voltage_raw2cooked mcu_vdd_raw2cooked +inline uint8_t mcu_vdd_raw2cooked(uint16_t measurement); +inline uint8_t mcu_vdivider_raw2cooked(uint16_t measurement); + +// return (temp in Kelvin << 6) +#define temp_raw2cooked mcu_temp_raw2cooked +inline uint16_t mcu_temp_raw2cooked(uint16_t measurement); + +inline uint8_t mcu_adc_lsb(); + + +////////// WDT ////////// + +inline void mcu_wdt_active(); + +inline void mcu_wdt_standby(); + +inline void mcu_wdt_stop(); + +// *** Note for the AVRXMEGA3 (1-Series, eg 816 and 817), the WDT +// is not used for time-based interrupts. A new peripheral, the +// Periodic Interrupt Timer ("PIT") is used for this purpose. + +#define WDT_vect RTC_PIT_vect +inline void mcu_wdt_vect_clear(); + + +////////// PCINT - pin change interrupt (e-switch) ////////// + +// set these in hwdef +//#define SWITCH_PORT PINA +//#define SWITCH_VECT PCINT0_vect + +inline void mcu_switch_vect_clear(); + +inline void mcu_pcint_on(); + +inline void mcu_pcint_off(); + + +////////// misc ////////// + +void reboot(); + +inline void prevent_reboot_loop(); + diff --git a/arch/attiny1634.c b/arch/attiny1634.c new file mode 100644 index 00000000..e29d1c3e --- /dev/null +++ b/arch/attiny1634.c @@ -0,0 +1,214 @@ +// arch/attiny1634.c: attiny85 support functions +// Copyright (C) 2014-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "arch/attiny1634.h" + +////////// clock speed / delay stuff ////////// + +inline void mcu_clock_speed() { + // TODO? + // (or not; clock speed is set by the fuses) + // attiny1634 datasheet 6.5 + // CLKSR = [OSCRDY, CSTR, CKOUT_IO, SUT, CKSEL3/2/1/0] + // default 8MHz calibrated internal clock: SUT=0, CKSEL=0b0010 + #if 0 + cli(); + CCP = 0xD8; + CLKSR = 0b01000010; + CCP = 0xD8; + CLKPR = 0; // CLK / 1 = full speed, 8 MHz + sei(); + #endif +} + +///// clock dividers +inline void clock_prescale_set(uint8_t n) { + cli(); + // _PROTECTED_WRITE(CLKPR, n); + CCP = 0xD8; + CLKPR = n; + sei(); +} + +////////// default hw_setup() ////////// + + +////////// ADC voltage / temperature ////////// + +inline void mcu_set_admux_therm() { + // put the ADC in temperature mode + // DS table 19-3, 19-4, internal sensor / 1.1V ref + // [refs1, refs0, refen, adc0en, mux3, mux2, mux1, mux0] + // refs=0b10 : internal 1.1V ref + // mux=0b1110 : internal temperature sensor + //#define ADMUX_THERM 0b10001110 + ADMUX = ADMUX_THERM; + // other stuff is already set, so no need to re-set it +} + +inline void mcu_set_admux_voltage() { + // put the ADC in battery voltage measurement mode + // TODO: avr datasheet references + #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7 + ADMUX = ADMUX_VOLTAGE_DIVIDER; + // disable digital input on divider pin to reduce power consumption + // TODO: this should be in hwdef init, not here + VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); + #else // VCC / 1.1V reference + ADMUX = ADMUX_VCC; + // disable digital input on VCC pin to reduce power consumption + //VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); // FIXME: unsure how to handle for VCC pin + #endif + //ACSRA |= (1 << ACD); // turn off analog comparator to save power + // ADCSRB: [VDEN, VDPD, -, -, ADLAR, ADTS2, ADTS1, ADTS0] + ADCSRB = (1 << ADLAR); // left-adjust, free-running + //ADCSRB = 0; // right-adjust, free-running +} + +inline void mcu_adc_sleep_mode() { + set_sleep_mode(SLEEP_MODE_ADC); +} + +inline void mcu_adc_start_measurement() { + // [ADEN, ADSC, ADATE, adif, ADIE, ADPS2, ADPS1, ADPS0] + ADCSRA = (1 << ADEN) // enable + | (1 << ADSC) // start + | (1 << ADATE) // auto-retrigger + | (1 << ADIE) // interrupt enable + | ADC_PRSCL; // prescale +} + +inline void mcu_adc_off() { + ADCSRA &= ~(1<> 6); + #else + // ... spend the extra 84 bytes of ROM for better precision + // 4096 = how much ADC resolution we're using (12 bits) + uint8_t vbat40 = (uint32_t)(40 * 1.1 * 4096) / (measurement >> 4); + #endif + return vbat40; +} + + +#ifdef USE_VOLTAGE_DIVIDER +inline uint8_t mcu_vdivider_raw2cooked(uint16_t measurement) { + // In : 4095 * Vdiv / 1.1V + // Out: uint8_t: Vbat * 40 + // Vdiv = Vbat / 4.3 (typically) + // 1.1 = ADC Vref + const uint16_t adc_per_volt = + (((uint16_t)ADC_44 << 4) - ((uint16_t)ADC_22 << 4)) + / (4 * (44-22)); + uint8_t result = measurement / adc_per_volt; + return result; +} +#endif + +inline uint16_t mcu_temp_raw2cooked(uint16_t measurement) { + // convert raw ADC values to calibrated temperature + // In: ADC raw temperature (16-bit, or left-aligned) + // Out: Kelvin << 6 + // Precision: 1/64th Kelvin (but noisy) + // attiny1634 datasheet section 19.12 + // nothing to do; input value is already "cooked" + return measurement; +} + +inline uint8_t mcu_adc_lsb() { + // left-adjusted mode: + return (ADCL >> 6) + (ADCH << 2); + // right-adjusted mode: + // datasheet 19.13.3.2: + // "When ADCL is read, the ADC Data Register is not updated + // until ADCH is read. ... ADCL must be read first, then ADCH." + // So... gotta read it even if not needed? + // (the value doesn't matter here, the lower bits are only used + // for generating some random seed data) + //return ADCL + ADCH; +} + + +////////// WDT ////////// + +inline void mcu_wdt_active() { + wdt_reset(); // Reset the WDT + WDTCSR = (1<= 1 + DDRB |= (1 << PWM1_PIN); + TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) + TCCR0A = PHASE; + #if (PWM1_PIN == PB4) // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = 255; // Set ceiling value to maximum + #endif + #endif + // tint ramping needs second channel enabled, + // despite PWM_CHANNELS being only 1 + #if (PWM_CHANNELS >= 2) || defined(USE_TINT_RAMPING) + DDRB |= (1 << PWM2_PIN); + #if (PWM2_PIN == PB4) // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = 255; // Set ceiling value to maximum + #endif + #endif + #if PWM_CHANNELS >= 3 + DDRB |= (1 << PWM3_PIN); + #if (PWM3_PIN == PB4) // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = 255; // Set ceiling value to maximum + #endif + #endif + #if PWM_CHANNELS >= 4 + // 4th PWM channel is ... not actually supported in hardware :( + DDRB |= (1 << PWM4_PIN); + //OCR1C = 255; // Set ceiling value to maximum + TCCR1 = 1<> 6); + return vbat40; +} + + +#ifdef USE_VOLTAGE_DIVIDER +inline uint8_t mcu_vdivider_raw2cooked(uint16_t measurement) { + // In : 4095 * Vdiv / 1.1V + // Out: uint8_t: Vbat * 40 + // Vdiv = Vbat / 4.3 (typically) + // 1.1 = ADC Vref + const uint16_t adc_per_volt = + (((uint16_t)ADC_44 << 4) - ((uint16_t)ADC_22 << 4)) + / (4 * (44-22)); + uint8_t result = measurement / adc_per_volt; + return result; +} +#endif + +inline uint16_t mcu_temp_raw2cooked(uint16_t measurement) { + // convert raw ADC values to calibrated temperature + // In: ADC raw temperature (16-bit, or left-aligned) + // Out: Kelvin << 6 + // Precision: 1/64th Kelvin (but noisy) + // attiny1634 datasheet section 19.12 + // nothing to do; input value is already "cooked" + return measurement; +} + +inline uint8_t mcu_adc_lsb() { + // left-adjusted mode: + return (ADCL >> 6) + (ADCH << 2); +} + + +////////// WDT ////////// + +inline void mcu_wdt_active() { + // interrupt every 16ms + //cli(); // Disable interrupts + wdt_reset(); // Reset the WDT + WDTCR |= (1<= 25 us * Fclk_adc (no sample delay needed) + ADC0.CTRLD = ADC_INITDLY_DLY32_gc | ADC_SAMPDLY_DLY0_gc; + // configure ADC sample length to >= 28 us * Fclk_adc + ADC0.SAMPCTRL = 32; + // set single-ended or differential + // set resolution to 12 bits + // set left- or right-adjust + // set free-running mode or not (yes) + ADC0.CTRLA = ADC_CONVMODE_SINGLEENDED_gc + | ADC_RESSEL_12BIT_gc + | ADC_LEFTADJ_bm + | ADC_FREERUN_bm; + // set number of samples (requires adjustment in formula too) + ADC0.CTRLB = ADC_SAMPNUM_NONE_gc; + // accumulate more samples for more resolution + ADC0.CTRLB = ADC_SAMPNUM_ACC16_gc; // 16 samples per result + // set a clock prescaler + //ADC0.CTRLC = ADC_PRESC_DIV64_gc; // use this when no accumulation + ADC0.CTRLC = ADC_PRESC_DIV4_gc; // measure faster when oversampling + // enable the ADC + ADC0.CTRLA |= ADC_ENABLE_bm; + // actually start measuring (happens in another function) + //ADC0.COMMAND |= ADC_STCONV_bm; + // for each measurement: + // process according to sigrow data + formula +} + +inline void mcu_set_admux_voltage() { + // ADC init: Datasheet section 33.3.2 + // set Vref + VREF.ADC0REF = VREF_REFSEL_1V024_gc; + // set single-ended or differential + // set resolution to 12 bits + // set left- or right-adjust (right) + // set free-running mode or not (yes) + ADC0.CTRLA = ADC_CONVMODE_SINGLEENDED_gc + | ADC_RESSEL_12BIT_gc + | ADC_LEFTADJ_bm // has no effect when 16+ samples taken + | ADC_FREERUN_bm + | ADC_RUNSTBY_bm // allow voltage sense in standby mode + ; + // set number of samples + ADC0.CTRLB = ADC_SAMPNUM_ACC16_gc; // 16 samples per result + // set a clock prescaler + ADC0.CTRLC = ADC_PRESC_DIV4_gc; // measure faster when oversampling + // select the positive ADC input with MUXPOS + #ifdef USE_VOLTAGE_DIVIDER // external voltage divider + // ADC input pin / Vref + ADC0.MUXPOS = ADMUX_VOLTAGE_DIVIDER; // external pin + #elif defined (USE_VOLTAGE_VDDIO2) // internal voltage divider + // (Vbat / 10) / Vref + ADC0.MUXPOS = ADC_MUXPOS_VDDIO2DIV10_gc; + #else // measure directly on VDD/VCC pin + // (Vbat / 10) / Vref + ADC0.MUXPOS = ADC_MUXPOS_VDDDIV10_gc; + #endif + // enable the ADC + ADC0.CTRLA |= ADC_ENABLE_bm; + // actually start measuring (happens in another function) + //ADC0.COMMAND |= ADC_STCONV_bm; +} + +inline void mcu_adc_sleep_mode() { + set_sleep_mode(SLEEP_MODE_STANDBY); +} + +inline void mcu_adc_start_measurement() { + ADC0.INTCTRL |= ADC_RESRDY_bm; // enable interrupt + ADC0.COMMAND |= ADC_STCONV_bm; // actually start measuring +} + +/* +void mcu_adc_on() { + hwdef_set_admux_voltage(); + mcu_adc_start_measurement(); +} +*/ + +inline void mcu_adc_off() { + ADC0.CTRLA &= ~(ADC_ENABLE_bm); // disable the ADC +} + +inline void mcu_adc_vect_clear() { + ADC0.INTFLAGS = ADC_RESRDY_bm; // clear the interrupt +} + +inline uint16_t mcu_adc_result() { + // value is 12-bit left-aligned + 16x oversampling = 16 bits total + return ADC0.RES; +} + +inline uint8_t mcu_vdd_raw2cooked(uint16_t measurement) { + // In : 65535 * (Vbat / 10) / 1.024V + // Out: uint8_t: Vbat * 40 + // (add 80 to round up near a boundary) + uint8_t vbat40 = (uint16_t)(measurement + 80) / 160; + return vbat40; +} + +#if 0 +inline uint16_t mcu_vdd_raw2fine(uint16_t measurement) { + // In : 65535 * (Vbat / 10) / 1.024V + // Out: 65535 * (Vbat / 10) / 1.024V + // This MCU's native format is already correct + return measurement; +} +#endif + +inline uint16_t mcu_temp_raw2cooked(uint16_t measurement) { + // convert raw ADC values to calibrated temperature + // In: ADC raw temperature (16-bit, or 12-bit left-aligned) + // Out: Kelvin << 6 + // Precision: 1/64th Kelvin (but noisy) + // AVR DD datasheet section 33.3.3.8 + uint16_t sigrow_slope = SIGROW.TEMPSENSE0; // factory calibration data + uint16_t sigrow_offset = SIGROW.TEMPSENSE1; // 12-bit value + //const uint32_t scaling_factor = 4096; // use top 12 bits of ADC data + //uint32_t temp = sigrow_offset - (measurement >> 4); + const uint32_t scaling_factor = 65536; // use all 16 bits of ADC data + uint32_t temp = (sigrow_offset << 4) - measurement; + temp *= sigrow_slope; // 24-bit result + temp += scaling_factor / 8; // Add 1/8th K to get correct rounding on later divisions + //temp = temp >> 6; // change (K << 12) to (K << 6) + temp = temp >> 10; // change (K << 16) to (K << 6) + return temp; // left-aligned uint16_t, 0 to 1023.98 Kelvin +} + +inline uint8_t mcu_adc_lsb() { + // volts and temp are both 16-bit, so the LSB is useful as-is + return ADC0_RESL; +} + + +////////// WDT ////////// +// this uses the RTC PIT interrupt instead of WDT, +// as recommended on AVR 0/1-series and later: +// https://github.com/SpenceKonde/DxCore/blob/master/megaavr/extras/PowerSave.md#using-the-real-time-counter-rtcpit +// The PIT runs even in power-down mode, unlike RTC, +// and its cycles are relative to the AVR's internal 32768 Hz ULP oscillator +// AVR datasheet sections 26, 26.5, 26.9, 26.12, 26.13.12 + +// PIT tick speeds: +// 0 (none) +// 1 8192 Hz (CYC4) +// 2 4096 Hz +// 3 2048 Hz +// 4 1024 Hz (CYC32) +// 5 512 Hz +// 6 256 Hz +// 7 128 Hz +// 8 64 Hz (default) (CYC512) +inline void mcu_wdt_active() { + RTC.PITINTCTRL = RTC_PI_bm; // enable the Periodic Interrupt + while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated + // Period = 16ms (64 Hz), enable the PI Timer + RTC.PITCTRLA = RTC_PERIOD_CYC512_gc | RTC_PITEN_bm; +} + +// STANDBY_TICK_SPEED: +// 0 64 Hz +// 1 32 Hz +// 2 16 Hz +// 3 8 Hz (default) +// 4 4 Hz +// 5 2 Hz +// 6 1 Hz +inline void mcu_wdt_standby() { + RTC.PITINTCTRL = RTC_PI_bm; // enable the Periodic Interrupt + while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated + // Set period (64 Hz / STANDBY_TICK_SPEED = 8 Hz), enable the PI Timer + RTC.PITCTRLA = ((8+STANDBY_TICK_SPEED)<<3) | RTC_PITEN_bm; +} + +inline void mcu_wdt_stop() { + while (RTC.PITSTATUS > 0) {} // make sure the register is ready to be updated + RTC.PITCTRLA = 0; // Disable the PI Timer +} + +inline void mcu_wdt_vect_clear() { + RTC.PITINTFLAGS = RTC_PI_bm; // clear the PIT interrupt flag +} + + +////////// PCINT - pin change interrupt (e-switch) ////////// + +inline void mcu_switch_vect_clear() { + // Write a '1' to clear the interrupt flag + SWITCH_INTFLG |= (1 << SWITCH_PIN); +} + +inline void mcu_pcint_on() { + SWITCH_ISC_REG |= PORT_ISC_BOTHEDGES_gc; +} + +inline void mcu_pcint_off() { + SWITCH_ISC_REG &= ~(PORT_ISC_gm); +} + + +////////// misc ////////// + +void reboot() { + // request a reboot (software reset) + _PROTECTED_WRITE(RSTCTRL.SWRR, RSTCTRL_SWRST_bm); +} + +inline void prevent_reboot_loop() { + // if previous reset was a crash (WDT time-out), + // prevent it from happening again immediately + //RSTCTRL.RSTFR &= ~(RSTCTRL_WDRF_bm); // reset wdt flag only + RSTCTRL.RSTFR = 0; // reset all reset status flags (maybe unneeded?) + wdt_disable(); // from avr/wdt.h +} + diff --git a/arch/avr32dd20.h b/arch/avr32dd20.h new file mode 100644 index 00000000..09b4096b --- /dev/null +++ b/arch/avr32dd20.h @@ -0,0 +1,115 @@ +// arch/avr32dd20.h: avr32dd20 support header +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +////////// clock speed / delay stuff ////////// + +#define F_CPU 12000000UL +#define BOGOMIPS (F_CPU/3800) +#define DELAY_ZERO_TIME 1020 + +inline void mcu_clock_speed(); + +///// clock dividers +// this should work, but needs further validation +inline void clock_prescale_set(uint8_t n); + +// TODO: allow hwdef to define a base clock speed, +// and adjust these values accordingly +typedef enum +{ + // Actual clock is 12 MHz + clock_div_1 = (0), // 12 MHz + clock_div_2 = (CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm), // 6 MHz + clock_div_4 = (CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm), // 3 MHz + clock_div_8 = (CLKCTRL_PDIV_8X_gc | CLKCTRL_PEN_bm), // 1.5 MHz + clock_div_16 = (CLKCTRL_PDIV_16X_gc | CLKCTRL_PEN_bm), // 0.75 MHz + clock_div_32 = (CLKCTRL_PDIV_32X_gc | CLKCTRL_PEN_bm), // 375 kHz + clock_div_64 = (CLKCTRL_PDIV_64X_gc | CLKCTRL_PEN_bm), // 187.5 kHz +} clock_div_t; + + +////////// DAC controls ////////// + +// main LED outputs +#define DAC_LVL DAC0_DATA // 0 to 1023, for 0V to Vref +#define DAC_VREF VREF_DAC0REF // 1.024V, 2.048V, 4.096V, or 2.5V + +// Vref values (suitable for DAC and ADC0) +#define V10 VREF_REFSEL_1V024_gc +#define V20 VREF_REFSEL_2V048_gc +#define V25 VREF_REFSEL_2V500_gc +#define V40 VREF_REFSEL_4V096_gc + + +////////// ADC voltage / temperature ////////// + +#define hwdef_set_admux_therm mcu_set_admux_therm +inline void mcu_set_admux_therm(); + +#define hwdef_set_admux_voltage mcu_set_admux_voltage +inline void mcu_set_admux_voltage(); + +inline void mcu_adc_sleep_mode(); + +inline void mcu_adc_start_measurement(); + +//#define mcu_adc_on hwdef_set_admux_voltage +//void mcu_adc_on(); + +inline void mcu_adc_off(); + +#define ADC_vect ADC0_RESRDY_vect +inline void mcu_adc_vect_clear(); + +// both readings are left-aligned +inline uint16_t mcu_adc_result(); + +// read ADC differently for temperature and voltage +//#define MCU_ADC_RESULT_PER_TYPE +//inline uint16_t mcu_adc_result_temp(); +//inline uint16_t mcu_adc_result_volts(); + +// return Volts * 40, range 0 to 6.375V +#define voltage_raw2cooked mcu_vdd_raw2cooked +inline uint8_t mcu_vdd_raw2cooked(uint16_t measurement); + +// return (temp in Kelvin << 6) +#define temp_raw2cooked mcu_temp_raw2cooked +inline uint16_t mcu_temp_raw2cooked(uint16_t measurement); + +inline uint8_t mcu_adc_lsb(); + + +////////// WDT ////////// + +inline void mcu_wdt_active(); + +inline void mcu_wdt_standby(); + +inline void mcu_wdt_stop(); + +#define WDT_vect RTC_PIT_vect +inline void mcu_wdt_vect_clear(); + + +////////// PCINT - pin change interrupt (e-switch) ////////// + +// set these in hwdef +//#define SWITCH_PORT VPORTD.IN +//#define SWITCH_VECT PORTD_PORT_vect + +inline void mcu_switch_vect_clear(); + +inline void mcu_pcint_on(); + +inline void mcu_pcint_off(); + + +////////// misc ////////// + +void reboot(); + +inline void prevent_reboot_loop(); + diff --git a/arch/mcu.c b/arch/mcu.c new file mode 100644 index 00000000..8881c161 --- /dev/null +++ b/arch/mcu.c @@ -0,0 +1,10 @@ +// arch/mcu.c: Attiny portability header. +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "arch/mcu.h" + +#define MCU_C arch/MCUNAME.c +#include incfile(MCU_C) + diff --git a/arch/mcu.h b/arch/mcu.h index 5de6ea9b..2080ea9c 100644 --- a/arch/mcu.h +++ b/arch/mcu.h @@ -5,153 +5,20 @@ // This helps abstract away the differences between various attiny MCUs. -// Choose your MCU here, or in the main .c file, or in the build script -//#define ATTINY 13 -//#define ATTINY 25 - -/******************** hardware-specific values **************************/ -#if (ATTINY == 13) - #define F_CPU 4800000UL - //#define EEPSIZE 64 - #define V_REF REFS0 - #define BOGOMIPS 950 - #define ADMUX_VCC 0b00001100 - #define DELAY_ZERO_TIME 252 - #define SWITCH_PORT PINB // PINA or PINB or PINC - #define VOLTAGE_ADC_DIDR DIDR0 // this MCU only has one DIDR -#elif (ATTINY == 25) - // TODO: Use 6.4 MHz instead of 8 MHz? - #define F_CPU 8000000UL - //#define EEPSIZE 128 - #define V_REF REFS1 - #define BOGOMIPS (F_CPU/4000) - #define ADMUX_VCC 0b00001100 - #define ADMUX_THERM 0b10001111 - #define DELAY_ZERO_TIME 1020 - #define SWITCH_PORT PINB // PINA or PINB or PINC - #define VOLTAGE_ADC_DIDR DIDR0 // this MCU only has one DIDR -#elif (ATTINY == 85) - // TODO: Use 6.4 MHz instead of 8 MHz? - #define F_CPU 8000000UL - //#define EEPSIZE 512 - #define V_REF REFS1 - #define BOGOMIPS (F_CPU/4000) - // (1 << V_REF) | (0 << ADLAR) | (VCC_CHANNEL) - #define ADMUX_VCC 0b00001100 - // (1 << V_REF) | (0 << ADLAR) | (THERM_CHANNEL) - #define ADMUX_THERM 0b10001111 - #define DELAY_ZERO_TIME 1020 - #define SWITCH_PORT PINB // PINA or PINB or PINC - #define VOLTAGE_ADC_DIDR DIDR0 // this MCU only has one DIDR -#elif (ATTINY == 1634) - #define F_CPU 8000000UL - #define V_REF REFS1 - #define BOGOMIPS (F_CPU/4000) - // DS table 19-3, 19-4, 1.1V ref / VCC - #define ADMUX_VCC 0b00001101 - // (1 << V_REF) | (THERM_CHANNEL) - // DS table 19-3, 19-4, internal sensor / 1.1V ref - #define ADMUX_THERM 0b10001110 - #define DELAY_ZERO_TIME 1020 - //#define SWITCH_PORT PINA // set this in hwdef - //#define VOLTAGE_ADC_DIDR DIDR0 // set this in hwdef -#elif (ATTINY == 412) || (ATTINY == 416) || (ATTINY == 417) || (ATTINY == 816) || (ATTINY == 817) || (ATTINY == 1616) || (ATTINY == 1617) || (ATTINY == 3216) || (ATTINY == 3217) - #define AVRXMEGA3 - #define F_CPU 10000000UL - #define BOGOMIPS (F_CPU/4700) - #define EEPSIZE 128 - #define DELAY_ZERO_TIME 1020 -#else - #error Hey, you need to define ATTINY. -#endif - -// auto-detect eeprom size from avr-libc headers -#ifndef EEPSIZE -#ifdef E2SIZE -#define EEPSIZE E2SIZE -#else -#define EEPSIZE (E2END+1) -#endif -#endif - - +#include #include +#include +#include +#include +#include -/******************** I/O pin and register layout ************************/ -#ifdef HWDEFFILE -#include "fsm/tk.h" -#include incfile(HWDEFFILE) -#endif - -#if 0 // placeholder -#elif defined(NANJG_LAYOUT) -#include "hwdef-nanjg.h" +// for consistency, ROM_SIZE + EEPROM_SIZE +#define ROM_SIZE PROGMEM_SIZE -#elif defined(FET_7135_LAYOUT) -#include "hwdef-FET_7135.h" - -#elif defined(TRIPLEDOWN_LAYOUT) -#include "hwdef-Tripledown.h" - -#elif defined(FERRERO_ROCHER_LAYOUT) -#include "hwdef-Ferrero_Rocher.h" - -#endif // no more recognized driver types - -#ifndef LAYOUT_DEFINED -#error Hey, you need to define an I/O pin layout. -#endif - -#if (ATTINY==13) - // no changes needed -#elif (ATTINY==25) || (ATTINY==45) || (ATTINY==85) - // use clock_prescale_set(n) instead; it's safer - //#define CLOCK_DIVIDER_SET(n) {CLKPR = 1< ui/$UI/version.h + # TODO: detect UI from $0 and/or $* + UI=anduril -PASS=0 -FAIL=0 -PASSED='' -FAILED='' + mkdir -p hex -# build targets are hw/*/**/$UI.h -for TARGET in $( find hw/*/*/ -name "$UI".h ) ; do + make-version-h # generate a version.h file - # friendly name for this build - NAME=$(echo "$TARGET" | perl -ne 's|/|-|g; /hw-(.*)-'"$UI"'.h/ && print "$1\n";') + PASS=0 + FAIL=0 + PASSED='' + FAILED='' + + # build targets are hw/$vendor/$model/**/$ui.h + for TARGET in hw/*/*/**/"$UI".h ; do + + # friendly name for this build + NAME=$(echo "$TARGET" | perl -ne 's|/|-|g; /hw-(.*)-'"$UI"'.h/ && print "$1\n";') + + # limit builds to searched patterns, if given + SKIP=0 + if [ ${#SEARCH[@]} -gt 0 ]; then + for text in "${SEARCH[@]}" ; do + if ! echo "$NAME $TARGET" | grep -i -- "$text" > /dev/null ; then + SKIP=1 + fi + done + fi + if [ 1 = $SKIP ]; then continue ; fi + + # announce what we're going to build + echo "===== $UI $REV : $NAME =====" + + # try to compile, track result, and rename compiled files + if bin/build.sh "$TARGET" ; then + HEX_OUT="hex/$UI.$NAME.hex" + mv -f "ui/$UI/$UI".hex "$HEX_OUT" + MD5=$(md5sum "$HEX_OUT" | cut -d ' ' -f 1) + echo " # $MD5" + echo " > $HEX_OUT" + PASS=$((PASS + 1)) + PASSED="$PASSED $NAME" + else + echo "ERROR: build failed" + FAIL=$((FAIL + 1)) + FAILED="$FAILED $NAME" + fi - # limit builds to searched patterns, if given - SKIP=0 - if [ ! -z "$SEARCH" ]; then - for text in $SEARCH ; do - echo "$NAME $TARGET" | grep -i -- "$text" > /dev/null - if [ 0 != $? ]; then SKIP=1 ; fi done - fi - if [ 1 = $SKIP ]; then continue ; fi - - # announce what we're going to build - echo "===== $UI : $NAME =====" - - # try to compile - bin/build.sh "$TARGET" - - # track result, and rename compiled files - if [ 0 = $? ] ; then - mv -f "ui/$UI/$UI".hex hex/"$UI".$NAME.hex - echo " > hex/$UI.$NAME.hex" - PASS=$(($PASS + 1)) - PASSED="$PASSED $NAME" - else - echo "ERROR: build failed" - FAIL=$(($FAIL + 1)) - FAILED="$FAILED $NAME" - fi - -done - -# summary -echo "===== $PASS builds succeeded, $FAIL failed =====" -#echo "PASS: $PASSED" -if [ 0 != $FAIL ]; then - echo "FAIL:$FAILED" - exit 1 -fi + + # summary + echo "===== $PASS builds succeeded, $FAIL failed =====" + #echo "PASS: $PASSED" + if [ 0 != $FAIL ]; then + echo "FAIL:$FAILED" + exit 1 + fi +} + +function make-version-h { + # old: version = build date + #date '+#define VERSION_NUMBER "%Y-%m-%d"' > ui/$UI/version.h + + REV=$(bin/version-string.sh c) + # save the version name to version.h + mkdir -p ".build/$UI" + echo '#define VERSION_NUMBER "'"$REV"'"' > ".build/$UI/version.h" +} + +main "$@" + diff --git a/bin/build.sh b/bin/build.sh index 50f93b76..ed0a837e 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Anduril / FSM build script # Copyright (C) 2014-2023 Selene ToyKeeper # SPDX-License-Identifier: GPL-3.0-or-later @@ -6,7 +6,7 @@ # Instead of using a Makefile, since most of the firmwares here build in the # same exact way, here's a script to do the same thing -if [ -z "$1" ]; then +if [ 0 = "$#" ]; then echo "Usage: build.sh TARGET USER" echo "Example: build.sh hw/hank/emisar-d4/anduril.h users/myuser" echo "(but USER isn't implemented yet)" @@ -14,18 +14,19 @@ if [ -z "$1" ]; then fi # repo root dir -BASEDIR=$(dirname $(dirname "$0")) +BASEDIR=$(dirname "$(dirname "$0")") -TARGET=$1 ; shift -UI=$(basename $TARGET .h) -MODEL=$(dirname $TARGET) +TARGET="$1" ; shift +ARGS="$*" +UI=$(basename "$TARGET" .h) +MODEL=$(dirname "$TARGET") PROGRAM="ui/$UI/$UI" # figure out the model number -MODEL_NUMBER=$(head -1 $MODEL/model) +MODEL_NUMBER=$(head -1 "$MODEL/model") # figure out the MCU type and set some vars -eval $( bin/detect-mcu.sh "$TARGET" ) +eval "$( bin/detect-mcu.sh "$TARGET" )" # detect and enable a relevant Atmel DFP if [[ $MCUNAME =~ "attiny" ]]; then @@ -36,19 +37,21 @@ else echo "Unrecognized MCU type: '$MCUNAME'" exit 1 fi -# ensure the DFP files exist -if [ ! -d "$DFPPATH" ]; then - echo "Atmel DFP files not found: '$DFPPATH'" - echo "Install DFP files with './make dfp'" - exit 1 -fi +# skip verification because newer avr-libc doesn't need DFPs, +# so the DFP shouldn't be mandatory +## ensure the DFP files exist +#if [ ! -d "$DFPPATH" ]; then +# echo "Atmel DFP files not found: '$DFPPATH'" +# echo "Install DFP files with './make dfp'" +# exit 1 +#fi export CC=avr-gcc export CPP=avr-cpp export OBJCOPY=avr-objcopy export DFPFLAGS="-B $DFPPATH/gcc/dev/$MCUNAME/ -I $DFPPATH/include/" # TODO: include $user/ first so it can override other stuff -INCLUDES="-I ui -I hw -I. -I.. -I../.. -I../../.." +INCLUDES="-I .build -I ui -I hw -I. -I.. -I../.. -I../../.." export CFLAGS=" -Wall -g -Os -mmcu=$MCUNAME -c -std=gnu99 -fgnu89-inline -fwhole-program $MCUFLAGS $INCLUDES -fshort-enums $DFPFLAGS" export CPPFLAGS="-Wall -g -Os -mmcu=$MCUNAME -C -std=gnu99 -fgnu89-inline -fwhole-program $MCUFLAGS $INCLUDES -fshort-enums $DFPFLAGS" export OFLAGS="-Wall -g -Os -mmcu=$MCUNAME -mrelax $DFPFLAGS" @@ -56,23 +59,19 @@ export LDFLAGS="-fgnu89-inline" export OBJCOPYFLAGS='--set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex --remove-section .fuse' export OBJS=$PROGRAM.o -OTHERFLAGS="-DCFG_H=$TARGET -DMODEL_NUMBER=\"$MODEL_NUMBER\"" -for arg in "$*" ; do - OTHERFLAGS="$OTHERFLAGS $arg" -done +OTHERFLAGS="-DCFG_H=$TARGET -DMODEL_NUMBER=\"$MODEL_NUMBER\" $ARGS" function run () { - #echo $1 ; shift - #echo $* - $* - if [ x"$?" != x0 ]; then exit 1 ; fi + #echo "$1" ; shift + #echo "$*" + $* || exit 1 } -run $CPP $OTHERFLAGS $CPPFLAGS -o foo.cpp $PROGRAM.c -grep -a -E -v '^#|^$' foo.cpp > $PROGRAM.cpp ; rm foo.cpp -run $CC $OTHERFLAGS $CFLAGS -o $PROGRAM.o -c $PROGRAM.c -run $CC $OFLAGS $LDFLAGS -o $PROGRAM.elf $PROGRAM.o -run $OBJCOPY $OBJCOPYFLAGS $PROGRAM.elf $PROGRAM.hex +run "$CPP" "$OTHERFLAGS" "$CPPFLAGS" -o foo.cpp "$PROGRAM.c" +grep -a -E -v '^#|^$' foo.cpp > "$PROGRAM.cpp" ; rm foo.cpp +run "$CC" "$OTHERFLAGS" "$CFLAGS" -o "$PROGRAM.o" -c "$PROGRAM.c" +run "$CC" "$OFLAGS" "$LDFLAGS" -o "$PROGRAM.elf" "$PROGRAM.o" +run "$OBJCOPY" "$OBJCOPYFLAGS" "$PROGRAM.elf" "$PROGRAM.hex" # deprecated #run avr-size -C --mcu=$MCUNAME $PROGRAM.elf | grep Full -run avr-objdump -Pmem-usage $PROGRAM.elf | grep -E 'Full|Device' | sed 's/^/ /;' +run avr-objdump -Pmem-usage "$PROGRAM".elf | grep -E 'Full|Device' | sed 's/^/ /;' diff --git a/bin/dac-scale.py b/bin/dac-scale.py new file mode 100755 index 00000000..d57f8c94 --- /dev/null +++ b/bin/dac-scale.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python + +# +# Calculates DAC values and Vref values from a list of raw intensity values +# Usage: dac-scale.py 5,11,18,25,...,370474,384985,400000 +# Output: #defines suitable for use in hw/*/anduril.h +# Assumptions: +# - DAC data range is 0 to 1023 +# - DAC Vrefs are 1.024V and 2.5V +# - HDR is available and has 2 steps +# - HDR channel ratio is "highest_ramp_value / 2500" +# +# Output values thus have 4 "engine gears": +# - HDR low , 1.024V Vref +# - HDR low , 2.5 V Vref +# - HDR high, 1.024V Vref +# - HDR high, 2.5 V Vref +# + +def main(args): + max_pwm = 1023 + raw_pwm = [int(x) for x in args[0].split(',')] + ratio = raw_pwm[-1] / 2500.0 + cooked = [[]] + + def limit(p): + return min(max_pwm, int(p)) + + phase = 0 + for raw in raw_pwm: + if 0 == phase: + if raw <= 1023: + cooked[-1].append(limit(raw)) + else: + phase += 1 + cooked.append([]) + if 1 == phase: + if raw <= int(2500): + cooked[-1].append(limit(raw * 1.024 / 2.5)) + else: + phase += 1 + cooked.append([]) + if 2 == phase: + if raw <= int(1024 * ratio): + cooked[-1].append(limit(raw / ratio)) + else: + phase += 1 + cooked.append([]) + if 3 == phase: + cooked[-1].append(limit(raw * 1.024 / 2.5 / ratio)) + + # "gear change" boundaries + b1 = len(cooked[0]) + b2 = b1 + len(cooked[1]) + b3 = b2 + len(cooked[2]) + b4 = b3 + len(cooked[3]) + + #print(','.join(['%4i' % n for n in cooked])) + + def fmt_pwms(l): + return ','.join(['%4i' % n for n in l]) + + def fmt_tops(v, l): + return ','.join([' %s' % v for n in l]) + + lines = [] + + lines.append('// top level for each "gear": %i %i %i %i' % (b1, b2, b3, b4)) + + lines.append('#define PWM1_LEVELS \\') + lines.append(' ' + fmt_pwms(cooked[0]) + ', \\') + lines.append(' ' + fmt_pwms(cooked[1]) + ', \\') + lines.append(' ' + fmt_pwms(cooked[2]) + ', \\') + lines.append(' ' + fmt_pwms(cooked[3])) + lines.append('#define PWM2_LEVELS \\') + lines.append(' ' + fmt_tops('V10', cooked[0]) + ', \\') + lines.append(' ' + fmt_tops('V25', cooked[1]) + ', \\') + lines.append(' ' + fmt_tops('V10', cooked[2]) + ', \\') + lines.append(' ' + fmt_tops('V25', cooked[3])) + + lines.append('#define MAX_1x7135 %3i' % b2) + lines.append('#define HDR_ENABLE_LEVEL_MIN %3i' % (b2+1)) + + print('\n'.join(lines)) + +if __name__ == "__main__": + import sys + main(sys.argv[1:]) + diff --git a/bin/detect-mcu.sh b/bin/detect-mcu.sh index 761eac1d..93b624be 100755 --- a/bin/detect-mcu.sh +++ b/bin/detect-mcu.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env bash # Anduril / FSM MCU type detection script # Copyright (C) 2014-2023 Selene ToyKeeper # SPDX-License-Identifier: GPL-3.0-or-later @@ -15,7 +15,7 @@ TARGET=$1 while [ -n "$TARGET" ]; do #echo "... $TARGET" if [ -f "$TARGET" ]; then # use the dir/$UI.h file - ATTINY=$(grep 'ATTINY:' $TARGET | awk '{ print $3 }') + ATTINY=$(grep 'ATTINY:' "$TARGET" | awk '{ print $3 }') if [ -n "$ATTINY" ]; then echo "export MCUNAME=attiny${ATTINY}" echo "export MCU=0x${ATTINY}" @@ -30,7 +30,7 @@ while [ -n "$TARGET" ]; do NUM=$( echo "$MCU" | sed 's/^avr//; s/^attiny//;' ) echo "export MCUNAME=${MCU}" echo "export MCU=0x${NUM}" - echo "export ATTINY=${NUM}" + [[ "$MCU" =~ "attiny" ]] && echo "export ATTINY=${NUM}" echo "export MCUFLAGS=\"-DMCUNAME=${MCU} -DMCU=0x${NUM} -DATTINY=${NUM}\"" exit fi @@ -39,7 +39,7 @@ while [ -n "$TARGET" ]; do # move up one dir # if target doesn't change here, exit to avoid infinite loop FOO="$TARGET" - TARGET=$(dirname $TARGET) + TARGET=$(dirname "$TARGET") [ "$FOO" = "$TARGET" ] && exit 1 done diff --git a/bin/dfp-install.sh b/bin/dfp-install.sh index a73c4d5c..24b49080 100755 --- a/bin/dfp-install.sh +++ b/bin/dfp-install.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh # Atmel DFP download/install/setup script # Copyright (C) 2023 Selene ToyKeeper # SPDX-License-Identifier: GPL-3.0-or-later diff --git a/bin/flash-avr32dd20.sh b/bin/flash-avr32dd20.sh new file mode 100755 index 00000000..a4faab81 --- /dev/null +++ b/bin/flash-avr32dd20.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# AVR firmware flashing script, a wrapper for other tools +# Copyright (C) 2023 Selene ToyKeeper +# SPDX-License-Identifier: GPL-3.0-or-later + +# Usage: flash-MCUTYPE.sh hex/foo.hex +# (where the script name specifies the type of MCU chip, +# and the first parameter is the path to a .hex file) +# Example: +# ./bin/flash-avr32dd20.sh hex/anduril.thefreeman-avr32dd20-devkit.hex + +set -e + +# Get the path to a .hex file +[[ -z "$1" ]] && echo "No .hex file specified." && exit 1 +HEX="$1" + +# assume the highest-numbered USB serial device is the correct one, +# since it was probably the most recently plugged in +TTYUSB=$(ls -1 /dev/tty* | grep -i usb | tail -1) + +# figure out the MCU type... +# TODO: find the relevant hw/*/arch file and use that to get MCU type +# use $2 if it exists, and use the name of this script maybe +MCUTYPE="unset" +[[ -n "$2" ]] && MCUTYPE="$2" +#MCUTYPE=$(echo "$0" | sed 's/.*flash-\(.*\).sh.*/\1/') +[[ "$0" =~ flash-(.*).sh ]] && MCUTYPE="${BASH_REMATCH[1]}" + +# Do the actual flashing +echo "Flashing $MCUTYPE MCU on port $TTYUSB: $HEX" +pymcuprog write \ + --erase \ + --verify \ + --timing \ + -t uart \ + -u "$TTYUSB" \ + -d "$MCUTYPE" \ + -f "$HEX" + diff --git a/bin/flash-tiny13-fuses.bat b/bin/flash-tiny13-fuses.bat deleted file mode 100755 index cec982e6..00000000 --- a/bin/flash-tiny13-fuses.bat +++ /dev/null @@ -1 +0,0 @@ -avrdude -c usbasp -p t13 -u -Ulfuse:w:0x75:m -Uhfuse:w:0xFF:m diff --git a/bin/flash-tiny13-fuses.sh b/bin/flash-tiny13-fuses.sh deleted file mode 100755 index fe479a89..00000000 --- a/bin/flash-tiny13-fuses.sh +++ /dev/null @@ -1,8 +0,0 @@ -#/bin/sh -# 4.8 MHz (~4.0 MHz actual), 4ms boot delay, enable flashing -# (everything else disabled) -# Use low fuse 0x75 for 4ms startup delay, -# or 0x79 for 64ms (useful on a twisty light) -avrdude -c usbasp -p t13 -u -Ulfuse:w:0x75:m -Uhfuse:w:0xFF:m - -# http://www.engbedded.com/cgi-bin/fcx.cgi?P_PREV=ATtiny13A&P=ATtiny13A&M_LOW_0x0F=0x05&M_LOW_0x80=0x00&M_HIGH_0x06=0x06&B_SPIEN=P&B_SUT1=P&B_CKSEL1=P&V_LOW=75&V_HIGH=FF&O_HEX=Apply+values diff --git a/bin/flash-tiny13.bat b/bin/flash-tiny13.bat deleted file mode 100755 index db75fd8c..00000000 --- a/bin/flash-tiny13.bat +++ /dev/null @@ -1 +0,0 @@ -avrdude -p t13 -c usbasp -u -Uflash:w:%1:a diff --git a/bin/flash-tiny13.sh b/bin/flash-tiny13.sh deleted file mode 100755 index 47b2bfe1..00000000 --- a/bin/flash-tiny13.sh +++ /dev/null @@ -1,3 +0,0 @@ -#/bin/sh -FIRMWARE=$1 -avrdude -c usbasp -p t13 -u -Uflash:w:$FIRMWARE diff --git a/bin/flash-tiny1616.sh b/bin/flash-tiny1616.sh index 44d716cb..3ad37b91 100755 --- a/bin/flash-tiny1616.sh +++ b/bin/flash-tiny1616.sh @@ -1,5 +1,5 @@ -#/bin/sh -FIRMWARE=$1 +#!/usr/bin/env sh +FIRMWARE="$1" if [ -z "$AVRDUDE_TTYUSB" ]; then AVRDUDE_TTYUSB=/dev/ttyUSB0 ; fi # In your shell config: @@ -7,8 +7,8 @@ if [ -z "$AVRDUDE_TTYUSB" ]; then AVRDUDE_TTYUSB=/dev/ttyUSB0 ; fi # export AVRDUDE_CONF="-C$HOME/path/to/jtag2updi/avrdude.conf" # export AVRDUDE_TTYUSB="/dev/ttyUSB2" -avrdude $AVRDUDE_CONF \ +avrdude "$AVRDUDE_CONF" \ -c jtag2updi \ - -P $AVRDUDE_TTYUSB \ + -P "$AVRDUDE_TTYUSB" \ -p t1616 \ - -u -Uflash:w:$FIRMWARE + -u -Uflash:w:"$FIRMWARE" diff --git a/bin/flash-tiny1634-fuses.sh b/bin/flash-tiny1634-fuses.sh index 1bc73e1f..5b954116 100755 --- a/bin/flash-tiny1634-fuses.sh +++ b/bin/flash-tiny1634-fuses.sh @@ -1,4 +1,4 @@ -#/bin/sh +#!/usr/bin/env sh # 8 MHz, 64ms boot delay, enable flashing # (everything else disabled) # Use low fuse 0xD2 for 4ms startup delay, diff --git a/bin/flash-tiny1634.sh b/bin/flash-tiny1634.sh index 2eb9b774..5516d086 100755 --- a/bin/flash-tiny1634.sh +++ b/bin/flash-tiny1634.sh @@ -1,3 +1,3 @@ -#/bin/sh -FIRMWARE=$1 -avrdude -c usbasp -p t1634 -u -Uflash:w:$FIRMWARE +#!/usr/bin/env sh +FIRMWARE="$1" +avrdude -c usbasp -p t1634 -u -Uflash:w:"$FIRMWARE" diff --git a/bin/flash-tiny25-fuses.sh b/bin/flash-tiny25-fuses.sh deleted file mode 100755 index 65d5b1df..00000000 --- a/bin/flash-tiny25-fuses.sh +++ /dev/null @@ -1,8 +0,0 @@ -#/bin/sh -# 8 MHz, 4ms boot delay, enable flashing -# (everything else disabled) -# Use low fuse 0xD2 for 4ms startup delay, -# or 0xE2 for 64ms (useful on a twisty light) -avrdude -c usbasp -p t25 -u -U lfuse:w:0xd2: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=0x22&M_HIGH_0x07=0x07&M_HIGH_0x20=0x00&B_SPIEN=P&B_SUT0=P&B_CKSEL3=P&B_CKSEL2=P&B_CKSEL0=P&V_LOW=E2&V_HIGH=DF&V_EXTENDED=FF&O_HEX=Apply+values diff --git a/bin/flash-tiny25.sh b/bin/flash-tiny25.sh deleted file mode 100755 index 99756718..00000000 --- a/bin/flash-tiny25.sh +++ /dev/null @@ -1,3 +0,0 @@ -#/bin/sh -FIRMWARE=$1 -avrdude -c usbasp -p t25 -u -Uflash:w:$FIRMWARE diff --git a/bin/flash-tiny85-fuses.sh b/bin/flash-tiny85-fuses.sh index f49049a1..d73eae0f 100755 --- a/bin/flash-tiny85-fuses.sh +++ b/bin/flash-tiny85-fuses.sh @@ -1,4 +1,4 @@ -#/bin/sh +#!/usr/bin/env sh # 8 MHz, 64ms boot delay, enable flashing # (everything else disabled) # Use low fuse 0xD2 for 4ms startup delay, diff --git a/bin/flash-tiny85.sh b/bin/flash-tiny85.sh index 0f5a2925..a0dfae96 100755 --- a/bin/flash-tiny85.sh +++ b/bin/flash-tiny85.sh @@ -1,3 +1,3 @@ -#/bin/sh -FIRMWARE=$1 -avrdude -c usbasp -p t85 -u -Uflash:w:$FIRMWARE +#!/usr/bin/env sh +FIRMWARE="$1" +avrdude -c usbasp -p t85 -u -Uflash:w:"$FIRMWARE" diff --git a/bin/flash.sh b/bin/flash.sh index 0423c907..a0eafc54 100755 --- a/bin/flash.sh +++ b/bin/flash.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Flashes both fuses and firmware. @@ -11,9 +11,9 @@ fi set -e -BASEDIR=$(dirname "$0") -export ATTINY=$1 ; shift -export PROGRAM=$1 ; shift +BASEDIR="$(dirname "$0")" +export ATTINY="$1" ; shift +export PROGRAM="$1" ; shift if [ ! -f "$PROGRAM" ]; then PROGRAM="$PROGRAM".hex ; fi -$BASEDIR/flash-tiny"$ATTINY"-fuses.sh -$BASEDIR/flash-tiny"$ATTINY".sh "$PROGRAM" +"$BASEDIR"/flash-tiny"$ATTINY"-fuses.sh +"$BASEDIR"/flash-tiny"$ATTINY".sh "$PROGRAM" diff --git a/bin/make-release.sh b/bin/make-release.sh new file mode 100755 index 00000000..da985d12 --- /dev/null +++ b/bin/make-release.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# Create a release file for Anduril .hex files. +# Copyright (C) 2023 Selene ToyKeeper +# SPDX-License-Identifier: GPL-3.0-or-later + +set -e # abort on error + +# run from repo root +REPODIR=$(dirname "$0")/.. +cd "$REPODIR" + +# get rid of 1st arg if it's "release" passed from 'make' +[[ "$1" = "release" ]] && shift + +# try to get the repo ready for a release +# (or not; probably better to do these steps manually) +#make clean +#make + +# release name +#REV=$(date +'%Y-%m-%d') +REV=$(git describe --tags --dirty --match='r2*') +REV="${REV:1}" # convert 'r2023-...' to '2023-...' +# allow manually specifying a release name +[[ -n "$1" ]] && REV="$1" + +# releases are named "$project.$revision" +RELNAME="anduril.$REV" + +# release directory +RELDIR="releases/$RELNAME" +mkdir -p "$RELDIR" "$RELDIR/hex" + +# add documentation and stuff +cp -a \ + ChangeLog.md \ + LICENSE \ + MODELS \ + README.md \ + docs/anduril-manual.md \ + docs/battery-rainbow.png \ + docs/which-hex-file.md \ + "$RELDIR" + +# add the .hex files +rename -f 's|hex/anduril.|'"$RELDIR/hex/$RELNAME"'.|;' hex/*.hex + +# make a .zip file +cd releases +mkdir -p zip +ZPATH=zip/"$RELNAME".zip +zip -q -r "$ZPATH" "$RELNAME" +cd .. +ls -l "releases/$ZPATH" + diff --git a/bin/models.py b/bin/models.py index 8e54d1ca..1a1152e5 100755 --- a/bin/models.py +++ b/bin/models.py @@ -24,12 +24,18 @@ def main(args): foo.sort() models = [x[-1] for x in foo] + colsizes = [ + max(len(m.model) for m in models), + max(len(m.mcu) for m in models), + max(len(m.name) for m in models), + ] + print('Models: %i\n' % len(models)) - fmt = '%s\t%-30s\t%s' - print(fmt % ('Model', 'Name', 'MCU')) - print(fmt % ('-----', '----', '---')) + fmt = '%%-%is %%-%is %%s' % (colsizes[0], colsizes[1]) + print(fmt % ('Model', 'MCU', 'Name')) + print(fmt % ('-----', '---', '----')) for m in models: - print(fmt % (m.model, m.name, m.mcu)) + print(fmt % (m.model, m.mcu, m.name)) print('\nDuplicates:') for i, m in enumerate(models): @@ -56,6 +62,7 @@ def load_model(path): m.name = path.replace('hw/','').replace('/', '-') m.mcu = inherit(path, 'arch') m.model = inherit(path, 'model') + if m.model: m.model = model_translate(m.model) return m @@ -73,6 +80,24 @@ def inherit(path, field): return None +def model_translate(m): + """Convert raw ordinal hex codes into human-friendly a-f digits. + """ + m = str(m) + replace = { + chr(ord('0') + 10): 'a', + chr(ord('0') + 11): 'b', + chr(ord('0') + 12): 'c', + chr(ord('0') + 13): 'd', + chr(ord('0') + 14): 'e', + chr(ord('0') + 15): 'f', + } + for s, r in replace.items(): + m = m.replace(s, r) + + return m + + if __name__ == "__main__": import sys main(sys.argv[1:]) diff --git a/bin/version-string.sh b/bin/version-string.sh new file mode 100755 index 00000000..c1c51552 --- /dev/null +++ b/bin/version-string.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# Print a version string for the currently-checked-out code. +# Copyright (C) 2023 Selene ToyKeeper +# SPDX-License-Identifier: GPL-3.0-or-later + +# Usage: version-string.sh [c|git|both] +# Prints in C or Git format. Defaults to both. + +function main { + # eat first arg if invoked via 'make' + [[ "version" = "$1" ]] && shift + + # default to showing both formats + ARGS="$*" + [[ -z "$ARGS" ]] && ARGS="both" + + for arg in $ARGS ; do + case "$arg" in + git|g) + git-describe + ;; + c|C) + c-version-string + ;; + *) + echo -n 'C: ' ; c-version-string + echo -n 'git: ' ; git-describe + ;; + esac + done +} + +function git-describe { + git describe --tags --dirty --match='r2*' +} + +function c-version-string { + # version = git tag + revs since + dirty flag + REV=$(git-describe) + # convert "r2020-01-01-158-g0abcdef-dirty" to "2020-01-01+158#1" + REV=$(echo "$REV" | + sed -E 's/^r//; + s/-dirty/#1/; + s/-g[0-9a-f]+//; + s/^([0-9]{4}-[0-9]{2}-[0-9]{2})-/\1+/; + ' + ) + # handle an empty name (can happen during github action runs) + if [[ -z "$REV" ]]; then + HASH=$(git describe --always) + REV="0.$HASH" + fi + # print the version string + echo "$REV" +} + +main "$@" + diff --git a/docs/anduril-manual.md b/docs/anduril-manual.md index 29f555df..9ede6716 100644 --- a/docs/anduril-manual.md +++ b/docs/anduril-manual.md @@ -36,12 +36,12 @@ Button presses Button presses are abbreviated using a simple notation: - - `1C`: One click. Press and then quickly release the button. - - `1H`: Hold. Press the button, but keep holding it. - - `2C`: Two clicks. Press and release quickly, twice. - - `2H`: Click, hold. Click two times, but hold the second press. - - `3C`: Three clicks. Press and release quickly, three times. - - `3H`: Click, click, hold. Click three times, but hold the final press. + - `1C`: **One click.** Press and then quickly release the button. + - `1H`: **Hold.** Press the button, but keep holding it. + - `2C`: **Two clicks.** Press and release quickly, twice. + - `2H`: **Click, hold.** Click two times, but hold the second press. + - `3C`: **Three clicks.** Press and release quickly, three times. + - `3H`: **Click, click, hold.** Click three times, but hold the final press. The same pattern is used with higher numbers too. For example, `10C` means ten clicks... and `10H` means ten clicks but hold the final press. @@ -739,26 +739,63 @@ Version Check Mode ------------------ This allows people to see which version of the firmware is installed on -their light. The format for this is (usually) 12 digits -- a model -number and a date. `BBPP.YYYY-MM-DD` +their light. The format for this is usually a model number and a date. +`MODEL.YYYY-MM-DD` - - `BB`: Brand ID - - `PP`: Product ID + - `MODEL`: Model number + (usually `BBPP` where BB is the brand ID, and PP is the product ID) - `YYYY`: Year - `MM`: Month - `DD`: Day -Versions before 2023-05-30 used `YYYYMMDDBBPP` format. -Anduril 1 used only `YYYYMMDD` format, or none at all. +The version number format has changed a few times, so write down the version +info and check it against the formats below. -The date is when the firmware was compiled. If the vendor did not set -this value, it defaults to 1969-07-20, the date of first human contact -with the moon. However, it might not be a date at all; some vendors may -specify a completely different type of value here. +The model number is very important when flashing new firmware. Make sure +the new firmware has the same model number as the old firmware. More details +on this are in [Which Hex File](which-hex-file.md). Use the +[MODELS](../MODELS) file to map a model number to the name of a .hex file. -The brand/product values are also known as the model number. These are -hard-coded in the source code for each light's build target, and can be -looked up in the "MODELS" file or by using the "make models" command. +## Version Check Formats + +The Version Check function should blink out a series of numbers in one of +several formats: + + - `MODEL-YYYY-MM-DD-SINCE-DIRTY` + Anduril 2 from 2023-12 or later. "SINCE" and "DIRTY" may be omitted. + Punctuation makes a "buzz" between sections. + - `MODEL`: model number + - `YYYY-MM-DD`: Year, month, day. This uses the most recent release tag + from git, not the build date. + - `SINCE`: How many commits since the last official release tag? + - `DIRTY`: Adds a "-1" to the end if the repository was locally modified + without committing changes. + + - `NNNN-YYYY-MM-DD` + Anduril 2 from 2023-05 or later. + It's a model number and build date, + with "buzz" flashes between sections. + - `NNNN`: model number + - `YYYY`: year + - `MM`: month + - `DD`: day + + - `YYYYMMDDNNNN` + Anduril 2 from 2023-05 or earlier. + It's a build date and model number. + +- `YYYYMMDD` + This is an old Anduril 1 version. It's just a build date. + If the model name isn't obvious, try looking it up in the PRODUCTS file. + +- `1969-07-20` + The date of first human contact with the moon. This value indicates that + the person who built the firmware probably made some sort of error. + +If the version doesn't include a model number, you may be able to find +the model in the PRODUCTS file to see which firmware model it probably uses: + + https://bazaar.launchpad.net/~toykeeper/flashlight-firmware/anduril2/view/head:/PRODUCTS Protection Features @@ -822,6 +859,8 @@ In voltage mode, the colors follow the same sequence, in the same order as a rainbow... with red indicating a low battery and purple indicating a full battery. +![battery charge colors](battery-rainbow.png) + For lights with a button LED, the button LED typically stays on while the main emitters are on. Its brightness level is set in a way which mirrors the main LED -- off, low, or high. diff --git a/docs/battery-rainbow.png b/docs/battery-rainbow.png new file mode 100644 index 00000000..499866dc Binary files /dev/null and b/docs/battery-rainbow.png differ diff --git a/docs/which-hex-file.md b/docs/which-hex-file.md index 88cc1d29..9dcc6443 100644 --- a/docs/which-hex-file.md +++ b/docs/which-hex-file.md @@ -1,40 +1,24 @@ # How to figure out which .hex file to use -1. Use the version check function (15 or more clicks from Off) to find out - which flavor of the firmware the light has installed. - **WRITE THIS DOWN.** - -2. Look up the model number in the MODELS file, to get the name and MCU type: - https://toykeeper.net/torches/fsm/anduril2/MODELS - -3. Find the newest firmware for that model. - https://toykeeper.net/torches/fsm/anduril2/?C=M;O=D - -If the version doesn't include a model number, you may be able to find -the model in the PRODUCTS file to see which version it probably uses: +Using the wrong firmware will make the light stop working, so when flashing +firmware, **be sure the model number matches**! - https://bazaar.launchpad.net/~toykeeper/flashlight-firmware/anduril2/view/head:/PRODUCTS +The name of a product is *not* enough information to find the right .hex +file. Ask the light what firmware it needs: +1. Use the Version Check function (15 or more clicks from Off) to find out + which flavor of the firmware the light has installed. + **WRITE THIS DOWN.** -## Version Check Formats - -The Version Check function should blink out a series of numbers in one of -several formats: - - - `NNNN-YYYY-MM-DD` - Anduril 2 from 2023-05 or later. - It's a model number and build date, - with "buzz" flashes between sections. - - `NNNN`: model number - - `YYYY`: year - - `MM`: month - - `DD`: day +2. Look up the model number in the [MODELS file](../MODELS), + to get the name and MCU type. - - `YYYYMMDDNNNN` - Anduril 2 from 2023-05 or earlier. - It's a build date and model number. +3. Find (or build) the newest firmware for that model. + https://github.com/ToyKeeper/anduril/releases -- `YYYYMMDD` - This is an old Anduril 1 version. It's just a build date. - If the model name isn't obvious, try looking it up in the PRODUCTS file. +The Version Check format has changed a few times. Use +[this section of the manual](anduril-manual.md#Version_Check_Formats) +to learn about those formats and how to use them. In most cases, it should +have a model number and a date... and **you need the model number** to find +the correct .hex file. diff --git a/fsm/adc.c b/fsm/adc.c index 31b250f5..fbe84a1f 100644 --- a/fsm/adc.c +++ b/fsm/adc.c @@ -15,139 +15,22 @@ #include -static inline void set_admux_therm() { - #if (ATTINY == 1634) - ADMUX = ADMUX_THERM; - #elif (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - ADMUX = ADMUX_THERM | (1 << ADLAR); - #elif (ATTINY == 841) // FIXME: not tested - ADMUXA = ADMUXA_THERM; - ADMUXB = ADMUXB_THERM; - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - ADC0.MUXPOS = ADC_MUXPOS_TEMPSENSE_gc; // read temperature - ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_INTREF_gc; // Internal ADC reference - #else - #error Unrecognized MCU type - #endif +static inline void adc_therm_mode() { + hwdef_set_admux_therm(); adc_channel = 1; adc_sample_count = 0; // first result is unstable ADC_start_measurement(); } -inline void set_admux_voltage() { - #if (ATTINY == 1634) - #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7 - ADMUX = ADMUX_VOLTAGE_DIVIDER; - #else // VCC / 1.1V reference - ADMUX = ADMUX_VCC; - #endif - #elif (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7 - ADMUX = ADMUX_VOLTAGE_DIVIDER | (1 << ADLAR); - #else // VCC / 1.1V reference - ADMUX = ADMUX_VCC | (1 << ADLAR); - #endif - #elif (ATTINY == 841) // FIXME: not tested - #ifdef USE_VOLTAGE_DIVIDER // 1.1V / pin7 - ADMUXA = ADMUXA_VOLTAGE_DIVIDER; - ADMUXB = ADMUXB_VOLTAGE_DIVIDER; - #else // VCC / 1.1V reference - ADMUXA = ADMUXA_VCC; - ADMUXB = ADMUXB_VCC; - #endif - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - #ifdef USE_VOLTAGE_DIVIDER // 1.1V / ADC input pin - // verify that this is correct!!! untested - ADC0.MUXPOS = ADMUX_VOLTAGE_DIVIDER; // read the requested ADC pin - ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_INTREF_gc; // Use internal ADC reference - #else // VCC / 1.1V reference - ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc; // read internal reference - ADC0.CTRLC = ADC_SAMPCAP_bm | ADC_PRESC_DIV64_gc | ADC_REFSEL_VDDREF_gc; // Vdd (Vcc) be ADC reference - #endif - #else - #error Unrecognized MCU type - #endif +void adc_voltage_mode() { + hwdef_set_admux_voltage(); adc_channel = 0; adc_sample_count = 0; // first result is unstable ADC_start_measurement(); } -#ifdef TICK_DURING_STANDBY -inline void adc_sleep_mode() { - // needs a special sleep mode to get accurate measurements quickly - // ... full power-down ends up using more power overall, and causes - // some weird issues when the MCU doesn't stay awake enough cycles - // to complete a reading - #ifdef SLEEP_MODE_ADC - // attiny1634 - set_sleep_mode(SLEEP_MODE_ADC); - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - set_sleep_mode(SLEEP_MODE_STANDBY); - #else - #error No ADC sleep mode defined for this hardware. - #endif -} -#endif - -inline void ADC_start_measurement() { - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 841) || (ATTINY == 1634) - ADCSRA |= (1 << ADSC) | (1 << ADIE); - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - ADC0.INTCTRL |= ADC_RESRDY_bm; // enable interrupt - ADC0.COMMAND |= ADC_STCONV_bm; // Start the ADC conversions - #else - #error unrecognized MCU type - #endif -} - -// set up ADC for reading battery voltage -inline void ADC_on() -{ - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634) - set_admux_voltage(); - #ifdef USE_VOLTAGE_DIVIDER - // disable digital input on divider pin to reduce power consumption - VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); - #else - // disable digital input on VCC pin to reduce power consumption - //VOLTAGE_ADC_DIDR |= (1 << VOLTAGE_ADC); // FIXME: unsure how to handle for VCC pin - #endif - #if (ATTINY == 1634) - //ACSRA |= (1 << ACD); // turn off analog comparator to save power - ADCSRB |= (1 << ADLAR); // left-adjust flag is here instead of ADMUX - #endif - // enable, start, auto-retrigger, prescale - ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL; - // end tiny25/45/85 - #elif (ATTINY == 841) // FIXME: not tested, missing left-adjust - ADCSRB = 0; // Right adjusted, auto trigger bits cleared. - //ADCSRA = (1 << ADEN ) | 0b011; // ADC on, prescaler division factor 8. - set_admux_voltage(); - // enable, start, auto-retrigger, prescale - ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | ADC_PRSCL; - //ADCSRA |= (1 << ADSC); // start measuring - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - VREF.CTRLA |= VREF_ADC0REFSEL_1V1_gc; // Set Vbg ref to 1.1V - // Enabled, free-running (aka, auto-retrigger), run in standby - ADC0.CTRLA = ADC_ENABLE_bm | ADC_FREERUN_bm | ADC_RUNSTBY_bm; - // set a INITDLY value because the AVR manual says so (section 30.3.5) - // (delay 1st reading until Vref is stable) - ADC0.CTRLD |= ADC_INITDLY_DLY16_gc; - set_admux_voltage(); - #else - #error Unrecognized MCU type - #endif -} - -inline void ADC_off() { - #ifdef AVRXMEGA3 // ATTINY816, 817, etc - ADC0.CTRLA &= ~(ADC_ENABLE_bm); // disable the ADC - #else - ADCSRA &= ~(1<>= 8; // Divide result to get Kelvin - m = (temp << 6); // left align it - } - else { m = (ADC0.RES << 6); } // voltage, force left-alignment - + #ifdef MCU_ADC_RESULT_PER_TYPE + if (channel) m = mcu_adc_result_temp(); + else m = mcu_adc_result_volts(); #else - m = ADC; + m = mcu_adc_result(); #endif adc_raw[channel] = m; @@ -235,11 +104,7 @@ void adc_deferred() { // real-world entropy makes this a true random, not pseudo // Why here instead of the ISR? Because it makes the time-critical ISR // code a few cycles faster and we don't need crypto-grade randomness. - #ifdef AVRXMEGA3 // ATTINY816, 817, etc - pseudo_rand_seed += ADC0.RESL; // right aligned, not left... so should be equivalent? - #else - pseudo_rand_seed += (ADCL >> 6) + (ADCH << 2); - #endif + pseudo_rand_seed += mcu_adc_lsb(); #endif // the ADC triggers repeatedly when it's on, but we only need to run the @@ -281,7 +146,7 @@ void adc_deferred() { ADC_voltage_handler(); #ifdef USE_THERMAL_REGULATION // set the correct type of measurement for next time - if (! go_to_standby) set_admux_therm(); + if (! go_to_standby) adc_therm_mode(); #endif } #endif @@ -291,7 +156,7 @@ void adc_deferred() { ADC_temperature_handler(); #ifdef USE_LVP // set the correct type of measurement for next time - set_admux_voltage(); + adc_voltage_mode(); #endif } #endif @@ -301,7 +166,7 @@ void adc_deferred() { #ifdef USE_LVP -static inline void ADC_voltage_handler() { +static void ADC_voltage_handler() { // rate-limit low-voltage warnings to a max of 1 per N seconds static uint8_t lvp_timer = 0; #define LVP_TIMER_START (VOLTAGE_WARNING_SECONDS*ADC_CYCLES_PER_SECOND) // N seconds between LVP warnings @@ -344,38 +209,23 @@ static inline void ADC_voltage_handler() { #endif else measurement = adc_smooth[0]; - // values stair-step between intervals of 64, with random variations - // of 1 or 2 in either direction, so if we chop off the last 6 bits - // it'll flap between N and N-1... but if we add half an interval, - // the values should be really stable after right-alignment - // (instead of 99.98, 100.00, and 100.02, it'll hit values like - // 100.48, 100.50, and 100.52... which are stable when truncated) - //measurement += 32; - //measurement = (measurement + 16) >> 5; - measurement = (measurement + 16) & 0xffe0; // 1111 1111 1110 0000 - - #ifdef USE_VOLTAGE_DIVIDER - voltage = calc_voltage_divider(measurement); - #else - // calculate actual voltage: volts * 10 - // ADC = 1.1 * 1024 / volts - // volts = 1.1 * 1024 / ADC - voltage = ((uint16_t)(2*1.1*1024*10)/(measurement>>6) - + VOLTAGE_FUDGE_FACTOR - #ifdef USE_VOLTAGE_CORRECTION - + VOLT_CORR - 7 - #endif - ) >> 1; - #endif + // convert raw ADC value to FSM voltage units: Volts * 40 + // 0 .. 200 = 0.0V .. 5.0V + voltage = voltage_raw2cooked(measurement) + + (VOLTAGE_FUDGE_FACTOR << 1) + #ifdef USE_VOLTAGE_CORRECTION + + ((VOLT_CORR - 7) << 1) + #endif + ; // if low, callback EV_voltage_low / EV_voltage_critical // (but only if it has been more than N seconds since last call) if (lvp_timer) { lvp_timer --; } else { // it has been long enough since the last warning - #ifdef DUAL_VOLTAGE_FLOOR - if (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) || (voltage < DUAL_VOLTAGE_LOW_LOW)) { - #else + #ifdef DUAL_VOLTAGE_FLOOR + if (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) || (voltage < DUAL_VOLTAGE_LOW_LOW)) { + #else if (voltage < VOLTAGE_LOW) { #endif // send out a warning @@ -390,7 +240,7 @@ static inline void ADC_voltage_handler() { #ifdef USE_THERMAL_REGULATION // generally happens once per second while awake -static inline void ADC_temperature_handler() { +static void ADC_temperature_handler() { // coarse adjustment #ifndef THERM_LOOKAHEAD #define THERM_LOOKAHEAD 4 @@ -415,19 +265,24 @@ static inline void ADC_temperature_handler() { static uint16_t temperature_history[NUM_TEMP_HISTORY_STEPS]; static int8_t warning_threshold = 0; - if (adc_reset) { // wipe out old data - // ignore average, use latest sample - uint16_t foo = adc_raw[1]; - adc_smooth[1] = foo; - - // forget any past measurements - for(uint8_t i=0; i> 5; - } + if (adc_reset) adc_smooth[1] = adc_raw[1]; // latest 16-bit ADC reading - uint16_t measurement = adc_smooth[1]; + // convert raw ADC value to Kelvin << 6 + // 0 .. 65535 = 0 K .. 1024 K + uint16_t measurement = temp_raw2cooked(adc_smooth[1]); + // let the UI see the current temperature in C + // (Kelvin << 6) to Celsius + // Why 275? Because Atmel's docs use 275 instead of 273. + temperature = (measurement>>6) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; + + // instead of (K << 6), use (K << 1) now + // TODO: use more precision, if it can be done without overflow in 16 bits + // (and still work on attiny85 without increasing ROM size) + #if 1 + measurement = measurement >> 5; + #else // TODO: is this still needed? // values stair-step between intervals of 64, with random variations // of 1 or 2 in either direction, so if we chop off the last 6 bits // it'll flap between N and N-1... but if we add half an interval, @@ -437,17 +292,14 @@ static inline void ADC_temperature_handler() { //measurement += 32; measurement = (measurement + 16) >> 5; //measurement = (measurement + 16) & 0xffe0; // 1111 1111 1110 0000 - - // let the UI see the current temperature in C - // Convert ADC units to Celsius (ish) - #ifndef USE_EXTERNAL_TEMP_SENSOR - // onboard sensor for attiny25/45/85/1634 - temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; - #else - // external sensor - temperature = EXTERN_TEMP_FORMULA(measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL; #endif + if (adc_reset) { // wipe out old data after waking up + // forget any past measurements + for(uint8_t i=0; i= pgm_read_byte(voltage_blinks + i); - i++) {} - #ifdef DONT_DELAY_AFTER_BATTCHECK - blink_digit(i); + blink_num(voltage / 4); + #ifdef USE_EXTRA_BATTCHECK_DIGIT + // 0 1 2 3 --> 0 2 5 7, representing x.x00 x.x25 x.x50 x.x75 + blink_num(((voltage % 4)<<1) + ((voltage % 4)>>1)); + #endif #else - if (blink_digit(i)) - nice_delay_ms(1000); - #endif + uint8_t i; + for(i=0; + voltage >= pgm_read_byte(voltage_blinks + i); + i++) {} + #ifdef DONT_DELAY_AFTER_BATTCHECK + blink_digit(i); + #else + if (blink_digit(i)) + nice_delay_ms(1000); + #endif #endif } #endif diff --git a/fsm/adc.h b/fsm/adc.h index 1bb67ed2..02e33f85 100644 --- a/fsm/adc.h +++ b/fsm/adc.h @@ -17,11 +17,11 @@ volatile uint8_t adc_reset = 2; #endif // low-battery threshold in volts * 10 #ifndef VOLTAGE_LOW -#define VOLTAGE_LOW 29 +#define VOLTAGE_LOW (4*29) #endif // battery is low but not critical #ifndef VOLTAGE_RED -#define VOLTAGE_RED 33 +#define VOLTAGE_RED (4*33) #endif // MCU sees voltage 0.X volts lower than actual, add X/2 to readings #ifndef VOLTAGE_FUDGE_FACTOR @@ -32,6 +32,9 @@ volatile uint8_t adc_reset = 2; #endif #endif + +void adc_voltage_mode(); + #ifdef TICK_DURING_STANDBY volatile uint8_t adc_active_now = 0; // sleep LVP needs a different sleep mode #endif @@ -46,7 +49,7 @@ uint16_t adc_smooth[2]; // lowpassed ADC measurements (0=voltage, 1=temperature uint8_t adc_deferred_enable = 0; // stop waiting and run the deferred code void adc_deferred(); // do the actual ADC-related calculations -static inline void ADC_voltage_handler(); +static void ADC_voltage_handler(); uint8_t voltage = 0; #ifdef USE_VOLTAGE_CORRECTION #ifdef USE_CFG @@ -98,15 +101,21 @@ int16_t temperature; uint8_t therm_ceil = DEFAULT_THERM_CEIL; int8_t therm_cal_offset = 0; #endif -static inline void ADC_temperature_handler(); +static void ADC_temperature_handler(); #endif // ifdef USE_THERMAL_REGULATION -inline void ADC_on(); -inline void ADC_off(); -inline void ADC_start_measurement(); +//inline void ADC_on(); +#define ADC_on adc_voltage_mode +//inline void ADC_off(); +#define ADC_off mcu_adc_off +//inline void ADC_start_measurement(); +#define ADC_start_measurement mcu_adc_start_measurement -#ifdef TICK_DURING_STANDBY -inline void adc_sleep_mode(); -#endif +// needs a special sleep mode to get accurate measurements quickly +// ... full power-down ends up using more power overall, and causes +// some weird issues when the MCU doesn't stay awake enough cycles +// to complete a reading +//inline void adc_sleep_mode(); +#define adc_sleep_mode mcu_adc_sleep_mode diff --git a/fsm/eeprom.h b/fsm/eeprom.h index 440d2b3a..1e10fd28 100644 --- a/fsm/eeprom.h +++ b/fsm/eeprom.h @@ -7,44 +7,49 @@ #include // set this higher to enable normal eeprom functions +// TODO: rename to EEPROM_BYTES_NEEDED or similar, to make purpose clearer #ifndef EEPROM_BYTES #define EEPROM_BYTES 0 #endif // set this higher to enable wear-levelled eeprom functions +// TODO: rename to EEPROM_WL_BYTES_NEEDED or similar, to make purpose clearer #ifndef EEPROM_WL_BYTES #define EEPROM_WL_BYTES 0 #endif #ifdef USE_EEPROM -// this fails when EEPROM_BYTES is a sizeof() -//#if EEPROM_BYTES >= (EEPSIZE/2) -//#error Requested EEPROM_BYTES too big. -//#endif -#ifdef EEPROM_OVERRIDE -uint8_t *eeprom; -#else -uint8_t eeprom[EEPROM_BYTES]; -#endif -uint8_t load_eeprom(); // returns 1 for success, 0 for no data found -void save_eeprom(); -#define EEP_START (EEPSIZE/2) + #ifdef USE_EEPROM_WL + // split eeprom in half + #define EEP_START (EEPROM_SIZE/2) + BUILD_ASSERT(eep_less_than_half, EEPROM_BYTES <= (EEPROM_SIZE/2)); + #else + // use entire eeprom + #define EEP_START 0 + BUILD_ASSERT(eep_data_fits, EEPROM_BYTES <= EEPROM_SIZE); + #endif + #ifdef EEPROM_OVERRIDE + uint8_t *eeprom; + #else + uint8_t eeprom[EEPROM_BYTES]; + #endif + uint8_t load_eeprom(); // returns 1 for success, 0 for no data found + void save_eeprom(); #endif #ifdef USE_EEPROM_WL -#if EEPROM_WL_BYTES >= (EEPSIZE/4) -#error Requested EEPROM_WL_BYTES too big. -#endif -uint8_t eeprom_wl[EEPROM_WL_BYTES]; -uint8_t load_eeprom_wl(); // returns 1 for success, 0 for no data found -void save_eeprom_wl(); -#define EEP_WL_SIZE (EEPSIZE/2) + #define EEP_WL_SIZE (EEPROM_SIZE/2) + // ensure space for at least 2 slots for wear levelling + BUILD_ASSERT(eepwl_two_slots_minimum, EEPROM_WL_BYTES <= (EEP_WL_SIZE/2)); + uint8_t eeprom_wl[EEPROM_WL_BYTES]; + uint8_t load_eeprom_wl(); // returns 1 for success, 0 for no data found + void save_eeprom_wl(); #endif -#if EEPSIZE > 256 -#define EEP_OFFSET_T uint16_t +#if EEPROM_SIZE > 256 + #define EEP_OFFSET_T uint16_t #else -#define EEP_OFFSET_T uint8_t + #define EEP_OFFSET_T uint8_t #endif // if this marker isn't found, the eeprom is assumed to be blank diff --git a/fsm/main.c b/fsm/main.c index 05241153..bb93862d 100644 --- a/fsm/main.c +++ b/fsm/main.c @@ -6,108 +6,16 @@ #include "fsm/main.h" -#if PWM_CHANNELS == 4 -#ifdef AVRXMEGA3 // ATTINY816, 817, etc -#error 4-channel PWM not currently set up for the AVR 1-Series -#endif -// 4th PWM channel requires manually turning the pin on/off via interrupt :( -ISR(TIMER1_OVF_vect) { - //bitClear(PORTB, 3); - PORTB &= 0b11110111; - //PORTB |= 0b00001000; -} -ISR(TIMER1_COMPA_vect) { - //if (!bitRead(TIFR,TOV1)) bitSet(PORTB, 3); - if (! (TIFR & (1<= 1 - DDRB |= (1 << PWM1_PIN); - TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) - TCCR0A = PHASE; - #if (PWM1_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - // tint ramping needs second channel enabled, - // despite PWM_CHANNELS being only 1 - #if (PWM_CHANNELS >= 2) || defined(USE_TINT_RAMPING) - DDRB |= (1 << PWM2_PIN); - #if (PWM2_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - #if PWM_CHANNELS >= 3 - DDRB |= (1 << PWM3_PIN); - #if (PWM3_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - #if PWM_CHANNELS >= 4 - // 4th PWM channel is ... not actually supported in hardware :( - DDRB |= (1 << PWM4_PIN); - //OCR1C = 255; // Set ceiling value to maximum - TCCR1 = 1<= 1 - PWM1_LVL = 0; - #endif - #if PWM_CHANNELS >= 2 - PWM2_LVL = 0; - #endif - #if PWM_CHANNELS >= 3 - PWM3_LVL = 0; - #endif - #if PWM_CHANNELS >= 4 - PWM4_LVL = 255; // inverted :( - #endif - #endif standby_mode(); } diff --git a/fsm/misc.c b/fsm/misc.c index bc10ea1c..fa8ddd73 100644 --- a/fsm/misc.c +++ b/fsm/misc.c @@ -118,7 +118,8 @@ uint8_t blink_num(uint8_t num) { #ifdef USE_INDICATOR_LED void indicator_led(uint8_t lvl) { switch (lvl) { - #ifdef AVRXMEGA3 // ATTINY816, 817, etc + // FIXME: move this logic to arch/* + #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc case 0: // indicator off AUXLED_PORT.DIRSET = (1 << AUXLED_PIN); // set as output @@ -192,7 +193,8 @@ void indicator_led_auto() { void button_led_set(uint8_t lvl) { switch (lvl) { - #ifdef AVRXMEGA3 // ATTINY816, 817, etc + // FIXME: move this logic to arch/* + #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc case 0: // LED off BUTTON_LED_PORT.DIRSET = (1 << BUTTON_LED_PIN); // set as output @@ -240,7 +242,8 @@ void rgb_led_set(uint8_t value) { uint8_t pin = pins[i]; switch (lvl) { - #ifdef AVRXMEGA3 // ATTINY816, 817, etc + // FIXME: move this logic to arch/* + #if (MCU==0x1616) || (MCU==0x32dd20) // ATTINY816, 817, etc case 0: // LED off AUXLED_RGB_PORT.DIRSET = (1 << pin); // set as output @@ -288,25 +291,3 @@ uint8_t triangle_wave(uint8_t phase) { } #endif -#ifdef USE_REBOOT -void reboot() { - // put the WDT in hard reset mode, then trigger it - cli(); - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - WDTCR = 0xD8 | WDTO_15MS; - #elif (ATTINY == 1634) - // allow protected configuration changes for next 4 clock cycles - CCP = 0xD8; // magic number - // reset (WDIF + WDE), no WDIE, fastest (16ms) timing (0000) - // (DS section 8.5.2 and table 8-4) - WDTCSR = 0b10001000; - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc - CCP = CCP_IOREG_gc; // temporarily disable change protection - WDT.CTRLA = WDT_PERIOD_8CLK_gc; // Enable, timeout 8ms - #endif - sei(); - wdt_reset(); - while (1) {} -} -#endif - diff --git a/fsm/misc.h b/fsm/misc.h index 8de6b293..ba1f8d9d 100644 --- a/fsm/misc.h +++ b/fsm/misc.h @@ -62,7 +62,3 @@ void rgb_led_set(uint8_t value); uint8_t triangle_wave(uint8_t phase); #endif -#ifdef USE_REBOOT -void reboot(); -#endif - diff --git a/fsm/pcint.c b/fsm/pcint.c index 131d0c3c..d00b51db 100644 --- a/fsm/pcint.c +++ b/fsm/pcint.c @@ -13,58 +13,8 @@ uint8_t button_is_pressed() { return value; } -inline void PCINT_on() { - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - // enable pin change interrupt - GIMSK |= (1 << PCIE); - // only pay attention to the e-switch pin - #if 0 // this is redundant; was already done in main() - PCMSK = (1 << SWITCH_PCINT); - #endif - // set bits 1:0 to 0b01 (interrupt on rising *and* falling edge) (default) - // MCUCR &= 0b11111101; MCUCR |= 0b00000001; - #elif (ATTINY == 1634) - // enable pin change interrupt - #ifdef SWITCH2_PCIE - GIMSK |= ((1 << SWITCH_PCIE) | (1 << SWITCH2_PCIE)); - #else - GIMSK |= (1 << SWITCH_PCIE); - #endif - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc) - SWITCH_ISC_REG |= PORT_ISC_BOTHEDGES_gc; - #else - #error Unrecognized MCU type - #endif -} - -inline void PCINT_off() { - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - // disable all pin-change interrupts - GIMSK &= ~(1 << PCIE); - #elif (ATTINY == 1634) - // disable all pin-change interrupts - GIMSK &= ~(1 << SWITCH_PCIE); - #elif defined(AVRXMEGA3) // ATTINY816, 817, etc) - SWITCH_ISC_REG &= ~(PORT_ISC_gm); - #else - #error Unrecognized MCU type - #endif -} - -//void button_change_interrupt() { -#if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 1634) - #ifdef PCINT_vect - ISR(PCINT_vect) { - #else - ISR(PCINT0_vect) { - #endif -#elif defined(AVRXMEGA3) // ATTINY816, 817, etc) - ISR(SWITCH_VECT) { - // Write a '1' to clear the interrupt flag - SWITCH_INTFLG |= (1 << SWITCH_PIN); -#else - #error Unrecognized MCU type -#endif +ISR(SWITCH_VECT) { + mcu_switch_vect_clear(); irq_pcint = 1; // let deferred code know an interrupt happened diff --git a/fsm/pcint.h b/fsm/pcint.h index cd7ba024..62f93abf 100644 --- a/fsm/pcint.h +++ b/fsm/pcint.h @@ -9,7 +9,9 @@ volatile uint8_t irq_pcint = 0; // pin change interrupt happened? #define BP_SAMPLES 32 volatile uint8_t button_last_state; uint8_t button_is_pressed(); -inline void PCINT_on(); -inline void PCINT_off(); +//inline void PCINT_on(); +//inline void PCINT_off(); +#define PCINT_on mcu_pcint_on +#define PCINT_off mcu_pcint_off void PCINT_inner(uint8_t pressed); diff --git a/fsm/spaghetti-monster.h b/fsm/spaghetti-monster.h index c035d5b8..7084ad44 100644 --- a/fsm/spaghetti-monster.h +++ b/fsm/spaghetti-monster.h @@ -13,10 +13,9 @@ * - ... */ -#include "arch/mcu.h" +////////// include all the .h files ////////// -#include -#include +#include "arch/mcu.h" // include project definitions to help with recognizing symbols #include "fsm/events.h" @@ -39,6 +38,10 @@ #include "arch/delay.h" #endif +////////// include all the .c files ////////// + +#include "arch/mcu.c" + #ifdef USE_DEBUG_BLINK #define DEBUG_FLASH PWM1_LVL = 64; delay_4ms(2); PWM1_LVL = 0; void debug_blink(uint8_t num) { diff --git a/fsm/tk.h b/fsm/tk.h index 785808dd..f2e7efea 100644 --- a/fsm/tk.h +++ b/fsm/tk.h @@ -24,3 +24,17 @@ // use it like this: //#include incfile(CONFIGFILE) + +// cause a build failure if `condition` is true +// (gcc compile trick taken from an old version of include/linux/kernel.h) +// more info here: +// https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/ +#define BUILD_FAIL_IF(name, condition) \ + __attribute__((unused)) static void name() \ + { ((void)sizeof(char[1 - 2*!!(condition)])); } + +// cause a build failure if `condition` is false +#define BUILD_ASSERT(name, condition) \ + __attribute__((unused)) static void name() \ + { ((void)sizeof(char[1 - 2*!(condition)])); } + diff --git a/fsm/wdt.c b/fsm/wdt.c index 64f006e5..1095d448 100644 --- a/fsm/wdt.c +++ b/fsm/wdt.c @@ -7,85 +7,9 @@ #include #include -// *** Note for the AVRXMEGA3 (1-Series, eg 816 and 817), the WDT -// is not used for time-based interrupts. A new peripheral, the -// Periodic Interrupt Timer ("PIT") is used for this purpose. - -void WDT_on() -{ - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - // interrupt every 16ms - //cli(); // Disable interrupts - wdt_reset(); // Reset the WDT - WDTCR |= (1< 0) {} // make sure the register is ready to be updated - RTC.PITCTRLA = RTC_PERIOD_CYC512_gc | RTC_PITEN_bm; // Period = 16ms, enable the PI Timer - #else - #error Unrecognized MCU type - #endif -} - -#ifdef TICK_DURING_STANDBY -inline void WDT_slow() -{ - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - // interrupt slower - //cli(); // Disable interrupts - wdt_reset(); // Reset the WDT - WDTCR |= (1< 0) {} // make sure the register is ready to be updated - RTC.PITCTRLA = (1<<6) | (STANDBY_TICK_SPEED<<3) | RTC_PITEN_bm; // Set period, enable the PI Timer - #else - #error Unrecognized MCU type - #endif -} -#endif - -inline void WDT_off() -{ - #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) - //cli(); // Disable interrupts - wdt_reset(); // Reset the WDT - MCUSR &= ~(1< 0) {} // make sure the register is ready to be updated - RTC.PITCTRLA = 0; // Disable the PI Timer - #else - #error Unrecognized MCU type - #endif -} - // clock tick -- this runs every 16ms (62.5 fps) -#ifdef AVRXMEGA3 // ATTINY816, 817, etc -ISR(RTC_PIT_vect) { - RTC.PITINTFLAGS = RTC_PI_bm; // clear the PIT interrupt flag -#else ISR(WDT_vect) { -#endif + mcu_wdt_vect_clear(); irq_wdt = 1; // WDT event happened } diff --git a/fsm/wdt.h b/fsm/wdt.h index abf34c5e..98eaf25e 100644 --- a/fsm/wdt.h +++ b/fsm/wdt.h @@ -6,8 +6,11 @@ #define TICKS_PER_SECOND 62 -void WDT_on(); -inline void WDT_off(); +//void WDT_on(); +//inline void WDT_off(); +#define WDT_on mcu_wdt_active +#define WDT_slow mcu_wdt_standby +#define WDT_off mcu_wdt_stop volatile uint8_t irq_wdt = 0; // WDT interrupt happened? diff --git a/hw/BRANDS b/hw/BRANDS index 059f3119..b55c5694 100644 --- a/hw/BRANDS +++ b/hw/BRANDS @@ -8,4 +8,8 @@ Fireflies 0400 - 0499 Mateminco 0500 - 0599 Sofirn 0600 - 0699 Wurkkos 0700 - 0799 -gChart 1600 - 1699 +... +gChart 1600 - 1699 (also thefreeman, since he picked 163X) +... +reserved 1900 - 2199 (to ensure no overlap between years and model numbers) + (assumes this project won't be relevant in the year 2200 or later) diff --git a/hw/gchart/fet1-t1616/hwdef.h b/hw/gchart/fet1-t1616/hwdef.h index ac4fd538..40083fc5 100644 --- a/hw/gchart/fet1-t1616/hwdef.h +++ b/hw/gchart/fet1-t1616/hwdef.h @@ -11,11 +11,9 @@ * Read voltage from VCC pin, has diode with ~0.4v drop */ -#include - // nearly all t1616-based FET+1 drivers work pretty much the same // (this one has single-color aux like the TS10) -#define HWDEF_C_FILE wurkkos/ts10/hwdef.c +#define HWDEF_C wurkkos/ts10/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-aux.h" diff --git a/hw/hank/emisar-2ch/fet/hwdef.h b/hw/hank/emisar-2ch/fet/hwdef.h index 0778e101..33eef7ea 100644 --- a/hw/hank/emisar-2ch/fet/hwdef.h +++ b/hw/hank/emisar-2ch/fet/hwdef.h @@ -32,9 +32,7 @@ * The first channel also has a direct-drive FET for turbo. */ -#include - -#define HWDEF_C_FILE hank/emisar-2ch/fet/hwdef.c +#define HWDEF_C hank/emisar-2ch/fet/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -106,38 +104,10 @@ enum channel_modes_e { #define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #endif -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif +#include "hank/vdivider-1634.h" // this light has aux LEDs under the optic #define AUXLED_R_PIN PA5 // pin 2 diff --git a/hw/hank/emisar-2ch/hwdef.h b/hw/hank/emisar-2ch/hwdef.h index e3707c78..28d1b457 100644 --- a/hw/hank/emisar-2ch/hwdef.h +++ b/hw/hank/emisar-2ch/hwdef.h @@ -31,9 +31,7 @@ * and one pin to control the Opamp power level. */ -#include - -#define HWDEF_C_FILE hank/emisar-2ch/hwdef.c +#define HWDEF_C hank/emisar-2ch/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -103,38 +101,10 @@ enum channel_modes_e { #define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #endif -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif +#include "hank/vdivider-1634.h" // this light has aux LEDs under the optic #define AUXLED_R_PIN PA5 // pin 2 diff --git a/hw/hank/emisar-d18/hwdef.h b/hw/hank/emisar-d18/hwdef.h index 86c97c27..a0d3cd03 100644 --- a/hw/hank/emisar-d18/hwdef.h +++ b/hw/hank/emisar-d18/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE lumintop/fw3a/hwdef.c +#define HWDEF_C lumintop/fw3a/hwdef.c // channel modes // * 0. FET+N+1 stacked diff --git a/hw/hank/emisar-d4/hwdef.h b/hw/hank/emisar-d4/hwdef.h index 55ef72ef..6257ddb6 100644 --- a/hw/hank/emisar-d4/hwdef.h +++ b/hw/hank/emisar-d4/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE hank/emisar-d4/hwdef.c +#define HWDEF_C hank/emisar-d4/hwdef.c // allow using aux LEDs as extra channel modes (when they exist) //#ifdef AUXLED_PIN diff --git a/hw/hank/emisar-d4k-3ch/hwdef.h b/hw/hank/emisar-d4k-3ch/hwdef.h index 7cfe6991..81206c2c 100644 --- a/hw/hank/emisar-d4k-3ch/hwdef.h +++ b/hw/hank/emisar-d4k-3ch/hwdef.h @@ -35,9 +35,7 @@ * So this code should support both wire layouts. */ -#include - -#define HWDEF_C_FILE hank/emisar-d4k-3ch/hwdef.c +#define HWDEF_C hank/emisar-d4k-3ch/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -132,38 +130,10 @@ uint8_t led4_pwm, led4_dsm; #define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #endif -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif +#include "hank/vdivider-1634.h" // this light has aux LEDs under the optic #define AUXLED_R_PIN PA5 // pin 2 diff --git a/hw/hank/emisar-d4sv2/hwdef.h b/hw/hank/emisar-d4sv2/hwdef.h index d1e04528..121593a0 100644 --- a/hw/hank/emisar-d4sv2/hwdef.h +++ b/hw/hank/emisar-d4sv2/hwdef.h @@ -30,9 +30,7 @@ * ADC12 thermal sensor */ -#include - -#define HWDEF_C_FILE hank/emisar-d4sv2/hwdef.c +#define HWDEF_C hank/emisar-d4sv2/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -89,7 +87,7 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #define ADC_PRSCL 0x07 // clk/128 diff --git a/hw/hank/emisar-d4v2/hwdef.h b/hw/hank/emisar-d4v2/hwdef.h index 9e3f755a..1c100043 100644 --- a/hw/hank/emisar-d4v2/hwdef.h +++ b/hw/hank/emisar-d4v2/hwdef.h @@ -28,10 +28,8 @@ * ADC12 thermal sensor */ -#include - -#ifndef HWDEF_C_FILE -#define HWDEF_C_FILE hank/emisar-d4v2/hwdef.c +#ifndef HWDEF_C +#define HWDEF_C hank/emisar-d4v2/hwdef.c #endif // allow using aux LEDs as extra channel modes @@ -84,7 +82,7 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] #define ADC_PRSCL 0x07 // clk/128 diff --git a/hw/hank/emisar-d4v2/nofet/anduril.h b/hw/hank/emisar-d4v2/nofet/anduril.h index b5f9304e..e05fb2e8 100644 --- a/hw/hank/emisar-d4v2/nofet/anduril.h +++ b/hw/hank/emisar-d4v2/nofet/anduril.h @@ -4,7 +4,7 @@ #pragma once // switch to 1-channel support functions -#define HWDEF_C_FILE hank/emisar-d4v2/nofet/hwdef.c +#define HWDEF_C hank/emisar-d4v2/nofet/hwdef.c #include "hank/emisar-d4v2/anduril.h" diff --git a/hw/hank/noctigon-dm11/boost/hwdef.h b/hw/hank/noctigon-dm11/boost/hwdef.h index 5ac2dafd..789eac9b 100644 --- a/hw/hank/noctigon-dm11/boost/hwdef.h +++ b/hw/hank/noctigon-dm11/boost/hwdef.h @@ -36,9 +36,7 @@ * not to change brightness. */ -#include - -#define HWDEF_C_FILE hank/noctigon-dm11/boost/hwdef.c +#define HWDEF_C hank/noctigon-dm11/boost/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -101,37 +99,9 @@ uint8_t ch1_pwm, ch1_dsm; #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] + +#include "hank/vdivider-1634.h" // this light has aux LEDs under the optic #define AUXLED_R_PIN PA5 // pin 2 diff --git a/hw/hank/noctigon-dm11/hwdef.h b/hw/hank/noctigon-dm11/hwdef.h index cd21eae3..3e3d4269 100644 --- a/hw/hank/noctigon-dm11/hwdef.h +++ b/hw/hank/noctigon-dm11/hwdef.h @@ -37,10 +37,8 @@ * Some models also have a direct-drive FET for turbo. */ -#include - -#ifndef HWDEF_C_FILE -#define HWDEF_C_FILE hank/noctigon-kr4/hwdef.c +#ifndef HWDEF_C +#define HWDEF_C hank/noctigon-kr4/hwdef.c #endif // allow using aux LEDs as extra channel modes @@ -95,38 +93,10 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] + + +#include "hank/vdivider-1634.h" // this light has aux LEDs under the optic #define AUXLED_R_PIN PA5 // pin 2 diff --git a/hw/hank/noctigon-dm11/nofet/anduril.h b/hw/hank/noctigon-dm11/nofet/anduril.h index 12336f17..c13f4ab9 100644 --- a/hw/hank/noctigon-dm11/nofet/anduril.h +++ b/hw/hank/noctigon-dm11/nofet/anduril.h @@ -4,7 +4,7 @@ #pragma once // same support functions as a KR4 -#define HWDEF_C_FILE hank/noctigon-kr4/nofet/hwdef.c +#define HWDEF_C hank/noctigon-kr4/nofet/hwdef.c #include "hank/noctigon-dm11/anduril.h" // turn off the DD FET diff --git a/hw/hank/noctigon-k1/boost/hwdef.h b/hw/hank/noctigon-k1/boost/hwdef.h index 951932a7..db1584c5 100644 --- a/hw/hank/noctigon-k1/boost/hwdef.h +++ b/hw/hank/noctigon-k1/boost/hwdef.h @@ -34,9 +34,7 @@ * not to change brightness. */ -#include - -#define HWDEF_C_FILE hank/noctigon-dm11/boost/hwdef.c +#define HWDEF_C hank/noctigon-dm11/boost/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -99,37 +97,9 @@ uint8_t ch1_pwm, ch1_dsm; #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] + +#include "hank/vdivider-1634.h" // this light has aux LEDs under the optic #define AUXLED_R_PIN PA5 // pin 2 diff --git a/hw/hank/noctigon-k1/hwdef.h b/hw/hank/noctigon-k1/hwdef.h index 9a68401d..0d20871d 100644 --- a/hw/hank/noctigon-k1/hwdef.h +++ b/hw/hank/noctigon-k1/hwdef.h @@ -36,10 +36,8 @@ * not to change brightness. */ -#include - -#ifndef HWDEF_C_FILE -#define HWDEF_C_FILE hank/noctigon-k1/hwdef.c +#ifndef HWDEF_C +#define HWDEF_C hank/noctigon-k1/hwdef.c #endif // allow using aux LEDs as extra channel modes @@ -88,38 +86,10 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] + + +#include "hank/vdivider-1634.h" // this light has aux LEDs under the optic #define AUXLED_R_PIN PA5 // pin 2 diff --git a/hw/hank/noctigon-k1/sbt90/hwdef.h b/hw/hank/noctigon-k1/sbt90/hwdef.h index 8186b49b..e2d04a91 100644 --- a/hw/hank/noctigon-k1/sbt90/hwdef.h +++ b/hw/hank/noctigon-k1/sbt90/hwdef.h @@ -37,9 +37,7 @@ * Also has a direct-drive FET for turbo. */ -#include - -#define HWDEF_C_FILE hank/noctigon-kr4/hwdef.c +#define HWDEF_C hank/noctigon-kr4/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -93,38 +91,9 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] #define SWITCH_PORT PINB // PINA or PINB or PINC #define SWITCH_PUE PUEB // pullup group B -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// TODO: calibrate this -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif +#define SWITCH_VECT PCINT1_vect // ISR for PCINT[11:8] + +#include "hank/vdivider-1634.h" #define TEMP_CHANNEL 0b00001111 diff --git a/hw/hank/noctigon-kr4/2ch/hwdef.h b/hw/hank/noctigon-kr4/2ch/hwdef.h index b23c7ccd..28a686d6 100644 --- a/hw/hank/noctigon-kr4/2ch/hwdef.h +++ b/hw/hank/noctigon-kr4/2ch/hwdef.h @@ -30,8 +30,6 @@ * ADC12 thermal sensor */ -#include - // move the switch to a different pin #define SWITCH_PIN PB2 // pin 17 #define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt @@ -39,7 +37,7 @@ #define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] #define SWITCH_PORT PINB // PINA or PINB or PINC #define SWITCH_PUE PUEB // pullup group B -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] +#define SWITCH_VECT PCINT1_vect // ISR for PCINT[11:8] // the rest of the config is the same as the generic Emisar 2ch build #include "hank/emisar-2ch/hwdef.h" diff --git a/hw/hank/noctigon-kr4/boost/hwdef.h b/hw/hank/noctigon-kr4/boost/hwdef.h index f17d2636..b923b307 100644 --- a/hw/hank/noctigon-kr4/boost/hwdef.h +++ b/hw/hank/noctigon-kr4/boost/hwdef.h @@ -46,12 +46,12 @@ #undef SWITCH_PCMSK #undef SWITCH_PORT #undef SWITCH_PUE -#undef PCINT_vect +#undef SWITCH_VECT #define SWITCH_PIN PB2 // pin 17 #define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt #define SWITCH_PCIE PCIE1 // PCIE1 is for PCINT[11:8] #define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] #define SWITCH_PORT PINB // PINA or PINB or PINC #define SWITCH_PUE PUEB // pullup group B -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] +#define SWITCH_VECT PCINT1_vect // ISR for PCINT[11:8] diff --git a/hw/hank/noctigon-kr4/hwdef.h b/hw/hank/noctigon-kr4/hwdef.h index 586f8489..49e71fa0 100644 --- a/hw/hank/noctigon-kr4/hwdef.h +++ b/hw/hank/noctigon-kr4/hwdef.h @@ -35,10 +35,8 @@ * Some models also have a direct-drive FET for turbo. */ -#include - -#ifndef HWDEF_C_FILE -#define HWDEF_C_FILE hank/noctigon-kr4/hwdef.c +#ifndef HWDEF_C +#define HWDEF_C hank/noctigon-kr4/hwdef.c #endif // allow using aux LEDs as extra channel modes @@ -93,41 +91,13 @@ enum CHANNEL_MODES { #define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] #define SWITCH_PORT PINB // PINA or PINB or PINC #define SWITCH_PUE PUEB // pullup group B -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] +#define SWITCH_VECT PCINT1_vect // ISR for PCINT[11:8] // the button tends to short out the voltage divider, // so ignore voltage while the button is being held //#define NO_LVP_WHILE_BUTTON_PRESSED -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif +#include "hank/vdivider-1634.h" // this light has aux LEDs under the optic #define AUXLED_R_PIN PA5 // pin 2 diff --git a/hw/hank/noctigon-kr4/nofet/anduril.h b/hw/hank/noctigon-kr4/nofet/anduril.h index 4522cded..ad3f0125 100644 --- a/hw/hank/noctigon-kr4/nofet/anduril.h +++ b/hw/hank/noctigon-kr4/nofet/anduril.h @@ -5,7 +5,7 @@ // (and Noctigon KR1) // (and Emisar D4v2 E21A, a.k.a. "D4v2.5") -#define HWDEF_C_FILE hank/noctigon-kr4/nofet/hwdef.c +#define HWDEF_C hank/noctigon-kr4/nofet/hwdef.c #include "hank/noctigon-kr4/anduril.h" // brightness w/ SST-20 4000K LEDs: diff --git a/hw/hank/noctigon-m44/hwdef.h b/hw/hank/noctigon-m44/hwdef.h index af942d9b..a3972121 100644 --- a/hw/hank/noctigon-m44/hwdef.h +++ b/hw/hank/noctigon-m44/hwdef.h @@ -28,9 +28,7 @@ * ADC12 thermal sensor */ -#include - -#define HWDEF_C_FILE hank/noctigon-m44/hwdef.c +#define HWDEF_C hank/noctigon-m44/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -110,37 +108,9 @@ uint8_t ch2_pwm, ch2_dsm; #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif +#define SWITCH_VECT PCINT0_vect // ISR for PCINT[7:0] + +#include "hank/vdivider-1634.h" // this light has aux LEDs under the optic #define AUXLED_R_PIN PA5 // pin 2 diff --git a/hw/hank/vdivider-1634.h b/hw/hank/vdivider-1634.h new file mode 100644 index 00000000..171267d2 --- /dev/null +++ b/hw/hank/vdivider-1634.h @@ -0,0 +1,39 @@ +// attiny1634 voltage divider common defs +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 +// pin to ADC mappings are in DS table 19-4 +#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 +// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 +#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D +// DS tables 19-3, 19-4 +// Bit 7 6 5 4 3 2 1 0 +// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 +// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 +// divided by ... +// REFS[1:0] = 1, 0 for internal 1.1V reference +// other bits reserved +#define ADMUX_VOLTAGE_DIVIDER 0b10000110 +#undef voltage_raw2cooked +#define voltage_raw2cooked mcu_vdivider_raw2cooked + +#define ADC_PRSCL 0x07 // clk/128 + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// D1, R1, R2 = 0, 330, 100 +#ifndef ADC_44 +//#define ADC_44 (4*981) // raw value at 4.40V +#define ADC_44 (4*967) // manually tweaked so 4.16V will blink out 4.2 +#endif +#ifndef ADC_22 +//#define ADC_22 (4*489) // raw value at 2.20V +#define ADC_22 (4*482) // manually tweaked so 4.16V will blink out 4.2 +#endif + + diff --git a/hw/lumintop/blf-gt/anduril.h b/hw/lumintop/blf-gt/anduril.h index 2fc359e5..cc2f9406 100644 --- a/hw/lumintop/blf-gt/anduril.h +++ b/hw/lumintop/blf-gt/anduril.h @@ -54,7 +54,14 @@ #undef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_FLOOR +#define USE_SMOOTH_STEPS + // too big, turn off extra features //#undef USE_TACTICAL_MODE #undef USE_SOS_MODE +#undef USE_BEACON_MODE +#undef USE_RAMP_AFTER_MOON_CONFIG +//#undef USE_RAMP_SPEED_CONFIG +//#undef USE_VOLTAGE_CORRECTION +#undef USE_2C_STYLE_CONFIG diff --git a/hw/lumintop/blf-gt/hwdef.h b/hw/lumintop/blf-gt/hwdef.h index bf3790d6..68197acb 100644 --- a/hw/lumintop/blf-gt/hwdef.h +++ b/hw/lumintop/blf-gt/hwdef.h @@ -16,9 +16,7 @@ * and its output gets PWM'd by pin 5. */ -#include - -#define HWDEF_C_FILE hank/emisar-d4/hwdef.c +#define HWDEF_C hank/emisar-d4/hwdef.c // channel modes // * 0. main LEDs @@ -69,14 +67,18 @@ enum CHANNEL_MODES { //#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | (1 << ADLAR) | VOLTAGE_CHANNEL) // 1.1V reference, no left-adjust, ADC1/PB2 #define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | VOLTAGE_CHANNEL) + +#undef voltage_raw2cooked +#define voltage_raw2cooked mcu_vdivider_raw2cooked + #define ADC_PRSCL 0x07 // clk/128 // Raw ADC readings at 4.4V and 2.2V (in-between, we assume values form a straight line) #ifndef ADC_44 -#define ADC_44 (184*4) +#define ADC_44 (184*4*4) #endif #ifndef ADC_22 -#define ADC_22 (92*4) +#define ADC_22 (92*4*4) #endif #define FAST 0xA3 // fast PWM both channels diff --git a/hw/lumintop/fw3a/hwdef.h b/hw/lumintop/fw3a/hwdef.h index 649dc19c..7809fa9d 100644 --- a/hw/lumintop/fw3a/hwdef.h +++ b/hw/lumintop/fw3a/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE lumintop/fw3a/hwdef.c +#define HWDEF_C lumintop/fw3a/hwdef.c // channel modes // * 0. FET+7+1 stacked diff --git a/hw/lumintop/fw3x-lume1/README.md b/hw/lumintop/fw3x-lume1/README.md new file mode 100644 index 00000000..d155ebad --- /dev/null +++ b/hw/lumintop/fw3x-lume1/README.md @@ -0,0 +1,35 @@ +# Lumintop FW3X Lume1 + +A BLF FW3A with a new driver from LoneOceans. The new driver adds efficient +constant-current power regulation, RGB aux LEDs, and an upgraded temperature +sensor. + +## Notes of interest + +**Flashing firmware**: The MOSI and MISO pin are swapped on PCBs dated 01/20, +compared to a Hanklight. LoneOceans sent a fixed driver design (dated 06/20) +to Lumintop, but the new design didn't get produced. So to flash firmware, +swap the wires for those two pins first. + +**Fuses**: Lumintop seems to have shipped the FW3X with the wrong fuse values, +so it has the MCU severely underclocked and everything runs much slower than it +should. Use [flash-tiny1634-fuses.sh](../../../bin/flash-tiny1634-fuses.sh) to +fix those fuse values and get it running at the correct speed. + +**RGB mixup**: Lumintop seems to have swapped the wires for aux R and aux B. +This was fixed in firmware in 2023-12, but some lights were fixed in hardware +before that, so the firmware fix might cause the colors to be swapped again. + +**Turbo**: The driver uses regulation for levels 1 to 149, and level 150 is a +direct-drive FET. This is by design, and the FET cannot be ramped smoothly up +and down. Turbo is a single level at the top of the ramp, with a big sudden +drop to the next level. + +**Moon**: This light has a pretty bright preflash at moon level, and the +output is unstable so there is very visible ripple. The user can either raise +the ramp floor to a level high enough to avoid these issues, or learn to live +with the ripple and preflash. + +LoneOceans has some extra notes here, which mostly apply only to older versions +of the code: https://budgetlightforum.com/t/anduril-2/62656/531 + diff --git a/hw/lumintop/fw3x-lume1/anduril.h b/hw/lumintop/fw3x-lume1/anduril.h index b208fbc9..852e1c47 100644 --- a/hw/lumintop/fw3x-lume1/anduril.h +++ b/hw/lumintop/fw3x-lume1/anduril.h @@ -8,10 +8,9 @@ * For more information: www.loneoceans.com/labs/ * Datasheets: * - 1634: http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8303-8-bit-AVR-Microcontroller-tinyAVR-ATtiny1634_Datasheet.pdf - * - 85: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf */ -#include "lumintop/fw3x-lume1/hwdef.h" +#define HWDEF_H lumintop/fw3x-lume1/hwdef.h // set this light for 50C thermal ceiling #undef DEFAULT_THERM_CEIL @@ -20,60 +19,61 @@ // this light has three aux LED channels: R, G, B #define USE_AUX_RGB_LEDS -// it has no independent LED in the button unlike emisar d4 -//#define USE_BUTTON_LED - // the aux LEDs are front-facing, so turn them off while main LEDs are on #ifdef USE_INDICATOR_LED_WHILE_RAMPING #undef USE_INDICATOR_LED_WHILE_RAMPING #endif -// ../../bin/level_calc.py cube 1 149 7135 0 0.5 1000, with 0 appended to the end. -// for FET PWM (PWM2), all values are 0, except for last value of 1023 -// (with max_pwm set to 1023) #define RAMP_SIZE 150 -//#define PWM1_LEVELS 0,0,0,0,1,1,1,1,2,2,2,3,3,4,4,5,5,6,7,7,8,9,10,11,12,13,14,15,16,17,19,20,22,23,25,26,28,30,32,34,36,38,40,42,45,47,49,52,55,58,60,63,66,70,73,76,80,83,87,91,94,98,102,107,111,115,120,124,129,134,139,144,150,155,160,166,172,178,184,190,196,203,209,216,223,230,237,244,252,259,267,275,283,291,299,308,316,325,334,343,353,362,372,382,392,402,412,423,433,444,455,466,478,489,501,513,525,538,550,563,576,589,602,616,630,644,658,672,687,701,716,731,747,762,778,794,810,827,844,861,878,895,913,930,948,967,985,1004,1023,0 -#define PWM1_LEVELS 1,1,1,1,2,2,2,2,3,3,3,4,4,5,5,6,6,7,8,8,9,10,11,12,13,14,15,16,17,18,20,21,23,24,26,27,29,31,33,35,37,39,41,43,45,48,50,53,56,58,61,64,67,70,74,77,80,84,88,91,95,99,103,108,112,116,121,125,130,135,140,145,150,156,161,167,173,178,184,191,197,203,210,217,223,230,238,245,252,260,268,275,283,292,300,308,317,326,335,344,353,363,372,382,392,402,413,423,434,445,456,467,478,490,502,514,526,538,551,563,576,589,603,616,630,644,658,672,687,702,717,732,747,763,778,794,811,827,844,861,878,895,913,931,949,967,985,1004,1023,0 -#define PWM2_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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1023 + +// level_calc.py 5.01 1 149 7135 0 0.2 2000 --pwm 32640 +// regulated channel: 16-bit PWM+DSM for low lows and very smooth ramp +#define PWM1_LEVELS 0,1,2,3,4,5,6,7,9,10,12,14,17,19,22,25,29,33,37,41,46,51,57,63,70,77,85,93,103,112,123,134,146,159,172,187,203,219,237,256,276,297,319,343,368,394,422,452,483,516,551,587,625,666,708,753,799,848,900,954,1010,1069,1131,1195,1263,1333,1407,1483,1563,1647,1734,1825,1919,2017,2119,2226,2336,2451,2571,2694,2823,2957,3095,3239,3388,3542,3702,3868,4040,4217,4401,4591,4788,4992,5202,5419,5644,5876,6115,6362,6617,6880,7152,7432,7721,8018,8325,8641,8967,9302,9647,10003,10369,10745,11133,11531,11941,12363,12796,13241,13699,14169,14652,15148,15657,16180,16717,17268,17834,18414,19009,19620,20246,20888,21546,22221,22913,23621,24348,25091,25853,26634,27433,28251,29089,29946,30823,31721,32640,0 +// DD FET: 8-bit PWM (but hardware can only handle 0 and MAX) +#define PWM2_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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255 #define DEFAULT_LEVEL 56 #define MAX_1x7135 149 -// TODO: test if underclocking works on lume1 -//#define HALFSPEED_LEVEL 14 -//#define QUARTERSPEED_LEVEL 5 -// don't slow down at low levels; this isn't that sort of light -// (it needs to stay at full speed for the 10-bit PWM to work) -#ifdef USE_DYNAMIC_UNDERCLOCKING -#undef USE_DYNAMIC_UNDERCLOCKING -#endif - -// the entire ramp is regulated except turbo; don't blink halfway up -#ifdef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_MIDDLE -#endif +#define MIN_THERM_STEPDOWN 50 +#define HALFSPEED_LEVEL 11 +#define QUARTERSPEED_LEVEL 2 #define RAMP_SMOOTH_FLOOR 1 #define RAMP_SMOOTH_CEIL 149 -// turn on BuckBoost from level 1 to 149, but not 150 -// Level 150 is when BuckBoost is off and FET is ON 100% -#define LED_ENABLE_PIN_LEVEL_MIN 1 -#define LED_ENABLE_PIN_LEVEL_MAX 149 // 10 33 56 79 102 125 [149] #define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL #define RAMP_DISCRETE_STEPS 7 #define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR #define SIMPLE_UI_CEIL 120 #define SIMPLE_UI_STEPS 5 +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// blink numbers on the main LEDs by default (but allow user to change it) +#define DEFAULT_BLINK_CHANNEL CM_MAIN + // slow down party strobe; this driver can't pulse for too short a time -#define PARTY_STROBE_ONTIME 4 +#define PARTY_STROBE_ONTIME 1 + +// use aux red + aux blue for police strobe +#define USE_POLICE_COLOR_STROBE_MODE +#define POLICE_STROBE_USES_AUX +#define POLICE_COLOR_STROBE_CH1 CM_AUXRED +#define POLICE_COLOR_STROBE_CH2 CM_AUXBLU // stop panicking at ~85% regulated power or ~750 lm #define THERM_FASTER_LEVEL 140 #define THERM_CAL_OFFSET 0 // not needed due to external sensor +// don't blink while ramping +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + + // can't reset the normal way because power is connected before the button #define USE_SOFT_FACTORY_RESET diff --git a/hw/lumintop/fw3x-lume1/hwdef.c b/hw/lumintop/fw3x-lume1/hwdef.c index 71cd7990..306a58c9 100644 --- a/hw/lumintop/fw3x-lume1/hwdef.c +++ b/hw/lumintop/fw3x-lume1/hwdef.c @@ -1,10 +1,11 @@ -// FW3X Lume1 PWM helper functions +// FW3X Lume1 helper functions // Copyright (C) 2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "fsm/chan-rgbaux.c" + void set_level_zero(); void set_level_main(uint8_t level); @@ -21,6 +22,12 @@ Channel 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; CH1_PWM = 0; CH2_PWM = 0; PWM_CNT = 0; // reset phase @@ -29,32 +36,109 @@ void set_level_zero() { // single set of LEDs with 2 stacked power channels, regulated + DD FET void set_level_main(uint8_t level) { - CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable regulator + if (level == actual_level - 1) return; // prevent flicker on no-op - PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); - PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); + PWM1_DATATYPE ch1 = PWM1_GET(level); + PWM2_DATATYPE ch2 = PWM2_GET(level); - CH1_PWM = ch1_pwm; - CH2_PWM = ch2_pwm; + // set delta-sigma soft levels + ch1_dsm_lvl = ch1; + + // set hardware PWM levels and init dsm loop + CH1_PWM = ch1_pwm = ch1 >> 7; + CH2_PWM = ch2; + + // enable timer overflow interrupt so DSM can work + DSM_INTCTRL |= DSM_OVF_bm; // force reset phase when turning on from zero // (for faster, more consistent initial response) if (! actual_level) PWM_CNT = 0; + + // don't enable ch1 and ch2 at the same time + if (ch2) CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable regulator + else CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable regulator } +// 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; + + // 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; +} + + bool gradual_tick_main(uint8_t gt) { // 150/150 is full FET + zero regulated, // 149/150 is zero FET + full regulated, // so don't try to gradually adjust between - if ((RAMP_SIZE == actual_level) || (gt >= RAMP_SIZE-1)) { - set_level(gt + 1); - return true; - } + // if target is in the top 2 levels, just let the parent handle it + if (gt >= RAMP_SIZE-2) return true; - PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); - GRADUAL_ADJUST_SIMPLE(pwm1, CH1_PWM); + PWM1_DATATYPE ch1 = PWM1_GET(gt); - if (pwm1 == CH1_PWM) return true; // done + // 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); + + if ((ch1 == ch1_dsm_lvl) + ) { + return true; // done + } return false; // not done yet } +////////// external temperature sensor ////////// + +#ifdef ADMUX_THERM_EXTERNAL_SENSOR + +void hwdef_set_admux_therm() { + // put the ADC in temperature mode + // ADCSRB: [VDEN, VDPD, -, -, ADLAR, ADTS2, ADTS1, ADTS0] + ADCSRB = (1 << ADLAR); // left-adjust, free-running + // DS table 19-3, 19-4 + // [refs1, refs0, refen, adc0en, mux3, mux2, mux1, mux0] + // refs=0b00 : VCC (2.5V) + // mux=0b1011 : ADC11 (pin PC2) + ADMUX = ADMUX_THERM_EXTERNAL_SENSOR; + // other stuff is already set, so no need to re-set it +} + +uint16_t temp_raw2cooked(uint16_t measurement) { + // In: (raw ADC average) << 6 + // Out: Kelvin << 6 + /* notes from old versions of the code... + // Used for Lume1 Driver: MCP9700 - T_Celsius = 100*(VOUT - 0.5V) + // ADC is 2.5V reference, 0 to 1023 + // due to floating point, this calculation takes 916 extra bytes + // (should use an integer equivalent instead) + //#define EXTERN_TEMP_FORMULA(m) (((m)-205)/4.09) + //int16_t celsius = (((measurement-205)/4.09)) + THERM_CAL_OFFSET + (int16_t)therm_cal_offset; + */ + + // this formula could probably be simplified... but meh, it works + uint16_t k6 = ((uint32_t)(measurement - (205 << 6)) * 100 / 409) + + (273 << 6); // convert back from C to K + return k6; +} + +#endif + diff --git a/hw/lumintop/fw3x-lume1/hwdef.h b/hw/lumintop/fw3x-lume1/hwdef.h index 943921fa..021c4cf9 100644 --- a/hw/lumintop/fw3x-lume1/hwdef.h +++ b/hw/lumintop/fw3x-lume1/hwdef.h @@ -8,9 +8,9 @@ * * Pin / Name / Function in Lume1 Rev B * 1 PA6 Regulated PWM (PWM1B) - * 2 PA5 R: red aux LED (PWM0B) + * 2 PA5 B: blue aux LED (PWM0B) (or red) * 3 PA4 G: green aux LED - * 4 PA3 B: blue aux LED + * 4 PA3 R: red aux LED (or blue) * 5 PA2 e-switch (PCINT2) * 6 PA1 Jumper 1 * 7 PA0 Jumper 2 @@ -34,9 +34,7 @@ * Another pin is used for DD FET control. */ -#include - -#define HWDEF_C_FILE lumintop/fw3x-lume1/hwdef.c +#define HWDEF_C lumintop/fw3x-lume1/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -56,29 +54,38 @@ enum CHANNEL_MODES { #define CHANNEL_MODES_ENABLED 0b0000000000000001 -#define PWM_CHANNELS 2 // old, remove this - -// Added for Lume1 Buck Boost Driver -#define PWM_BITS 16 // 0 to 1023 at 3.9 kHz, not 0 to 255 at 15.6 kHz -#define PWM_GET PWM_GET16 +#define PWM_BITS 16 // 0 to 32640 (0 to 255 PWM + 0 to 127 DSM) at constant kHz #define PWM_DATATYPE uint16_t #define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 #define PWM1_DATATYPE uint16_t // regulated ramp -#define PWM2_DATATYPE uint16_t // DD FET ramp +#define PWM1_GET(x) PWM_GET16(pwm1_levels, x) +#define PWM2_DATATYPE uint8_t // DD FET ramp +#define PWM2_GET(x) PWM_GET8(pwm2_levels, x) // PWM parameters of both channels are tied together because they share a counter #define PWM_TOP ICR1 // holds the TOP value for variable-resolution PWM -#define PWM_TOP_INIT 1023 -#define PWM_CNT TCNT1 // for dynamic PWM, reset phase +#define PWM_TOP_INIT 255 +#define PWM_CNT TCNT1 // for checking / resetting phase +// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) +#define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry + +// timer interrupt for DSM +#define DSM_vect TIMER1_OVF_vect +#define DSM_INTCTRL TIMSK +#define DSM_OVF_bm (1< - -#define HWDEF_C_FILE lumintop/fw3a/hwdef.c +#define HWDEF_C lumintop/fw3a/hwdef.c // channel modes // * 0. FET+N+1 stacked diff --git a/hw/mateminco/mf01s/hwdef.h b/hw/mateminco/mf01s/hwdef.h index 12451d79..21ea1fd3 100644 --- a/hw/mateminco/mf01s/hwdef.h +++ b/hw/mateminco/mf01s/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE hank/emisar-d4/hwdef.c +#define HWDEF_C hank/emisar-d4/hwdef.c // channel modes // * 0. small FET + big FET stacked @@ -69,14 +67,18 @@ enum CHANNEL_MODES { // 1.1V reference, no left-adjust, ADC1/PB2 #define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | VOLTAGE_CHANNEL) #endif + +#undef voltage_raw2cooked +#define voltage_raw2cooked mcu_vdivider_raw2cooked + #define ADC_PRSCL 0x07 // clk/128 // Raw ADC readings at 4.4V and 2.2V (in-between, we assume values form a straight line) #ifndef ADC_44 -#define ADC_44 (234*4) +#define ADC_44 (234*4*4) #endif #ifndef ADC_22 -#define ADC_22 (117*4) +#define ADC_22 (117*4*4) #endif #define FAST 0xA3 // fast PWM both channels diff --git a/hw/mateminco/mt35-mini/hwdef.h b/hw/mateminco/mt35-mini/hwdef.h index aec4eaf6..ac7bf073 100644 --- a/hw/mateminco/mt35-mini/hwdef.h +++ b/hw/mateminco/mt35-mini/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE hank/emisar-d4/hwdef.c +#define HWDEF_C hank/emisar-d4/hwdef.c // channel modes // * 0. FET+7135 stacked diff --git a/hw/sofirn/blf-lt1-t1616/hwdef.h b/hw/sofirn/blf-lt1-t1616/hwdef.h index 66575def..c9ae1ea8 100644 --- a/hw/sofirn/blf-lt1-t1616/hwdef.h +++ b/hw/sofirn/blf-lt1-t1616/hwdef.h @@ -12,9 +12,7 @@ * Voltage: VCC */ -#include - -#define HWDEF_C_FILE sofirn/blf-lt1-t1616/hwdef.c +#define HWDEF_C sofirn/blf-lt1-t1616/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-aux.h" diff --git a/hw/sofirn/blf-lt1/hwdef.h b/hw/sofirn/blf-lt1/hwdef.h index 03f35684..a57b1c4a 100644 --- a/hw/sofirn/blf-lt1/hwdef.h +++ b/hw/sofirn/blf-lt1/hwdef.h @@ -12,9 +12,7 @@ * ---- */ -#include - -#define HWDEF_C_FILE sofirn/blf-lt1/hwdef.c +#define HWDEF_C sofirn/blf-lt1/hwdef.c // channel modes: // * 0. channel 1 only diff --git a/hw/sofirn/blf-q8-t1616/hwdef.h b/hw/sofirn/blf-q8-t1616/hwdef.h index 29c2ffaa..638a2c15 100644 --- a/hw/sofirn/blf-q8-t1616/hwdef.h +++ b/hw/sofirn/blf-q8-t1616/hwdef.h @@ -15,11 +15,9 @@ * Voltage: VCC */ -#include - // nearly all t1616-based FET+1 drivers work pretty much the same // (this one has single-color aux like the TS10) -#define HWDEF_C_FILE wurkkos/ts10/hwdef.c +#define HWDEF_C wurkkos/ts10/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-aux.h" diff --git a/hw/sofirn/lt1s-pro/anduril.h b/hw/sofirn/lt1s-pro/anduril.h index 1840b589..578afde0 100644 --- a/hw/sofirn/lt1s-pro/anduril.h +++ b/hw/sofirn/lt1s-pro/anduril.h @@ -86,13 +86,13 @@ #define USE_SIMPLE_UI_RAMPING_TOGGLE // allow Aux Config and Strobe Modes in Simple UI -#define USE_EXTENDED_SIMPLE_UI +//#define USE_EXTENDED_SIMPLE_UI // turn on at med-low brightness by default (level 50/150, or ramp step 3/7) // (also sets lockout mode 2H to a useful level) -#define DEFAULT_MANUAL_MEMORY 50 +//#define DEFAULT_MANUAL_MEMORY 50 // reset to default after being off for 10 minutes -#define DEFAULT_MANUAL_MEMORY_TIMER 10 +//#define DEFAULT_MANUAL_MEMORY_TIMER 10 // enable 2 click turbo (Anduril 1 style) #define DEFAULT_2C_STYLE 1 diff --git a/hw/sofirn/lt1s-pro/hwdef.h b/hw/sofirn/lt1s-pro/hwdef.h index cd4dd4e1..7708631f 100644 --- a/hw/sofirn/lt1s-pro/hwdef.h +++ b/hw/sofirn/lt1s-pro/hwdef.h @@ -13,9 +13,7 @@ * Voltage: VCC */ -#include - -#define HWDEF_C_FILE sofirn/lt1s-pro/hwdef.c +#define HWDEF_C sofirn/lt1s-pro/hwdef.c // channel modes: // * 0. warm/cool white blend diff --git a/hw/sofirn/sp10-pro/hwdef.h b/hw/sofirn/sp10-pro/hwdef.h index a52166d7..f220318f 100644 --- a/hw/sofirn/sp10-pro/hwdef.h +++ b/hw/sofirn/sp10-pro/hwdef.h @@ -12,9 +12,7 @@ * PA1 : Boost Enable */ -#include - -#define HWDEF_C_FILE sofirn/sp10-pro/hwdef.c +#define HWDEF_C sofirn/sp10-pro/hwdef.c // channel modes: // * 0. low+high PWM stacked @@ -61,25 +59,26 @@ enum CHANNEL_MODES { #define SWITCH_ISC_REG PORTB.PIN3CTRL #define SWITCH_VECT PORTB_PORT_vect #define SWITCH_INTFLG VPORTB.INTFLAGS -#define SWITCH_PCINT PCINT0 -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] // Voltage divider battLVL #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated -#define DUAL_VOLTAGE_FLOOR 21 // for AA/14500 boost drivers, don't indicate low voltage if below this level -#define DUAL_VOLTAGE_LOW_LOW 7 // the lower voltage range's danger zone 0.7 volts (NiMH) +#define DUAL_VOLTAGE_FLOOR (4*21) // for AA/14500 boost drivers, don't indicate low voltage if below this level +#define DUAL_VOLTAGE_LOW_LOW (4*7) // the lower voltage range's danger zone 0.7 volts (NiMH) #define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN9_gc // which ADC channel to read +#undef voltage_raw2cooked +#define voltage_raw2cooked mcu_vdivider_raw2cooked + // Raw ADC readings at 4.4V and 2.2V // calibrate the voltage readout here // estimated / calculated values are: // (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) // Resistors are 300,000 and 100,000 #ifndef ADC_44 -#define ADC_44 1023 // raw value at 4.40V +#define ADC_44 (4*1023) // raw value at 4.40V #endif #ifndef ADC_22 -#define ADC_22 512 // raw value at 2.20V +#define ADC_22 (4*512) // raw value at 2.20V #endif diff --git a/hw/thefreeman/avr32dd20-devkit/anduril.h b/hw/thefreeman/avr32dd20-devkit/anduril.h new file mode 100644 index 00000000..3152183f --- /dev/null +++ b/hw/thefreeman/avr32dd20-devkit/anduril.h @@ -0,0 +1,122 @@ +// thefreeman's avr32dd20 devkit board +// Copyright (C) 2023 thefreeman, Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#define HWDEF_H thefreeman/avr32dd20-devkit/hwdef.h + +// HPRsense : 1.7+0.3+5 = 7mR (DMN22M5UFG+trace resistance+5mR) +// Vsense=42.46mV, R1= 191k +// LPRsense : 1R +// transition DAC level 8, ramp level 45 +// fifth power ramp 0.1mA to 6066mA + +#define RAMP_SIZE 150 + +// 4 ramp segments: +// - low 1.024V +// - low 2.5 V +// - high 1.024V +// - high 2.5 V +// HDR ratio: 160 +// PWM1: DAC Data +// level_calc.py 4.3287 1 150 7135 5 0.01 1400 --pwm 400000 +// top level for each "gear": 30 40 120 150 +#define PWM1_LEVELS \ + 6, 7, 9, 11, 14, 18, 23, 30, 37, 46, 56, 69, 83, 100, 120, 142, 168, 196, 229, 266, 307, 353, 403, 460, 522, 591, 667, 750, 840, 939, \ + 428, 476, 528, 584, 645, 710, 780, 856, 937,1023, \ + 17, 18, 20, 21, 23, 25, 27, 29, 32, 34, 37, 40, 42, 46, 49, 52, 56, 60, 64, 68, 72, 77, 81, 86, 92, 97, 103, 109, 115, 122, 128, 136, 143, 151, 159, 167, 176, 185, 194, 204, 214, 224, 235, 246, 258, 270, 283, 295, 309, 323, 337, 352, 367, 383, 399, 416, 434, 452, 470, 489, 509, 529, 550, 572, 594, 617, 640, 664, 689, 715, 741, 768, 796, 824, 854, 884, 915, 947, 979,1013, \ + 429, 443, 458, 473, 489, 505, 521, 538, 555, 572, 590, 609, 628, 647, 667, 687, 708, 729, 751, 773, 796, 819, 843, 867, 891, 917, 943, 969, 996,1023 +#define PWM2_LEVELS \ + V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, \ + V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, \ + V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, V10, \ + V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25, V25 +#define MAX_1x7135 40 +#define HDR_ENABLE_LEVEL_MIN 41 +#define DEFAULT_LEVEL 50 + +// no PWM, so MCU clock speed can be slow +#define HALFSPEED_LEVEL 41 +#define QUARTERSPEED_LEVEL 40 // seems to run fine at 10kHz/4, try reducing more + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 130 // 50% / 3A / 1000 lm +// 1 22 [44] 65 87 108 130 +#define RAMP_DISCRETE_FLOOR 1 +#define RAMP_DISCRETE_CEIL 130 +#define RAMP_DISCRETE_STEPS 7 + +// 20 [45] 70 95 120 +#define SIMPLE_UI_FLOOR 20 +#define SIMPLE_UI_CEIL 120 // ~2.25A / ~750 lm +#define SIMPLE_UI_STEPS 5 + +// don't blink mid-ramp +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + +// thermal config + +// temperature limit +#define THERM_FASTER_LEVEL 130 // stop panicking at 50%/3A +#define MIN_THERM_STEPDOWN MAX_1x7135 + + +// UI + +#define SIMPLE_UI_ACTIVE 0 // advanced UI by default, because it's a dev board + +// allow Aux Config and Strobe Modes in Simple UI +//#define USE_EXTENDED_SIMPLE_UI + +// Allow 3C in Simple UI for switching between smooth and stepped ramping +#define USE_SIMPLE_UI_RAMPING_TOGGLE + +#define DEFAULT_2C_STYLE 1 // enable 2 click turbo + + +// AUX + +//#define USE_BUTTON_LED + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS +// turn on the aux LEDs while main LEDs are on +// because this is a dev board and it's useful to see that +#define USE_AUX_RGB_LEDS_WHILE_ON 20 +#define USE_INDICATOR_LED_WHILE_RAMPING + +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// blink numbers on the main LEDs by default +#define DEFAULT_BLINK_CHANNEL CM_MAIN + +// use aux red + aux blue for police strobe +#define USE_POLICE_COLOR_STROBE_MODE +#define POLICE_STROBE_USES_AUX +#define POLICE_COLOR_STROBE_CH1 CM_AUXRED +#define POLICE_COLOR_STROBE_CH2 CM_AUXBLU + +// the aux LEDs are front-facing, so turn them off while main LEDs are on +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif + + +// Misc + +#define PARTY_STROBE_ONTIME 1 // slow down party strobe +#define STROBE_OFF_LEVEL 1 // keep the regulator chip on between pulses +#define BLIP_LEVEL 1 // same + +// smoother candle mode with bigger oscillations +#define CANDLE_AMPLITUDE 40 + +// enable 13H factory reset so it can be used on tail e-switch lights +#define USE_SOFT_FACTORY_RESET + +// TODO: disable lowpass while asleep; the MCU oversamples + diff --git a/hw/thefreeman/avr32dd20-devkit/arch b/hw/thefreeman/avr32dd20-devkit/arch new file mode 100644 index 00000000..bcf4552b --- /dev/null +++ b/hw/thefreeman/avr32dd20-devkit/arch @@ -0,0 +1 @@ +avr32dd20 diff --git a/hw/thefreeman/avr32dd20-devkit/hwdef.c b/hw/thefreeman/avr32dd20-devkit/hwdef.c new file mode 100644 index 00000000..3e5dd797 --- /dev/null +++ b/hw/thefreeman/avr32dd20-devkit/hwdef.c @@ -0,0 +1,118 @@ +// thefreeman boost driver 2.1 output helper functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "fsm/chan-rgbaux.c" + +void set_level_zero(); + +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // main LEDs + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, + RGB_AUX_CHANNELS +}; + + +void set_level_zero() { + DAC_LVL = 0; // DAC off + DAC_VREF = V10; // low Vref + HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); // HDR off + + // prevent post-off flash + IN_NFET_ENABLE_PORT |= (1 << IN_NFET_ENABLE_PIN); + delay_4ms(IN_NFET_DELAY_TIME/4); + IN_NFET_ENABLE_PORT &= ~(1 << IN_NFET_ENABLE_PIN); + + // turn off boost last + BST_ENABLE_PORT &= ~(1 << BST_ENABLE_PIN); // BST off +} + +// single set of LEDs with 1 regulated power channel +// and low/high HDR plus low/high Vref as different "gears" +void set_level_main(uint8_t level) { + uint8_t noflash = 0; + + // when turning on from off, use IN_NFET to prevent a flash + if ((! actual_level) && (level < HDR_ENABLE_LEVEL_MIN)) { + noflash = 1; + IN_NFET_ENABLE_PORT |= (1 << IN_NFET_ENABLE_PIN); + } + + // BST on first, to give it a few extra microseconds to spin up + BST_ENABLE_PORT |= (1 << BST_ENABLE_PIN); + + // pre-load ramp data so it can be assigned faster later + // DAC level register is left-aligned + PWM1_DATATYPE dac_lvl = PWM1_GET(level) << 6; + PWM2_DATATYPE dac_vref = PWM2_GET(level); + + // enable HDR on top half of ramp + if (level >= (HDR_ENABLE_LEVEL_MIN-1)) + HDR_ENABLE_PORT |= (1 << HDR_ENABLE_PIN); + else + HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); + + // set these in successive clock cycles to avoid getting out of sync + // (minimizes ramp bumps when changing gears) + DAC_LVL = dac_lvl; + DAC_VREF = dac_vref; + + if (noflash) { + // wait for flash prevention to finish + delay_4ms(IN_NFET_DELAY_TIME/4); + IN_NFET_ENABLE_PORT &= ~(1 << IN_NFET_ENABLE_PIN); + } +} + +bool gradual_tick_main(uint8_t gt) { + // if HDR and Vref "engine gear" is the same, do a small adjustment... + // otherwise, simply jump to the next ramp level + // and let set_level() handle any gear changes + + // different gear = full adjustment + PWM2_DATATYPE vref_next = PWM2_GET(gt); + if (vref_next != DAC_VREF) return true; // let parent set_level() for us + + // same gear = small adjustment + PWM1_DATATYPE dac_now = DAC_LVL >> 6; // register is left-aligned + PWM1_DATATYPE dac_next = PWM1_GET(gt); + + // adjust multiple times based on how far until the next level + // (so it adjusts faster/coarser for big steps) + + int16_t diff = (dac_next - dac_now); + if (diff < 0) diff = -diff; + + // ~70 max DAC levels per ramp step, 1 + (70 >> 3) = max 10 + uint8_t steps; + steps = 1 + (diff >> 3); + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(dac_next, dac_now); + + DAC_LVL = dac_now << 6; + + if (dac_next == dac_now) return true; // done + + return false; // not done yet +} + + +uint8_t voltage_raw2cooked(uint16_t measurement) { + // In : 65535 * BATTLVL / 1.024V + // Out: uint8_t: Vbat * 40 + // BATTLVL = Vbat * (100.0/(330+100)) = Vbat / 4.3 + // So, Out = In * 4.3 / 1600 + // (plus a bit of fudging to fix the slope and offset, + // based on measuring actual hardware) + uint8_t result = (uint32_t)(measurement + (65535 * 4 / 1024)) + * 43 / 16128; + return result; +} + diff --git a/hw/thefreeman/avr32dd20-devkit/hwdef.h b/hw/thefreeman/avr32dd20-devkit/hwdef.h new file mode 100644 index 00000000..f1b60953 --- /dev/null +++ b/hw/thefreeman/avr32dd20-devkit/hwdef.h @@ -0,0 +1,206 @@ +// hwdef for thefreeman's avr32dd20 dev kit +// Copyright (C) 2023 thefreeman, Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* thefreeman’s avr32dd20 dev kit + * Boost driver based on MP3431(?) + * with high dynamic range and DAC control + aux RGB + * + * Pin Name Function + * 1 PA4 - + * 2 PA5 LVB (unused) + * 3 PA6 BATT LVL (voltage divider) + * 4 PA7 HDR: high/low Rsense range + * 5 PC1 - + * 6 PC2 - + * 7 PC3 - + * 8 VDDIO2 VCC2 (unused) + * 9 PD4 e-switch + * 10 PD5 EN: boost enable + * 11 PD6 DAC: control voltage out + * 12 PD7 IN- NFET: absorb startup flash + * 13 VDD VCC + * 14 GND GND + * 15 PF6 RESET + * 16 PF7 UPDI + * 17 PA0 R: aux red + * 18 PA1 G: aux green + * 19 PA2 B: aux blue + * 20 PA3 CH: detect charging + * + * BST EN enable the boost regulator and Op-Amp + * DAC sets the current, max current depends on Vset voltage divider and Rsense + * HDR FET switches between high value Rsense (low current range, pin low), + * and low value Rsense (high current range, pin high) + * IN- NFET : pull up after BST enable to eliminate startup flash, pull down otherwise + * CH senses the status of the onboard charger + * BATT LVL : Vbat * (100.0/(330+100)) + * LVB is for OTSM firmware, not used here + */ + +#define HWDEF_C thefreeman/avr32dd20-devkit/hwdef.c + +// allow using aux LEDs as extra channel modes +#include "fsm/chan-rgbaux.h" + +// channel modes: +// * 0. main LEDs +// * 1+. aux RGB +#define NUM_CHANNEL_MODES (1 + NUM_RGB_AUX_CHANNEL_MODES) +enum CHANNEL_MODES { + CM_MAIN = 0, + RGB_AUX_ENUMS +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 + + +#undef GRADUAL_ADJUST_SPEED +#define GRADUAL_ADJUST_SPEED 4 + +#define PWM_BITS 16 // 10-bit DAC +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // main LED ramp +#define PWM1_GET(l) PWM_GET16(pwm1_levels, l) +#define PWM2_DATATYPE uint8_t // DAC Vref table +#define PWM2_GET(l) PWM_GET8(pwm2_levels, l) + +// main LED outputs +// (DAC_LVL + DAC_VREF + Vref values are defined in arch/*.h) + +// BST enable +#define BST_ENABLE_PIN PIN5_bp +#define BST_ENABLE_PORT PORTD_OUT + +// HDR +// turns on HDR FET for the high current range +#define HDR_ENABLE_PIN PIN7_bp +#define HDR_ENABLE_PORT PORTA_OUT + +// IN- NFET +// pull high to force output to zero to eliminate the startup flash +#define IN_NFET_DELAY_TIME 12 // (ms) +#define IN_NFET_ENABLE_PIN PIN7_bp +#define IN_NFET_ENABLE_PORT PORTD_OUT + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PIN4_bp +#define SWITCH_PORT VPORTD.IN +#define SWITCH_ISC_REG PORTD.PIN4CTRL +#define SWITCH_VECT PORTD_PORT_vect +#define SWITCH_INTFLG VPORTD.INTFLAGS +#endif + +// TODO: define stuff for the voltage divider +// AVR datasheet table 3.1 I/O Multiplexing, PA6 ADC0 = AIN26 +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated +#define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN26_gc +#define DUAL_VOLTAGE_FLOOR (4*21) // for AA/14500 boost drivers, don't indicate low voltage if below this level +#define DUAL_VOLTAGE_LOW_LOW (4*7) // the lower voltage range's danger zone 0.7 volts (NiMH) +// don't use the default VDD converter +// convert BATT LVL pin readings to FSM volt units +#undef voltage_raw2cooked +uint8_t voltage_raw2cooked(uint16_t measurement); + + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 0 // using a PFET so no appreciable drop +#endif + +// this driver allows for aux LEDs under the optic +#define AUXLED_R_PIN PIN0_bp +#define AUXLED_G_PIN PIN1_bp +#define AUXLED_B_PIN PIN2_bp +#define AUXLED_RGB_PORT PORTA + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + + +inline void hwdef_setup() { + + // TODO: for this DAC controlled-light, try to decrease the clock speed + // to reduce overall system power + mcu_clock_speed(); + + VPORTA.DIR = PIN0_bm // R + | PIN1_bm // G + | PIN2_bm // B + //| PIN3_bm // CH + | PIN7_bm; // HDR + VPORTD.DIR = PIN5_bm // EN + | PIN6_bm // DAC + | PIN7_bm; // IN- NFET + + // enable pullups on the unused and input pins to reduce power + //PORTA.PIN0CTRL = PORT_PULLUPEN_bm; // R + //PORTA.PIN1CTRL = PORT_PULLUPEN_bm; // G + //PORTA.PIN2CTRL = PORT_PULLUPEN_bm; // B + //PORTA.PIN3CTRL = PORT_PULLUPEN_bm; // CH + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm; + //PORTA.PIN6CTRL = PORT_PULLUPEN_bm; // BATT LVL + //PORTA.PIN7CTRL = PORT_PULLUPEN_bm; // HDR + + //PORTC.PIN0CTRL = PORT_PULLUPEN_bm; // doesn't exist + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + //PORTC.PIN4CTRL = PORT_PULLUPEN_bm; // doesn't exist + //PORTC.PIN5CTRL = PORT_PULLUPEN_bm; // doesn't exist + + //PORTD.PIN0CTRL = PORT_PULLUPEN_bm; // doesn't exist + //PORTD.PIN1CTRL = PORT_PULLUPEN_bm; // doesn't exist + //PORTD.PIN2CTRL = PORT_PULLUPEN_bm; // doesn't exist + //PORTD.PIN3CTRL = PORT_PULLUPEN_bm; // doesn't exist + PORTD.PIN4CTRL = PORT_PULLUPEN_bm + | PORT_ISC_BOTHEDGES_gc; // e-switch + //PORTD.PIN5CTRL = PORT_PULLUPEN_bm; // EN + // AVR datasheet 34.3.1 #2, DAC pin must have input disable set + PORTD.PIN6CTRL = PORT_ISC_INPUT_DISABLE_gc; // DAC + //PORTD.PIN7CTRL = PORT_PULLUPEN_bm; // IN- NFET + + // set up the DAC + // DAC ranges from 0V to (255 * Vref) / 256 + DAC_VREF = V10; + // TODO: try DAC_RUNSTDBY_bm for extra-efficient moon + DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; + DAC_LVL = 0; // turn off output at boot + // TODO: instead of enabling the DAC at boot, pull pin down + // to generate a zero without spending power on the DAC + // (and do this in set_level_zero() too) + +} + + +// set fuses, these carry over to the ELF file +// we need this for enabling BOD in Active Mode from the factory. +// settings can be verified / dumped from the ELF file using this +// command: avr-objdump -d -S -j .fuse anduril.elf +FUSES = { + .WDTCFG = FUSE_WDTCFG_DEFAULT, // Watchdog Configuration + + // enable BOD (continuous) in active mode + .BODCFG = ACTIVE_ENABLE_gc, // BOD Configuration + + .OSCCFG = FUSE_OSCCFG_DEFAULT, // Oscillator Configuration + .SYSCFG0 = FUSE_SYSCFG0_DEFAULT, // System Configuration 0 + + // enable MVIO because VDDIO2 pin isn't connected + // set startup time to 64ms to allow power to stabilize + .SYSCFG1 = MVSYSCFG_DUAL_gc | SUT_64MS_gc, + + .CODESIZE = FUSE_CODESIZE_DEFAULT, + .BOOTSIZE = FUSE_BOOTSIZE_DEFAULT, +}; + + +#define LAYOUT_DEFINED + diff --git a/hw/thefreeman/avr32dd20-devkit/model b/hw/thefreeman/avr32dd20-devkit/model new file mode 100644 index 00000000..216403c9 --- /dev/null +++ b/hw/thefreeman/avr32dd20-devkit/model @@ -0,0 +1 @@ +1632==20 diff --git a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h index eea8887d..d1b16619 100644 --- a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h +++ b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/anduril.h @@ -19,15 +19,17 @@ // - high 0.55V // - high 2.5V // PWM1: DAC Data -#define PWM1_LEVELS 2, 3, 4, 5, 6, 8, 9, 11, 14, 16, 19, 23, 26, 31, 35, 41, 47, 54, 61, 69, 78, 89,100,112,125,140,155,173,191,212,234, \ - 56, 62, 68, 74, 82, 89, 97,106,115,125,136,147,159,172,186,200,215,232,249, \ - 14, 15, 17, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 38, 40, 43, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81, 86, 90, 95, 99,104,109,114,120,126,131,138,144,150,157,164,171,179,187,195,203,212,221,230,239,249, \ - 57, 59, 61, 64, 66, 69, 72, 74, 77, 80, 83, 86, 90, 93, 96,100,103,107,111,115,119,123,127,132,136,141,145,150,155,160,166,171,176,182,188,194,200,206,213,219,226,233,240,247,255 -// PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) -#define PWM_TOPS 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, \ - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 +#define PWM1_LEVELS \ + 2, 3, 4, 5, 6, 8, 9, 11, 14, 16, 19, 23, 26, 31, 35, 41, 47, 54, 61, 69, 78, 89,100,112,125,140,155,173,191,212,234, \ + 56, 62, 68, 74, 82, 89, 97,106,115,125,136,147,159,172,186,200,215,232,249, \ + 14, 15, 17, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 38, 40, 43, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81, 86, 90, 95, 99,104,109,114,120,126,131,138,144,150,157,164,171,179,187,195,203,212,221,230,239,249, \ + 57, 59, 61, 64, 66, 69, 72, 74, 77, 80, 83, 86, 90, 93, 96,100,103,107,111,115,119,123,127,132,136,141,145,150,155,160,166,171,176,182,188,194,200,206,213,219,226,233,240,247,255 +// PWM2: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) +#define PWM2_LEVELS \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25, \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25 #define MAX_1x7135 50 #define DEFAULT_LEVEL 44 @@ -39,6 +41,7 @@ #define RAMP_SMOOTH_FLOOR 1 #define RAMP_SMOOTH_CEIL 130 // ~50% power, ~??? mA / ??? lm +// 1 22 [44] 65 87 108 130 #define RAMP_DISCRETE_FLOOR 1 #define RAMP_DISCRETE_CEIL 130 #define RAMP_DISCRETE_STEPS 7 @@ -70,7 +73,7 @@ //#define SIMPLE_UI_ACTIVE 0 // advanced UI by default // allow Aux Config and Strobe Modes in Simple UI -#define USE_EXTENDED_SIMPLE_UI +//#define USE_EXTENDED_SIMPLE_UI // Allow 3C in Simple UI for switching between smooth and stepped ramping #define USE_SIMPLE_UI_RAMPING_TOGGLE diff --git a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h index cd883fa7..bc1d9a7a 100644 --- a/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h +++ b/hw/thefreeman/boost-fwaa-mp3432-hdr-dac-rgb/hwdef.h @@ -36,9 +36,7 @@ * IN- NFET : pull up after BST enable to eliminate startup flash, pull down otherwise */ -#include - -#define HWDEF_C_FILE thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c +#define HWDEF_C thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -58,24 +56,16 @@ enum CHANNEL_MODES { #define CHANNEL_MODES_ENABLED 0b0000000000000001 -#define PWM_CHANNELS 1 // old, remove this - #define PWM_BITS 8 // 8-bit DAC -#define PWM_GET PWM_GET8 #define PWM_DATATYPE uint8_t #define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 #define PWM1_DATATYPE uint8_t // main LED ramp +#define PWM1_GET(l) PWM_GET8(pwm1_levels, l) +#define PWM2_DATATYPE uint8_t // DAC Vref table +#define PWM2_GET(l) PWM_GET8(pwm2_levels, l) // main LED outputs -#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref -#define DAC_VREF VREF.CTRLA // 0.55V or 2.5V -#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) -// Vref values -#define V055 16 -#define V11 17 -#define V25 18 -#define V43 19 -#define V15 20 +// (DAC_LVL + DAC_VREF + Vref values are defined in arch/*.h) // BST enable #define BST_ENABLE_PIN PIN4_bp @@ -99,27 +89,25 @@ enum CHANNEL_MODES { #define SWITCH_ISC_REG PORTC.PIN3CTRL #define SWITCH_VECT PORTC_PORT_vect #define SWITCH_INTFLG VPORTC.INTFLAGS -#define SWITCH_PCINT PCINT0 -#define PCINT_vect PCINT0_vect #endif // Voltage divider battLVL #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated -#define DUAL_VOLTAGE_FLOOR 21 // for AA/14500 boost drivers, don't indicate low voltage if below this level -#define DUAL_VOLTAGE_LOW_LOW 7 // the lower voltage range's danger zone 0.7 volts (NiMH) #define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN2_gc // which ADC channel to read +#define DUAL_VOLTAGE_FLOOR (4*21) // for AA/14500 boost drivers, don't indicate low voltage if below this level +#define DUAL_VOLTAGE_LOW_LOW (4*7) // the lower voltage range's danger zone 0.7 volts (NiMH) +// don't use the default VDD converter +#undef voltage_raw2cooked +#define voltage_raw2cooked mcu_vdivider_raw2cooked + // Raw ADC readings at 4.4V and 2.2V // calibrate the voltage readout here // estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// (voltage - D1) * (R2/(R2+R1) * 4096 / 1.1) // Resistors are 330k and 100k -#ifndef ADC_44 -#define ADC_44 951 // raw value at 4.40V -#endif -#ifndef ADC_22 -#define ADC_22 476 // raw value at 2.20V -#endif +#define ADC_44 3810 // raw value at 4.40V +#define ADC_22 1905 // raw value at 2.20V // this driver allows for aux LEDs under the optic #define AUXLED_R_PIN PIN3_bp @@ -133,10 +121,9 @@ enum CHANNEL_MODES { inline void hwdef_setup() { - // TODO: for this DAC controlled-light, try to decrease the clock speed or use the ULP - // set up the system clock to run at 10 MHz to match other attiny1616 lights - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, - CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + // TODO: for this DAC controlled-light, try to decrease the clock speed + // to reduce overall system power + mcu_clock_speed(); VPORTA.DIR = PIN4_bm // BST EN | PIN5_bm // HDR @@ -173,11 +160,10 @@ inline void hwdef_setup() { // set up the DAC // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf // DAC ranges from 0V to (255 * Vref) / 256 - // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc - VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; - VREF.CTRLB |= VREF_DAC0REFEN_bm; - DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; - DAC0.DATA = 255; // set the output voltage + mcu_set_dac_vref(V05); // boot at lowest Vref setting + VREF.CTRLB |= VREF_DAC0REFEN_bm; // enable DAC Vref + DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // enable DAC + DAC_LVL = 0; // turn off output at boot } diff --git a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h index 64da638f..8319d138 100644 --- a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h +++ b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/anduril.h @@ -3,7 +3,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -#include "thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h" +#define HWDEF_H thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h // HPRsense : 1.7+0.3+5 = 7mR (DMN22M5UFG+trace resistance+5mR) // Vsense=42.46mV, R1= 191k @@ -19,15 +19,17 @@ // - high 0.55V // - high 2.5V // PWM1: DAC Data -#define PWM1_LEVELS 2, 3, 4, 5, 7, 9, 11, 13, 16, 19, 23, 28, 33, 39, 45, 53, 61, 71, 81, 93,106,121,137,155,175,196,220,246, \ - 60, 67, 74, 82, 91,100,110,121,133,146,159,174,190,207,224,244, \ - 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 24, 26, 27, 29, 31, 33, 35, 37, 40, 42, 45, 47, 50, 53, 56, 59, 62, 66, 69, 73, 77, 81, 85, 90, 94, 99,104,109,114,120,126,132,138,144,151,158,165,173,180,188,196,205,214,223,232,242,252, \ - 57, 60, 62, 65, 67, 70, 73, 76, 78, 82, 85, 88, 91, 95, 98,102,105,109,113,117,121,126,130,135,139,144,149,154,159,164,170,175,181,187,193,199,206,212,219,225,232,240,247,255 -// PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) -#define PWM_TOPS 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, \ - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 +#define PWM1_LEVELS \ + 2, 3, 4, 5, 7, 9, 11, 13, 16, 19, 23, 28, 33, 39, 45, 53, 61, 71, 81, 93,106,121,137,155,175,196,220,246, \ + 60, 67, 74, 82, 91,100,110,121,133,146,159,174,190,207,224,244, \ + 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 24, 26, 27, 29, 31, 33, 35, 37, 40, 42, 45, 47, 50, 53, 56, 59, 62, 66, 69, 73, 77, 81, 85, 90, 94, 99,104,109,114,120,126,132,138,144,151,158,165,173,180,188,196,205,214,223,232,242,252, \ + 57, 60, 62, 65, 67, 70, 73, 76, 78, 82, 85, 88, 91, 95, 98,102,105,109,113,117,121,126,130,135,139,144,149,154,159,164,170,175,181,187,193,199,206,212,219,225,232,240,247,255 +// PWM2: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) +#define PWM2_LEVELS \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25, \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25 #define MAX_1x7135 44 #define DEFAULT_LEVEL 44 @@ -71,7 +73,7 @@ //#define SIMPLE_UI_ACTIVE 0 // advanced UI by default // allow Aux Config and Strobe Modes in Simple UI -#define USE_EXTENDED_SIMPLE_UI +//#define USE_EXTENDED_SIMPLE_UI // Allow 3C in Simple UI for switching between smooth and stepped ramping #define USE_SIMPLE_UI_RAMPING_TOGGLE diff --git a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c index 97f5fc9d..573ec2fb 100644 --- a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c +++ b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c @@ -22,7 +22,7 @@ Channel channels[] = { void set_level_zero() { DAC_LVL = 0; // DAC off - DAC_VREF = V055; // low Vref + mcu_set_dac_vref(V055); // low Vref HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); // HDR off // prevent post-off flash @@ -49,8 +49,8 @@ void set_level_main(uint8_t level) { BST_ENABLE_PORT |= (1 << BST_ENABLE_PIN); // pre-load ramp data so it can be assigned faster later - PWM_DATATYPE dac_lvl = PWM_GET(pwm1_levels, level); - PWM_DATATYPE dac_vref = PWM_GET(pwm_tops, level); + PWM1_DATATYPE dac_lvl = PWM1_GET(level); + PWM2_DATATYPE dac_vref = PWM2_GET(level); // enable HDR on top half of ramp if (level >= (HDR_ENABLE_LEVEL_MIN-1)) @@ -61,7 +61,7 @@ void set_level_main(uint8_t level) { // set these in successive clock cycles to avoid getting out of sync // (minimizes ramp bumps when changing gears) DAC_LVL = dac_lvl; - DAC_VREF = dac_vref; + mcu_set_dac_vref(dac_vref); if (noflash) { // wait for flash prevention to finish @@ -75,11 +75,11 @@ bool gradual_tick_main(uint8_t gt) { // otherwise, simply jump to the next ramp level // and let set_level() handle any gear changes - PWM_DATATYPE dac_next = PWM_GET(pwm1_levels, gt); - PWM_DATATYPE vref_next = PWM_GET(pwm_tops, gt); + PWM1_DATATYPE dac_next = PWM1_GET(gt); + PWM2_DATATYPE vref_next = PWM2_GET(gt); // different gear = full adjustment - if (vref_next != DAC_VREF) return true; // let parent set_level() for us + if (vref_next != (DAC_VREF & VREF_DAC0REFSEL_gm)) return true; // let parent set_level() for us // same gear = small adjustment GRADUAL_ADJUST_SIMPLE(dac_next, DAC_LVL); diff --git a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h index 3f64287b..d83aa462 100644 --- a/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h +++ b/hw/thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.h @@ -37,9 +37,7 @@ * IN- NFET : pull up after BST enable to eliminate startup flash, pull down otherwise */ -#include - -#define HWDEF_C_FILE thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c +#define HWDEF_C thefreeman/boost21-mp3431-hdr-dac-argb/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -59,24 +57,16 @@ enum CHANNEL_MODES { #define CHANNEL_MODES_ENABLED 0b0000000000000001 -#define PWM_CHANNELS 1 // old, remove this - #define PWM_BITS 8 // 8-bit DAC -#define PWM_GET PWM_GET8 #define PWM_DATATYPE uint8_t #define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 #define PWM1_DATATYPE uint8_t // main LED ramp +#define PWM1_GET(l) PWM_GET8(pwm1_levels, l) +#define PWM2_DATATYPE uint8_t // DAC Vref table +#define PWM2_GET(l) PWM_GET8(pwm2_levels, l) // main LED outputs -#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref -#define DAC_VREF VREF.CTRLA // 0.55V or 2.5V -#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) -// Vref values -#define V055 16 -#define V11 17 -#define V25 18 -#define V43 19 -#define V15 20 +// (DAC_LVL + DAC_VREF + Vref values are defined in arch/*.h) // BST enable #define BST_ENABLE_PIN PIN0_bp @@ -100,8 +90,6 @@ enum CHANNEL_MODES { #define SWITCH_ISC_REG PORTC.PIN2CTRL #define SWITCH_VECT PORTC_PORT_vect #define SWITCH_INTFLG VPORTC.INTFLAGS -#define SWITCH_PCINT PCINT0 -#define PCINT_vect PCINT0_vect #endif // average drop across diode on this hardware @@ -127,10 +115,9 @@ enum CHANNEL_MODES { inline void hwdef_setup() { - // TODO: for this DAC controlled-light, try to decrease the clock speed or use the ULP - // set up the system clock to run at 10 MHz to match other attiny1616 lights - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, - CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + // TODO: for this DAC controlled-light, try to decrease the clock speed + // to reduce overall system power + mcu_clock_speed(); VPORTA.DIR = PIN6_bm; // DAC VPORTB.DIR = PIN1_bm // R @@ -167,11 +154,10 @@ inline void hwdef_setup() { // set up the DAC // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf // DAC ranges from 0V to (255 * Vref) / 256 - // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc - VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; - VREF.CTRLB |= VREF_DAC0REFEN_bm; - DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; - DAC0.DATA = 255; // set the output voltage + mcu_set_dac_vref(V05); // boot at lowest Vref setting + VREF.CTRLB |= VREF_DAC0REFEN_bm; // enable DAC Vref + DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // enable DAC + DAC_LVL = 0; // turn off output at boot } diff --git a/hw/thefreeman/lin16dac/anduril.h b/hw/thefreeman/lin16dac/anduril.h index 8ca8b9f0..8f9d6e4f 100644 --- a/hw/thefreeman/lin16dac/anduril.h +++ b/hw/thefreeman/lin16dac/anduril.h @@ -3,7 +3,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -#include "thefreeman/lin16dac/hwdef.h" +#define HWDEF_H thefreeman/lin16dac/hwdef.h // the button lights up #define USE_INDICATOR_LED @@ -24,15 +24,17 @@ // PWM1: DAC Data // FIXME: ramp stalls with 8 duplicate levels in a row // (maybe use 1.1V Vref during that part of the ramp?) -#define PWM1_LEVELS 25, 25, 33, 41, 41, 50, 58, 66, 75, 83, 92,108,117,133,150,167,192,209,234, \ - 58, 64, 71, 80, 90, 99,110,121,134,149,163,180,198,218,241, \ - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 11, 12, 13, 14, 15, 16, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 39, 41, 44, 47, 50, 53, 56, 59, 63, 67, 71, 75, 79, 84, 89, 94,100,105,112,118,124,131,139,146,154,163,172,181,191,201,212,223,234,246, \ - 57, 60, 63, 66, 69, 73, 76, 80, 84, 88, 93, 97,102,107,112,117,123,129,135,141,147,154,161,169,176,184,193,201,210,220,229,239,250,255 -// PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) -#define PWM_TOPS 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, \ - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 +#define PWM1_LEVELS \ + 25, 25, 33, 41, 41, 50, 58, 66, 75, 83, 92,108,117,133,150,167,192,209,234, \ + 58, 64, 71, 80, 90, 99,110,121,134,149,163,180,198,218,241, \ + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 11, 12, 13, 14, 15, 16, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 39, 41, 44, 47, 50, 53, 56, 59, 63, 67, 71, 75, 79, 84, 89, 94,100,105,112,118,124,131,139,146,154,163,172,181,191,201,212,223,234,246, \ + 57, 60, 63, 66, 69, 73, 76, 80, 84, 88, 93, 97,102,107,112,117,123,129,135,141,147,154,161,169,176,184,193,201,210,220,229,239,250,255 +// PWM2: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) +#define PWM2_LEVELS \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25, \ + V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05,V05, \ + V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25,V25 #define MAX_1x7135 34 #define HDR_ENABLE_LEVEL_MIN 35 // bottom level of top half of the ramp diff --git a/hw/thefreeman/lin16dac/hwdef.c b/hw/thefreeman/lin16dac/hwdef.c index 191444ee..89700d7d 100644 --- a/hw/thefreeman/lin16dac/hwdef.c +++ b/hw/thefreeman/lin16dac/hwdef.c @@ -22,7 +22,7 @@ Channel channels[] = { void set_level_zero() { DAC_LVL = 0; // DAC off - DAC_VREF = V055; // low Vref + mcu_set_dac_vref(V055); // low Vref HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); // HDR off // prevent post-off flash @@ -50,8 +50,8 @@ void set_level_main(uint8_t level) { OPAMP_ENABLE_PORT |= (1 << OPAMP_ENABLE_PIN); // pre-load ramp data so it can be assigned faster later - PWM_DATATYPE dac_lvl = PWM_GET(pwm1_levels, level); - PWM_DATATYPE dac_vref = PWM_GET(pwm_tops, level); + PWM1_DATATYPE dac_lvl = PWM1_GET(level); + PWM2_DATATYPE dac_vref = PWM2_GET(level); // enable HDR on top half of ramp if (level >= (HDR_ENABLE_LEVEL_MIN-1)) @@ -69,7 +69,8 @@ void set_level_main(uint8_t level) { // set these in successive clock cycles to avoid getting out of sync // (minimizes ramp bumps when changing gears) DAC_LVL = dac_lvl; - DAC_VREF = dac_vref; + mcu_set_dac_vref(dac_vref); + } bool gradual_tick_main(uint8_t gt) { @@ -77,11 +78,11 @@ bool gradual_tick_main(uint8_t gt) { // otherwise, simply jump to the next ramp level // and let set_level() handle any gear changes - PWM_DATATYPE dac_next = PWM_GET(pwm1_levels, gt); - PWM_DATATYPE vref_next = PWM_GET(pwm_tops, gt); + PWM1_DATATYPE dac_next = PWM1_GET(gt); + PWM2_DATATYPE vref_next = PWM2_GET(gt); // different gear = full adjustment - if (vref_next != DAC_VREF) return true; // let parent set_level() for us + if (vref_next != (DAC_VREF & VREF_DAC0REFSEL_gm)) return true; // let parent set_level() for us // same gear = small adjustment GRADUAL_ADJUST_SIMPLE(dac_next, DAC_LVL); diff --git a/hw/thefreeman/lin16dac/hwdef.h b/hw/thefreeman/lin16dac/hwdef.h index 2066d043..a68d9c2b 100644 --- a/hw/thefreeman/lin16dac/hwdef.h +++ b/hw/thefreeman/lin16dac/hwdef.h @@ -12,9 +12,7 @@ * Read voltage from VCC pin, has PFET so no drop */ -#include - -#define HWDEF_C_FILE thefreeman/lin16dac/hwdef.c +#define HWDEF_C thefreeman/lin16dac/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-aux.h" @@ -34,24 +32,16 @@ enum CHANNEL_MODES { #define CHANNEL_MODES_ENABLED 0b0000000000000001 -#define PWM_CHANNELS 1 // old, remove this - #define PWM_BITS 8 // 8-bit DAC -#define PWM_GET PWM_GET8 #define PWM_DATATYPE uint8_t #define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 #define PWM1_DATATYPE uint8_t // main LED ramp +#define PWM1_GET(l) PWM_GET8(pwm1_levels, l) +#define PWM2_DATATYPE uint8_t // DAC Vref table +#define PWM2_GET(l) PWM_GET8(pwm2_levels, l) // main LED outputs -#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref -#define DAC_VREF VREF.CTRLA // 0.55V or 2.5V -#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) -// Vref values -#define V055 16 -#define V11 17 -#define V25 18 -#define V43 19 -#define V15 20 +// (DAC_LVL + DAC_VREF + Vref values are defined in arch/*.h) // Opamp enable // For turning on and off the op-amp @@ -86,11 +76,9 @@ enum CHANNEL_MODES { inline void hwdef_setup() { - // set up the system clock to run at 10 MHz instead of the default 3.33 MHz - // (it'll get underclocked to 2.5 MHz later) - // TODO: maybe run even slower? - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, - CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + // TODO: for this DAC controlled-light, try to decrease the clock speed + // to reduce overall system power + mcu_clock_speed(); VPORTA.DIR = PIN6_bm // DAC | PIN7_bm; // Opamp @@ -123,11 +111,10 @@ inline void hwdef_setup() { // set up the DAC // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf // DAC ranges from 0V to (255 * Vref) / 256 - // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc - VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; - VREF.CTRLB |= VREF_DAC0REFEN_bm; - DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; - DAC0.DATA = 255; // set the output voltage + mcu_set_dac_vref(V05); // boot at lowest Vref setting + VREF.CTRLB |= VREF_DAC0REFEN_bm; // enable DAC Vref + DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // enable DAC + DAC_LVL = 0; // turn off output at boot } diff --git a/hw/wurkkos/fc13/README.md b/hw/wurkkos/fc13/README.md new file mode 100644 index 00000000..ab9b87fe --- /dev/null +++ b/hw/wurkkos/fc13/README.md @@ -0,0 +1,10 @@ +# Wurkkos FC13 + +Single LED 18650 torch with FET+1 driver and RGB button. Includes a built-in +charger / powerbank too, separate from the main torch circuit. + +The Wurkkos SP30S Pro also uses this firmware. + +Either torch may ship with the `0715` (wurkkos-ts25) firmware installed, but +the RGB button does not work fully until upgrading to this FC13 firmware. + diff --git a/hw/wurkkos/ts10/hwdef.h b/hw/wurkkos/ts10/hwdef.h index b1239b8e..92898fb3 100644 --- a/hw/wurkkos/ts10/hwdef.h +++ b/hw/wurkkos/ts10/hwdef.h @@ -13,9 +13,7 @@ * Voltage: VCC */ -#include - -#define HWDEF_C_FILE wurkkos/ts10/hwdef.c +#define HWDEF_C wurkkos/ts10/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-aux.h" @@ -60,12 +58,10 @@ enum CHANNEL_MODES { // e-switch #define SWITCH_PIN PIN5_bp -//#define SWITCH_PCINT PCINT0 #define SWITCH_PORT VPORTA.IN #define SWITCH_ISC_REG PORTA.PIN2CTRL #define SWITCH_VECT PORTA_PORT_vect #define SWITCH_INTFLG VPORTA.INTFLAGS -//#define PCINT_vect PCINT0_vect // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR diff --git a/hw/wurkkos/ts11/README.md b/hw/wurkkos/ts11/README.md new file mode 100644 index 00000000..e53e0386 --- /dev/null +++ b/hw/wurkkos/ts11/README.md @@ -0,0 +1,8 @@ +# Wurkkos TS11 + +Single LED 18350 / 18650 torch with FET+1 driver, RGB button, and RGB front +aux. Includes a built-in charger too, separate from the main torch circuit. + +May ship with the `0715` (wurkkos-ts25) firmware installed, but the RGB button +does not work fully until upgrading to this TS11 firmware. + diff --git a/hw/wurkkos/ts25/README.md b/hw/wurkkos/ts25/README.md new file mode 100644 index 00000000..b3c33afc --- /dev/null +++ b/hw/wurkkos/ts25/README.md @@ -0,0 +1,20 @@ +# Wurkkos TS25 + +A quad LED 21700 light with FET+1 driver and RGB front aux. A charge port is +built in too, but operates independently and is not visible to the main +firmware. + +Some other Wurkkos models may also ship with this firmware, and should be +upgraded to use a more specific build: + + - FC13: use wurkkos-fc13 + - TS11: use wurkkos-ts11 + - SP30S Pro: use wurkkos-fc13 + +These builds have different aux LED behavior. The difference is whether the +RGB aux is on the front, the side (button), or both. + + - Front: TS25 + - Side: FC13 + - Both: TS11 + diff --git a/hw/wurkkos/ts25/anduril.h b/hw/wurkkos/ts25/anduril.h index 722bc5d3..ecf0db19 100644 --- a/hw/wurkkos/ts25/anduril.h +++ b/hw/wurkkos/ts25/anduril.h @@ -3,7 +3,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -#include "wurkkos/ts25/hwdef.h" +//#include "wurkkos/ts25/hwdef.h" +#define HWDEF_H wurkkos/ts25/hwdef.h #include "wurkkos/anduril.h" // this light has three aux LED channels: R, G, B diff --git a/hw/wurkkos/ts25/hwdef.h b/hw/wurkkos/ts25/hwdef.h index 024a18d9..ac1e5740 100644 --- a/hw/wurkkos/ts25/hwdef.h +++ b/hw/wurkkos/ts25/hwdef.h @@ -14,9 +14,7 @@ * Aux Blue: PC1 */ -#include - -#define HWDEF_C_FILE wurkkos/ts25/hwdef.c +#define HWDEF_C wurkkos/ts25/hwdef.c // allow using aux LEDs as extra channel modes #include "fsm/chan-rgbaux.h" @@ -61,12 +59,10 @@ enum CHANNEL_MODES { // e-switch #define SWITCH_PIN PIN5_bp -//#define SWITCH_PCINT PCINT0 #define SWITCH_PORT VPORTA.IN #define SWITCH_ISC_REG PORTA.PIN2CTRL #define SWITCH_VECT PORTA_PORT_vect #define SWITCH_INTFLG VPORTA.INTFLAGS -//#define PCINT_vect PCINT0_vect // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR diff --git a/make b/make index 89e196dc..ca3a84a4 100755 --- a/make +++ b/make @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Anduril / FSM "make" script # Copyright (C) 2023 Selene ToyKeeper # SPDX-License-Identifier: GPL-3.0-or-later @@ -27,6 +27,7 @@ Usage: ./make TASK docs Convert all .md files to .html models Generate the MODELS file release Zip up all .hex files to prep for publishing a release + version Show the current version string todo Show tasks noted in source code files ... or TASK can be the partial name of a build target. @@ -50,12 +51,12 @@ ENDOFHELP # sub-command parser / dispatcher function main() { case "$MODE" in - -h|--help|help|/?|/h|/help) + -h|--help|help|/\?|/h|/help) help ;; clean) - echo 'rm -vf **/*~ hex/*.hex ui/**/*.elf ui/**/*.o ui/**/*.cpp' - rm -vf **/*~ hex/*.hex ui/**/*.elf ui/**/*.o ui/**/*.cpp + echo 'rm -vf -- **/*~ hex/*.hex ui/**/*.elf ui/**/*.o ui/**/*.cpp' + rm -vf -- **/*~ hex/*.hex ui/**/*.elf ui/**/*.o ui/**/*.cpp ;; dfp) shift @@ -73,10 +74,13 @@ function main() { cat MODELS ;; release) - echo "Not implemented yet." + ./bin/make-release.sh "$@" + ;; + version) + ./bin/version-string.sh "$@" ;; todo) - grep -E 'TODO:|FIXME:' **/*.[ch] + grep -E 'TODO:|FIXME:' -- **/*.[ch] **/*.md ;; *) exec ./bin/build-all.sh "$@" @@ -86,15 +90,15 @@ function main() { function make-docs () { for md in **/*.md ; do - echo "$md" - html=$(echo "$md" | sed 's/.md$/.html/') + html=${md//.md/.html} + echo "$md --> $html" cmark-gfm "$md" > "$html" done } # go to the repo root -BASEDIR=$(dirname $0) -cd "$BASEDIR" +BASEDIR=$(dirname "$0") +cd "$BASEDIR" || (echo "Error: Can't cd to basedir." && exit 1) # do whatever the user requested main "$@" diff --git a/ui/anduril/anduril.c b/ui/anduril/anduril.c index 97ecb306..20a0e0fb 100644 --- a/ui/anduril/anduril.c +++ b/ui/anduril/anduril.c @@ -34,16 +34,19 @@ * as possible. These are mostly "USE" flags. */ +/********* load up MCU info, like ROM size and such *********/ +#include "arch/mcu.h" + /********* User-configurable options *********/ #include "anduril/config-default.h" /********* specific settings for known driver types *********/ -// Anduril config file name (set it here or define it at the gcc command line) -//#define CFG_H cfg-blf-q8.h -#include "fsm/tk.h" #include incfile(CFG_H) +#ifdef HWDEF_H +#include incfile(HWDEF_H) +#endif /********* Include headers which need to be before FSM *********/ @@ -77,11 +80,12 @@ #include "fsm/spaghetti-monster.h" /********* does this build target have special code to include? *********/ -#ifdef HWDEF_C_FILE -#include incfile(HWDEF_C_FILE) +#ifdef CFG_C +#include incfile(CFG_C) #endif -#ifdef CFG_C_FILE -#include incfile(CFG_C_FILE) + +#ifdef HWDEF_C +#include incfile(HWDEF_C) #endif @@ -316,6 +320,7 @@ void loop() { #ifdef USE_BATTCHECK else if (state == battcheck_state) { + nice_delay_ms(1000); // wait a moment for a more accurate reading battcheck(); #ifdef USE_SIMPLE_UI // in simple mode, turn off after one readout diff --git a/ui/anduril/aux-leds.c b/ui/anduril/aux-leds.c index 1b30d34e..fd184fc3 100644 --- a/ui/anduril/aux-leds.c +++ b/ui/anduril/aux-leds.c @@ -58,27 +58,27 @@ void indicator_led_update(uint8_t mode, uint8_t tick) { uint8_t voltage_to_rgb() { static const uint8_t levels[] = { // voltage, color - 0, 0, // black + 0, 0, // black #ifdef DUAL_VOLTAGE_FLOOR // AA / NiMH voltages - 9, 1, // R - 10, 2, // R+G - 11, 3, // G - 12, 4, // G+B - 13, 5, // B - 14, 6, // R + B - 15, 7, // R+G+B - 20, 0, // black + 4* 9, 1, // R + 4*10, 2, // R+G + 4*11, 3, // G + 4*12, 4, // G+B + 4*13, 5, // B + 4*14, 6, // R + B + 4*16, 7, // R+G+B + 4*20, 0, // black #endif // li-ion voltages - 29, 1, // R - 33, 2, // R+G - 35, 3, // G - 37, 4, // G+B - 39, 5, // B - 41, 6, // R + B - 44, 7, // R+G+B // skip; looks too similar to G+B - 255, 7, // R+G+B + 4*29, 1, // R + 4*33, 2, // R+G + 4*35, 3, // G + 4*37, 4, // G+B + 4*39, 5, // B + 4*41, 6, // R + B + 4*44, 7, // R+G+B // skip; looks too similar to G+B + 255, 7, // R+G+B }; uint8_t volts = voltage; //if (volts < VOLTAGE_LOW) return 0; diff --git a/ui/anduril/config-default.h b/ui/anduril/config-default.h index 899bc4ad..1b34e8c0 100644 --- a/ui/anduril/config-default.h +++ b/ui/anduril/config-default.h @@ -20,7 +20,7 @@ // overheat protection #define USE_THERMAL_REGULATION -#if (ATTINY==85) || (ATTINY==1634) +#if (MCU==0x85) || (MCU==0x1634) // sloppy temperature sensor needs bigger error margin #define DEFAULT_THERM_CEIL 45 // try not to get hotter than this (in C) #else @@ -113,6 +113,12 @@ // timer is available in regular ramp mode and candle mode #define USE_SUNSET_TIMER +// optionally make gradual ticks happen faster +// Affects: thermal regulation speed, sunset mode, maybe other features +// (default is calibrated for 8-bit PWM, +// but 10-bit should set this value to 4 instead of 1) +#define GRADUAL_ADJUST_SPEED 1 + ///// What to do when power is connected ///// // factory reset function erases user's runtime configuration in eeprom @@ -137,6 +143,10 @@ #define BATTCHECK_VpT //#define BATTCHECK_8bars // FIXME: breaks build //#define BATTCHECK_4bars // FIXME: breaks build +#if ROM_SIZE > 10000 + // battcheck displays 1.25V instead of 1.2V + #define USE_EXTRA_BATTCHECK_DIGIT +#endif // allow the user to calibrate the voltage readings? // (adjust in 0.05V increments from -0.30V to +0.30V) // (1 = -0.30V, 2 = -0.25V, ... 7 = 0V, ... 13 = +0.30V) @@ -185,7 +195,7 @@ // if the aux LEDs oscillate between "full battery" and "empty battery" // while in "voltage" mode, enable this to reduce the amplitude of // those oscillations -#if (ATTINY==1616) || (ATTINY==1634) +#if (ROM_SIZE > 10000) #define USE_LOWPASS_WHILE_ASLEEP #endif @@ -195,7 +205,7 @@ // Use "smooth steps" to soften on/off and step changes // on MCUs with enough room for extra stuff like this -#if (ATTINY==1616) || (ATTINY==1634) +#if (ROM_SIZE > 10000) #define USE_SMOOTH_STEPS #endif // 0 = none, 1 = smooth, 2+ = undefined diff --git a/ui/anduril/load-save-config.h b/ui/anduril/load-save-config.h index bef10e10..6a521717 100644 --- a/ui/anduril/load-save-config.h +++ b/ui/anduril/load-save-config.h @@ -118,7 +118,7 @@ Config cfg = { .strobe_delays = { 41, 67 }, #endif #ifdef USE_BIKE_FLASHER_MODE - .bike_flasher_brightness = MAX_1x7135, + .bike_flasher_brightness = DEFAULT_BIKING_LEVEL, #endif #ifdef USE_BEACON_MODE // beacon timing diff --git a/ui/anduril/misc.c b/ui/anduril/misc.c index 3715f341..9144b283 100644 --- a/ui/anduril/misc.c +++ b/ui/anduril/misc.c @@ -25,7 +25,7 @@ void blink_confirm(uint8_t num) { void blink_once() { uint8_t brightness = actual_level; uint8_t bump = brightness + BLINK_BRIGHTNESS; - if (bump > MAX_LEVEL) bump = 0; + if (bump > MAX_LEVEL) bump = BLIP_LEVEL; set_level(bump); delay_4ms(BLINK_ONCE_TIME/4); @@ -35,7 +35,7 @@ void blink_once() { // Just go dark for a moment to indicate to user that something happened void blip() { uint8_t temp = actual_level; - set_level(0); + set_level(BLIP_LEVEL); delay_4ms(3); set_level(temp); } diff --git a/ui/anduril/misc.h b/ui/anduril/misc.h index 0f2992a3..b259a6e4 100644 --- a/ui/anduril/misc.h +++ b/ui/anduril/misc.h @@ -4,6 +4,10 @@ #pragma once +#ifndef BLIP_LEVEL +#define BLIP_LEVEL 0 +#endif + //void blink_confirm(uint8_t num); // no longer used void blink_once(); void blip(); diff --git a/ui/anduril/momentary-mode.c b/ui/anduril/momentary-mode.c index 94f6bc24..327302ac 100644 --- a/ui/anduril/momentary-mode.c +++ b/ui/anduril/momentary-mode.c @@ -47,14 +47,17 @@ uint8_t momentary_state(Event event, uint16_t arg) { } else { #endif + // turn off lighted button + #ifdef USE_INDICATOR_LED + indicator_led(0); + #elif defined(USE_AUX_RGB_LEDS) + rgb_led_set(0); + #endif + #ifdef USE_BUTTON_LED + button_led_set(0); + #endif if (arg > TICKS_PER_SECOND*5) { // sleep after 5 seconds go_to_standby = 1; // sleep while light is off - // turn off lighted button - #ifdef USE_INDICATOR_LED - indicator_led(0); - #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(0, 0); - #endif } #ifdef USE_STROBE_STATE } diff --git a/ui/anduril/ramp-mode.c b/ui/anduril/ramp-mode.c index 5ce1b54b..4c535b4c 100644 --- a/ui/anduril/ramp-mode.c +++ b/ui/anduril/ramp-mode.c @@ -287,7 +287,7 @@ uint8_t steady_state(Event event, uint16_t arg) { static uint16_t ticks_since_adjust = 0; ticks_since_adjust++; if (diff) { - uint16_t ticks_per_adjust = 256; + uint16_t ticks_per_adjust = 256 / GRADUAL_ADJUST_SPEED; if (diff < 0) { //diff = -diff; if (actual_level > THERM_FASTER_LEVEL) { @@ -468,6 +468,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_MOMENTARY_MODE // 5 clicks: shortcut to momentary mode else if (event == EV_5clicks) { + memorized_level = actual_level; // allow turbo in momentary mode set_level(0); set_state(momentary_state, 0); return EVENT_HANDLED; diff --git a/ui/anduril/ramp-mode.h b/ui/anduril/ramp-mode.h index 59c8db04..1392981c 100644 --- a/ui/anduril/ramp-mode.h +++ b/ui/anduril/ramp-mode.h @@ -4,14 +4,15 @@ #pragma once -#ifndef RAMP_LENGTH -#define RAMP_LENGTH 150 // default, if not overridden in a driver cfg file +#ifndef RAMP_SIZE +#define RAMP_SIZE 150 // default, if not overridden in a driver cfg file #endif +// TODO: Replace MAX_Xx7135 with MAX_CH1, MAX_CH2, MAX_REGULATED, etc + // thermal properties, if not defined per-driver #ifndef MIN_THERM_STEPDOWN -// TODO: Replace MAX_Xx7135 with MAX_CH1, MAX_CH2, MAX_REGULATED, etc -#define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to +#define MIN_THERM_STEPDOWN (RAMP_SIZE/3) // lowest value it'll step down to #endif #ifndef THERM_FASTER_LEVEL #ifdef MAX_Nx7135 diff --git a/ui/anduril/strobe-modes.h b/ui/anduril/strobe-modes.h index 058cea5e..1890b8c1 100644 --- a/ui/anduril/strobe-modes.h +++ b/ui/anduril/strobe-modes.h @@ -55,9 +55,15 @@ inline void lightning_storm_iter(); // bike mode config options #ifdef USE_BIKE_FLASHER_MODE -#define MAX_BIKING_LEVEL 120 // should be 127 or less -inline void bike_flasher_iter(); -#endif + #if !defined(DEFAULT_BIKING_LEVEL) + #define DEFAULT_BIKING_LEVEL (RAMP_SIZE/3) + #elif DEFAULT_BIKING_LEVEL > MAX_BIKING_LEVEL + #undef DEFAULT_BIKING_LEVEL + #define DEFAULT_BIKING_LEVEL MAX_BIKING_LEVEL + #endif + #define MAX_BIKING_LEVEL 120 // should be 127 or less + inline void bike_flasher_iter(); +#endif // ifdef USE_BIKE_FLASHER_MODE #ifdef USE_CANDLE_MODE #include "anduril/candle-mode.h" diff --git a/ui/anduril/version-check-mode.c b/ui/anduril/version-check-mode.c index eebe59b6..1cd69688 100644 --- a/ui/anduril/version-check-mode.c +++ b/ui/anduril/version-check-mode.c @@ -15,7 +15,10 @@ uint8_t version_check_state(Event event, uint16_t arg) { inline void version_check_iter() { for (uint8_t i=0; i ? + if (digit < 16) blink_digit(digit); else { // "buzz" for non-numeric characters for(uint8_t frame=0; frame<25; frame++) { set_level((frame&1) << 5); diff --git a/ui/fireflies-ui/build-all.sh b/ui/fireflies-ui/build-all.sh index 81ebd97b..83c6964d 100755 --- a/ui/fireflies-ui/build-all.sh +++ b/ui/fireflies-ui/build-all.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh cp -av --no-clobber ../anduril/cfg-ff*.h . diff --git a/ui/rampingios/build-all.sh b/ui/rampingios/build-all.sh index 106dc154..c788b1f1 100755 --- a/ui/rampingios/build-all.sh +++ b/ui/rampingios/build-all.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh cp -av ../anduril/cfg-emisar*.h . diff --git a/ui/werner/build-all.sh b/ui/werner/build-all.sh index b1141013..4c88369e 100755 --- a/ui/werner/build-all.sh +++ b/ui/werner/build-all.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/env sh cp -av ../anduril/cfg*.h .