Skip to content
This repository was archived by the owner on Jan 29, 2023. It is now read-only.

Commit b7dcbd4

Browse files
authored
v1.2.0 to fix multiple-definitions linker error
### Releases v1.2.0 1. Fix `multiple-definitions` linker error. Drop `src_cpp` and `src_h` directories 2. Add example [multiFileProject](examples/multiFileProject) to demo for multiple-file project 3. Improve accuracy by using `double`, instead of `uint32_t` for `dutycycle`, `period` 4. Optimize library code by using `reference-passing` instead of `value-passing` 5. Update examples accordingly
1 parent ccb1ac7 commit b7dcbd4

20 files changed

+2147
-1927
lines changed

CONTRIBUTING.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ If you don't find anything, please [open a new issue](https://github.com/khoih-p
1414

1515
Please ensure to specify the following:
1616

17-
* Arduino IDE version (e.g. 1.8.16) or Platform.io version
17+
* Arduino IDE version (e.g. 1.8.19) or Platform.io version
1818
* Arduino / Adafruit / Sparkfun `AVR` Core Version (e.g. Arduino AVR core v1.8.3)
1919
* Contextual information (e.g. what you were trying to achieve)
2020
* Simplest possible steps to reproduce
@@ -26,10 +26,10 @@ Please ensure to specify the following:
2626
### Example
2727

