From 768a50b069db1252901c9617654053ddb4a677d7 Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Sat, 21 Mar 2020 01:07:14 +0430 Subject: [PATCH 01/16] added some new functions and STM32F1 Supported --- src/Dimmer.cpp | 186 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 146 insertions(+), 40 deletions(-) diff --git a/src/Dimmer.cpp b/src/Dimmer.cpp index c2ca3ce..b7c55a9 100644 --- a/src/Dimmer.cpp +++ b/src/Dimmer.cpp @@ -6,10 +6,10 @@ */ #include "Arduino.h" -#include "Dimmer.h" -#include +#include "Dimmer_2.h" +////#include -// Timer configuration macros +// Timer configuration macros_TIMER(X) #define _TCNT(X) TCNT ## X #define TCNT(X) _TCNT(X) #define _TCCRxA(X) TCCR ## X ## A @@ -22,6 +22,10 @@ #define OCRxA(X) _OCRxA(X) #define _TIMER_COMPA_VECTOR(X) TIMER ## X ## _COMPA_vect #define TIMER_COMPA_VECTOR(X) _TIMER_COMPA_VECTOR(X) +#define _Timer(X) Timer ## X +#define Timer(X) _Timer(X) +#define _NVIC_TIMER(X) NVIC_TIMER ## X +#define NVIC_TIMER(X) _NVIC_TIMER(X) // Helper macros #define DIMMER_PULSES_TO_VALUE(pulses, bits) ((uint16_t)(pulses) * 100 / (bits)) @@ -63,8 +67,14 @@ static Dimmer* dimmmers[DIMMER_MAX_TRIAC]; // Pointers to all registered dim static uint8_t dimmerCount = 0; // Number of registered dimmer objects // Triac pin and timing variables. Using global arrays to make ISR fast. -static volatile uint8_t* triacPinPorts[DIMMER_MAX_TRIAC]; // Triac ports for registered dimmers -static uint8_t triacPinMasks[DIMMER_MAX_TRIAC]; // Triac pin mask for registered dimmers +#if defined(ARDUINO_ARCH_AVR) + static volatile uint8_t* triacPinPorts[DIMMER_MAX_TRIAC]; // Triac ports for registered dimmers + static uint8_t triacPinMasks[DIMMER_MAX_TRIAC]; // Triac pin mask for registered dimmers +#elif defined(ARDUINO_ARCH_STM32F1) + static volatile uint32_t* triacPinPorts[DIMMER_MAX_TRIAC]; // Triac ports for registered dimmers + static uint32_t triacPinMasks[DIMMER_MAX_TRIAC]; // Triac pin mask for registered dimmers +#endif + static uint8_t triacTimes[DIMMER_MAX_TRIAC]; // Triac time for registered dimmers // Timer ticks since zero crossing @@ -73,12 +83,52 @@ static uint8_t tmrCount = 0; // Global state variables bool Dimmer::started = false; // At least one dimmer has started +//================== added by Hamid ================== +#ifdef Auto_Main_frequency_detection + + bool Main_frequency_detection_Mode=true; + volatile uint8_t sample_for_Main_frequency_detection; + unsigned long lastTime_for_Main_frequency_detection; + volatile unsigned long frequency_detection_timings_sum; + +#endif +//==================================================== + // Zero cross interrupt void callZeroCross() { + + //================== added by Hamid =================== + #ifdef Auto_Main_frequency_detection + if(Main_frequency_detection_Mode){ + if(sample_for_Main_frequency_detection <= NUMBER_OF_SAMLPLES_FOR_MAIN_FREQUENCY_DETECTION){ + + const long time = micros(); + const unsigned long duration = time - lastTime_for_Main_frequency_detection; + + if (duration <= (1000.0/MIN_INPUT_FREQUENCY)*1000.0/2.0 && duration >= (1000.0/MAX_INPUT_FREQUENCY)*1000.0/2.0){ + if(sample_for_Main_frequency_detection!=0) frequency_detection_timings_sum += duration; // dump first one + sample_for_Main_frequency_detection++; + } + lastTime_for_Main_frequency_detection = time; + } + return; + } + #endif + //==================================================== + + // Clear the timer and enable nested interrupts so that the timer can be updated while this ISR is executed - TCNT(DIMMER_TIMER) = 0; + #if defined(ARDUINO_ARCH_AVR) + TCNT(DIMMER_TIMER) = 0; + //sei(); + #elif defined(ARDUINO_ARCH_STM32F1) + //Timer(DIMMER_TIMER).setCount(0); //The new count value to set. If this value exceeds the timer’s overflow value, it is truncated to the overflow value. + Timer(DIMMER_TIMER).refresh(); //This will reset the counter to 0 in upcounting mode (the default). It will also update the timer’s prescaler and overflow, if you have set them up to be changed using HardwareTimer::setPrescaleFactor() or HardwareTimer::setOverflow(). + + #endif + + interrupts(); tmrCount = 0; - sei(); // Turn off all triacs and disable further triac activation before anything else for (uint8_t i = 0; i < dimmerCount; i++) { @@ -98,24 +148,30 @@ void callZeroCross() { } // Timer interrupt -ISR(TIMER_COMPA_VECTOR(DIMMER_TIMER)) { - // Increment ticks - if (tmrCount < 254) { - tmrCount++; - } +#if defined(ARDUINO_ARCH_STM32F1) + void onTimerISR() +#elif defined(ARDUINO_ARCH_AVR) + ISR(TIMER_COMPA_VECTOR(DIMMER_TIMER)) +#endif + { + // Increment ticks + if (tmrCount < 254) { + tmrCount++; + } - // Process each registered triac and turn it on if needed - for (uint8_t i = 0; i < dimmerCount; i++) { - if (tmrCount == triacTimes[i]) { - *triacPinPorts[i] |= triacPinMasks[i]; + // Process each registered triac and turn it on if needed + for (uint8_t i = 0; i < dimmerCount; i++) { + if (tmrCount == triacTimes[i]) { + *triacPinPorts[i] |= triacPinMasks[i]; + } } } -} // Constructor -Dimmer::Dimmer(uint8_t pin, uint8_t mode, double rampTime, uint8_t freq) : - triacPin(pin), - operatingMode(mode), +Dimmer::Dimmer(uint8_t out_dimmer_pin, uint8_t zc_dimmer_pin, uint8_t mode, double rampTime, uint8_t freq) : + triacPin(out_dimmer_pin), + zc_pin(zc_dimmer_pin), + operatingMode(mode), lampState(false), lampValue(0), rampStartValue(0), @@ -130,8 +186,8 @@ Dimmer::Dimmer(uint8_t pin, uint8_t mode, double rampTime, uint8_t freq) : // Register dimmer object being created dimmerIndex = dimmerCount; dimmmers[dimmerCount++] = this; - triacPinPorts[dimmerIndex] = portOutputRegister(digitalPinToPort(pin)); - triacPinMasks[dimmerIndex] = digitalPinToBitMask(pin); + triacPinPorts[dimmerIndex] = portOutputRegister(digitalPinToPort(out_dimmer_pin)); + triacPinMasks[dimmerIndex] = digitalPinToBitMask(out_dimmer_pin); } if (mode == DIMMER_RAMP) { @@ -139,7 +195,7 @@ Dimmer::Dimmer(uint8_t pin, uint8_t mode, double rampTime, uint8_t freq) : } } -void Dimmer::begin(uint8_t value, bool on) { +void Dimmer::begin(uint8_t value, bool on ) { // Initialize lamp state and value set(value, on); @@ -149,16 +205,52 @@ void Dimmer::begin(uint8_t value, bool on) { if (!started) { // Start zero cross circuit if not started yet - pinMode(DIMMER_ZERO_CROSS_PIN, INPUT); - attachInterrupt(DIMMER_ZERO_CROSS_INTERRUPT, callZeroCross, RISING); - + pinMode(zc_pin, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(zc_pin), callZeroCross, RISING); + + //================== added by Hamid ================= + #ifdef Auto_Main_frequency_detection + + while(sample_for_Main_frequency_detection <= NUMBER_OF_SAMLPLES_FOR_MAIN_FREQUENCY_DETECTION){ + // Zerocross-Interrupt doing his job + } + + //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { //Creates a block of code that is guaranteed to be executed atomically. Upon entering the block the Global Interrupt Status flag in SREG is disabled, and re-enabled upon exiting the block from any exit path. + noInterrupts(); // go atomic level - avoid interrupts to surely get the previously received data + + /* If the volatile variable is bigger than a byte (e.g. a 16 bit int or a 32 bit long), then the microcontroller can not read it in one step, because it is an 8 bit microcontroller. This means that while your main code section (e.g. your loop) reads the first 8 bits of the variable, the interrupt might already change the second 8 bits. This will produce random values for the variable. + Remedy: + While the variable is read, interrupts need to be disabled, so they can’t mess with the bits, while they are read. There are several ways to do this: + */ + float Main_frequency; + Main_frequency = (1/((frequency_detection_timings_sum/NUMBER_OF_SAMLPLES_FOR_MAIN_FREQUENCY_DETECTION)/1000000.0))/2.0 ;// ( /2) because zerocross occur in half cycle + acFreq = round(Main_frequency); + Main_frequency_detection_Mode= false;// must be after all to execute "return" in ISR + + interrupts(); // let systick do its job + + //} + + #endif + //================================================== + // Setup timer to fire every 50us @ 60Hz - TCNT(DIMMER_TIMER) = 0; // Clear timer + + #if defined(ARDUINO_ARCH_STM32F1) + + Timer(DIMMER_TIMER).setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE); + Timer(DIMMER_TIMER).setPeriod(50*(60.0/acFreq)); // in microseconds + Timer(DIMMER_TIMER).setCompare(TIMER_CH1, 1); // Interrupt 1 count after each update, overflow might be small + Timer(DIMMER_TIMER).attachInterrupt(TIMER_CH1, onTimerISR); + //nvic_irq_set_priority(NVIC_TIMER(DIMMER_TIMER), 15);// interrupt must not be preempted. highest interrupt priority is 0. All other interrupts have been initialized to priority level 16. See nvic_init(). + + #elif defined(ARDUINO_ARCH_AVR) + TCNT(DIMMER_TIMER) = 0; // Clear timer TCCRxA(DIMMER_TIMER) = TCCRxA_VALUE; // Timer config byte A TCCRxB(DIMMER_TIMER) = TCCRxB_VALUE; // Timer config byte B TIMSKx(DIMMER_TIMER) = 0x02; // Timer Compare Match Interrupt Enable - OCRxA(DIMMER_TIMER) = 100 * 60 / acFreq - 1; // Compare value (frequency adjusted) - + OCRxA(DIMMER_TIMER) = 100 * 60.0 / acFreq - 1; // Compare value (frequency adjusted) + #endif started = true; } } @@ -172,9 +264,11 @@ void Dimmer::on() { } void Dimmer::toggle() { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + noInterrupts(); lampState = !lampState; - } + interrupts(); + //} } bool Dimmer::getState() { @@ -182,9 +276,12 @@ bool Dimmer::getState() { } uint8_t Dimmer::getValue() { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - return rampStartValue + ((int32_t) lampValue - rampStartValue) * rampCounter / rampCycles; - } + //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + noInterrupts(); + uint8_t val = rampStartValue + ((int32_t) lampValue - rampStartValue) * rampCounter / rampCycles ; + interrupts(); + return val; + //} } void Dimmer::set(uint8_t value) { @@ -196,7 +293,8 @@ void Dimmer::set(uint8_t value) { value = minValue; } - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + noInterrupts(); if (value != lampValue) { if (operatingMode == DIMMER_RAMP) { rampStartValue = getValue(); @@ -209,7 +307,7 @@ void Dimmer::set(uint8_t value) { } lampValue = value; } - } + interrupts(); } void Dimmer::set(uint8_t value, bool on) { @@ -224,19 +322,23 @@ void Dimmer::setMinimum(uint8_t value) { minValue = value; - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + noInterrupts(); if (lampValue < minValue) { set(value); } - } + interrupts(); + //} } void Dimmer::setRampTime(double rampTime) { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + noInterrupts(); rampTime = rampTime * 2 * acFreq; rampCycles = rampTime > 0xFFFF ? 0xFFFF : rampTime; rampCounter = rampCycles; - } + interrupts(); + //} } void Dimmer::zeroCross() { @@ -282,3 +384,7 @@ void Dimmer::zeroCross() { } } } + +uint8_t Dimmer::getAcFrequency(){ + return acFreq; +} From a656c5292935782a311650ae724070583efee09a Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Sat, 21 Mar 2020 01:08:30 +0430 Subject: [PATCH 02/16] added some new functions and STM32F1 Supported --- src/Dimmer.h | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/Dimmer.h b/src/Dimmer.h index 1e7f9c1..a8464f6 100644 --- a/src/Dimmer.h +++ b/src/Dimmer.h @@ -5,13 +5,13 @@ * This software is released under the MIT license. See the attached LICENSE file for details. */ -#ifndef DIMMER_H -#define DIMMER_H +#ifndef DIMMER_2_H +#define DIMMER_2_H /** * Maximum number of triacs that can be used. Can be decreased to save RAM. */ -#define DIMMER_MAX_TRIAC 10 +#define DIMMER_MAX_TRIAC 1 /** * Timer to use for control of triac timing. @@ -20,6 +20,8 @@ #define DIMMER_TIMER 4 #elif defined(__AVR_ATmega32U4__) #define DIMMER_TIMER 3 +#elif defined(ARDUINO_ARCH_STM32F1) +#define DIMMER_TIMER 3 #else #define DIMMER_TIMER 2 #endif @@ -32,8 +34,8 @@ * * @see https://www.arduino.cc/en/Reference/attachInterrupt for more information. */ -#define DIMMER_ZERO_CROSS_PIN 2 -#define DIMMER_ZERO_CROSS_INTERRUPT 0 +//#define DIMMER_ZERO_CROSS_PIN 2 +//#define DIMMER_ZERO_CROSS_INTERRUPT 0 /** * Possible operating modes for the dimmer library. @@ -42,6 +44,19 @@ #define DIMMER_RAMP 1 #define DIMMER_COUNT 2 +//================== added by Hamid ================ + +#define Auto_Main_frequency_detection + +#ifdef Auto_Main_frequency_detection + #define NUMBER_OF_SAMLPLES_FOR_MAIN_FREQUENCY_DETECTION 25 +#endif + +#define MAX_INPUT_FREQUENCY 80 // Hz +#define MIN_INPUT_FREQUENCY 30 // Hz + +//================================================== + /** * A dimmer channel. * @@ -65,7 +80,7 @@ class Dimmer { * * @see begin() */ - Dimmer(uint8_t pin, uint8_t mode = DIMMER_NORMAL, double rampTime = 1.5, uint8_t freq = 60); + Dimmer(uint8_t pin, uint8_t zc_dimmer_pin, uint8_t mode = DIMMER_NORMAL, double rampTime = 1.5, uint8_t freq = 60); /** * Initializes the module. @@ -135,11 +150,15 @@ class Dimmer { * @param value the ramp time. Maximum is 2^16 / (2 * AC frequency) */ void setRampTime(double rampTime); + + uint8_t getAcFrequency(); + private: static bool started; uint8_t dimmerIndex; uint8_t triacPin; + uint8_t zc_pin; uint8_t operatingMode; bool lampState; uint8_t lampValue; @@ -152,11 +171,14 @@ class Dimmer { uint8_t pulsesUsed; uint64_t pulsesHigh; uint64_t pulsesLow; + void zeroCross(); friend void callTriac(); friend void callZeroCross(); + friend void onTimerISR(); + }; #endif From 697cd8cbf99edd11248c8ae02d8973a31ed3a56b Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Sat, 21 Mar 2020 01:09:58 +0430 Subject: [PATCH 03/16] Update Dimmer.h --- src/Dimmer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Dimmer.h b/src/Dimmer.h index a8464f6..ffb1d1d 100644 --- a/src/Dimmer.h +++ b/src/Dimmer.h @@ -2,6 +2,7 @@ * This is a library to control the intensity of dimmable AC lamps or other AC loads using triacs. * * Copyright (c) 2015 Circuitar + * Updated by hamidsaffari@yahoo.com @ 2020 * This software is released under the MIT license. See the attached LICENSE file for details. */ From e8a83dbcd7e2de75d05d1836658b3f082ca790fc Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Sat, 21 Mar 2020 01:10:42 +0430 Subject: [PATCH 04/16] added some new functions and STM32F1 Supported --- src/Dimmer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Dimmer.cpp b/src/Dimmer.cpp index b7c55a9..8532c13 100644 --- a/src/Dimmer.cpp +++ b/src/Dimmer.cpp @@ -2,6 +2,7 @@ * This is a library to control the intensity of dimmable AC lamps or other AC loads using triacs. * * Copyright (c) 2015 Circuitar + * Updated by hamidsaffari@yahoo.com @ 2020 * This software is released under the MIT license. See the attached LICENSE file for details. */ From 9decfb55ea83bdb1221a9d1eba2c73151d66749b Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Sat, 21 Mar 2020 01:20:30 +0430 Subject: [PATCH 05/16] Update README.rst --- README.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 954065f..fcbcdfd 100644 --- a/README.rst +++ b/README.rst @@ -29,7 +29,11 @@ The following examples_ are provided: .. _WaveLamps: https://github.com/circuitar/Dimmer/blob/master/examples/WaveLamps/WaveLamps.ino .. _CountMode: https://github.com/circuitar/Dimmer/blob/master/examples/CountMode/CountMode.ino ----- +Updated by hamidsaffari@yahoo.com @ 2020: + +Supported Arduino_STM32 as well. https://github.com/rogerclarkmelbourne/Arduino_STM32 + +Added Auto_Main_frequency_detection option and getAcFrequency() to give you the AC main frequency. Copyright (c) 2015 Circuitar All rights reserved. From 7c63ef5ee333d6904cba0dc321caf38f3a10f5c7 Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Fri, 27 Mar 2020 06:20:09 +0430 Subject: [PATCH 06/16] Update Dimmer.cpp Added Arduino_Core_STM32 compatibility. --- src/Dimmer.cpp | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/Dimmer.cpp b/src/Dimmer.cpp index 8532c13..194adc1 100644 --- a/src/Dimmer.cpp +++ b/src/Dimmer.cpp @@ -2,7 +2,6 @@ * This is a library to control the intensity of dimmable AC lamps or other AC loads using triacs. * * Copyright (c) 2015 Circuitar - * Updated by hamidsaffari@yahoo.com @ 2020 * This software is released under the MIT license. See the attached LICENSE file for details. */ @@ -25,6 +24,8 @@ #define TIMER_COMPA_VECTOR(X) _TIMER_COMPA_VECTOR(X) #define _Timer(X) Timer ## X #define Timer(X) _Timer(X) +#define _TIM(X) TIM ## X +#define TIM(X) _TIM(X) #define _NVIC_TIMER(X) NVIC_TIMER ## X #define NVIC_TIMER(X) _NVIC_TIMER(X) @@ -71,11 +72,15 @@ static uint8_t dimmerCount = 0; // Number of registered dimmer ob #if defined(ARDUINO_ARCH_AVR) static volatile uint8_t* triacPinPorts[DIMMER_MAX_TRIAC]; // Triac ports for registered dimmers static uint8_t triacPinMasks[DIMMER_MAX_TRIAC]; // Triac pin mask for registered dimmers -#elif defined(ARDUINO_ARCH_STM32F1) +#elif defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32F4) || defined(ARDUINO_ARCH_STM32) static volatile uint32_t* triacPinPorts[DIMMER_MAX_TRIAC]; // Triac ports for registered dimmers static uint32_t triacPinMasks[DIMMER_MAX_TRIAC]; // Triac pin mask for registered dimmers #endif +#if defined(ARDUINO_ARCH_STM32) + HardwareTimer *MyTim; +#endif + static uint8_t triacTimes[DIMMER_MAX_TRIAC]; // Triac time for registered dimmers // Timer ticks since zero crossing @@ -122,10 +127,11 @@ void callZeroCross() { #if defined(ARDUINO_ARCH_AVR) TCNT(DIMMER_TIMER) = 0; //sei(); - #elif defined(ARDUINO_ARCH_STM32F1) + #elif defined(ARDUINO_ARCH__STM32F1) || defined(ARDUINO_ARCH__STM32F4) //Timer(DIMMER_TIMER).setCount(0); //The new count value to set. If this value exceeds the timer’s overflow value, it is truncated to the overflow value. Timer(DIMMER_TIMER).refresh(); //This will reset the counter to 0 in upcounting mode (the default). It will also update the timer’s prescaler and overflow, if you have set them up to be changed using HardwareTimer::setPrescaleFactor() or HardwareTimer::setOverflow(). - + #elif defined(ARDUINO_ARCH_STM32) + MyTim->setCount(0); #endif interrupts(); @@ -149,10 +155,15 @@ void callZeroCross() { } // Timer interrupt -#if defined(ARDUINO_ARCH_STM32F1) +#if defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32F4) void onTimerISR() + +#elif defined(ARDUINO_ARCH_STM32) + void onTimerISR(HardwareTimer*) + #elif defined(ARDUINO_ARCH_AVR) ISR(TIMER_COMPA_VECTOR(DIMMER_TIMER)) + #endif { // Increment ticks @@ -237,7 +248,7 @@ void Dimmer::begin(uint8_t value, bool on ) { // Setup timer to fire every 50us @ 60Hz - #if defined(ARDUINO_ARCH_STM32F1) + #if defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH__STM32F4) Timer(DIMMER_TIMER).setMode(TIMER_CH1, TIMER_OUTPUTCOMPARE); Timer(DIMMER_TIMER).setPeriod(50*(60.0/acFreq)); // in microseconds @@ -245,12 +256,22 @@ void Dimmer::begin(uint8_t value, bool on ) { Timer(DIMMER_TIMER).attachInterrupt(TIMER_CH1, onTimerISR); //nvic_irq_set_priority(NVIC_TIMER(DIMMER_TIMER), 15);// interrupt must not be preempted. highest interrupt priority is 0. All other interrupts have been initialized to priority level 16. See nvic_init(). + #elif defined(ARDUINO_ARCH_STM32) + + // Instantiate HardwareTimer object. Thanks to 'new' instanciation, HardwareTimer is not destructed when setup() function is finished. + HardwareTimer *MyTim = new HardwareTimer(TIM(DIMMER_TIMER)); + MyTim->setOverflow(50*(60.0/acFreq), MICROSEC_FORMAT); + MyTim->attachInterrupt(onTimerISR); + MyTim->resume(); + #elif defined(ARDUINO_ARCH_AVR) + TCNT(DIMMER_TIMER) = 0; // Clear timer TCCRxA(DIMMER_TIMER) = TCCRxA_VALUE; // Timer config byte A TCCRxB(DIMMER_TIMER) = TCCRxB_VALUE; // Timer config byte B TIMSKx(DIMMER_TIMER) = 0x02; // Timer Compare Match Interrupt Enable OCRxA(DIMMER_TIMER) = 100 * 60.0 / acFreq - 1; // Compare value (frequency adjusted) + #endif started = true; } From 7c789569aa5688bd6a8fbfbdc5372273470ddc25 Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Fri, 27 Mar 2020 06:21:49 +0430 Subject: [PATCH 07/16] Added Arduino_Core_STM32 compatibility --- src/Dimmer.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Dimmer.h b/src/Dimmer.h index ffb1d1d..2aed5cd 100644 --- a/src/Dimmer.h +++ b/src/Dimmer.h @@ -2,7 +2,6 @@ * This is a library to control the intensity of dimmable AC lamps or other AC loads using triacs. * * Copyright (c) 2015 Circuitar - * Updated by hamidsaffari@yahoo.com @ 2020 * This software is released under the MIT license. See the attached LICENSE file for details. */ @@ -21,7 +20,7 @@ #define DIMMER_TIMER 4 #elif defined(__AVR_ATmega32U4__) #define DIMMER_TIMER 3 -#elif defined(ARDUINO_ARCH_STM32F1) +#elif defined(ARDUINO_ARCH__STM32F1) || defined(ARDUINO_ARCH__STM32F4) || defined(ARDUINO_ARCH_STM32) #define DIMMER_TIMER 3 #else #define DIMMER_TIMER 2 From cd67bd97ee5c1a10ac963ae4fe6d0b130488f752 Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Fri, 27 Mar 2020 06:22:58 +0430 Subject: [PATCH 08/16] Update README.rst --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index fcbcdfd..29489e8 100644 --- a/README.rst +++ b/README.rst @@ -32,6 +32,7 @@ The following examples_ are provided: Updated by hamidsaffari@yahoo.com @ 2020: Supported Arduino_STM32 as well. https://github.com/rogerclarkmelbourne/Arduino_STM32 +Supported Arduino_Core_STM32 too. https://github.com/stm32duino/Arduino_Core_STM32 Added Auto_Main_frequency_detection option and getAcFrequency() to give you the AC main frequency. From 80d25cd00dca0c661e5c3a1229ea31f30accace6 Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Fri, 27 Mar 2020 06:23:40 +0430 Subject: [PATCH 09/16] Update README.rst --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 29489e8..2e9f138 100644 --- a/README.rst +++ b/README.rst @@ -32,6 +32,7 @@ The following examples_ are provided: Updated by hamidsaffari@yahoo.com @ 2020: Supported Arduino_STM32 as well. https://github.com/rogerclarkmelbourne/Arduino_STM32 + Supported Arduino_Core_STM32 too. https://github.com/stm32duino/Arduino_Core_STM32 Added Auto_Main_frequency_detection option and getAcFrequency() to give you the AC main frequency. From ab5981fe0d61d4b927dddeb3d54dba484ee4ee12 Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Thu, 9 Apr 2020 00:31:15 +0430 Subject: [PATCH 10/16] Update Dimmer.cpp --- src/Dimmer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Dimmer.cpp b/src/Dimmer.cpp index 194adc1..76ed3d6 100644 --- a/src/Dimmer.cpp +++ b/src/Dimmer.cpp @@ -6,7 +6,7 @@ */ #include "Arduino.h" -#include "Dimmer_2.h" +#include "Dimmer.h" ////#include // Timer configuration macros_TIMER(X) From 99e5fac2dfc5886cdae8cde8ac97619d0bc63c82 Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Thu, 9 Apr 2020 00:31:45 +0430 Subject: [PATCH 11/16] Update Dimmer.h --- src/Dimmer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Dimmer.h b/src/Dimmer.h index 2aed5cd..c6bcd3f 100644 --- a/src/Dimmer.h +++ b/src/Dimmer.h @@ -5,8 +5,8 @@ * This software is released under the MIT license. See the attached LICENSE file for details. */ -#ifndef DIMMER_2_H -#define DIMMER_2_H +#ifndef DIMMER_H +#define DIMMER_H /** * Maximum number of triacs that can be used. Can be decreased to save RAM. From ce840941ccca2ad5599e47a06dd1c3a8a1fe7839 Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Thu, 9 Apr 2020 21:12:16 +0430 Subject: [PATCH 12/16] Update Dimmer.cpp --- src/Dimmer.cpp | 82 ++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/src/Dimmer.cpp b/src/Dimmer.cpp index 76ed3d6..7867299 100644 --- a/src/Dimmer.cpp +++ b/src/Dimmer.cpp @@ -78,9 +78,10 @@ static uint8_t dimmerCount = 0; // Number of registered dimmer ob #endif #if defined(ARDUINO_ARCH_STM32) - HardwareTimer *MyTim; + HardwareTimer MyTim = HardwareTimer(TIM(DIMMER_TIMER)); + #endif - + static uint8_t triacTimes[DIMMER_MAX_TRIAC]; // Triac time for registered dimmers // Timer ticks since zero crossing @@ -90,36 +91,33 @@ static uint8_t tmrCount = 0; bool Dimmer::started = false; // At least one dimmer has started //================== added by Hamid ================== -#ifdef Auto_Main_frequency_detection - bool Main_frequency_detection_Mode=true; - volatile uint8_t sample_for_Main_frequency_detection; - unsigned long lastTime_for_Main_frequency_detection; - volatile unsigned long frequency_detection_timings_sum; +bool Auto_Main_frequency_detection=false; +volatile uint8_t sample_for_Main_frequency_detection; +unsigned long lastTime_for_Main_frequency_detection; +volatile unsigned long frequency_detection_timings_sum; -#endif //==================================================== // Zero cross interrupt void callZeroCross() { //================== added by Hamid =================== - #ifdef Auto_Main_frequency_detection - if(Main_frequency_detection_Mode){ - if(sample_for_Main_frequency_detection <= NUMBER_OF_SAMLPLES_FOR_MAIN_FREQUENCY_DETECTION){ - - const long time = micros(); - const unsigned long duration = time - lastTime_for_Main_frequency_detection; + if(Auto_Main_frequency_detection){ + + if(sample_for_Main_frequency_detection <= NUMBER_OF_SAMLPLES_FOR_MAIN_FREQUENCY_DETECTION){ - if (duration <= (1000.0/MIN_INPUT_FREQUENCY)*1000.0/2.0 && duration >= (1000.0/MAX_INPUT_FREQUENCY)*1000.0/2.0){ - if(sample_for_Main_frequency_detection!=0) frequency_detection_timings_sum += duration; // dump first one - sample_for_Main_frequency_detection++; - } - lastTime_for_Main_frequency_detection = time; + const long time = micros(); + const unsigned long duration = time - lastTime_for_Main_frequency_detection; + + if (duration <= (1000.0/MIN_INPUT_FREQUENCY)*1000.0/2.0 && duration >= (1000.0/MAX_INPUT_FREQUENCY)*1000.0/2.0){ + if(sample_for_Main_frequency_detection!=0) frequency_detection_timings_sum += duration; // dump first one + sample_for_Main_frequency_detection++; } - return; + lastTime_for_Main_frequency_detection = time; } - #endif + return; + } //==================================================== @@ -131,7 +129,7 @@ void callZeroCross() { //Timer(DIMMER_TIMER).setCount(0); //The new count value to set. If this value exceeds the timer’s overflow value, it is truncated to the overflow value. Timer(DIMMER_TIMER).refresh(); //This will reset the counter to 0 in upcounting mode (the default). It will also update the timer’s prescaler and overflow, if you have set them up to be changed using HardwareTimer::setPrescaleFactor() or HardwareTimer::setOverflow(). #elif defined(ARDUINO_ARCH_STM32) - MyTim->setCount(0); + MyTim.setCount(0); #endif interrupts(); @@ -193,7 +191,9 @@ Dimmer::Dimmer(uint8_t out_dimmer_pin, uint8_t zc_dimmer_pin, uint8_t mode, doub pulsesLow(0), pulseCount(0), pulsesUsed(0), - acFreq(freq) { + _rampTime(rampTime), + acFreq(freq) { + if (dimmerCount < DIMMER_MAX_TRIAC) { // Register dimmer object being created dimmerIndex = dimmerCount; @@ -202,7 +202,7 @@ Dimmer::Dimmer(uint8_t out_dimmer_pin, uint8_t zc_dimmer_pin, uint8_t mode, doub triacPinMasks[dimmerIndex] = digitalPinToBitMask(out_dimmer_pin); } - if (mode == DIMMER_RAMP) { + if (mode == DIMMER_RAMP && freq!=false) { setRampTime(rampTime); } } @@ -214,19 +214,22 @@ void Dimmer::begin(uint8_t value, bool on ) { // Initialize triac pin pinMode(triacPin, OUTPUT); digitalWrite(triacPin, LOW); - + if (!started) { + + if (acFreq == false) Auto_Main_frequency_detection = true; + // Start zero cross circuit if not started yet pinMode(zc_pin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(zc_pin), callZeroCross, RISING); //================== added by Hamid ================= - #ifdef Auto_Main_frequency_detection + if(Auto_Main_frequency_detection){ while(sample_for_Main_frequency_detection <= NUMBER_OF_SAMLPLES_FOR_MAIN_FREQUENCY_DETECTION){ // Zerocross-Interrupt doing his job } - + //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { //Creates a block of code that is guaranteed to be executed atomically. Upon entering the block the Global Interrupt Status flag in SREG is disabled, and re-enabled upon exiting the block from any exit path. noInterrupts(); // go atomic level - avoid interrupts to surely get the previously received data @@ -237,15 +240,17 @@ void Dimmer::begin(uint8_t value, bool on ) { float Main_frequency; Main_frequency = (1/((frequency_detection_timings_sum/NUMBER_OF_SAMLPLES_FOR_MAIN_FREQUENCY_DETECTION)/1000000.0))/2.0 ;// ( /2) because zerocross occur in half cycle acFreq = round(Main_frequency); - Main_frequency_detection_Mode= false;// must be after all to execute "return" in ISR + Auto_Main_frequency_detection= false;// must be after all to execute "return" in ISR + + if (operatingMode == DIMMER_RAMP ) { + setRampTime(_rampTime); + } - interrupts(); // let systick do its job - + interrupts(); // let interrupt do its job //} - - #endif - //================================================== - + } + + //====================================================== // Setup timer to fire every 50us @ 60Hz #if defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH__STM32F4) @@ -258,11 +263,10 @@ void Dimmer::begin(uint8_t value, bool on ) { #elif defined(ARDUINO_ARCH_STM32) - // Instantiate HardwareTimer object. Thanks to 'new' instanciation, HardwareTimer is not destructed when setup() function is finished. - HardwareTimer *MyTim = new HardwareTimer(TIM(DIMMER_TIMER)); - MyTim->setOverflow(50*(60.0/acFreq), MICROSEC_FORMAT); - MyTim->attachInterrupt(onTimerISR); - MyTim->resume(); + MyTim.setMode(2, TIMER_OUTPUT_COMPARE); + MyTim.setOverflow(50*(60.0/acFreq), MICROSEC_FORMAT); + MyTim.attachInterrupt(onTimerISR); + MyTim.resume(); #elif defined(ARDUINO_ARCH_AVR) From 79feb7ea81a169aa513cde1b4bde0a565dc3a33c Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Thu, 9 Apr 2020 21:12:52 +0430 Subject: [PATCH 13/16] Update Dimmer.h --- src/Dimmer.h | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/Dimmer.h b/src/Dimmer.h index c6bcd3f..5c6b450 100644 --- a/src/Dimmer.h +++ b/src/Dimmer.h @@ -44,18 +44,13 @@ #define DIMMER_RAMP 1 #define DIMMER_COUNT 2 -//================== added by Hamid ================ - -#define Auto_Main_frequency_detection - -#ifdef Auto_Main_frequency_detection - #define NUMBER_OF_SAMLPLES_FOR_MAIN_FREQUENCY_DETECTION 25 -#endif +//===== added by Hamid for Auto_Main_frequency_detection ================ +#define NUMBER_OF_SAMLPLES_FOR_MAIN_FREQUENCY_DETECTION 25 #define MAX_INPUT_FREQUENCY 80 // Hz #define MIN_INPUT_FREQUENCY 30 // Hz -//================================================== +//================================================================ /** * A dimmer channel. @@ -80,7 +75,7 @@ class Dimmer { * * @see begin() */ - Dimmer(uint8_t pin, uint8_t zc_dimmer_pin, uint8_t mode = DIMMER_NORMAL, double rampTime = 1.5, uint8_t freq = 60); + Dimmer(uint8_t pin, uint8_t zc_dimmer_pin, uint8_t mode = DIMMER_NORMAL, double rampTime = 1.5, uint8_t freq = 60); //if freq=false then Auto_Main_frequency_detection /** * Initializes the module. @@ -171,7 +166,7 @@ class Dimmer { uint8_t pulsesUsed; uint64_t pulsesHigh; uint64_t pulsesLow; - + double _rampTime; void zeroCross(); From 72ac85e62cc1816e5d9c78b3ed512b13e0e8e8dc Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Thu, 9 Apr 2020 21:14:42 +0430 Subject: [PATCH 14/16] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2e9f138..a11700f 100644 --- a/README.rst +++ b/README.rst @@ -39,5 +39,5 @@ Added Auto_Main_frequency_detection option and getAcFrequency() to give you the Copyright (c) 2015 Circuitar All rights reserved. - +Updated @ 2020 by HamidSaffari@yahoo.com This software is released under an MIT license. See the attached LICENSE file for details. From a252e825844de7818f0bf9c59bba30fcdf536c89 Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Thu, 9 Apr 2020 21:15:12 +0430 Subject: [PATCH 15/16] Update Dimmer.cpp --- src/Dimmer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Dimmer.cpp b/src/Dimmer.cpp index 7867299..dd48f44 100644 --- a/src/Dimmer.cpp +++ b/src/Dimmer.cpp @@ -2,6 +2,7 @@ * This is a library to control the intensity of dimmable AC lamps or other AC loads using triacs. * * Copyright (c) 2015 Circuitar + * Updated @ 2020 by HamidSaffari@yahoo.com * This software is released under the MIT license. See the attached LICENSE file for details. */ From 5de222469fe6ab58e733c68cdf7432d75d1499d2 Mon Sep 17 00:00:00 2001 From: Hamid Saffari <35362339+HamidSaffari@users.noreply.github.com> Date: Thu, 9 Apr 2020 21:15:35 +0430 Subject: [PATCH 16/16] Update Dimmer.h --- src/Dimmer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Dimmer.h b/src/Dimmer.h index 5c6b450..3867d40 100644 --- a/src/Dimmer.h +++ b/src/Dimmer.h @@ -2,6 +2,7 @@ * This is a library to control the intensity of dimmable AC lamps or other AC loads using triacs. * * Copyright (c) 2015 Circuitar + * Updated @ 2020 by HamidSaffari@yahoo.com * This software is released under the MIT license. See the attached LICENSE file for details. */