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

Commit

Permalink
v1.1.0 for new PWM_manual example, etc.
Browse files Browse the repository at this point in the history
1. Add example [PWM_manual](https://github.com/khoih-prog/ATtiny_PWM/tree/main/examples/PWM_manual) to demo how to correctly use PWM to generate waveform. Check [About DCValue in setPWM_manual #2](khoih-prog/AVR_PWM#2)
2. Add function `setPWM_DCPercentage_manual()` to facilitate the setting PWM DC manually by using `DCPercentage`, instead of `absolute DCValue` depending on varying PWMPeriod
3. Catch low frequency error and use lowest permissible frequency
  • Loading branch information
khoih-prog authored Jan 25, 2023
1 parent b9629d5 commit 4b7546d
Show file tree
Hide file tree
Showing 8 changed files with 410 additions and 15 deletions.
216 changes: 210 additions & 6 deletions README.md

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
## Table of Contents

* [Changelog](#changelog)
* [Releases v1.1.0](#Releases-v110)
* [Releases v1.0.1](#Releases-v101)
* [Initial Releases v1.0.0](#Initial-Releases-v100)

Expand All @@ -25,6 +26,12 @@

## Changelog

### Releases v1.1.0

1. Add example [PWM_manual](https://github.com/khoih-prog/ATtiny_PWM/tree/main/examples/PWM_manual) to demo how to correctly use PWM to generate waveform. Check [About DCValue in setPWM_manual #2](https://github.com/khoih-prog/AVR_PWM/discussions/2)
2. Add function `setPWM_DCPercentage_manual()` to facilitate the setting PWM DC manually by using `DCPercentage`, instead of `absolute DCValue` depending on varying PWMPeriod
3. Catch low frequency error and use lowest permissible frequency

### Releases v1.0.1

1. Add example [PWM_StepperControl](https://github.com/khoih-prog/ATtiny_PWM/tree/main/examples/PWM_StepperControl) to demo how to control Stepper Motor using PWM. Check [Using PWM to step a stepper driver #16](https://github.com/khoih-prog/RP2040_PWM/issues/16)
Expand Down
164 changes: 164 additions & 0 deletions examples/PWM_manual/PWM_manual.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/****************************************************************************************************************************
PWM_manual.ino
For Arduino AVR ATtiny-based boards (ATtiny3217, etc.) using megaTinyCore
Written by Khoi Hoang
Built by Khoi Hoang https://github.com/khoih-prog/ATtiny_PWM
Licensed under MIT license
*****************************************************************************************************************************/

#define _PWM_LOGLEVEL_ 1

// Select false to use PWM
#define USING_TIMER false //true

#include "ATtiny_PWM.h"

#define UPDATE_INTERVAL 1000L

// Using setPWM_DCPercentage_manual if true
#define USING_DC_PERCENT true

/*
const uint8_t digital_pin_to_timer[] = {
// Left side, top to bottom
TIMERA0, // 0 PA4 WO4 WOA
TIMERA0, // 1 PA5 WO5 WOB
#if defined(DAC0)
DACOUT, // 2 PA6
#else
NOT_ON_TIMER, // 2 PA6
#endif
NOT_ON_TIMER, // 3 PA7
NOT_ON_TIMER, // 4 PB7
NOT_ON_TIMER, // 5 PB6
NOT_ON_TIMER, // 6 PB5 WO2 Alt
NOT_ON_TIMER, // 7 PB4 WO1 Alt
NOT_ON_TIMER, // 8 PB3 WO0 Alt
TIMERA0, // 9 PB2 WO2
TIMERA0, // 10 PB1 WO1
// Right side, bottom to top
TIMERA0, // 11 PB0 WO0
#if (defined(TCD0) && defined(USE_TIMERD0_PWM))
TIMERD0, // 12 PC0 WOC
TIMERD0, // 13 PC1 WOD
#else
NOT_ON_TIMER, // 12 PC0
NOT_ON_TIMER, // 13 PC1
#endif
NOT_ON_TIMER, // 14 PC2
NOT_ON_TIMER, // 15 PC3 WO3 Alt
NOT_ON_TIMER, // 16 PC4 WO4 Alt
NOT_ON_TIMER, // 17 PC5 WO5 Alt
NOT_ON_TIMER, // 18 PA1
NOT_ON_TIMER, // 19 PA2
TIMERA0, // 20 PA3 WO3
NOT_ON_TIMER // 21 PA0
};
*/

// OK, only PIN_PA4-5:TCA0
// PIN_PC0-1: TCD0 => not OK yet for frequency
// Not OK, PIN_PA6, 7, PIN_PB0-2:TCA0

#define pinToUse PIN_PA5 //PIN_PB4

//creates pwm instance
ATtiny_PWM* PWM_Instance;

// Min freq. is 1220Hz = F_CPU / (256 * 64) for TCA0
float frequency = 2000.0f;
//float frequency = 10000.0f;

#if USING_DC_PERCENT
float dutycyclePercent = 0.0f;
float DCStepPercent = 5.0f;
#else
uint16_t dutycycle = 0;
uint16_t DCStep;
#endif

char dashLine[] = "=================================================================================================";

void printPWMInfo(ATtiny_PWM* PWM_Instance)
{
Serial.println(dashLine);
Serial.print("Actual data: pin = ");
Serial.print(PWM_Instance->getPin());
Serial.print(", PWM DutyCycle % = ");
Serial.print(PWM_Instance->getActualDutyCycle());
Serial.print(", PWMPeriod = ");
Serial.print(PWM_Instance->getPWMPeriod());
Serial.print(", PWM Freq (Hz) = ");
Serial.println(PWM_Instance->getActualFreq(), 4);
Serial.println(dashLine);
}

void setup()
{
Serial.begin(115200);

while (!Serial && millis() < 5000);

delay(100);

Serial.print(F("\nStarting PWM_manual on "));
Serial.println(BOARD_NAME);
Serial.println(AT_TINY_PWM_VERSION);

// Create a dummy instance
PWM_Instance = new ATtiny_PWM(pinToUse, frequency, 0);

if ( (PWM_Instance) && PWM_Instance->isPWMEnabled() )
{
// setPWM_manual(uint8_t pin, uint16_t level)
PWM_Instance->setPWM(pinToUse, frequency, 0);

//printPWMInfo(PWM_Instance);
}
else
{
Serial.print(F("Stop here forever"));

while (true)
delay(10000);
}

#if !USING_DC_PERCENT
// 5% steps
DCStep = round(MAX_16BIT / 20.0f);
#endif
}

void loop()
{
static unsigned long update_timeout = UPDATE_INTERVAL;

// Update DC every UPDATE_INTERVAL (1000) milliseconds
if (millis() > update_timeout)
{
#if USING_DC_PERCENT
PWM_Instance->setPWM_DCPercentage_manual(pinToUse, dutycyclePercent);

dutycyclePercent += DCStepPercent;

if (dutycyclePercent > 100.0f)
dutycyclePercent = 0.0f;
#else
if (dutycycle > MAX_16BIT)
{
PWM_Instance->setPWM_manual(pinToUse, MAX_16BIT);
dutycycle = 0;
}
else
{
PWM_Instance->setPWM_manual(pinToUse, dutycycle);
dutycycle += DCStep;
}
#endif

printPWMInfo(PWM_Instance);

update_timeout = millis() + UPDATE_INTERVAL;
}
}
1 change: 1 addition & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ setPWM_Int KEYWORD2
setPWM KEYWORD2
setPWM_Period KEYWORD2
setPWM_manual KEYWORD2
setPWM_DCPercentage_manual KEYWORD2
getActualDutyCycle KEYWORD2
getActualFreq KEYWORD2
getPWMPeriod KEYWORD2
Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ATtiny_PWM",
"version": "1.0.1",
"version": "1.1.0",
"keywords": "timing, device, control, timer, pwm, pwm-driver, pwm-frequency, dynamic-pwm, duty-cycle, hardware-based-pwm, multi-channel-pwm, waveform-generator, mission-critical, accuracy, non-blocking, megaavr, avr-attiny, attiny, megatinycore, megatiny-core",
"description": "This library enables you to use Hardware-based PWM channels on Arduino AVR ATtiny-based boards (ATtiny3217, etc.), using megaTinyCore, to create and output PWM to pins. Using the same functions as other FastPWM libraries to enable you to port PWM code easily between platforms. The most important feature is they are purely hardware-based PWM channels, supporting very high PWM frequencies. Therefore, their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks. These hardware-based PWMs, still work even if other software functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software-based PWM using ISR, millis() or micros(). That is necessary if you need to control devices requiring high precision. New efficient setPWM_manual function to facilitate waveform creation using PWM",
"authors":
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=ATtiny_PWM
version=1.0.1
version=1.1.0
author=Khoi Hoang
maintainer=Khoi Hoang <khoih.prog@gmail.com>
sentence=This library enables you to use Hardware-based PWM channels on Arduino AVR ATtiny-based boards (ATtiny3217, etc.), using megaTinyCore, to create and output PWM to pins.
Expand Down
30 changes: 24 additions & 6 deletions src/ATtiny_PWM.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
Built by Khoi Hoang https://github.com/khoih-prog/ATtiny_PWM
Licensed under MIT license
Version: 1.0.1
Version: 1.1.0
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 08/11/2022 Initial coding for AVR ATtiny (ATtiny3217, etc.) using megaTinyCore
1.0.1 K Hoang 22/01/2023 Add `PWM_StepperControl` example
1.1.0 K Hoang 25/01/2023 Add `PWM_manual` example and function. Catch low frequency error
*****************************************************************************************************************************/

#pragma once
Expand Down Expand Up @@ -145,13 +146,13 @@
///////////////////////////////////////////////////////////////////////////////

#ifndef AT_TINY_PWM_VERSION
#define AT_TINY_PWM_VERSION F("ATtiny_PWM v1.0.1")
#define AT_TINY_PWM_VERSION F("ATtiny_PWM v1.1.0")

#define AT_TINY_PWM_VERSION_MAJOR 1
#define AT_TINY_PWM_VERSION_MINOR 0
#define AT_TINY_PWM_VERSION_PATCH 1
#define AT_TINY_PWM_VERSION_MINOR 1
#define AT_TINY_PWM_VERSION_PATCH 0

#define AT_TINY_PWM_VERSION_INT 1000001
#define AT_TINY_PWM_VERSION_INT 1001000
#endif

////////////////////////////////////////
Expand Down Expand Up @@ -311,7 +312,7 @@ class ATtiny_PWM

public:

// dutycycle from 0-65536 for 0%-100% to make use of 16-bit top register
// dutycycle from 0-65535 for 0%-100% to make use of 16-bit top register
bool setPWM_Int(const uint8_t& pin, const float& frequency, uint16_t dutycycle)
{
dutycycle = map(dutycycle, 0, MAX_16BIT, 0, MAX_8BIT);
Expand All @@ -338,6 +339,9 @@ class ATtiny_PWM
{
case TIMERA0:
{
if ( frequency < F_CPU / ( 64 * 256 ) )
PWM_LOGERROR1("setPWM_Int: frequency must be >=", F_CPU / ( 64 * 256 ) );

setPeriod_TimerA0(1000000UL / frequency);

// start from 0, so to add 1 to DC and period
Expand Down Expand Up @@ -390,6 +394,9 @@ class ATtiny_PWM
//////

PWM_LOGDEBUG3("setPWM_Int: TIMERD0, _dutycycle =", _dutycycle, ", dutycycle =", dutycycle);

if ( frequency < F_CPU / ( 32 * 256 ) )
PWM_LOGERROR1("setPWM_Int: frequency must be >=", F_CPU / ( 32 * 256 ) );

uint8_t oldSREG = SREG;

Expand Down Expand Up @@ -503,6 +510,17 @@ class ATtiny_PWM

return setPWM_Int(pin, _frequency, DCValue);
}

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

// DCPercentage from 0.0f - 100.0f for 0-65535
bool setPWM_DCPercentage_manual(const uint8_t& pin, const float& DCPercentage)
{
// Convert to DCValue based on resolution = MAX_16BIT
PWM_LOGDEBUG3(F("setPWM_DCPercentage_manual: DCPercentage ="), DCPercentage, F(", dc ="), ( DCPercentage * MAX_16BIT ) / 100.0f);

return setPWM_manual(pin, ( DCPercentage * MAX_16BIT ) / 100.0f);
}

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

Expand Down
3 changes: 2 additions & 1 deletion src/PWM_Generic_Debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
Built by Khoi Hoang https://github.com/khoih-prog/ATtiny_PWM
Licensed under MIT license
Version: 1.0.1
Version: 1.1.0
Version Modified By Date Comments
------- ----------- ---------- -----------
1.0.0 K Hoang 08/11/2022 Initial coding for AVR ATtiny (ATtiny3217, etc.) using megaTinyCore
1.0.1 K Hoang 22/01/2023 Add `PWM_StepperControl` example
1.1.0 K Hoang 25/01/2023 Add `PWM_manual` example and function. Catch low frequency error
*****************************************************************************************************************************/

#pragma once
Expand Down

0 comments on commit 4b7546d

Please sign in to comment.