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

Commit

Permalink
v1.0.0 for ATmega using MightyCore
Browse files Browse the repository at this point in the history
### 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.
  • Loading branch information
khoih-prog committed Aug 23, 2022
1 parent 841ba40 commit 4a5264e
Show file tree
Hide file tree
Showing 22 changed files with 4,069 additions and 0 deletions.
60 changes: 60 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
## Contributing to ATmega_Slow_PWM

### Reporting Bugs

Please report bugs in ATmega_Slow_PWM if you find them.

However, before reporting a bug please check through the following:

* [Existing Open Issues](https://github.com/khoih-prog/ATmega_Slow_PWM/issues) - someone might have already encountered this.

If you don't find anything, please [open a new issue](https://github.com/khoih-prog/ATmega_Slow_PWM/issues/new).

---

### How to submit a bug report

Please ensure to specify the following:

* Arduino IDE version (e.g. 1.8.19) or Platform.io version
* `Arduino MightyCore` Core Version (e.g. Arduino MightyCore Core v2.1.3)
* Board type (e.g. ATmega164, ATmega324, ATmega644, ATmega1284, etc.)
* Contextual information (e.g. what you were trying to achieve)
* Simplest possible steps to reproduce
* Anything that might be relevant in your opinion, such as:
* Operating system (Windows, Ubuntu, etc.) and the output of `uname -a`
* Network configuration

---

### Example

```
Arduino IDE version: 1.8.19
Arduino MightyCore Core v2.1.3
ATmega1284 with Optiboot
OS: Ubuntu 20.04 LTS
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
Context:
I encountered a crash while trying to use the Timer Interrupt.
Steps to reproduce:
1. ...
2. ...
3. ...
4. ...
```

---

### Sending Feature Requests

Feel free to post feature requests. It's helpful if you can explain exactly why the feature would be useful.

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.

### Sending Pull Requests

Pull Requests with changes and fixes are also welcome!

21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022 Khoi Hoang

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
28 changes: 28 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# AVR_Slow_PWM Library

[![arduino-library-badge](https://www.ardu-badge.com/badge/AVR_Slow_PWM.svg?)](https://www.ardu-badge.com/AVR_Slow_PWM)
[![GitHub release](https://img.shields.io/github/release/khoih-prog/AVR_Slow_PWM.svg)](https://github.com/khoih-prog/AVR_Slow_PWM/releases)
[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/khoih-prog/AVR_Slow_PWM/blob/master/LICENSE)
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#Contributing)
[![GitHub issues](https://img.shields.io/github/issues/khoih-prog/AVR_Slow_PWM.svg)](http://github.com/khoih-prog/AVR_Slow_PWM/issues)

---
---

## Table of Contents

* [Changelog](#changelog)
* [Initial Releases v1.0.0](#Initial-Releases-v100)

---
---

## Changelog


### 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.


280 changes: 280 additions & 0 deletions examples/ISR_8_PWMs_Array/ISR_8_PWMs_Array.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
/****************************************************************************************************************************
ISR_8_PWMs_Array.ino
For AVR ATmega164, ATmega324, ATmega644, ATmega1284 with MightyCore
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/ATmega_Slow_PWM
Licensed under MIT license
Now with we can use these new 16 ISR-based PWM channels, while consuming only 1 hwarware Timer.
Their independently-selected, maximum interval is practically unlimited (limited only by unsigned long miliseconds)
The accuracy is nearly perfect compared to software timers. The most important feature is they're ISR-based timers
Therefore, their executions are not blocked by bad-behaving functions / tasks.
This important feature is absolutely necessary for mission-critical tasks.
*****************************************************************************************************************************/

// Select just 1 TIMER to be true
#define USE_TIMER_1 true
#define USE_TIMER_2 false
// TIMER_3 Only valid for ATmega1284 and ATmega324PB (not ready in core yet)
#define USE_TIMER_3 false
// TIMER_4 Only valid for ATmega324PB, not ready in core yet
#define USE_TIMER_4 false

// These define's must be placed at the beginning before #include "ATmega_Slow_PWM.h"
// _PWM_LOGLEVEL_ from 0 to 4
// Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
#define _PWM_LOGLEVEL_ 3

#if (_PWM_LOGLEVEL_ > 3)
#if USE_TIMER_1
#warning Using Timer1
#elif USE_TIMER_3
#warning Using Timer3
#endif
#endif

#define USING_MICROS_RESOLUTION true //false

// Default is true, uncomment to false
//#define CHANGING_PWM_END_OF_CYCLE false

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

#include <SimpleTimer.h> // https://github.com/jfturcot/SimpleTimer

#define LED_OFF HIGH
#define LED_ON LOW

#ifndef LED_BUILTIN
#define LED_BUILTIN 13
#endif

#ifndef LED_BLUE
#define LED_BLUE 10
#endif

#ifndef LED_RED
#define LED_RED 11
#endif

#define USING_HW_TIMER_INTERVAL_MS true

// Don't change these numbers to make higher Timer freq. System can hang
#define HW_TIMER_INTERVAL_MS 0.1f
#define HW_TIMER_INTERVAL_FREQ 10000L

volatile uint32_t startMicros = 0;

// Init ATmega_Slow_PWM, each can service 16 different ISR-based PWM channels
ATmega_Slow_PWM ISR_PWM;

//////////////////////////////////////////////////////

void TimerHandler()
{
ISR_PWM.run();
}

//////////////////////////////////////////////////////

#define PIN_D0 0
#define PIN_D1 1
#define PIN_D2 2
#define PIN_D3 3
#define PIN_D4 4
#define PIN_D5 5
#define PIN_D6 6

//////////////////////////////////////////////////////

// You can assign pins here. Be careful to select good pin to use or crash, e.g pin 6-11
uint32_t PWM_Pin[] =
{
LED_BUILTIN, PIN_D0, PIN_D1, PIN_D2, PIN_D3, PIN_D4, PIN_D5, PIN_D6
};

#define NUMBER_ISR_PWMS ( sizeof(PWM_Pin) / sizeof(uint32_t) )

// You can assign any interval for any timer here, in Hz
float PWM_Freq[] =
{
1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f,
};

// You can assign any interval for any timer here, in Microseconds
float PWM_DutyCycle[] =
{
5.0, 10.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0
};

typedef void (*irqCallback) ();


// In Portenta_H7, avoid doing something fancy in ISR, for example complex Serial.print with String() argument
// The pure simple Serial.prints here are just for demonstration and testing. Must be eliminate in working environment
// Or you can get this run-time error / crash
void doingSomething0()
{
}

void doingSomething1()
{
}

void doingSomething2()
{
}

void doingSomething3()
{
}

void doingSomething4()
{
}

void doingSomething5()
{
}

void doingSomething6()
{
}

void doingSomething7()
{
}


irqCallback irqCallbackStartFunc[] =
{
doingSomething0, doingSomething1, doingSomething2, doingSomething3,
doingSomething4, doingSomething5, doingSomething6, doingSomething7
};

////////////////////////////////////////////////

void setup()
{
Serial.begin(115200);
while (!Serial && millis() < 5000);

delay(2000);

Serial.print(F("\nStarting ISR_8_PWMs_Array on ")); Serial.println(BOARD_NAME);
Serial.println(ATMEGA_SLOW_PWM_VERSION);
Serial.print(F("CPU Frequency = ")); Serial.print(F_CPU / 1000000); Serial.println(F(" MHz"));

// Timer0 is used for micros(), millis(), delay(), etc and can't be used
// Select Timer 1-2 for UNO, 1-5 for MEGA, 1,3,4 for 16u4/32u4
// Timer 2 is 8-bit timer, only for higher frequency
// Timer 4 of 16u4 and 32u4 is 8/10-bit timer, only for higher frequency

#if USING_HW_TIMER_INTERVAL_MS

/////////////////////////////////////////

#if USE_TIMER_1

ITimer1.init();

// Using ATmega324 with 16MHz CPU clock ,
// For 16-bit timer 1, set frequency from 0.2385 to some KHz
// For 8-bit timer 2 (prescaler up to 1024, set frequency from 61.5Hz to some KHz

if (ITimer1.attachInterruptInterval(HW_TIMER_INTERVAL_MS, TimerHandler))
{
Serial.print(F("Starting ITimer1 OK, micros() = ")); Serial.println(micros());
}
else
Serial.println(F("Can't set ITimer1. Select another freq. or timer"));

#elif USE_TIMER_2

ITimer2.init();

if (ITimer2.attachInterruptInterval(HW_TIMER_INTERVAL_MS, TimerHandler))
{
Serial.print(F("Starting ITimer2 OK, micros() = ")); Serial.println(micros());
}
else
Serial.println(F("Can't set ITimer2. Select another freq. or timer"));

#elif USE_TIMER_3

ITimer3.init();

if (ITimer3.attachInterruptInterval(HW_TIMER_INTERVAL_MS, TimerHandler))
{
Serial.print(F("Starting ITimer3 OK, micros() = ")); Serial.println(micros());
}
else
Serial.println(F("Can't set ITimer3. Select another freq. or timer"));

#endif

/////////////////////////////////////////

#else

/////////////////////////////////////////

#if USE_TIMER_1

ITimer1.init();

// Using ATmega324 with 16MHz CPU clock ,
// For 16-bit timer 1, set frequency from 0.2385 to some KHz
// For 8-bit timer 2 (prescaler up to 1024, set frequency from 61.5Hz to some KHz

if (ITimer1.attachInterrupt(HW_TIMER_INTERVAL_FREQ, TimerHandler))
{
Serial.print(F("Starting ITimer1 OK, micros() = ")); Serial.println(micros());
}
else
Serial.println(F("Can't set ITimer1. Select another freq. or timer"));

#elif USE_TIMER_2

ITimer2.init();

if (ITimer2.attachInterrupt(HW_TIMER_INTERVAL_FREQ, TimerHandler))
{
Serial.print(F("Starting ITimer2 OK, micros() = ")); Serial.println(micros());
}
else
Serial.println(F("Can't set ITimer2. Select another freq. or timer"));

#elif USE_TIMER_3

ITimer3.init();

if (ITimer3.attachInterrupt(HW_TIMER_INTERVAL_FREQ, TimerHandler))
{
Serial.print(F("Starting ITimer3 OK, micros() = ")); Serial.println(micros());
}
else
Serial.println(F("Can't set ITimer3. Select another freq. or timer"));

#endif

#endif


// Just to demonstrate, don't use too many ISR Timers if not absolutely necessary
// You can use up to 16 timer for each ISR_PWM
for (uint16_t i = 0; i < NUMBER_ISR_PWMS; i++)
{
//void setPWM(uint32_t pin, float frequency, float dutycycle
// , timer_callback_p StartCallback = nullptr, timer_callback_p StopCallback = nullptr)

// You can use this with PWM_Freq in Hz
ISR_PWM.setPWM(PWM_Pin[i], PWM_Freq[i], PWM_DutyCycle[i], irqCallbackStartFunc[i]);
}
}

void loop()
{
}

0 comments on commit 4a5264e

Please sign in to comment.