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

Commit 4a5264e

Browse files
authored
v1.0.0 for ATmega using MightyCore
### Initial Releases v1.0.0 1. Initial coding for AVR **ATmega164(A/P), ATmega324(A/P/PA/PB), ATmega644(A/P), ATmega1284(P)** using [MightyCore](https://github.com/MCUdude/MightyCore) 2. The hybrid ISR-based PWM channels can generate from very low (much less than 1Hz) to highest PWM frequencies up to 500Hz with acceptable accuracy.
1 parent 841ba40 commit 4a5264e

22 files changed

+4069
-0
lines changed

CONTRIBUTING.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
## Contributing to ATmega_Slow_PWM
2+
3+
### Reporting Bugs
4+
5+
Please report bugs in ATmega_Slow_PWM if you find them.
6+
7+
However, before reporting a bug please check through the following:
8+
9+
* [Existing Open Issues](https://github.com/khoih-prog/ATmega_Slow_PWM/issues) - someone might have already encountered this.
10+
11+
If you don't find anything, please [open a new issue](https://github.com/khoih-prog/ATmega_Slow_PWM/issues/new).
12+
13+
---
14+
15+
### How to submit a bug report
16+
17+
Please ensure to specify the following:
18+
19+
* Arduino IDE version (e.g. 1.8.19) or Platform.io version
20+
* `Arduino MightyCore` Core Version (e.g. Arduino MightyCore Core v2.1.3)
21+
* Board type (e.g. ATmega164, ATmega324, ATmega644, ATmega1284, etc.)
22+
* Contextual information (e.g. what you were trying to achieve)
23+
* Simplest possible steps to reproduce
24+
* Anything that might be relevant in your opinion, such as:
25+
* Operating system (Windows, Ubuntu, etc.) and the output of `uname -a`
26+
* Network configuration
27+
28+
---
29+
30+
### Example
31+
32+
```
33+
Arduino IDE version: 1.8.19
34+
Arduino MightyCore Core v2.1.3
35+
ATmega1284 with Optiboot
36+
OS: Ubuntu 20.04 LTS
37+
Linux xy-Inspiron-3593 5.15.0-46-generic #49~20.04.1-Ubuntu SMP Thu Aug 4 19:15:44 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
38+
39+
Context:
40+
I encountered a crash while trying to use the Timer Interrupt.
41+
42+
Steps to reproduce:
43+
1. ...
44+
2. ...
45+
3. ...
46+
4. ...
47+
```
48+
49+
---
50+
51+
### Sending Feature Requests
52+
53+
Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful.
54+
55+
There are usually some outstanding feature requests in the [existing issues list](https://github.com/khoih-prog/ATmega_Slow_PWM/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement), feel free to add comments to them.
56+
57+
### Sending Pull Requests
58+
59+
Pull Requests with changes and fixes are also welcome!
60+

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Khoi Hoang
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

changelog.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# AVR_Slow_PWM Library
2+
3+
[![arduino-library-badge](https://www.ardu-badge.com/badge/AVR_Slow_PWM.svg?)](https://www.ardu-badge.com/AVR_Slow_PWM)
4+
[![GitHub release](https://img.shields.io/github/release/khoih-prog/AVR_Slow_PWM.svg)](https://github.com/khoih-prog/AVR_Slow_PWM/releases)
5+
[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/AVR_Slow_PWM/blob/master/LICENSE)
6+
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing)
7+
[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/AVR_Slow_PWM.svg)](http://github.com/khoih-prog/AVR_Slow_PWM/issues)
8+
9+
---
10+
---
11+
12+
## Table of Contents
13+
14+
* [Changelog](#changelog)
15+
* [Initial Releases v1.0.0](#Initial-Releases-v100)
16+
17+
---
18+
---
19+
20+
## Changelog
21+
22+
23+
### Initial Releases v1.0.0
24+
25+
1. Initial coding for AVR **ATmega164(A/P), ATmega324(A/P/PA/PB), ATmega644(A/P), ATmega1284(P)** using [MightyCore](https://github.com/MCUdude/MightyCore)
26+
2. The hybrid ISR-based PWM channels can generate from very low (much less than 1Hz) to highest PWM frequencies up to 500Hz with acceptable accuracy.
27+
28+
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
/****************************************************************************************************************************
2+
ISR_8_PWMs_Array.ino
3+
For AVR ATmega164, ATmega324, ATmega644, ATmega1284 with MightyCore
4+
Written by Khoi Hoang
5+
6+
Built by Khoi Hoang https://github.com/khoih-prog/ATmega_Slow_PWM
7+
Licensed under MIT license
8+
9+
Now with we can use these new 16 ISR-based PWM channels, while consuming only 1 hwarware Timer.
10+
Their independently-selected, maximum interval is practically unlimited (limited only by unsigned long miliseconds)
11+
The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
12+
Therefore, their executions are not blocked by bad-behaving functions / tasks.
13+
This important feature is absolutely necessary for mission-critical tasks.
14+
*****************************************************************************************************************************/
15+
16+
// Select just 1 TIMER to be true
17+
#define USE_TIMER_1 true
18+
#define USE_TIMER_2 false
19+
// TIMER_3 Only valid for ATmega1284 and ATmega324PB (not ready in core yet)
20+
#define USE_TIMER_3 false
21+
// TIMER_4 Only valid for ATmega324PB, not ready in core yet
22+
#define USE_TIMER_4 false
23+
24+
// These define's must be placed at the beginning before #include "ATmega_Slow_PWM.h"
25+
// _PWM_LOGLEVEL_ from 0 to 4
26+
// Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
27+
#define _PWM_LOGLEVEL_ 3
28+
29+
#if (_PWM_LOGLEVEL_ > 3)
30+
#if USE_TIMER_1
31+
#warning Using Timer1
32+
#elif USE_TIMER_3
33+
#warning Using Timer3
34+
#endif
35+
#endif
36+
37+
#define USING_MICROS_RESOLUTION true //false
38+
39+
// Default is true, uncomment to false
40+
//#define CHANGING_PWM_END_OF_CYCLE false
41+
42+
// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
43+
#include "ATmega_Slow_PWM.h"
44+
45+
#include <SimpleTimer.h> // https://github.com/jfturcot/SimpleTimer
46+
47+
#define LED_OFF HIGH
48+
#define LED_ON LOW
49+
50+
#ifndef LED_BUILTIN
51+
#define LED_BUILTIN 13
52+
#endif
53+
54+
#ifndef LED_BLUE
55+
#define LED_BLUE 10
56+
#endif
57+
58+
#ifndef LED_RED
59+
#define LED_RED 11
60+
#endif
61+
62+
#define USING_HW_TIMER_INTERVAL_MS true
63+
64+
// Don't change these numbers to make higher Timer freq. System can hang
65+
#define HW_TIMER_INTERVAL_MS 0.1f
66+
#define HW_TIMER_INTERVAL_FREQ 10000L
67+
68+
volatile uint32_t startMicros = 0;
69+
70+
// Init ATmega_Slow_PWM, each can service 16 different ISR-based PWM channels
71+
ATmega_Slow_PWM ISR_PWM;
72+
73+
//////////////////////////////////////////////////////
74+
75+
void TimerHandler()
76+
{
77+
ISR_PWM.run();
78+
}
79+
80+
//////////////////////////////////////////////////////
81+
82+
#define PIN_D0 0
83+
#define PIN_D1 1
84+
#define PIN_D2 2
85+
#define PIN_D3 3
86+
#define PIN_D4 4
87+
#define PIN_D5 5
88+
#define PIN_D6 6
89+
90+
//////////////////////////////////////////////////////
91+
92+
// You can assign pins here. Be careful to select good pin to use or crash, e.g pin 6-11
93+
uint32_t PWM_Pin[] =
94+
{
95+
LED_BUILTIN, PIN_D0, PIN_D1, PIN_D2, PIN_D3, PIN_D4, PIN_D5, PIN_D6
96+
};
97+
98+
#define NUMBER_ISR_PWMS ( sizeof(PWM_Pin) / sizeof(uint32_t) )
99+
100+
// You can assign any interval for any timer here, in Hz
101+
float PWM_Freq[] =
102+
{
103+
1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
104+
};
105+
106+
// You can assign any interval for any timer here, in Microseconds
107+
float PWM_DutyCycle[] =
108+
{
109+
5.0, 10.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0
110+
};
111+
112+
typedef void (*irqCallback) ();
113+
114+
115+
// In Portenta_H7, avoid doing something fancy in ISR, for example complex Serial.print with String() argument
116+
// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment
117+
// Or you can get this run-time error / crash
118+
void doingSomething0()
119+
{
120+
}
121+
122+
void doingSomething1()
123+
{
124+
}
125+
126+
void doingSomething2()
127+
{
128+
}
129+
130+
void doingSomething3()
131+
{
132+
}
133+
134+
void doingSomething4()
135+
{
136+
}
137+
138+
void doingSomething5()
139+
{
140+
}
141+
142+
void doingSomething6()
143+
{
144+
}
145+
146+
void doingSomething7()
147+
{
148+
}
149+
150+
151+
irqCallback irqCallbackStartFunc[] =
152+
{
153+
doingSomething0, doingSomething1, doingSomething2, doingSomething3,
154+
doingSomething4, doingSomething5, doingSomething6, doingSomething7
155+
};
156+
157+
////////////////////////////////////////////////
158+
159+
void setup()
160+
{
161+
Serial.begin(115200);
162+
while (!Serial && millis() < 5000);
163+
164+
delay(2000);
165+
166+
Serial.print(F("\nStarting ISR_8_PWMs_Array on ")); Serial.println(BOARD_NAME);
167+
Serial.println(ATMEGA_SLOW_PWM_VERSION);
168+
Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));
169+
170+
// Timer0 is used for micros(), millis(), delay(), etc and can't be used
171+
// Select Timer 1-2 for UNO, 1-5 for MEGA, 1,3,4 for 16u4/32u4
172+
// Timer 2 is 8-bit timer, only for higher frequency
173+
// Timer 4 of 16u4 and 32u4 is 8/10-bit timer, only for higher frequency
174+
175+
#if USING_HW_TIMER_INTERVAL_MS
176+
177+
/////////////////////////////////////////
178+
179+
#if USE_TIMER_1
180+
181+
ITimer1.init();
182+
183+
// Using ATmega324 with 16MHz CPU clock ,
184+
// For 16-bit timer 1, set frequency from 0.2385 to some KHz
185+
// For 8-bit timer 2 (prescaler up to 1024, set frequency from 61.5Hz to some KHz
186+
187+
if (ITimer1.attachInterruptInterval(HW_TIMER_INTERVAL_MS, TimerHandler))
188+
{
189+
Serial.print(F("Starting ITimer1 OK, micros() = ")); Serial.println(micros());
190+
}
191+
else
192+
Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
193+
194+
#elif USE_TIMER_2
195+
196+
ITimer2.init();
197+
198+
if (ITimer2.attachInterruptInterval(HW_TIMER_INTERVAL_MS, TimerHandler))
199+
{
200+
Serial.print(F("Starting ITimer2 OK, micros() = ")); Serial.println(micros());
201+
}
202+
else
203+
Serial.println(F("Can't set ITimer2. Select another freq. or timer"));
204+
205+
#elif USE_TIMER_3
206+
207+
ITimer3.init();
208+
209+
if (ITimer3.attachInterruptInterval(HW_TIMER_INTERVAL_MS, TimerHandler))
210+
{
211+
Serial.print(F("Starting ITimer3 OK, micros() = ")); Serial.println(micros());
212+
}
213+
else
214+
Serial.println(F("Can't set ITimer3. Select another freq. or timer"));
215+
216+
#endif
217+
218+
/////////////////////////////////////////
219+
220+
#else
221+
222+
/////////////////////////////////////////
223+
224+
#if USE_TIMER_1
225+
226+
ITimer1.init();
227+
228+
// Using ATmega324 with 16MHz CPU clock ,
229+
// For 16-bit timer 1, set frequency from 0.2385 to some KHz
230+
// For 8-bit timer 2 (prescaler up to 1024, set frequency from 61.5Hz to some KHz
231+
232+
if (ITimer1.attachInterrupt(HW_TIMER_INTERVAL_FREQ, TimerHandler))
233+
{
234+
Serial.print(F("Starting ITimer1 OK, micros() = ")); Serial.println(micros());
235+
}
236+
else
237+
Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
238+
239+
#elif USE_TIMER_2
240+
241+
ITimer2.init();
242+
243+
if (ITimer2.attachInterrupt(HW_TIMER_INTERVAL_FREQ, TimerHandler))
244+
{
245+
Serial.print(F("Starting ITimer2 OK, micros() = ")); Serial.println(micros());
246+
}
247+
else
248+
Serial.println(F("Can't set ITimer2. Select another freq. or timer"));
249+
250+
#elif USE_TIMER_3
251+
252+
ITimer3.init();
253+
254+
if (ITimer3.attachInterrupt(HW_TIMER_INTERVAL_FREQ, TimerHandler))
255+
{
256+
Serial.print(F("Starting ITimer3 OK, micros() = ")); Serial.println(micros());
257+
}
258+
else
259+
Serial.println(F("Can't set ITimer3. Select another freq. or timer"));
260+
261+
#endif
262+
263+
#endif
264+
265+
266+
// Just to demonstrate, don't use too many ISR Timers if not absolutely necessary
267+
// You can use up to 16 timer for each ISR_PWM
268+
for (uint16_t i = 0; i < NUMBER_ISR_PWMS; i++)
269+
{
270+
//void setPWM(uint32_t pin, float frequency, float dutycycle
271+
// , timer_callback_p StartCallback = nullptr, timer_callback_p StopCallback = nullptr)
272+
273+
// You can use this with PWM_Freq in Hz
274+
ISR_PWM.setPWM(PWM_Pin[i], PWM_Freq[i], PWM_DutyCycle[i], irqCallbackStartFunc[i]);
275+
}
276+
}
277+
278+
void loop()
279+
{
280+
}

0 commit comments

Comments
 (0)