Skip to content

Commit

Permalink
Merge pull request #14 from rv0/annoying_slave
Browse files Browse the repository at this point in the history
Annoying slave sync issue in pattern edit
  • Loading branch information
HomoElectromagneticus authored Mar 1, 2019
2 parents 80e6684 + 0e977a1 commit 1535c12
Show file tree
Hide file tree
Showing 13 changed files with 1,042 additions and 151 deletions.
26 changes: 0 additions & 26 deletions Library/TimerOne/examples/ISRBlink/ISRBlink.pde

This file was deleted.

674 changes: 674 additions & 0 deletions Library/TimerOneThree/LICENSE

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions Library/TimerOneThree/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
TimerOneThree
=============

The arduino TimerOne library adapted for ATmega1284P and extended for timer3

The arduino TimerOne library described at http://playground.arduino.cc/Code/Timer1 is the starting point for this lib. The original library can be found at http://code.google.com/p/arduino-timerone/downloads/list.

The commands are the same as in the TimerOne library. The pinmapping is taken from maniacbug's mighty ATmega1284P. http://maniacbug.wordpress.com/2011/11/27/arduino-on-atmega1284p-4/
* pin 6 is Timer3A
* pin 7 is Timer3B
* pin 13 is Timer1A
* pin 12 is Timer1B

### Installation and usage

To install simply create a folder named TimerOneThree in your libraries folder of the arduino IDE. Download the zip archive. Copy all files from the zip archive into the TimerOneThree folger. Then restart the IDE. In your sketch type:
`#include <TimerOneThree.h>`

With the TimerOneThree lib both timer1 and timer3 of the ATmega1284P can be used in the same way, e. g:

`Timer1.initialize(2000); // sets timer1 to a period of 2000 microseconds`
`Timer3.initialize(2000); // does the same for timer3`

So when you want to set use timer3A to generate a pwm with 50% duty cycle:

`Timer3.pwm(6, 511); // duty cycle goes from 0 to 1023`
213 changes: 197 additions & 16 deletions Library/TimerOne/TimerOne.cpp → Library/TimerOneThree/TimerOneThree.cpp
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/*
* Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
* Original Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
* Original code by Jesse Tane for http://labs.ideo.com August 2008
* Now modified for ATmega1284P Timer1 and Timer3
*
* Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
* Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
* Modified June 2011 by Lex Talionis to add a function to read the timer
Expand All @@ -17,6 +19,14 @@
* Modiied 7:26 PM Sunday, October 09, 2011 by Lex Talionis
* - renamed start() to resume() to reflect it's actual role
* - renamed startBottom() to start(). This breaks some old code that expects start to continue counting where it left off
* Modified December 16, 2013 by Friedrich Lauterbach
* - added Timer3 support
* - changed pins to fit to ATmega1284P pinmapping
* from maniacbug http://maniacbug.wordpress.com/2011/11/27/arduino-on-atmega1284p-4/
* pin 6 is Timer3A
* pin 7 is Timer3B
* pin 13 is Timer1A
* pin 12 is Timer1B
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -31,12 +41,14 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* See Google Code project http://code.google.com/p/arduino-timerone/ for latest
* See Google Code project http://code.google.com/p/arduino-timerone/ for latest of original TimerOne
*
* See github http://github.com/heliosoph/TimerOneThree/ for latest
*/
#ifndef TIMERONE_cpp
#define TIMERONE_cpp
#ifndef TIMERONETHREE_cpp
#define TIMERONETHREE_cpp

#include "TimerOne.h"
#include "TimerOneThree.h"

TimerOne Timer1; // preinstatiate

Expand Down Expand Up @@ -83,19 +95,19 @@ void TimerOne::setPwmDuty(char pin, int duty)

oldSREG = SREG;
cli();
if(pin == 1 || pin == 9) OCR1A = dutyCycle;
else if(pin == 2 || pin == 10) OCR1B = dutyCycle;
if(pin == 13) OCR1A = dutyCycle;
else if(pin == 12) OCR1B = dutyCycle;
SREG = oldSREG;
}

