From 2f97a4b146aca5da90681ebc8d524e265504ccdc Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 26 Aug 2006 09:56:40 +0000 Subject: [PATCH] Got timer and pwm functions working with the ATmega168 (including pwm on pin 3); no longer relying on timer.c or timer.h from avrlib. --- readme.txt | 3 +- targets/arduino/pins_arduino.c | 31 ++- targets/arduino/timer.c | 483 --------------------------------- targets/arduino/timer.h | 278 ------------------- targets/arduino/wiring.c | 163 ++++++----- targets/arduino/wiring.h | 11 +- 6 files changed, 133 insertions(+), 836 deletions(-) delete mode 100755 targets/arduino/timer.c delete mode 100755 targets/arduino/timer.h diff --git a/readme.txt b/readme.txt index cb9f585b0..583d6dd51 100644 --- a/readme.txt +++ b/readme.txt @@ -30,6 +30,7 @@ UPDATES 0005 +ATmega168 support on the way (currently timers and pwm working). New Wiring-compatible randomSeed(), random(max) and random(min, max) functions (except operating on longs instead of floats). Fixed bug that sometimes caused uploading of old versions of a sketch. @@ -115,4 +116,4 @@ Yaniv Steiner and Giorgio Olivero have been supporting the project and are working at using it with the Instant Soup platform. Arduino uses the GNU avr-gcc toolchain, uisp, avr-libc, avrlib, and code -from Processing and Wiring. \ No newline at end of file +from Processing and Wiring. diff --git a/targets/arduino/pins_arduino.c b/targets/arduino/pins_arduino.c index c2e52de57..94d1b9615 100755 --- a/targets/arduino/pins_arduino.c +++ b/targets/arduino/pins_arduino.c @@ -105,6 +105,35 @@ pin_t digital_pin_to_port_array[NUM_DIGITAL_PINS] = { pin_t *digital_pin_to_port = digital_pin_to_port_array; +int analog_out_pin_to_timer_array[NUM_DIGITAL_PINS] = { + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + // on the ATmega168, digital pin 3 has pwm +#if defined(__AVR_ATmega168__) + TIMER2B, +#else + NOT_ON_TIMER, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + TIMER1A, + TIMER1B, +#if defined(__AVR_ATmega168__) + TIMER2A, +#else + TIMER2, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, +}; + +int *analog_out_pin_to_timer = analog_out_pin_to_timer_array; + +/* // Some of the digital pins also support hardware PWM (analog output). pin_t analog_out_pin_to_port_array[NUM_DIGITAL_PINS] = { { NOT_A_PIN, NOT_A_PIN }, @@ -124,7 +153,7 @@ pin_t analog_out_pin_to_port_array[NUM_DIGITAL_PINS] = { }; pin_t *analog_out_pin_to_port = analog_out_pin_to_port_array; - +*/ pin_t analog_in_pin_to_port_array[NUM_ANALOG_IN_PINS] = { { PC, 0 }, { PC, 1 }, diff --git a/targets/arduino/timer.c b/targets/arduino/timer.c deleted file mode 100755 index 5b3c767ae..000000000 --- a/targets/arduino/timer.c +++ /dev/null @@ -1,483 +0,0 @@ -/*! \file timer.c \brief System Timer function library. */ -//***************************************************************************** -// -// File Name : 'timer.c' -// Title : System Timer function library -// Author : Pascal Stang - Copyright (C) 2000-2002 -// Created : 11/22/2000 -// Revised : 07/09/2003 -// Version : 1.1 -// Target MCU : Atmel AVR Series -// Editor Tabs : 4 -// -// This code is distributed under the GNU Public License -// which can be found at http://www.gnu.org/licenses/gpl.txt -// -//***************************************************************************** -// -// Modified by David A. Mellis, 9 July 2006. - -#ifndef WIN32 - #include - #include - #include - #include - #include -#endif - -#include "global.h" -#include "timer.h" - -#include "rprintf.h" - -// Program ROM constants -// the prescale division values stored in order of timer control register index -// STOP, CLK, CLK/8, CLK/64, CLK/256, CLK/1024 -unsigned short __attribute__ ((progmem)) TimerPrescaleFactor[] = {0,1,8,64,256,1024}; -// the prescale division values stored in order of timer control register index -// STOP, CLK, CLK/8, CLK/32, CLK/64, CLK/128, CLK/256, CLK/1024 -unsigned short __attribute__ ((progmem)) TimerRTCPrescaleFactor[] = {0,1,8,32,64,128,256,1024}; - -// Global variables -// time registers -volatile unsigned long TimerPauseReg; -volatile unsigned long Timer0Reg0; -volatile unsigned long Timer2Reg0; - -typedef void (*voidFuncPtr)(void); -volatile static voidFuncPtr TimerIntFunc[TIMER_NUM_INTERRUPTS]; -/* -// delay for a minimum of microseconds -// the time resolution is dependent on the time the loop takes -// e.g. with 4Mhz and 5 cycles per loop, the resolution is 1.25 us -void delay_us(unsigned short time_us) -{ - unsigned short delay_loops; - register unsigned short i; - - delay_loops = (time_us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty) - - // one loop takes 5 cpu cycles - for (i=0; i < delay_loops; i++) {}; -} -*/ -/* -void delay_ms(unsigned char time_ms) -{ - unsigned short delay_count = F_CPU / 4000; - - unsigned short cnt; - asm volatile ("\n" - "L_dl1%=:\n\t" - "mov %A0, %A2\n\t" - "mov %B0, %B2\n" - "L_dl2%=:\n\t" - "sbiw %A0, 1\n\t" - "brne L_dl2%=\n\t" - "dec %1\n\t" "brne L_dl1%=\n\t":"=&w" (cnt) - :"r"(time_ms), "r"((unsigned short) (delay_count)) - ); -} -*/ -/* -void timerInit(void) -{ - u08 intNum; - // detach all user functions from interrupts - for(intNum=0; intNum number of milliseconds - u08 timerThres; - u32 ticRateHz; - u32 pause; - - // capture current pause timer value - timerThres = inb(TCNT0); - // reset pause timer overflow count - TimerPauseReg = 0; - // calculate delay for [pause_ms] milliseconds - // prescaler division = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0))) - ticRateHz = F_CPU/timer0GetPrescaler(); - // precision management - // prevent overflow and precision underflow - // -could add more conditions to improve accuracy - if( ((ticRateHz < 429497) && (pause_ms <= 10000)) ) - pause = (pause_ms*ticRateHz)/1000; - else - pause = pause_ms*(ticRateHz/1000); - - // loop until time expires - while( ((TimerPauseReg<<8) | inb(TCNT0)) < (pause+timerThres) ) - { - // DAM: these lines (in particular, the call to set_sleep_mode) - // caused avr-gcc to give an error about a misplaced } in linux, - // presumambly caused by a macro somewhere. Since they're not - // vital (and are causing problems), I'm commenting them out. - //if( TimerPauseReg < (pause>>8)); - //{ - // save power by idling the processor - //set_sleep_mode(SLEEP_MODE_IDLE); - //sleep_mode(); - //} - } - - // old inaccurate code, for reference - - // calculate delay for [pause_ms] milliseconds - //u16 prescaleDiv = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0))); - //u32 pause = (pause_ms*(F_CPU/(prescaleDiv*256)))/1000; - - //TimerPauseReg = 0; - //while(TimerPauseReg < pause); -} - -void timer0ClearOverflowCount(void) -{ - // clear the timer overflow counter registers - Timer0Reg0 = 0; // initialize time registers -} - -long timer0GetOverflowCount(void) -{ - // return the current timer overflow count - // (this is since the last timer0ClearOverflowCount() command was called) - return Timer0Reg0; -} -*/ -#ifdef TCNT2 // support timer2 only if it exists -void timer2ClearOverflowCount(void) -{ - // clear the timer overflow counter registers - Timer2Reg0 = 0; // initialize time registers -} -/* -long timer2GetOverflowCount(void) -{ - // return the current timer overflow count - // (this is since the last timer2ClearOverflowCount() command was called) - return Timer2Reg0; -} -*/ -#endif - -void timer1PWMInit(u08 bitRes) -{ - // configures timer1 for use with PWM output - // on OC1A and OC1B pins - - // enable timer1 as 8,9,10bit PWM - if(bitRes == 9) - { // 9bit mode - sbi(TCCR1A,PWM11); - cbi(TCCR1A,PWM10); - } - else if( bitRes == 10 ) - { // 10bit mode - sbi(TCCR1A,PWM11); - sbi(TCCR1A,PWM10); - } - else - { // default 8bit mode - cbi(TCCR1A,PWM11); - sbi(TCCR1A,PWM10); - } - - // clear output compare value A - outb(OCR1AH, 0); - outb(OCR1AL, 0); - // clear output compare value B - outb(OCR1BH, 0); - outb(OCR1BL, 0); -} - -#ifdef WGM10 -// include support for arbitrary top-count PWM -// on new AVR processors that support it -void timer1PWMInitICR(u16 topcount) -{ - // set PWM mode with ICR top-count - cbi(TCCR1A,WGM10); - sbi(TCCR1A,WGM11); - sbi(TCCR1B,WGM12); - sbi(TCCR1B,WGM13); - - // set top count value - ICR1 = topcount; - - // clear output compare value A - OCR1A = 0; - // clear output compare value B - OCR1B = 0; - -} -#endif - -void timer1PWMOff(void) -{ - // turn off timer1 PWM mode - cbi(TCCR1A,PWM11); - cbi(TCCR1A,PWM10); - // set PWM1A/B (OutputCompare action) to none - timer1PWMAOff(); - timer1PWMBOff(); -} - -void timer1PWMAOn(void) -{ - // turn on channel A (OC1A) PWM output - // set OC1A as non-inverted PWM - sbi(TCCR1A,COM1A1); - cbi(TCCR1A,COM1A0); -} - -void timer1PWMBOn(void) -{ - // turn on channel B (OC1B) PWM output - // set OC1B as non-inverted PWM - sbi(TCCR1A,COM1B1); - cbi(TCCR1A,COM1B0); -} - -void timer1PWMAOff(void) -{ - // turn off channel A (OC1A) PWM output - // set OC1A (OutputCompare action) to none - cbi(TCCR1A,COM1A1); - cbi(TCCR1A,COM1A0); -} - -void timer1PWMBOff(void) -{ - // turn off channel B (OC1B) PWM output - // set OC1B (OutputCompare action) to none - cbi(TCCR1A,COM1B1); - cbi(TCCR1A,COM1B0); -} - -void timer1PWMASet(u16 pwmDuty) -{ - // set PWM (output compare) duty for channel A - // this PWM output is generated on OC1A pin - // NOTE: pwmDuty should be in the range 0-255 for 8bit PWM - // pwmDuty should be in the range 0-511 for 9bit PWM - // pwmDuty should be in the range 0-1023 for 10bit PWM - //outp( (pwmDuty>>8), OCR1AH); // set the high 8bits of OCR1A - //outp( (pwmDuty&0x00FF), OCR1AL); // set the low 8bits of OCR1A - OCR1A = pwmDuty; -} - -void timer1PWMBSet(u16 pwmDuty) -{ - // set PWM (output compare) duty for channel B - // this PWM output is generated on OC1B pin - // NOTE: pwmDuty should be in the range 0-255 for 8bit PWM - // pwmDuty should be in the range 0-511 for 9bit PWM - // pwmDuty should be in the range 0-1023 for 10bit PWM - //outp( (pwmDuty>>8), OCR1BH); // set the high 8bits of OCR1B - //outp( (pwmDuty&0x00FF), OCR1BL); // set the low 8bits of OCR1B - OCR1B = pwmDuty; -} -/* -//! Interrupt handler for tcnt0 overflow interrupt -TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW0) -{ - Timer0Reg0++; // increment low-order counter - - // increment pause counter - TimerPauseReg++; - - // if a user function is defined, execute it too - if(TimerIntFunc[TIMER0OVERFLOW_INT]) - TimerIntFunc[TIMER0OVERFLOW_INT](); -} -*/ -//! Interrupt handler for tcnt1 overflow interrupt -TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW1) -{ - // if a user function is defined, execute it - if(TimerIntFunc[TIMER1OVERFLOW_INT]) - TimerIntFunc[TIMER1OVERFLOW_INT](); -} - -#ifdef TCNT2 // support timer2 only if it exists -//! Interrupt handler for tcnt2 overflow interrupt -TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW2) -{ - Timer2Reg0++; // increment low-order counter - - // if a user function is defined, execute it - if(TimerIntFunc[TIMER2OVERFLOW_INT]) - TimerIntFunc[TIMER2OVERFLOW_INT](); -} -#endif - -#ifdef OCR0 -/* -// include support for Output Compare 0 for new AVR processors that support it -//! Interrupt handler for OutputCompare0 match (OC0) interrupt -TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE0) -{ - // if a user function is defined, execute it - if(TimerIntFunc[TIMER0OUTCOMPARE_INT]) - TimerIntFunc[TIMER0OUTCOMPARE_INT](); -} -*/ -#endif - -//! Interrupt handler for CutputCompare1A match (OC1A) interrupt -TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE1A) -{ - // if a user function is defined, execute it - if(TimerIntFunc[TIMER1OUTCOMPAREA_INT]) - TimerIntFunc[TIMER1OUTCOMPAREA_INT](); -} - -//! Interrupt handler for OutputCompare1B match (OC1B) interrupt -TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE1B) -{ - // if a user function is defined, execute it - if(TimerIntFunc[TIMER1OUTCOMPAREB_INT]) - TimerIntFunc[TIMER1OUTCOMPAREB_INT](); -} - -//! Interrupt handler for InputCapture1 (IC1) interrupt -TIMER_INTERRUPT_HANDLER(SIG_INPUT_CAPTURE1) -{ - // if a user function is defined, execute it - if(TimerIntFunc[TIMER1INPUTCAPTURE_INT]) - TimerIntFunc[TIMER1INPUTCAPTURE_INT](); -} - -//! Interrupt handler for OutputCompare2 match (OC2) interrupt -TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE2) -{ - // if a user function is defined, execute it - if(TimerIntFunc[TIMER2OUTCOMPARE_INT]) - TimerIntFunc[TIMER2OUTCOMPARE_INT](); -} diff --git a/targets/arduino/timer.h b/targets/arduino/timer.h deleted file mode 100755 index ed5c59964..000000000 --- a/targets/arduino/timer.h +++ /dev/null @@ -1,278 +0,0 @@ -/*! \file timer.h \brief System Timer function library. */ -//***************************************************************************** -// -// File Name : 'timer.h' -// Title : System Timer function library -// Author : Pascal Stang - Copyright (C) 2000-2002 -// Created : 11/22/2000 -// Revised : 02/10/2003 -// Version : 1.1 -// Target MCU : Atmel AVR Series -// Editor Tabs : 4 -// -// This code is distributed under the GNU Public License -// which can be found at http://www.gnu.org/licenses/gpl.txt -// -// -// Notes: The Atmel AVR Series Processors each contain at least one -// hardware timer/counter. Many of the processors contain 2 or 3 -// timers. Generally speaking, a timer is a hardware counter inside -// the processor which counts at a rate related to the main CPU clock -// frequency. Because the counter value increasing (counting up) at -// a precise rate, we can use it as a timer to create or measure -// precise delays, schedule events, or generate signals of a certain -// frequency or pulse-width. -// As an example, the ATmega163 processor has 3 timer/counters. -// Timer0, Timer1, and Timer2 are 8, 16, and 8 bits wide respectively. -// This means that they overflow, or roll over back to zero, at a -// count value of 256 for 8bits or 65536 for 16bits. A prescaler is -// avaiable for each timer, and the prescaler allows you to pre-divide -// the main CPU clock rate down to a slower speed before feeding it to -// the counting input of a timer. For example, if the CPU clock -// frequency is 3.69MHz, and Timer0's prescaler is set to divide-by-8, -// then Timer0 will "tic" at 3690000/8 = 461250Hz. Because Timer0 is -// an 8bit timer, it will count to 256 in just 256/461250Hz = 0.555ms. -// In fact, when it hits 255, it will overflow and start again at -// zero. In this case, Timer0 will overflow 461250/256 = 1801.76 -// times per second. -// Timer0 can be used a number of ways simultaneously. First, the -// value of the timer can be read by accessing the CPU register TCNT0. -// We could, for example, figure out how long it takes to execute a -// C command by recording the value of TCNT0 before and after -// execution, then subtract (after-before) = time elapsed. Or we can -// enable the overflow interrupt which goes off every time T0 -// overflows and count out longer delays (multiple overflows), or -// execute a special periodic function at every overflow. -// The other timers (Timer1 and Timer2) offer all the abilities of -// Timer0 and many more features. Both T1 and T2 can operate as -// general-purpose timers, but T1 has special hardware allowing it to -// generate PWM signals, while T2 is specially designed to help count -// out real time (like hours, minutes, seconds). See the -// Timer/Counter section of the processor datasheet for more info. -// -//***************************************************************************** - -#ifndef TIMER_H -#define TIMER_H - -#include "global.h" - -// constants/macros/typdefs - -// processor compatibility fixes -#ifdef __AVR_ATmega323__ - // redefinition for the Mega323 - #define CTC1 CTC10 -#endif -#ifndef PWM10 - // mega128 PWM bits - #define PWM10 WGM10 - #define PWM11 WGM11 -#endif - -// Timer/clock prescaler values and timer overflow rates -// tics = rate at which the timer counts up -// 8bitoverflow = rate at which the timer overflows 8bits (or reaches 256) -// 16bit [overflow] = rate at which the timer overflows 16bits (65536) -// -// overflows can be used to generate periodic interrupts -// -// for 8MHz crystal -// 0 = STOP (Timer not counting) -// 1 = CLOCK tics= 8MHz 8bitoverflow= 31250Hz 16bit= 122.070Hz -// 2 = CLOCK/8 tics= 1MHz 8bitoverflow= 3906.25Hz 16bit= 15.259Hz -// 3 = CLOCK/64 tics= 125kHz 8bitoverflow= 488.28Hz 16bit= 1.907Hz -// 4 = CLOCK/256 tics= 31250Hz 8bitoverflow= 122.07Hz 16bit= 0.477Hz -// 5 = CLOCK/1024 tics= 7812.5Hz 8bitoverflow= 30.52Hz 16bit= 0.119Hz -// 6 = External Clock on T(x) pin (falling edge) -// 7 = External Clock on T(x) pin (rising edge) - -// for 4MHz crystal -// 0 = STOP (Timer not counting) -// 1 = CLOCK tics= 4MHz 8bitoverflow= 15625Hz 16bit= 61.035Hz -// 2 = CLOCK/8 tics= 500kHz 8bitoverflow= 1953.125Hz 16bit= 7.629Hz -// 3 = CLOCK/64 tics= 62500Hz 8bitoverflow= 244.141Hz 16bit= 0.954Hz -// 4 = CLOCK/256 tics= 15625Hz 8bitoverflow= 61.035Hz 16bit= 0.238Hz -// 5 = CLOCK/1024 tics= 3906.25Hz 8bitoverflow= 15.259Hz 16bit= 0.060Hz -// 6 = External Clock on T(x) pin (falling edge) -// 7 = External Clock on T(x) pin (rising edge) - -// for 3.69MHz crystal -// 0 = STOP (Timer not counting) -// 1 = CLOCK tics= 3.69MHz 8bitoverflow= 14414Hz 16bit= 56.304Hz -// 2 = CLOCK/8 tics= 461250Hz 8bitoverflow= 1801.758Hz 16bit= 7.038Hz -// 3 = CLOCK/64 tics= 57625.25Hz 8bitoverflow= 225.220Hz 16bit= 0.880Hz -// 4 = CLOCK/256 tics= 14414.063Hz 8bitoverflow= 56.305Hz 16bit= 0.220Hz -// 5 = CLOCK/1024 tics= 3603.516Hz 8bitoverflow= 14.076Hz 16bit= 0.055Hz -// 6 = External Clock on T(x) pin (falling edge) -// 7 = External Clock on T(x) pin (rising edge) - -// for 32.768KHz crystal on timer 2 (use for real-time clock) -// 0 = STOP -// 1 = CLOCK tics= 32.768kHz 8bitoverflow= 128Hz -// 2 = CLOCK/8 tics= 4096kHz 8bitoverflow= 16Hz -// 3 = CLOCK/32 tics= 1024kHz 8bitoverflow= 4Hz -// 4 = CLOCK/64 tics= 512Hz 8bitoverflow= 2Hz -// 5 = CLOCK/128 tics= 256Hz 8bitoverflow= 1Hz -// 6 = CLOCK/256 tics= 128Hz 8bitoverflow= 0.5Hz -// 7 = CLOCK/1024 tics= 32Hz 8bitoverflow= 0.125Hz - -#define TIMER_CLK_STOP 0x00 ///< Timer Stopped -#define TIMER_CLK_DIV1 0x01 ///< Timer clocked at F_CPU -#define TIMER_CLK_DIV8 0x02 ///< Timer clocked at F_CPU/8 -#define TIMER_CLK_DIV64 0x03 ///< Timer clocked at F_CPU/64 -#define TIMER_CLK_DIV256 0x04 ///< Timer clocked at F_CPU/256 -#define TIMER_CLK_DIV1024 0x05 ///< Timer clocked at F_CPU/1024 -#define TIMER_CLK_T_FALL 0x06 ///< Timer clocked at T falling edge -#define TIMER_CLK_T_RISE 0x07 ///< Timer clocked at T rising edge -#define TIMER_PRESCALE_MASK 0x07 ///< Timer Prescaler Bit-Mask - -#define TIMERRTC_CLK_STOP 0x00 ///< RTC Timer Stopped -#define TIMERRTC_CLK_DIV1 0x01 ///< RTC Timer clocked at F_CPU -#define TIMERRTC_CLK_DIV8 0x02 ///< RTC Timer clocked at F_CPU/8 -#define TIMERRTC_CLK_DIV32 0x03 ///< RTC Timer clocked at F_CPU/32 -#define TIMERRTC_CLK_DIV64 0x04 ///< RTC Timer clocked at F_CPU/64 -#define TIMERRTC_CLK_DIV128 0x05 ///< RTC Timer clocked at F_CPU/128 -#define TIMERRTC_CLK_DIV256 0x06 ///< RTC Timer clocked at F_CPU/256 -#define TIMERRTC_CLK_DIV1024 0x07 ///< RTC Timer clocked at F_CPU/1024 -#define TIMERRTC_PRESCALE_MASK 0x07 ///< RTC Timer Prescaler Bit-Mask - -// default prescale settings for the timers -// these settings are applied when you call -// timerInit or any of the timerInit -#define TIMER0PRESCALE TIMER_CLK_DIV8 ///< timer 0 prescaler default -#define TIMER1PRESCALE TIMER_CLK_DIV64 ///< timer 1 prescaler default -#define TIMER2PRESCALE TIMERRTC_CLK_DIV64 ///< timer 2 prescaler default - -// interrupt macros for attaching user functions to timer interrupts -// use these with timerAttach( intNum, function ) -#define TIMER0OVERFLOW_INT 0 -#define TIMER1OVERFLOW_INT 1 -#define TIMER1OUTCOMPAREA_INT 2 -#define TIMER1OUTCOMPAREB_INT 3 -#define TIMER1INPUTCAPTURE_INT 4 -#define TIMER2OVERFLOW_INT 5 -#define TIMER2OUTCOMPARE_INT 6 -#ifdef OCR0 // for processors that support output compare on Timer0 -#define TIMER0OUTCOMPARE_INT 7 -#define TIMER_NUM_INTERRUPTS 8 -#else -#define TIMER_NUM_INTERRUPTS 7 -#endif - -// default type of interrupt handler to use for timers -// *do not change unless you know what you're doing -// Value may be SIGNAL or INTERRUPT -#ifndef TIMER_INTERRUPT_HANDLER -#define TIMER_INTERRUPT_HANDLER SIGNAL -#endif - -// functions -#define delay delay_us -#define delay_ms timerPause -void delay_us(unsigned short time_us); - -//! initializes timing system (all timers) -// runs all timer init functions -// sets all timers to default prescale values #defined in systimer.c -void timerInit(void); - -// default initialization routines for each timer -void timer0Init(void); ///< initialize timer0 -void timer1Init(void); ///< initialize timer1 -#ifdef TCNT2 // support timer2 only if it exists -void timer2Init(void); ///< initialize timer2 -#endif - -// Clock prescaler set/get commands for each timer/counter -// For setting the prescaler, you should use one of the #defines -// above like TIMER_CLK_DIVx, where [x] is the division rate -// you want. -// When getting the current prescaler setting, the return value -// will be the [x] division value currently set. -void timer0SetPrescaler(u08 prescale); ///< set timer0 prescaler -u16 timer0GetPrescaler(void); ///< get timer0 prescaler -void timer1SetPrescaler(u08 prescale); ///< set timer1 prescaler -u16 timer1GetPrescaler(void); ///< get timer0 prescaler -#ifdef TCNT2 // support timer2 only if it exists -void timer2SetPrescaler(u08 prescale); ///< set timer2 prescaler -u16 timer2GetPrescaler(void); ///< get timer2 prescaler -#endif - - -// TimerAttach and Detach commands -// These functions allow the attachment (or detachment) of any user function -// to a timer interrupt. "Attaching" one of your own functions to a timer -// interrupt means that it will be called whenever that interrupt happens. -// Using attach is better than rewriting the actual INTERRUPT() function -// because your code will still work and be compatible if the timer library -// is updated. Also, using Attach allows your code and any predefined timer -// code to work together and at the same time. (ie. "attaching" your own -// function to the timer0 overflow doesn't prevent timerPause from working, -// but rather allows you to share the interrupt.) -// -// timerAttach(TIMER1OVERFLOW_INT, myOverflowFunction); -// timerDetach(TIMER1OVERFLOW_INT) -// -// timerAttach causes the myOverflowFunction() to be attached, and therefore -// execute, whenever an overflow on timer1 occurs. timerDetach removes the -// association and executes no user function when the interrupt occurs. -// myOverflowFunction must be defined with no return value and no arguments: -// -// void myOverflowFunction(void) { ... } - -//! Attach a user function to a timer interrupt -void timerAttach(u08 interruptNum, void (*userFunc)(void) ); -//! Detach a user function from a timer interrupt -void timerDetach(u08 interruptNum); - - -// timing commands -//! timerPause pauses for the number of milliseconds specified in -void timerPause(unsigned short pause_ms); - -// overflow counters -void timer0ClearOverflowCount(void); ///< clear timer0's overflow counter -long timer0GetOverflowCount(void); ///< read timer0's overflow counter -#ifdef TCNT2 // support timer2 only if it exists -void timer2ClearOverflowCount(void); ///< clear timer2's overflow counter -long timer2GetOverflowCount(void); ///< read timer0's overflow counter -#endif - -// PWM initialization and set commands for timer1 -// timer1PWMInit() -// configures the timer1 hardware for PWM mode on pins OC1A and OC1B. -// bitRes should be 8,9,or 10 for 8,9,or 10bit PWM resolution -// -// timer1PWMOff() -// turns off all timer1 PWM output and set timer mode to normal state -// -// timer1PWMAOn() and timer1PWMBOn() -// turn on output of PWM signals to OC1A or OC1B pins -// NOTE: Until you define the OC1A and OC1B pins as outputs, and run -// this "on" command, no PWM output will be output -// -// timer1PWMAOff() and timer1PWMBOff() -// turn off output of PWM signals to OC1A or OC1B pins -// -// timer1PWMASet() and timer1PWMBSet() -// sets the PWM duty cycle for each channel -// NOTE: should be in the range 0-255 for 8bit PWM -// should be in the range 0-511 for 9bit PWM -// should be in the range 0-1023 for 10bit PWM -// NOTE: the PWM frequency can be controlled in increments by setting the -// prescaler for timer1 - -void timer1PWMInit(u08 bitRes); ///< initialize and set timer1 mode to PWM -void timer1PWMInitICR(u16 topcount);///< initialize and set timer1 mode to PWM with specific top count -void timer1PWMOff(void); ///< turn off all timer1 PWM output and set timer mode to normal -void timer1PWMAOn(void); ///< turn on timer1 Channel A (OC1A) PWM output -void timer1PWMBOn(void); ///< turn on timer1 Channel B (OC1B) PWM output -void timer1PWMAOff(void); ///< turn off timer1 Channel A (OC1A) PWM output -void timer1PWMBOff(void); ///< turn off timer1 Channel B (OC1B) PWM output -void timer1PWMASet(u16 pwmDuty); ///< set duty of timer1 Channel A (OC1A) PWM output -void timer1PWMBSet(u16 pwmDuty); ///< set duty of timer1 Channel B (OC1B) PWM output - -// Pulse generation commands have been moved to the pulse.c library - -#endif diff --git a/targets/arduino/wiring.c b/targets/arduino/wiring.c index 9f7d90c54..b202b9a3d 100755 --- a/targets/arduino/wiring.c +++ b/targets/arduino/wiring.c @@ -37,15 +37,8 @@ #endif // from Pascal's avrlib -#include "global.h" -//#include "a2d.h" -#include "timer.h" #include "uart.h" -// timer.h #defines delay to be delay_us, we need to undefine -// it so our delay can be in milliseconds. -#undef delay - #include "wiring.h" // The number of times timer 0 has overflowed since the program started. @@ -66,14 +59,9 @@ int digitalPinToBit(int pin) return digital_pin_to_port[pin].bit; } -int analogOutPinToPort(int pin) +int analogOutPinToTimer(int pin) { - return analog_out_pin_to_port[pin].port; -} - -int analogOutPinToBit(int pin) -{ - return analog_out_pin_to_port[pin].bit; + return analog_out_pin_to_timer[pin]; } int analogInPinToBit(int pin) @@ -81,26 +69,6 @@ int analogInPinToBit(int pin) return analog_in_pin_to_port[pin].bit; } -void timer2PWMOn() -{ - // configure timer 2 for normal (non-inverting) pwm operation - // this attaches the timer to the pwm pin - sbi(TCCR2, COM21); - cbi(TCCR2, COM20); -} - -void timer2PWMOff() -{ - // disconnect the timer from the pwm pin - cbi(TCCR2, COM21); - cbi(TCCR2, COM20); -} - -void timer2PWMSet(unsigned char val) -{ - OCR2 = val; -} - void pinMode(int pin, int mode) { if (digitalPinToPort(pin) != NOT_A_PIN) { @@ -119,14 +87,22 @@ void digitalWrite(int pin, int val) // If the pin that support PWM output, we need to turn it off // before doing a digital write. - if (analogOutPinToBit(pin) == 1) - timer1PWMAOff(); + if (analogOutPinToTimer(pin) == TIMER1A) + cbi(TCCR1A, COM1A1); - if (analogOutPinToBit(pin) == 2) - timer1PWMBOff(); - - if (analogOutPinToBit(pin) == 3) - timer2PWMOff(); + if (analogOutPinToTimer(pin) == TIMER1B) + cbi(TCCR1A, COM1B1); + +#if defined(__AVR_ATmega168__) + if (analogOutPinToTimer(pin) == TIMER2A) + cbi(TCCR2A, COM2A1); + + if (analogOutPinToTimer(pin) == TIMER2B) + cbi(TCCR2A, COM2B1); +#else + if (analogOutPinToTimer(pin) == TIMER2) + cbi(TCCR2, COM21); +#endif if (val == LOW) cbi(_SFR_IO8(port_to_output[digitalPinToPort(pin)]), @@ -143,14 +119,22 @@ int digitalRead(int pin) // If the pin that support PWM output, we need to turn it off // before getting a digital reading. - if (analogOutPinToBit(pin) == 1) - timer1PWMAOff(); + if (analogOutPinToTimer(pin) == TIMER1A) + cbi(TCCR1A, COM1A1); - if (analogOutPinToBit(pin) == 2) - timer1PWMBOff(); - - if (analogOutPinToBit(pin) == 3) - timer2PWMOff(); + if (analogOutPinToTimer(pin) == TIMER1B) + cbi(TCCR1A, COM1B1); + +#if defined(__AVR_ATmega168__) + if (analogOutPinToTimer(pin) == TIMER2A) + cbi(TCCR2A, COM2A1); + + if (analogOutPinToTimer(pin) == TIMER2B) + cbi(TCCR2A, COM2B1); +#else + if (analogOutPinToTimer(pin) == TIMER2) + cbi(TCCR2, COM21); +#endif return (_SFR_IO8(port_to_input[digitalPinToPort(pin)]) >> digitalPinToBit(pin)) & 0x01; @@ -197,18 +181,36 @@ void analogWrite(int pin, int val) // writing with them. Also, make sure the pin is in output mode // for consistenty with Wiring, which doesn't require a pinMode // call for the analog output pins. - if (analogOutPinToBit(pin) == 1) { - pinMode(pin, OUTPUT); - timer1PWMAOn(); - timer1PWMASet(val); - } else if (analogOutPinToBit(pin) == 2) { - pinMode(pin, OUTPUT); - timer1PWMBOn(); - timer1PWMBSet(val); - } else if (analogOutPinToBit(pin) == 3) { - pinMode(pin, OUTPUT); - timer2PWMOn(); - timer2PWMSet(val); + pinMode(pin, OUTPUT); + + if (analogOutPinToTimer(pin) == TIMER1A) { + // connect pwm to pin on timer 1, channel A + sbi(TCCR1A, COM1A1); + // set pwm duty + OCR1A = val; + } else if (analogOutPinToTimer(pin) == TIMER1B) { + // connect pwm to pin on timer 1, channel B + sbi(TCCR1A, COM1B1); + // set pwm duty + OCR1B = val; +#if defined(__AVR_ATmega168__) + } else if (analogOutPinToTimer(pin) == TIMER2A) { + // connect pwm to pin on timer 2, channel A + sbi(TCCR2A, COM2A1); + // set pwm duty + OCR2A = val; + } else if (analogOutPinToTimer(pin) == TIMER2B) { + // connect pwm to pin on timer 2, channel B + sbi(TCCR2A, COM2B1); + // set pwm duty + OCR2B = val; +#else + } else if (analogOutPinToTimer(pin) == TIMER2) { + // connect pwm to pin on timer 2, channel B + sbi(TCCR2, COM21); + // set pwm duty + OCR2 = val; +#endif } else if (val < 128) digitalWrite(pin, LOW); else @@ -319,7 +321,7 @@ void print(const char *format, ...) } */ -TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW0) +SIGNAL(SIG_OVERFLOW0) { timer0_overflow_count++; } @@ -434,30 +436,47 @@ unsigned long pulseIn(int pin, int state) int main(void) { // this needs to be called before setup() or some functions won't - // work there + // work there sei(); // timer 0 is used for millis() and delay() - //timer0Init(); timer0_overflow_count = 0; // set timer 0 prescale factor to 8 +#if defined(__AVR_ATmega168__) + sbi(TCCR0B, CS01); +#else sbi(TCCR0, CS01); +#endif // enable timer 0 overflow interrupt +#if defined(__AVR_ATmega168__) + sbi(TIMSK0, TOIE0); +#else sbi(TIMSK, TOIE0); +#endif - // timers 1 & 2 are used for the hardware pwm - timer1Init(); - //timer1SetPrescaler(TIMER_CLK_DIV1); - timer1PWMInit(8); - - timer2Init(); - - // configure timer 2 for phase correct pwm + // timers 1 and 2 are used for phase-correct hardware pwm // this is better for motors as it ensures an even waveform // note, however, that fast pwm mode can achieve a frequency of up // 8 MHz (with a 16 MHz clock) at 50% duty cycle - cbi(TCCR2, WGM21); + + // set timer 1 prescale factor to 64 + sbi(TCCR1B, CS11); + sbi(TCCR1B, CS10); + // put timer 1 in 8-bit phase correct pwm mode + sbi(TCCR1A, WGM10); + + // set timer 2 prescale factor to 64 +#if defined(__AVR_ATmega168__) + sbi(TCCR2B, CS22); +#else + sbi(TCCR2, CS22); +#endif + // configure timer 2 for phase correct pwm (8-bit) +#if defined(__AVR_ATmega168__) + sbi(TCCR2A, WGM20); +#else sbi(TCCR2, WGM20); +#endif // set a2d reference to AVCC (5 volts) cbi(ADMUX, REFS1); diff --git a/targets/arduino/wiring.h b/targets/arduino/wiring.h index b9ad6d0c5..cd61a5247 100755 --- a/targets/arduino/wiring.h +++ b/targets/arduino/wiring.h @@ -89,6 +89,15 @@ void loop(void); #define NOT_A_PIN 0 #define NOT_A_PORT -1 +#define NOT_ON_TIMER -1 +#define TIMER0A 0 +#define TIMER0B 1 +#define TIMER1A 2 +#define TIMER1B 3 +#define TIMER2 4 +#define TIMER2A 5 +#define TIMER2B 6 + typedef struct { int port; int bit; @@ -99,7 +108,7 @@ extern int port_to_input[]; extern int port_to_output[]; extern pin_t *digital_pin_to_port; extern pin_t *analog_in_pin_to_port; -extern pin_t *analog_out_pin_to_port; +extern int *analog_out_pin_to_timer; #ifdef __cplusplus } // extern "C"