From 59b7ad613b0a499f573fdbd31c57de41f7831488 Mon Sep 17 00:00:00 2001 From: Spence Konde Date: Sun, 6 Nov 2022 06:26:37 -0500 Subject: [PATCH] Fix comparator, and several largely trivial changes. 2.6.3 to fix bad release --- .github/workflows/compile-examples.yml | 6 ++ ChangeLog.md | 5 +- megaavr/cores/megatinycore/core_devices.h | 73 ++++++++++++++++++- megaavr/cores/megatinycore/core_parameters.h | 19 ++--- megaavr/cores/megatinycore/wiring_digital.c | 14 +++- megaavr/extras/LinkingAgainstStaticLibrary.md | 25 +++++++ megaavr/extras/Ref_Analog.md | 15 ++-- megaavr/extras/Ref_Digital.md | 3 +- megaavr/extras/Ref_Functions.md | 4 +- megaavr/extras/Ref_Reset.md | 5 +- megaavr/extras/Ref_Serial.md | 1 + megaavr/extras/Ref_Timers.md | 1 + .../libraries/Comparator/src/Comparator.cpp | 6 +- megaavr/platform.txt | 4 +- 14 files changed, 144 insertions(+), 37 deletions(-) create mode 100644 megaavr/extras/LinkingAgainstStaticLibrary.md diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 9d13a8a1..3e79f513 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -37,6 +37,7 @@ jobs: - megaavr/libraries/Wire/examples/SFRRanger_reader - megaavr/libraries/tinyNeoPixel/examples/RGBWstrandtest - megaavr/extras/CompileTestSketches/test_analog_read + - megaavr/libraries/Optiboot_flasher/examples/Flash_get_put - megaavr/libraries/Wire/examples/slave_address_mask - megaavr/libraries/Wire/examples/master_multi_address_write available-flash-4kB-plus-true-sketch-paths: | @@ -87,6 +88,11 @@ jobs: - megaavr/libraries/Servo_megaTinyCore/examples/Knob - megaavr/libraries/Servo_megaTinyCore/examples/ServoMaxTest - megaavr/libraries/Servo_megaTinyCore/examples/Sweep + - megaavr/libraries/Comparator/Hysteresis + - megaavr/libraries/Comparator/Internal_reference + - megaavr/libraries/Comparator/Interrupt + - megaavr/libraries/Comparator/simple_comparator + - megaavr/libraries/Event/simple_event IO-class-6-plus-true-sketch-paths: | - megaavr/libraries/Logic/examples/Five_input_NOR IO-class-2-series-1-sketch-paths: | diff --git a/ChangeLog.md b/ChangeLog.md index 53013548..c76f823e 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -25,8 +25,9 @@ Changes listed here are checked in to GitHub ("master" branch unless specificall ## Released versions ### 2.6.3 (2.6.2 respin due to json error) -* Correct installation error from trying to install non-functional withdrawn version of toolchain. -* Correct missing comma in Comparator.cpp. +* Correct installation error from trying to install non-functional withdrawn version of toolchain. +* Correct issues with compiling Comparator library. +* Ensure that at least one test per library is in the CI list. ### 2.6.2 (critical update) * Critical bugfix: Burn Bootloader corrected diff --git a/megaavr/cores/megatinycore/core_devices.h b/megaavr/cores/megatinycore/core_devices.h index a3caf525..e61897f6 100644 --- a/megaavr/cores/megatinycore/core_devices.h +++ b/megaavr/cores/megatinycore/core_devices.h @@ -268,7 +268,6 @@ #ifdef __AVR_ATtinyxy2__ #define _AVR_PINCOUNT 8 #endif -#define MEGATINYCORE_NUM (((MEGATINYCORE_MAJOR << 24)+(MEGATINYCORE_MINOR << 16)+(MEGATINYCORE_PATCH << 8)+MEGATINYCORE_RELEASED)) #if MEGATINYCORE_SERIES == 0 #define _AVR_FAMILY "T0" @@ -590,6 +589,8 @@ #if !defined(BACKWARD_COMBATIBILITY_MODE) // We default to seeking compatibility. for COMBATability you would uncomment that #define, and that turns all these off. + + #if defined(RTC_CLKSEL) /* Man they just *HAD* to change the names of these values that get assigned to the same register and do the same thing didn't they? * Worse still we can't even verify that they are present... just blindly define and pray. Enums can't be seen by macros */ @@ -693,7 +694,15 @@ #define CLKCTRL_FRQSEL_28M_gc (CLKCTRL_FREQSEL_28M_gc) /* 28 MHz system clock unofficial - this will just error out if used since it will replace one undefined symbol with another */ #define CLKCTRL_FRQSEL_32M_gc (CLKCTRL_FREQSEL_32M_gc) /* 32 MHz system clock unofficial - this will just error out if used since it will replace one undefined symbol with another */ #endif + // Note that it is intended to not hide the fact that 28 and 32 MHz are not official. If you choose it from the menu, it says "Overclocked" next to the speed too. We refer to them with the numeric constants in the wiring.c, so it doesn't matter when used that way. + // And now the most freaking boneheaded move from Microchip in a long while: They realized that they should have had some sort of delimiter between the bit number within a bitfield, and the name of the bitfield, since the names of many bitfields end in numbers, + // So they went ahead and made that change. That is what's called a "breaking change", really for no reason except codes style. Most companies even if they decided to go that route, would never do that without introducuing a compatibility layer. + // That wanton disregard for backwards compatibility is not acceptable in an Arduino core nor in a commercial product. + // Using the old names will produce warnings. These deprecated names should be fixed as support for these FOUR THOUSAND LINES of bandaids WILL BE REMOBVED in 1.6.0! + //typedef const uint8_t __attribute__ ((deprecated("\nMicrochip changed the spelling of bits within a bitfiels (macros that end in the bitnumber followed by _bm or _bp), you are using the old name, ex PERIPH_BITFIRLD1_bm.\nYou should use PERIPH_BITFIELD_1_bm; we do not guarantee that this 4000-line bandaid will not be removed in the future.\r\nWhy did they do this? Beats me. Ask their support folks - if enough of us do it, they might hesitate next time they have the urge to mass rename things in their headers"))) deprecated_constant_name; + // Okay, well that fix didn't work so well. back to plan A. +#if !defined(BACKWARD_COMBATIBILITY_MODE) /* Add a feature - yay! * Rename registers so people can't carry code back and forth - booo! */ @@ -4799,8 +4808,64 @@ #if !defined(WDT_WINDOW_0_bm) && defined(WDT_WINDOW0_bm) #define WDT_WINDOW_0_bm WDT_WINDOW0_bm #elif defined(WDT_WINDOW_0_bm) - //deprecated_constant_name WDT_WINDOW0_bm = WDT_WINDOW_0_bm; #define WDT_WINDOW0_bm WDT_WINDOW_0_bm //Deprecated as of Q2 2022 header change. #endif -#endif -#endif + #if !defined(WDT_WINDOW_0_bp) && defined(WDT_WINDOW0_bp) + #define WDT_WINDOW_0_bp WDT_WINDOW0_bp + #elif defined(WDT_WINDOW_0_bp) + #define WDT_WINDOW0_bp WDT_WINDOW_0_bp; //Deprecated as of Q2 2022 header change + #endif + #if !defined(WDT_WINDOW_1_bm) && defined(WDT_WINDOW1_bm) + #define WDT_WINDOW_1_bm WDT_WINDOW1_bm + #elif defined(WDT_WINDOW_1_bm) + #define WDT_WINDOW1_bm WDT_WINDOW_1_bm; //Deprecated as of Q2 2022 header change + #endif + #if !defined(WDT_WINDOW_1_bp) && defined(WDT_WINDOW1_bp) + #define WDT_WINDOW_1_bp WDT_WINDOW1_bp + #elif defined(WDT_WINDOW_1_bp) + #define WDT_WINDOW1_bp WDT_WINDOW_1_bp; //Deprecated as of Q2 2022 header change + #endif + #if !defined(WDT_WINDOW_2_bm) && defined(WDT_WINDOW2_bm) + #define WDT_WINDOW_2_bm WDT_WINDOW2_bm + #elif defined(WDT_WINDOW_2_bm) + #define WDT_WINDOW2_bm WDT_WINDOW_2_bm; //Deprecated as of Q2 2022 header change + #endif + #if !defined(WDT_WINDOW_2_bp) && defined(WDT_WINDOW2_bp) + #define WDT_WINDOW_2_bp WDT_WINDOW2_bp + #elif defined(WDT_WINDOW_2_bp) + #define WDT_WINDOW2_bp WDT_WINDOW_2_bp; //Deprecated as of Q2 2022 header change + #endif + #if !defined(WDT_WINDOW_3_bm) && defined(WDT_WINDOW3_bm) + #define WDT_WINDOW_3_bm WDT_WINDOW3_bm + #elif defined(WDT_WINDOW_3_bm) + #define WDT_WINDOW3_bm WDT_WINDOW_3_bm; //Deprecated as of Q2 2022 header change + #endif + #if !defined(WDT_WINDOW_3_bp) && defined(WDT_WINDOW3_bp) + #define WDT_WINDOW_3_bp WDT_WINDOW3_bp + #elif defined(WDT_WINDOW_3_bp) + #define WDT_WINDOW3_bp WDT_WINDOW_3_bp; //Deprecated as of Q2 2022 header change + #endif + + /* ======= ZCD ======= */ + #if !defined(ZCD_INTMODE_0_bm) && defined(ZCD_INTMODE0_bm) + #define ZCD_INTMODE_0_bm ZCD_INTMODE0_bm + #elif defined(ZCD_INTMODE_0_bm) + #define ZCD_INTMODE0_bm ZCD_INTMODE_0_bm; //Deprecated as of Q2 2022 header change + #endif + #if !defined(ZCD_INTMODE_0_bp) && defined(ZCD_INTMODE0_bp) + #define ZCD_INTMODE_0_bp ZCD_INTMODE0_bp + #elif defined(ZCD_INTMODE_0_bp) + #define ZCD_INTMODE0_bp ZCD_INTMODE_0_bp; //Deprecated as of Q2 2022 header change + #endif + #if !defined(ZCD_INTMODE_1_bm) && defined(ZCD_INTMODE1_bm) + #define ZCD_INTMODE_1_bm ZCD_INTMODE1_bm + #elif defined(ZCD_INTMODE_1_bm) + #define ZCD_INTMODE1_bm ZCD_INTMODE_1_bm; //Deprecated as of Q2 2022 header change + #endif + #if !defined(ZCD_INTMODE_1_bp) && defined(ZCD_INTMODE1_bp) + #define ZCD_INTMODE_1_bp ZCD_INTMODE1_bp + #elif defined(ZCD_INTMODE_1_bp) + #define ZCD_INTMODE1_bp ZCD_INTMODE_1_bp; //Deprecated as of Q2 2022 header change + #endif +#endif /* this is the end of the backwards compatibility defines */ +#endif // end of core_devices diff --git a/megaavr/cores/megatinycore/core_parameters.h b/megaavr/cores/megatinycore/core_parameters.h index 5c85d319..9fa80735 100644 --- a/megaavr/cores/megatinycore/core_parameters.h +++ b/megaavr/cores/megatinycore/core_parameters.h @@ -1,6 +1,15 @@ #ifndef __CORE_PARAMETERS_H__ #define __CORE_PARAMETERS_H__ +#if !defined(MEGATINYCORE_NUM) + #if !(defined(MEGATINYCORE_MAJOR) && defined(MEGATINYCORE_MINOR) && defined(MEGATINYCORE_PATCH) && defined(MEGATINYCORE_RELEASED)) + #warning "All of the version defines are missing, please correct your build environment; it is likely failing to define other critical values" + // Version related defines now handled in platform.txt + #else + #define MEGATINYCORE_NUM ((MEGATINYCORE_MAJOR << 24) + (MEGATINYCORE_MINOR << 16) + (MEGATINYCORE_PATCH << 8) + MEGATINYCORE_RELEASED) + #endif +#endif + #if !(defined(MEGATINYCORE) || defined(DXCORE) || defined(ATTIYNCORE)) // This define can get black-hole'ed somehow (reported on platformio) likely the ugly syntax to pass a string define from platform.txt via a -D @@ -13,17 +22,9 @@ // which becomes more and more important as more code is shared between the cores. #define MEGATINYCORE "Unknown 2.6.1+" - #if !defined(MEGATINYCORE_NUM) - #if !(defined(MEGATINYCORE_MAJOR) && defined(MEGATINYCORE_MINOR) && defined(MEGATINYCORE_PATCH) && defined(MEGATINYCORE_RELEASED)) - #warning "All of the version defines are missing, please correct your build environment; it is likely failing to define other critical values" - // Version related defines now handled in platform.txt - #else - #define MEGATINYCORE_NUM ((MEGATINYCORE_MAJOR << 24) + (MEGATINYCORE_MINOR << 16) + (MEGATINYCORE_PATCH << 8) + MEGATINYCORE_RELEASED) - #endif - #endif #else #if defined(DXCORE) || defined(ATTINYCORE) - #error "This is megaTinyCore being compiled, but DXCORE and/or ATTINYCORE is defined already" + #error "This is megaTinyCore being compiled, but DXCORE and/or ATTINYCORE is defined already, something is way wrong." #endif #endif #endif diff --git a/megaavr/cores/megatinycore/wiring_digital.c b/megaavr/cores/megatinycore/wiring_digital.c index 6af5f2fa..3078f69d 100644 --- a/megaavr/cores/megatinycore/wiring_digital.c +++ b/megaavr/cores/megatinycore/wiring_digital.c @@ -159,7 +159,7 @@ void pinMode(uint8_t pin, uint8_t mode) { check_valid_digital_pin(pin); /* generate compile error if a constant that is not a valid pin is used as the pin */ check_valid_pin_mode(mode); /* generate compile error if a constant that is not a valid pin mode is used as the mode */ uint8_t bit_mask = digitalPinToBitMask(pin); - if ((bit_mask == NOT_A_PIN) || (mode > 3)) { + if ((bit_mask == NOT_A_PIN) || (mode > INPUT_PULLUP)) { return; /* ignore invalid pins passed at runtime */ } volatile uint8_t * port_base = ((volatile uint8_t *) (uint16_t)(0x0400 | portToPortBaseOffset(digitalPinToPort(pin)))); @@ -202,9 +202,15 @@ void pinMode(uint8_t pin, uint8_t mode) { *port_base = bit_mask; } - - -void turnOffPWM(uint8_t pin) { +/* This turns off PWM, if enabled. It is called automatically on every digitalWrite(); + * This function can end up executing a heckovalotta code for one simple + * Note that it only operates on the PWM source with priority - TCA > TCD > TCB/DAC + * the order of the cases here doesn't matter - which one has priority is determined in + * digitalPinToTimerNow() in wiring_analog.c. That's why it's recommended to make sure + * that no pin you're about to move the PWM output of a TCA onto is currently outputting + * PWM. It can also be used from user code (unlike on the stock core). */ +void turnOffPWM(uint8_t pin) +{ /* Actually turn off compare channel, not the timer */ /* Get pin's timer diff --git a/megaavr/extras/LinkingAgainstStaticLibrary.md b/megaavr/extras/LinkingAgainstStaticLibrary.md new file mode 100644 index 00000000..2257bd51 --- /dev/null +++ b/megaavr/extras/LinkingAgainstStaticLibrary.md @@ -0,0 +1,25 @@ +# Linking against static library + +In some uses cases, it might be convenient to link against a static library/archive rather than compiling the code each time. For example if you don't have access to the source files, just the headers and the archive, you want to reduce compilation time for a larger codebase or want to have a bunch of board specific code for a larger library. The downside with using a library is that the code size will increase, since things are statically linked and the compiler can do fewer tricks on what it has got at hand. + +As things are with the Arduino environment at the moment, this requires your source code to be an Arduino library as well. This isn't a big deal, there are two steps: + +1. Move your project to Arduino's library folder (usually in the `Documents\Arduino\libraries` folder in your home folder on Windows and in the `Arduino/libraries` folder in your home folder on linux). More information ~here~ no longer available, link that used to work is now 404. +2. Create a `library.properties` file according to this [specification](https://arduino.github.io/arduino-cli/latest/library-specification/) in the root of your library. An example is: + +```text +name=your-library +version=1.0.0 +author=Your name +maintainer=Your name +sentence=Test library +paragraph=Links an archive +category=Other +url=http://example.com/ +architectures=* +precompiled=true +``` + +The `precompiled` keyword enables us to link against some archive. The archives have to be placed in `src//`, as detailed [here](https://arduino.github.io/arduino-cli/latest/library-specification/#precompiled-binaries). Board has to for example be `avr128db64`. + +After this, you should be able to compile your code against the archive. diff --git a/megaavr/extras/Ref_Analog.md b/megaavr/extras/Ref_Analog.md index 4fe7703d..993931de 100644 --- a/megaavr/extras/Ref_Analog.md +++ b/megaavr/extras/Ref_Analog.md @@ -104,9 +104,8 @@ These return the numbers listes in the reference table at the top as a `uint8_t` The standard analogRead(). Single-ended, and resolution set by analogReadResolution(), default 10 for compatibility. Negative return values indicate an error that we were not able to detect at compile time. Return type is a 16-bit signed integer (`int` or `int16_t`). ### analogReadResolution(resolution) -Sets resolution for the analogRead() function. Unlike stock version, this returns true/false. *If it returns false, the value passed was invalid, and resolution was set to the default, 10 bits*. Note that this can only happen when the value passed to it is determined at runtime - if you are passing a compile-time known constant which is invalid, we will issue a compile error. The only valid values are those that are supported natively by the hardware, plus 10 bit for compatibility where that is not natively supported (ie, the 2-series) for compatibility. - -Hence, the only valid values are 8, 10 and 12. +Sets resolution for the analogRead() function. Unlike stock version, this returns true/false. *If it returns false, the value passed was invalid, and resolution was set to the default, 10 bits*. Note that this can only happen when the value passed to it is determined at runtime - if you are passing a compile-time known constant which is invalid, we will issue a compile error. The only valid values are those that are supported natively by the hardware, plus 10 bit, even if not natively supported, for compatibility. +Hence, the only valid values are 10 and 12. The EA-series will likely launch with the same 8bit resolution option as tinyAVR 2-series which would add 8 to that list. This is different from the Zero/Due/etc implementations, which allow you to pass anything from 1-32, and rightshift the minimum resolution or leftshift the maximum resolution as needed to get the requested range of values. Within the limited resources of an 8-bit AVR with this is a silly waste of resources, and padding a reading with zeros so it matches the format of a more precise measuring method is in questionable territory in terms of best practices. Note also that we offer oversampling & decimation with `analogReadEnh()` and `analogReadDiff()`, which can extend the resolution while keep the extra bits meaningful at the cost of slowing down the reading. `analogReadResolution()` only controls the resolution of analogRead() itself. The other functions take desired resolution as an argument, and restore the previous setting. @@ -147,7 +146,7 @@ Enhanced `analogRead()` - Perform a single-ended read on the specified pin. `res // AVR Dx, Ex, and tinyAVR 2-series this will be sampled 4 times using the accumulation function, and then rightshifted once // tinyAVR 0/1-series, this will be sampled 64 times, as we need 3 more bits, hence we need to take 2^(3*2) = 64 samples then rightshift them 3 times., int32_t adc_reading2 = analogReadEnh(PIN_PD2, ADC_ACC128); - // Take 128 samples and accumulate them. This value, k, is 19 bits wide; on Dx-series parts, this is truncated to 16 bits - the hardware does not expose the three LSBs. 0/1-series can only measure to 15 + // Take 128 samples and accumulate them. This value, k, is 19 bits wide; on the Dx-series parts, this is truncated to 16 bits - the hardware does not expose the three LSBs. ``` Negative values from ADC_ENH always indicate a runtime error; these values are easily recognized, as they are huge negative numbers @@ -165,7 +164,7 @@ On the Dx-series, the measured voltages must be less than VRef; this makes diffe The 32-bit value returned should be between -65536 and 65535 at the extremes with the maximum 17-bit accumulation option, or, 32-times that if using raw accumulated values (-2.1 million to 2.1 million, approximately) -Error values are negative numbers close to -2.1 billion, so it should not be challenging to distinguish valid values from errors. +**ERRATA ALERT** There is a mildly annoying silicon bug in early revisions of the AVR DA parts (as of a year post-release in 2021, these are still the only ones available) where whatever pin the ADC positive multiplexer is pointed at, digital reads are disabled. This core works around it by always setting the the ADC multiplexer to point at ADC_GROUND when it is not actively in use; however, be aware that you cannot, say, set an interrupt on a pin being subject to analogReads (not that this is particularly useful). ### analogClockSpeed(int16_t frequency = 0, uint8_t options = 0) The accepted options for frequency are -1 (reset ADC clock to core default, 1-1.35 MHz), 0 (make no changes - just report current frequency) or a frequency, in kHz, to set the ADC clock to. Values between 125 and 2000 are considered valid for Dx-series parts and Ex-series parts 300-3000 with internal reference, and 300-6000 with Vdd or external reference. The prescaler options are discrete, not continuous, so there are a limited number of possible settings (the fastest and slowest of which are often outside the rated operating range). The core will choose the highest frequency which is within spec, and which does not exceed the value you requested. If a 1 is passed as the third argument, the validity check will be bypassed; this allows you to operate the ADC out of spec if you really want to, which may have unpredictable results. Microchip documentation has provided little in the way of guidance on selecting this (or other ADC parameters) other than giving us the upper and lower bounds. @@ -228,13 +227,13 @@ Note that the numeric values, though not the names, of some of these were change | Error name | Value | analogCheckError val | Notes |--------------------------------|-------------|--------------------------------------------------------------------- -|ADC_ERROR_BAD_PIN_OR_CHANNEL | -32001 | -1 | The specified pin or ADC channel does not exist or does support analog reads. +|ADC_ERROR_BAD_PIN_OR_CHANNEL | -32001 | -1 | The specified pin or ADC channel does not exist or does not support analog reads. |ADC_ERROR_BUSY | -32002 | -2 | The ADC is busy with another conversion. |ADC_ERROR_DISABLED | -32007 | -7 | The ADC is disabled at this time. Did you disable it before going to sleep and not re-enable it? -|ADC_ENH_ERROR_BAD_PIN_OR_CHANNEL| -2100000001 | -1 | The specified pin or ADC channel does not exist or does support analog reads. +|ADC_ENH_ERROR_BAD_PIN_OR_CHANNEL| -2100000001 | -1 | The specified pin or ADC channel does not exist or does not support analog reads. |ADC_ENH_ERROR_BUSY | -2100000002 | -2 | The ADC is busy with another conversion. |ADC_ENH_ERROR_RES_TOO_LOW | -2100000003 | -3 | Minimum ADC resolution is 8 bits. If you really want less, you can always rightshift it. -|ADC_ENH_ERROR_RES_TOO_HIGH | -2100000004 | -4 | Maximum resolution, using automatic oversampling and decimation is less than the requested resolution. +|ADC_ENH_ERROR_RES_TOO_HIGH | -2100000004 | -4 | Maximum resolution using automatic oversampling and decimation is less than the requested resolution. |ADC_DIFF_ERROR_BAD_NEG_PIN | -2100000005 | -5 | analogReadDiff() was called with a negative input that is not valid. |ADC_ENH_ERROR_DISABLED | -2100000007 | -7 | The ADC is currently disabled. You must enable it to take measurements. Did you disable it before going to sleep and not re-enable it? |ADC_IMPOSSIBLE_VALUE | N/A | -127 | 16-bit value > 4095, or 32-bit value that's not an error code and is outside the range of -2,097,152-4,194,303 (raw 1024-sample accumulation range. diff --git a/megaavr/extras/Ref_Digital.md b/megaavr/extras/Ref_Digital.md index 1fe20391..cb6bc5eb 100644 --- a/megaavr/extras/Ref_Digital.md +++ b/megaavr/extras/Ref_Digital.md @@ -27,9 +27,10 @@ The takeaways from this should be that: * If you know you won't have PWM coming out of a pin, pinConfigure is faster than pinMode() and digitalWrite(). Especially if only setting up the more common properties. * pinConfigure called with second argument constrained to 0x00-0x0F (setting only direction and output value) (1), with it constrained to that plus configuring pullups (2), and without restrictions (3). About 200 bytes of that space is used for lookup tables, not instructions. -* This is why the fast digital I/O functions exist. +* This is why the fast digital I/O functions exist, and why there are people who habitually do `VPORTA.OUT |= 0x80;` instead of `digitalWrite(PIN_PA7,HIGH);` It's also why I am not comfortable automatically switching digital I/O to "fast" type when constant arguments are given. The normal functions are just SO SLOW that you're sure to break code that hadn't realized they were depending on the time it took for digital write, even if just for setup or hold time for the thing it's talking to. + ## openDrain() It has always been possible to get the benefit of an open drain configuration - you set a pin's output value to 0 and toggle it between input and output. This core provides a slightly smoother (also faster) wrapper around this than using pinmode (since pinMode must also concern itself with configuring the pullup, whether it needs to be changed or not, every time - it's actually significantly slower setting things input vs output. The openDrain() function takes a pin and a value - `LOW`, `FLOATING` (or `HIGH`) or `CHANGE`. `openDrain()` always makes sure the output buffer is not set to drive the pin high; often the other end of a pin you're using in open drain mode may be connected to something running from a lower supply voltage, where setting it OUTPUT with the pin set high could damage the other device. diff --git a/megaavr/extras/Ref_Functions.md b/megaavr/extras/Ref_Functions.md index 810a12a9..9185a775 100644 --- a/megaavr/extras/Ref_Functions.md +++ b/megaavr/extras/Ref_Functions.md @@ -239,10 +239,10 @@ Longer clock-counting delays are more efficiently done with the 3 cycle loop (ld ## Time Manipulation ### `void stop_millis()` -Stop the timer being used for millis and disable the interrupt. This does not change the current count. Intended for internal use in the future timing and sleep library, so you would stop it before sleeping and start the RTC before going into standby sleep, or powerdown with the PIT. +Stop the timer being used for millis, and disable the interrupt. This does not change the current count. Intended for internal use in the future timing and sleep library, so you would stop it before sleeping and start the RTC before going into standby sleep, or powerdown with the PIT. ### `void set_millis(uint32_t newmillis)` -Sets the millisecond timer to the specified number of milliseconds. Be careful if you are setting to a number lower than the current millis count if you have any timeouts ongoing, since standard best practice is to always subtract `(oldmillis - millis())` and these are unsigned. So setting it oldmillis-1 will make it look like 4.2xx billion ms have passed, and your timeout may expire. +Sets the millisecond timer to the specified number of milliseconds. Be careful if you are setting to a number lower than the current millis count if you have any timeouts ongoing, since stanard best practice is to always subtract `(oldmillis - millis())` and these are unsigned. So setting it oldmillis-1 will make it look like 4.2xx billion ms have passed. and the timer will expire. ### `void restart_millis()` After having stopped millis either for sleep or to use timer for something else and optionally have set it to correct for passage of time, call this to restart it. diff --git a/megaavr/extras/Ref_Reset.md b/megaavr/extras/Ref_Reset.md index 441e6c61..25856b8b 100644 --- a/megaavr/extras/Ref_Reset.md +++ b/megaavr/extras/Ref_Reset.md @@ -26,7 +26,8 @@ The cause of reset is recorded whenever any reset takes place. These flags are n When you see unexpected resets, check the reset cause! If it's showing as software reset - this is likely what's happening. You can override init_reset_flags() to turn on LEDs or something like that to indicate how you got there - but you are forced to work under very painful conditions: Using Serial, any arduino timekeeping functions are out of the question, etc. The system is not so hosed that you can't turn on a pin, though, and you can generate delays with delay_us() and delay_ms() in `` (provided they are compile time known constant delays) and use that to blink a LED, thought the rate at which it is blinking may be very different than you intended). The best way to avoid this problem is to preempt it. Test often. If suddenly it starts throwing dirty resets, well, you know what you were working on before this started happening. Did you add some code to write to an array? Maybe you wrote past the end of it. Did you add an interrupt? Are you sure the vector is spelled right and you're enabling the right interrupt? (see below for more causes of a dirty reset). Dirty resets are BY FAR the most common cause of hangs and Arduinos getting into a "bad state"; the recent changes should make these far less likely to result in anything more than a surprise reset. Which is a very bad failure, but not as bad as the part hanging until the batteries die or you climb up the tree you mounted it in to press the reset button. ## The Reset Pin -When the reset pin is acting as reset - which unfortunately is uncommon on tinyAVRs because then, the pin can't be used for UPDI programming if set to act as reset unless you have an HV UPDI programmer, which is still quite rare. (On the 20 or 24-pin tinyAVR 2-series, PB4 can be configured to act as reset instead, but that is not an option on other parts). When acting as reset , the pullup is always enabled. If the pin is ever brought to a logic LOW, it will reset the chip. This is pretty much the same behavior as on classic AVR's (contrary to some posts on forums, you do not *need* to have an external pullup on reset - though it is recommended when the pin is used for reset, though it is wise, especially if there are long wires to the reset button, it is required for autoreset) Just like on the classic AVRs, you should never jumper an output pin to reset and drive it low to try to generate a reset! (We have two great ways to reset from software now!). +When the reset pin is acting as reset - which unfortunately is uncommon on tinyAVRs because the pin can't be used for UPDI programming if set to act as reset (on the 20 or 24-pin tinyAVR 2-series, PB4 can be configured to act as reset instead, but that is not an option on other parts), it requires HV reprogramming to write to them over UPDI afterwards; that is beyond the scope of this particular document). When acting as reset , the pullup is always enabled. If the pin is ever brought to a logic LOW, it will reset the chip. This is pretty much the same behavior as on classic AVR's (contrary to some posts on forums, you do not *need* to have an external pullup on reset - though it is recommended when the pin is used for reset. ) Just like on the classic AVRs, you should never jumper an output pin to reset and drive it low to reset. (We have two great ways to reset from software now!). + ### AutoReset Normal Arduino boards autoreset when the serial port is opened. It does this through the "DTR autoreset circuit". AVRdude, like any program that doesn't override the default behavior will set DTR and RTS lines low while the serial port is open. This circuit converts the transition into a pulse, allowing the chip to leave reset too. (your finer serial terminals let you control these two pins. Generally speaking DTR and RTS are interchangeable, and you use whichever one the serial adapter makes available more easily). @@ -57,7 +58,7 @@ These parts support a native software reset operation; on classic AVRs, the only These two methods of resetting the chip allow you a crude means of signaling to the application or bootloader what sort of condition triggered the reset. -The bootloader, if used (see below) will run after a software reset, but it will NOT run after a watchdog reset (well - it will run, but only long enough to read the reset flag register and see that it was restarted by the WDT: That means that either the bootloader just ran, finished, and reset the device (If we didn't jump to the app in this case, we'd just sit in the bootloader doing WDT resets forever), that the application suffered from a WDT timeout due to a bug or adverse conditions (that's not the bootloader's business to get involved in) or that the application intentionally triggered a WDT reset. None of those are "entry conditions" for the bootloader, so it just stashes the reset flags, clears them, and jumps to the app). This allows the application a convenient mechanism to restart itself without having to potentially wait through the bootloader attempting to communicate with whatever is connected to the serial port. +Additionally, while the bootloader, if used (see below) will run after a software reset, it will NOT run after a watchdog reset (well - it will run, but only long enough to read the reset flag register and see that it was restarted by the WDT: That means that either the bootloader just ran, finished, and reset the device (If we didn't jump to the app in this case, we'd just sit in the bootloader doing WDT resets forever), that the application suffered from a WDT timeout due to a bug or adverse conditions (that's not the bootloader's business to get involved in) or that the application intentionally triggered a WDT reset. None of those are "entry conditions" for the bootloader, so it just stashes the reset flags, clears them, and jumps to the app).This allows the application a convenient mechanism to restart itself without having to potentially wait through the bootloader attempting to communicate with whatever is connected to the serial port. Note: While the windowed mode would at first seem to suggest that you could trigger a WDT reset much faster by setting it and then executing `WDR` until it resets from missing the window, you don't gain nearly as much as you'd think. First, the initial WDR needs to be synchronized - 2-3 WDT clocks, ie, 2-3 ms. Additional WDRs executed while this is happening are ignored. Only when the second WDR makes it to the watchdog timer domain will it reset the system. So the overall time to restart is 6-9ms. Instead 10-11 ms (sync delay + minimum timeout). diff --git a/megaavr/extras/Ref_Serial.md b/megaavr/extras/Ref_Serial.md index 95b3a430..6816ebab 100644 --- a/megaavr/extras/Ref_Serial.md +++ b/megaavr/extras/Ref_Serial.md @@ -73,6 +73,7 @@ PIN_SERIAL_RX PIN_SERIAL_XCK PIN_SERIAL_XDIR ``` +**Warning** - on DD-series parts, this may return an inaccurate values in two specific cases. For the case of USART0 mapping 4, XDIR (that pin does not exist, but we return the the non-existent pin instead), and for USART1, mapping 0, TX on 14/20 pin parts (that pin doesn't exist, but we return it anyway). This function is meant for use by libraries to allow them to figure out which pin is in use without duplicating the logic we have already implemented. diff --git a/megaavr/extras/Ref_Timers.md b/megaavr/extras/Ref_Timers.md index b4099807..118a9784 100644 --- a/megaavr/extras/Ref_Timers.md +++ b/megaavr/extras/Ref_Timers.md @@ -315,6 +315,7 @@ while (digitalReadFast(pinb)); // make sure our pulse is over - can be omitted i ``` `*` internal oscillator is usually within a percent at room temperature, and within half a percent is common. We're assuming that at the moment millis started, an ideal stopwatch was started, and when it indicated 100us had gone by, drove the pin low effectively instantaneously. +A table is presented for each type of timer comparing the percentage of CPU time spent in the ISR, the resolution of the timekeeping functions, and the execution time of micros. Typically `micros()` can have one of three execution times, the shortest one being overwhelmingly more common, and the differences between them are small. ### TCAn for millis timekeeping diff --git a/megaavr/libraries/Comparator/src/Comparator.cpp b/megaavr/libraries/Comparator/src/Comparator.cpp index 6c69ba2c..27d355b9 100644 --- a/megaavr/libraries/Comparator/src/Comparator.cpp +++ b/megaavr/libraries/Comparator/src/Comparator.cpp @@ -83,8 +83,8 @@ AltOUT | PIN_PC6* | PIN_PC6* | PIN_PC6* | n/a | PIN_PC6* | PIN_PC6* | #elif defined(ANALOG_COMP_PINS_TINY_GOLDEN) /* other golden 1-series: 3 AC P0, P1 (AC1 on 24 only), P2, P3, N0, N1*/ AnalogComparator Comparator0(0, AC0, PORTA.PIN7CTRL, PORTB.PIN5CTRL, PORTB.PIN1CTRL, PORTA.PIN6CTRL, PORTA.PIN6CTRL, PORTB.PIN4CTRL); - AnalogComparator Comparator0(1, AC1, PORTA.PIN7CTRL, PORTB.PIN6CTRL, PORTB.PIN0CTRL, PORTA.PIN4CTRL, PORTA.PIN5CTRL, PORTB.PIN7CTRL); - AnalogComparator Comparator0(2, AC2, PORTA.PIN6CTRL, PORTB.PIN0CTRL, PORTB.PIN5CTRL, PORTA.PIN7CTRL, PORTA.PIN7CTRL, PORTB.PIN6CTRL); + AnalogComparator Comparator1(1, AC1, PORTA.PIN7CTRL, PORTB.PIN6CTRL, PORTB.PIN0CTRL, PORTA.PIN4CTRL, PORTA.PIN5CTRL, PORTB.PIN7CTRL); + AnalogComparator Comparator2(2, AC2, PORTA.PIN6CTRL, PORTB.PIN0CTRL, PORTB.PIN5CTRL, PORTA.PIN7CTRL, PORTA.PIN7CTRL, PORTB.PIN6CTRL); #elif defined(ANALOG_COMP_PINS_TINY_TWO_14) /* 14-pin 2-series: 1 AC P0, P2, N0, N2*/ @@ -239,7 +239,7 @@ AnalogComparator::AnalogComparator( register8_t& in0_p, register8_t& in1_p, register8_t& in2_p, - register8_t& in3_p + register8_t& in3_p, register8_t& in0_n, register8_t& in1_n ) diff --git a/megaavr/platform.txt b/megaavr/platform.txt index e5d66c68..edd06c23 100644 --- a/megaavr/platform.txt +++ b/megaavr/platform.txt @@ -7,7 +7,7 @@ name=megaTinyCore versionnum.major=2 versionnum.minor=6 -versionnum.patch=2 +versionnum.patch=3 versionnum.postfix= versionnum.released=1 @@ -16,7 +16,7 @@ version={versionnum.major}.{versionnum.minor}.{versionnum.patch}{versionnum.post # Stupid workaround # # for IDE bug # ##################### -version=2.6.2 +version=2.6.3 build.versiondefines=-DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DMEGATINYCORE="{version}" -DMEGATINYCORE_MAJOR={versionnum.major}UL -DMEGATINYCORE_MINOR={versionnum.minor}UL -DMEGATINYCORE_PATCH={versionnum.patch}UL -DMEGATINYCORE_RELEASED={versionnum.released}