void TimerOne::pwm(char pin, int duty, long microseconds) // expects duty cycle to be 10 bit (1024)
{
if(microseconds > 0) setPeriod(microseconds);
if(pin == 1 || pin == 9) {
if(pin == 13) {
DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin
TCCR1A |= _BV(COM1A1); // activates the output pin
}
else if(pin == 2 || pin == 10) {
else if(pin == 12) {
DDRB |= _BV(PORTB2);
TCCR1A |= _BV(COM1B1);
}
Expand All @@ -106,23 +118,24 @@ void TimerOne::pwm(char pin, int duty, long microseconds) // expects duty cycle

void TimerOne::disablePwm(char pin)
{
if(pin == 1 || pin == 9) TCCR1A &= ~_BV(COM1A1); // clear the bit that enables pwm on PB1
else if(pin == 2 || pin == 10) TCCR1A &= ~_BV(COM1B1); // clear the bit that enables pwm on PB2
if(pin == 13) TCCR1A &= ~_BV(COM1A1); // clear the bit that enables pwm on PB1
else if(pin == 12) TCCR1A &= ~_BV(COM1B1); // clear the bit that enables pwm on PB2
}

void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
{
if(microseconds > 0) setPeriod(microseconds);
isrCallback = isr; // register the user's callback with the real ISR
TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
// AR - remove sei() - might be running with interrupts disabled (eg inside an ISR), so leave unchanged
// sei(); // ensures that interrupts are globally enabled
resume();
// might be running with interrupts disabled (eg inside an ISR), so don't touch the global state
// sei();
resume();
}

void TimerOne::detachInterrupt()
{
TIMSK1 &= ~_BV(TOIE1); // clears the timer overflow interrupt enable bit
// timer continues to count without calling the isr
}

void TimerOne::resume() // AR suggested
Expand All @@ -146,7 +159,7 @@ void TimerOne::start() // AR addition, renamed by Lex to reflect it's actual rol
cli(); // AR - Disable interrupts
TCNT1 = 0;
SREG = oldSREG; // AR - Restore status register

resume();
do { // Nothing -- wait until timer moved on from zero - otherwise get a phantom interrupt
oldSREG = SREG;
cli();
Expand Down Expand Up @@ -205,4 +218,172 @@ unsigned long TimerOne::read() //returns the value of the timer in microseconds
return ((tmp*1000L)/(F_CPU /1000L))<<scale;
}

#endif
TimerThree Timer3; // preinstatiate

ISR(TIMER3_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
Timer3.isrCallback();
}


void TimerThree::initialize(long microseconds)
{
TCCR3A = 0; // clear control register A
TCCR3B = _BV(WGM33); // set mode 8: phase and frequency correct pwm, stop the timer
setPeriod(microseconds);
}


void TimerThree::setPeriod(long microseconds) // AR modified for atomic access
{

long cycles = (F_CPU / 2000000) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
if(cycles < RESOLUTION) clockSelectBits = _BV(CS30); // no prescale, full xtal
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS31); // prescale by /8
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS31) | _BV(CS30); // prescale by /64
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS32); // prescale by /256
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS32) | _BV(CS30); // prescale by /1024
else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS32) | _BV(CS30); // request was out of bounds, set as maximum

oldSREG = SREG;
cli(); // Disable interrupts for 16 bit register access
ICR3 = pwmPeriod = cycles; // ICR3 is TOP in p & f correct pwm mode
SREG = oldSREG;

TCCR3B &= ~(_BV(CS30) | _BV(CS31) | _BV(CS32));
TCCR3B |= clockSelectBits; // reset clock select register, and starts the clock
}

void TimerThree::setPwmDuty(char pin, int duty)
{
unsigned long dutyCycle = pwmPeriod;

dutyCycle *= duty;
dutyCycle >>= 10;

oldSREG = SREG;
cli();
if(pin == 6) OCR3A = dutyCycle;
else if(pin == 7) OCR3B = dutyCycle;
SREG = oldSREG;
}

void TimerThree::pwm(char pin, int duty, long microseconds) // expects duty cycle to be 10 bit (1024)
{
if(microseconds > 0) setPeriod(microseconds);
if(pin == 6) {
DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin
TCCR3A |= _BV(COM3A1); // activates the output pin
}
else if(pin == 7) {
DDRB |= _BV(PORTB2);
TCCR3A |= _BV(COM3B1);
}
setPwmDuty(pin, duty);
resume(); // Lex - make sure the clock is running. We don't want to restart the count, in case we are starting the second WGM
// and the first one is in the middle of a cycle
}

void TimerThree::disablePwm(char pin)
{
if(pin == 6) TCCR3A &= ~_BV(COM3A1); // clear the bit that enables pwm on PB1
else if(pin == 7) TCCR3A &= ~_BV(COM3B1); // clear the bit that enables pwm on PB2
}