2828
```
29-
Arduino IDE version: 1.8.16
29+
Arduino IDE version: 1.8.19
3030
Arduino AVR core v1.8.3
3131
OS: Ubuntu 20.04 LTS
32-
Linux xy-Inspiron-3593 5.4.0-90-generic #101-Ubuntu SMP Fri Oct 15 20:00:55 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
32+
Linux xy-Inspiron-3593 5.4.0-96-generic #109-Ubuntu SMP Wed Jan 12 16:49:16 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
3333
3434
Context:
3535
I encountered a crash while trying to use the Timer Interrupt.

README.md

+111-92
Large diffs are not rendered by default.

changelog.md

+9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
## Table of Contents
1313

1414
* [Changelog](#changelog)
15+
* [Releases v1.2.0](#releases-v120)
1516
* [Releases v1.1.0](#releases-v110)
1617
* [Initial Releases v1.0.0](#Initial-Releases-v100)
1718

@@ -20,6 +21,14 @@
2021

2122
## Changelog
2223

24+
### Releases v1.2.0
25+
26+
1. Fix `multiple-definitions` linker error. Drop `src_cpp` and `src_h` directories
27+
2. Add example [multiFileProject](examples/multiFileProject) to demo for multiple-file project
28+
3. Improve accuracy by using `double`, instead of `uint32_t` for `dutycycle`, `period`
29+
4. Optimize library code by using `reference-passing` instead of `value-passing`
30+
5. Update examples accordingly
31+
2332
### Releases v1.1.0
2433

2534
1. Add functions to modify PWM settings on-the-fly

examples/ISR_8_PWMs_Array/ISR_8_PWMs_Array.ino

+5-4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
#define USING_MICROS_RESOLUTION true //false
4141

42+
// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
4243
#include "AVR_Slow_PWM.h"
4344

4445
#include <SimpleTimer.h> // https://github.com/jfturcot/SimpleTimer
@@ -97,15 +98,15 @@ uint32_t PWM_Pin[] =
9798
#define NUMBER_ISR_PWMS ( sizeof(PWM_Pin) / sizeof(uint32_t) )
9899

99100
// You can assign any interval for any timer here, in Hz
100-
double PWM_Freq[NUMBER_ISR_PWMS] =
101+
double PWM_Freq[] =
101102
{
102103
1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
103104
};
104105

105106
// You can assign any interval for any timer here, in Microseconds
106-
uint32_t PWM_DutyCycle[NUMBER_ISR_PWMS] =
107+
double PWM_DutyCycle[] =
107108
{
108-
5, 10, 20, 25, 30, 35, 40, 45
109+
5.0, 10.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0
109110
};
110111

111112
typedef void (*irqCallback) ();
@@ -147,7 +148,7 @@ void doingSomething7()
147148
}
148149

149150

150-
irqCallback irqCallbackStartFunc[NUMBER_ISR_PWMS] =
151+
irqCallback irqCallbackStartFunc[] =
151152
{
152153
doingSomething0, doingSomething1, doingSomething2, doingSomething3,
153154
doingSomething4, doingSomething5, doingSomething6, doingSomething7

examples/ISR_8_PWMs_Array_Complex/ISR_8_PWMs_Array_Complex.ino

+26-25
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
#define USING_MICROS_RESOLUTION true //false
4141

42+
// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
4243
#include "AVR_Slow_PWM.h"
4344

4445
#include <SimpleTimer.h> // https://github.com/jfturcot/SimpleTimer
@@ -110,9 +111,9 @@ typedef struct
110111
irqCallback irqCallbackStartFunc;
111112
irqCallback irqCallbackStopFunc;
112113

113-
uint32_t PWM_Freq;
114+
double PWM_Freq;
114115

115-
uint32_t PWM_DutyCycle;
116+
double PWM_DutyCycle;
116117

117118
uint32_t deltaMicrosStart;
118119
uint32_t previousMicrosStart;
@@ -132,29 +133,29 @@ void doingSomethingStop(int index);
132133

133134
#else // #if USE_COMPLEX_STRUCT
134135

135-
volatile unsigned long deltaMicrosStart [NUMBER_ISR_PWMS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
136-
volatile unsigned long previousMicrosStart [NUMBER_ISR_PWMS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
136+
volatile unsigned long deltaMicrosStart [] = { 0, 0, 0, 0, 0, 0, 0, 0 };
137+
volatile unsigned long previousMicrosStart [] = { 0, 0, 0, 0, 0, 0, 0, 0 };
137138

138-
volatile unsigned long deltaMicrosStop [NUMBER_ISR_PWMS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
139-
volatile unsigned long previousMicrosStop [NUMBER_ISR_PWMS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
139+
volatile unsigned long deltaMicrosStop [] = { 0, 0, 0, 0, 0, 0, 0, 0 };
140+
volatile unsigned long previousMicrosStop [] = { 0, 0, 0, 0, 0, 0, 0, 0 };
140141

141142

142143
// You can assign any interval for any timer here, in Microseconds
143-
uint32_t PWM_Period[NUMBER_ISR_PWMS] =
144+
double PWM_Period[] =
144145
{
145-
1000L, 500L, 333L, 250L, 200L, 166L, 142L, 125L
146+
1000.0, 500.0, 333.333, 250.0, 200.0, 166.667, 142.857, 125.0
146147
};
147148

148149
// You can assign any interval for any timer here, in Hz
149-
double PWM_Freq[NUMBER_ISR_PWMS] =
150+
double PWM_Freq[] =
150151
{
151152
1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
152153
};
153154

154155
// You can assign any interval for any timer here, in Microseconds
155-
uint32_t PWM_DutyCycle[NUMBER_ISR_PWMS] =
156+
double PWM_DutyCycle[] =
156157
{
157-
5, 10, 20, 25, 30, 35, 40, 45
158+
5.0, 10.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0
158159
};
159160

160161
void doingSomethingStart(int index)
@@ -268,17 +269,17 @@ void doingSomethingStop7()
268269

269270
#if USE_COMPLEX_STRUCT
270271

271-
ISR_PWM_Data curISR_PWM_Data[NUMBER_ISR_PWMS] =
272+
ISR_PWM_Data curISR_PWM_Data[] =
272273
{
273274
// pin, irqCallbackStartFunc, irqCallbackStopFunc, PWM_Freq, PWM_DutyCycle, deltaMicrosStart, previousMicrosStart, deltaMicrosStop, previousMicrosStop
274-
{ LED_BUILTIN, doingSomethingStart0, doingSomethingStop0, 1, 5, 0, 0, 0, 0 },
275-
{ PIN_D0, doingSomethingStart1, doingSomethingStop1, 2, 10, 0, 0, 0, 0 },
276-
{ PIN_D1, doingSomethingStart2, doingSomethingStop2, 3, 20, 0, 0, 0, 0 },
277-
{ PIN_D2, doingSomethingStart3, doingSomethingStop3, 4, 25, 0, 0, 0, 0 },
278-
{ PIN_D3, doingSomethingStart4, doingSomethingStop4, 5, 30, 0, 0, 0, 0 },
279-
{ PIN_D4, doingSomethingStart5, doingSomethingStop5, 6, 35, 0, 0, 0, 0 },
280-
{ PIN_D5, doingSomethingStart6, doingSomethingStop6, 7, 40, 0, 0, 0, 0 },
281-
{ PIN_D6, doingSomethingStart7, doingSomethingStop7, 8, 45, 0, 0, 0, 0 },
275+
{ LED_BUILTIN, doingSomethingStart0, doingSomethingStop0, 1.0, 5.0, 0, 0, 0, 0 },
276+
{ PIN_D0, doingSomethingStart1, doingSomethingStop1, 2.0, 10.0, 0, 0, 0, 0 },
277+
{ PIN_D1, doingSomethingStart2, doingSomethingStop2, 3.0, 20.0, 0, 0, 0, 0 },
278+
{ PIN_D2, doingSomethingStart3, doingSomethingStop3, 4.0, 25.0, 0, 0, 0, 0 },
279+
{ PIN_D3, doingSomethingStart4, doingSomethingStop4, 5.0, 30.0, 0, 0, 0, 0 },
280+
{ PIN_D4, doingSomethingStart5, doingSomethingStop5, 6.0, 35.0, 0, 0, 0, 0 },
281+
{ PIN_D5, doingSomethingStart6, doingSomethingStop6, 7.0, 40.0, 0, 0, 0, 0 },
282+
{ PIN_D6, doingSomethingStart7, doingSomethingStop7, 8.0, 45.0, 0, 0, 0, 0 },
282283
};
283284

284285

@@ -302,13 +303,13 @@ void doingSomethingStop(int index)
302303

303304
#else // #if USE_COMPLEX_STRUCT
304305

305-
irqCallback irqCallbackStartFunc[NUMBER_ISR_PWMS] =
306+
irqCallback irqCallbackStartFunc[] =
306307
{
307308
doingSomethingStart0, doingSomethingStart1, doingSomethingStart2, doingSomethingStart3,
308309
doingSomethingStart4, doingSomethingStart5, doingSomethingStart6, doingSomethingStart7
309310
};
310311

311-
irqCallback irqCallbackStopFunc[NUMBER_ISR_PWMS] =
312+
irqCallback irqCallbackStopFunc[] =
312313
{
313314
doingSomethingStop0, doingSomethingStop1, doingSomethingStop2, doingSomethingStop3,
314315
doingSomethingStop4, doingSomethingStop5, doingSomethingStop6, doingSomethingStop7
@@ -343,9 +344,9 @@ void simpleTimerDoingSomething2s()
343344
Serial.print(F("PWM Channel : ")); Serial.print(i);
344345
Serial.print(F(", prog Period (ms): "));
345346

346-
Serial.print(1000.f / curISR_PWM_Data[i].PWM_Freq);
347+
Serial.print(1000.0f / curISR_PWM_Data[i].PWM_Freq);
347348

348-
Serial.print(F(", actual : ")); Serial.print((uint32_t) curISR_PWM_Data[i].deltaMicrosStart);
349+
Serial.print(F(", actual (uS) : ")); Serial.print(curISR_PWM_Data[i].deltaMicrosStart);
349350

350351
Serial.print(F(", prog DutyCycle : "));
351352

@@ -359,7 +360,7 @@ void simpleTimerDoingSomething2s()
359360

360361
Serial.print(F("PWM Channel : ")); Serial.print(i);
361362

362-
Serial.print(1000 / PWM_Freq[i]);
363+
Serial.print(1000.0f / PWM_Freq[i]);
363364

364365
Serial.print(F(", prog. Period (us): ")); Serial.print(PWM_Period[i]);
365366
Serial.print(F(", actual : ")); Serial.print(deltaMicrosStart[i]);

examples/ISR_8_PWMs_Array_Simple/ISR_8_PWMs_Array_Simple.ino

+4-3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
#define USING_MICROS_RESOLUTION true //false
4141

42+
// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
4243
#include "AVR_Slow_PWM.h"
4344

4445
#include <SimpleTimer.h> // https://github.com/jfturcot/SimpleTimer
@@ -97,15 +98,15 @@ uint32_t PWM_Pin[] =
9798
#define NUMBER_ISR_PWMS ( sizeof(PWM_Pin) / sizeof(uint32_t) )
9899

99100
// You can assign any interval for any timer here, in Hz
100-
double PWM_Freq[NUMBER_ISR_PWMS] =
101+
double PWM_Freq[] =
101102
{
102103
1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
103104
};
104105

105106
// You can assign any interval for any timer here, in Microseconds
106-
uint32_t PWM_DutyCycle[NUMBER_ISR_PWMS] =
107+
double PWM_DutyCycle[] =
107108
{
108-
5, 10, 20, 25, 30, 35, 40, 45
109+
5.0, 10.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0
109110
};
110111

111112
////////////////////////////////////////////////

examples/ISR_Changing_PWM/ISR_Changing_PWM.ino

+7-6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
#define USING_MICROS_RESOLUTION true //false
4141

42+
// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
4243
#include "AVR_Slow_PWM.h"
4344

4445
#define LED_OFF HIGH
@@ -87,14 +88,14 @@ double PWM_Freq1 = 1.0f;
8788
double PWM_Freq2 = 2.0f;
8889

8990
// You can assign any interval for any timer here, in microseconds
90-
uint32_t PWM_Period1 = 1000000 / PWM_Freq1;
91+
double PWM_Period1 = 1000000.0 / PWM_Freq1;
9192
// You can assign any interval for any timer here, in microseconds
92-
uint32_t PWM_Period2 = 1000000 / PWM_Freq2;
93+
double PWM_Period2 = 1000000.0 / PWM_Freq2;
9394

9495
// You can assign any duty_cycle for any PWM here, from 0-100
95-
uint32_t PWM_DutyCycle1 = 50;
96+
double PWM_DutyCycle1 = 50.0;
9697
// You can assign any duty_cycle for any PWM here, from 0-100
97-
uint32_t PWM_DutyCycle2 = 90;
98+
double PWM_DutyCycle2 = 90.0;
9899

99100
// Channel number used to identify associated channel
100101
int channelNum;
@@ -191,7 +192,7 @@ void loop()
191192
channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period1, PWM_DutyCycle1);
192193
#else
193194
// Or using period in millisecs resolution
194-
channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period1 / 1000, PWM_DutyCycle1);
195+
channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period1 / 1000.0, PWM_DutyCycle1);
195196
#endif
196197
#endif
197198

@@ -212,7 +213,7 @@ void loop()
212213
channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period2, PWM_DutyCycle2);
213214
#else
214215
// Or using period in millisecs resolution
215-
channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period2 / 1000, PWM_DutyCycle2);
216+
channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period2 / 1000.0, PWM_DutyCycle2);
216217
#endif
217218
#endif
218219

examples/ISR_Modify_PWM/ISR_Modify_PWM.ino

+6-5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
#define USING_MICROS_RESOLUTION true //false
4141

42+
// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
4243
#include "AVR_Slow_PWM.h"
4344

4445
#define LED_OFF HIGH
@@ -87,14 +88,14 @@ double PWM_Freq1 = 1.0f;
8788
double PWM_Freq2 = 2.0f;
8889

8990
// You can assign any interval for any timer here, in microseconds
90-
uint32_t PWM_Period1 = 1000000 / PWM_Freq1;
91+
double PWM_Period1 = 1000000.0 / PWM_Freq1;
9192
// You can assign any interval for any timer here, in microseconds
92-
uint32_t PWM_Period2 = 1000000 / PWM_Freq2;
93+
double PWM_Period2 = 1000000.0 / PWM_Freq2;
9394

9495
// You can assign any duty_cycle for any PWM here, from 0-100
95-
uint32_t PWM_DutyCycle1 = 10;
96+
double PWM_DutyCycle1 = 10.0;
9697
// You can assign any duty_cycle for any PWM here, from 0-100
97-
uint32_t PWM_DutyCycle2 = 90;
98+
double PWM_DutyCycle2 = 90.0;
9899

99100
// Channel number used to identify associated channel
100101
int channelNum;
@@ -192,7 +193,7 @@ void setup()
192193
channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period1, PWM_DutyCycle1);
193194
#else
194195
// Or using period in millisecs resolution
195-
channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period1 / 1000, PWM_DutyCycle1);
196+
channelNum = ISR_PWM.setPWM_Period(PWM_Pin, PWM_Period1 / 1000.0, PWM_DutyCycle1);
196197
#endif
197198
#endif
198199
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/****************************************************************************************************************************
2+
multiFileProject.cpp
3+
4+
For AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. )
5+
Written by Khoi Hoang
6+
7+
Built by Khoi Hoang https://github.com/khoih-prog/AVR_Slow_PWM
8+
Licensed under MIT license
9+
*****************************************************************************************************************************/
10+
11+
// To demo how to include files in multi-file Projects
12+
13+
#include "multiFileProject.h"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/****************************************************************************************************************************
2+
multiFileProject.h
3+
4+
For AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. )
5+
Written by Khoi Hoang
6+
7+
Built by Khoi Hoang https://github.com/khoih-prog/AVR_Slow_PWM
8+
Licensed under MIT license
9+
*****************************************************************************************************************************/
10+
11+
// To demo how to include files in multi-file Projects
12+
13+
#pragma once
14+
15+
#define USING_MICROS_RESOLUTION true //false
16+
17+
// Can be included as many times as necessary, without `Multiple Definitions` Linker Error
18+
#include "AVR_Slow_PWM.hpp"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/****************************************************************************************************************************
2+
multiFileProject.ino
3+
4+
For AVR-based boards (UNO, Nano, Mega, 32U4, 16U4, etc. )
5+
Written by Khoi Hoang
6+
7+
Built by Khoi Hoang https://github.com/khoih-prog/AVR_Slow_PWM
8+
Licensed under MIT license
9+
*****************************************************************************************************************************/
10+
11+
// To demo how to include files in multi-file Projects
12+
13+
#if ( defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || \
14+
defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_MINI) || defined(ARDUINO_AVR_ETHERNET) || \
15+
defined(ARDUINO_AVR_FIO) || defined(ARDUINO_AVR_BT) || defined(ARDUINO_AVR_LILYPAD) || defined(ARDUINO_AVR_PRO) || \
16+
defined(ARDUINO_AVR_NG) || defined(ARDUINO_AVR_UNO_WIFI_DEV_ED) || defined(ARDUINO_AVR_DUEMILANOVE) || defined(ARDUINO_AVR_FEATHER328P) || \
17+
defined(ARDUINO_AVR_METRO) || defined(ARDUINO_AVR_PROTRINKET5) || defined(ARDUINO_AVR_PROTRINKET3) || defined(ARDUINO_AVR_PROTRINKET5FTDI) || \
18+
defined(ARDUINO_AVR_PROTRINKET3FTDI) )
19+
#define USE_TIMER_1 true
20+
#warning Using Timer1
21+
#else
22+
#define USE_TIMER_3 true
23+
#warning Using Timer3
24+
#endif
25+
26+
#define AVR_SLOW_PWM_VERSION_MIN_TARGET F("AVR_Slow_PWM v1.2.0")
27+
#define AVR_SLOW_PWM_VERSION_MIN 1002000
28+
29+
#include "multiFileProject.h"
30+
31+
// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
32+
#include "AVR_Slow_PWM.h"
33+
34+
void setup()
35+
{
36+
Serial.begin(115200);
37+
while (!Serial);
38+
39+
Serial.println("\nStart multiFileProject");
40+
Serial.println(AVR_SLOW_PWM_VERSION);
41+
42+
#if defined(AVR_SLOW_PWM_VERSION_MIN)
43+
if (AVR_SLOW_PWM_VERSION_INT < AVR_SLOW_PWM_VERSION_MIN)
44+
{
45+
Serial.print("Warning. Must use this example on Version equal or later than : ");
46+
Serial.println(AVR_SLOW_PWM_VERSION_MIN_TARGET);
47+
}
48+
#endif
49+
}
50+
51+
void loop()
52+
{
53+
// put your main code here, to run repeatedly:
54+
}

0 commit comments

Comments
 (0)