void TimerThree::attachInterrupt(void (*isr)(), long microseconds)
{
if(microseconds > 0) setPeriod(microseconds);
isrCallback = isr; // register the user's callback with the real ISR
TIMSK3 = _BV(TOIE3); // sets the timer overflow interrupt enable bit
// might be running with interrupts disabled (eg inside an ISR), so don't touch the global state
// sei();
resume();
}

void TimerThree::detachInterrupt()
{
TIMSK3 &= ~_BV(TOIE3); // clears the timer overflow interrupt enable bit
// timer continues to count without calling the isr
}

void TimerThree::resume() // AR suggested
{
TCCR3B |= clockSelectBits;
}

void TimerThree::restart() // Depricated - Public interface to start at zero - Lex 10/9/2011
{
start();
}

void TimerThree::start() // AR addition, renamed by Lex to reflect it's actual role
{
unsigned int tcnt3;

TIMSK3 &= ~_BV(TOIE3); // AR added
GTCCR |= _BV(PSRSYNC); // AR added - reset prescaler (NB: shared with all 16 bit timers);

oldSREG = SREG; // AR - save status register
cli(); // AR - Disable interrupts
TCNT3 = 0;
SREG = oldSREG; // AR - Restore status register
resume();
do { // Nothing -- wait until timer moved on from zero - otherwise get a phantom interrupt
oldSREG = SREG;
cli();
tcnt3 = TCNT3;
SREG = oldSREG;
} while (tcnt3==0);

// TIFR3 = 0xff; // AR - Clear interrupt flags
// TIMSK3 = _BV(TOIE3); // sets the timer overflow interrupt enable bit
}

void TimerThree::stop()
{
TCCR3B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // clears all clock selects bits
}

unsigned long TimerThree::read() //returns the value of the timer in microseconds
{ //rember! phase and freq correct mode counts up to then down again
unsigned long tmp; // AR amended to hold more than 65536 (could be nearly double this)
unsigned int tcnt3; // AR added

oldSREG= SREG;
cli();
tmp=TCNT3;
SREG = oldSREG;

char scale=0;
switch (clockSelectBits)
{
case 1:// no prescalse
scale=0;
break;
case 2:// x8 prescale
scale=3;
break;
case 3:// x64
scale=6;
break;
case 4:// x256
scale=8;
break;
case 5:// x1024
scale=10;
break;
}

do { // Nothing -- max delay here is ~1023 cycles. AR modified
oldSREG = SREG;
cli();
tcnt3 = TCNT3;
SREG = oldSREG;
} while (tcnt3==tmp); //if the timer has not ticked yet

//if we are counting down add the top value to how far we have counted down
tmp = ( (tcnt3>tmp) ? (tmp) : (long)(ICR3-tcnt3)+(long)ICR3 ); // AR amended to add casts and reuse previous TCNT3
return ((tmp*1000L)/(F_CPU /1000L))<<scale;
}

#endif
35 changes: 32 additions & 3 deletions Library/TimerOne/TimerOne.h → Library/TimerOneThree/TimerOneThree.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
* Modiied 7:26 PM Sunday, October 09, 2011 by Lex Talionis
* - renamed start() to resume() to reflect it's actual role
* - renamed startBottom() to start(). This breaks some old code that expects start to continue counting where it left off
* Modified December 16, 2013 by Friedrich Lauterbach
* - added Timer3 support
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -33,8 +35,8 @@
*
* See Google Code project http://code.google.com/p/arduino-timerone/ for latest
*/
#ifndef TIMERONE_h
#define TIMERONE_h
#ifndef TIMERONETHREE_h
#define TIMERONETHREE_h

#include <avr/io.h>
#include <avr/interrupt.h>
Expand Down Expand Up @@ -66,5 +68,32 @@ class TimerOne
void (*isrCallback)();
};

class TimerThree
{
public:

// properties
unsigned int pwmPeriod;
unsigned char clockSelectBits;
char oldSREG; // To hold Status Register while ints disabled

// methods
void initialize(long microseconds=1000000);
void start();
void stop();
void restart();
void resume();
unsigned long read();
void pwm(char pin, int duty, long microseconds=-1);
void disablePwm(char pin);
void attachInterrupt(void (*isr)(), long microseconds=-1);
void detachInterrupt();
void setPeriod(long microseconds);
void setPwmDuty(char pin, int duty);
void (*isrCallback)();
};


extern TimerOne Timer1;
#endif
extern TimerThree Timer3;
#endif
Loading

0 comments on commit 1535c12

Please sign in to comment.