diff --git a/apps/arduino/arduino-process.c b/apps/arduino/arduino-process.c index b7a87c0b3..f6945a9bc 100644 --- a/apps/arduino/arduino-process.c +++ b/apps/arduino/arduino-process.c @@ -51,6 +51,7 @@ #include "arduino-process.h" #include "hw_timer.h" +#include "adc.h" #include "hw-arduino.h" PROCESS(arduino_sketch, "Arduino Sketch Wrapper"); @@ -60,6 +61,7 @@ PROCESS_THREAD(arduino_sketch, ev, data) PROCESS_BEGIN(); arduino_pwm_timer_init (); + adc_init (); setup (); while (1) { loop (); diff --git a/dev/arduino/arduino-compat.h b/dev/arduino/arduino-compat.h index 23e417623..d3f9b58ac 100644 --- a/dev/arduino/arduino-compat.h +++ b/dev/arduino/arduino-compat.h @@ -84,6 +84,7 @@ extern "C" { #include "contiki.h" #include "hw_timer.h" +#include "adc.h" #ifdef __cplusplus } // extern "C" @@ -145,6 +146,43 @@ static inline void analogWrite(uint8_t pin, int val) } } +/* + * turnOffPWM of arduino is implemented by hw_timer + */ +#define turnOffPWM(atimer) \ + ( (atimer) == NOT_ON_TIMER \ + ? (void)0 \ + : (void)hwtimer_pwm_disable \ + (atimer >> HW_TIMER_SHIFT, atimer & HWT_CHANNEL_MASK) \ + ) + +/* + * micros on arduino takes timer overflows into account. + * We put in the seconds counter. To get a consistent seconds / ticks + * value we have to disable interrupts. + */ +static inline uint32_t micros (void) +{ + uint32_t ticks; + uint8_t sreg = SREG; + cli (); + ticks = clock_seconds () * 1000000L + + clock_time () * 1000L / CLOCK_SECOND; + SREG = sreg; + return ticks; +} +/* + * millis counts only internal timer ticks since start, not trying to do + * something about overflows. Note that we don't try to emulate overflow + * behaviour of arduino implementation. + */ +#define millis() (((uint32_t)clock_time())*1000L/CLOCK_SECOND) +#define micros() (clock_seconds()*1000L+ +#define delay(ms) clock_delay_msec(ms) +#define delayMicroseconds(us) clock_delay_usec(us) + +#define analogRead(analogpin) readADC(analogpin) + #ifdef __cplusplus } // extern "C" #endif diff --git a/examples/osd/arduino-sketch/led_pwm.h b/examples/osd/arduino-sketch/led_pwm.h index 6ace57f8d..31356fd78 100644 --- a/examples/osd/arduino-sketch/led_pwm.h +++ b/examples/osd/arduino-sketch/led_pwm.h @@ -21,10 +21,15 @@ #include "erbium.h" #include "er-coap-13.h" -extern uint8_t pwm; -extern uint8_t period_100ms; +extern uint8_t pwm; +extern uint8_t period_100ms; +extern uint16_t analog1_voltage; +extern uint16_t analog5_voltage; + extern resource_t resource_led_pwm; extern resource_t resource_led_period; +extern resource_t resource_analog1_voltage; +extern resource_t resource_analog5_voltage; #endif // led_pwm_h /** @} */ diff --git a/examples/osd/arduino-sketch/resource_led_pwm.c b/examples/osd/arduino-sketch/resource_led_pwm.c index 1cca70bf1..2ed1cdd78 100644 --- a/examples/osd/arduino-sketch/resource_led_pwm.c +++ b/examples/osd/arduino-sketch/resource_led_pwm.c @@ -69,6 +69,38 @@ GENERIC_RESOURCE \ , period_to_string ); +size_t +analog1_v (const char *name, uint8_t is_json, char *buf, size_t bufsize) +{ + return snprintf + (buf, bufsize, "%d.%03d", analog1_voltage / 1000, analog1_voltage % 1000); +} + +GENERIC_RESOURCE \ + ( analog1_voltage, METHOD_GET + , "analog/1" + , Analog 1 voltage + , V + , NULL + , analog1_v + ); + +size_t +analog5_v (const char *name, uint8_t is_json, char *buf, size_t bufsize) +{ + return snprintf + (buf, bufsize, "%d.%03d", analog5_voltage / 1000, analog5_voltage % 1000); +} + +GENERIC_RESOURCE \ + ( analog5_voltage, METHOD_GET + , "analog/5" + , Analog 5 voltage + , V + , NULL + , analog5_v + ); + /* * VI settings, see coding style * ex:ts=8:et:sw=2 diff --git a/examples/osd/arduino-sketch/sketch.pde b/examples/osd/arduino-sketch/sketch.pde index 4a1250796..13da7e6bb 100644 --- a/examples/osd/arduino-sketch/sketch.pde +++ b/examples/osd/arduino-sketch/sketch.pde @@ -15,8 +15,10 @@ extern "C" { #include "led_pwm.h" #define LED_PIN 5 -uint8_t pwm = 128; -uint8_t period_100ms = 10; /* one second */ +uint8_t pwm = 128; +uint8_t period_100ms = 10; /* one second */ +uint16_t analog1_voltage = 0; +uint16_t analog5_voltage = 0; } void setup (void) @@ -24,12 +26,16 @@ void setup (void) rest_init_engine (); rest_activate_resource (&resource_led_pwm); rest_activate_resource (&resource_led_period); + rest_activate_resource (&resource_analog1_voltage); + rest_activate_resource (&resource_analog5_voltage); } void loop (void) { /* Use 255 - pwm, LED on merkur-board is wired to +3.3V */ analogWrite (LED_PIN, 255 - pwm); + analog1_voltage = analogRead (1) * 1600L / 1023L; + analog5_voltage = analogRead (5) * 1600L / 1023L; printf ("clock : %u\nmillis: %lu\n", clock_time (), millis ()); delay (period_100ms * 100); analogWrite (LED_PIN, 255); /* OFF: LED on merkur-board is wired to +3.3V */ diff --git a/platform/osd-merkur/Makefile.osd-merkur b/platform/osd-merkur/Makefile.osd-merkur index 9650a201b..3fb160bdd 100644 --- a/platform/osd-merkur/Makefile.osd-merkur +++ b/platform/osd-merkur/Makefile.osd-merkur @@ -27,7 +27,7 @@ CONTIKI_TARGET_SOURCEFILES += servo.c servo-sensor.c #Needed for Relay 1 to 4 CONTIKI_TARGET_SOURCEFILES += relay.c relay-sensor.c # Arduino -CONTIKI_TARGET_SOURCEFILES += wiring_digital.c wiring_analog.c +CONTIKI_TARGET_SOURCEFILES += wiring_digital.c CONTIKIBOARD=. BOOTLOADER_START = 0x1F000 diff --git a/platform/osd-merkur/dev/Arduino.h b/platform/osd-merkur/dev/Arduino.h index 4d9208864..e0ea47b10 100644 --- a/platform/osd-merkur/dev/Arduino.h +++ b/platform/osd-merkur/dev/Arduino.h @@ -42,15 +42,8 @@ extern "C"{ #define FALLING 2 #define RISING 3 -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -#define INTERNAL1V1 2 -#define INTERNAL2V56 3 -#elif defined(__AVR_ATmega128RFA1__) -#else -#define INTERNAL 3 -#endif -#define DEFAULT 1 -#define EXTERNAL 0 +#define DEFAULT ADC_DEFAULT +#define EXTERNAL ADC_EXTERNAL // undefine stdlib's abs if encountered #ifdef abs @@ -85,18 +78,9 @@ typedef unsigned int word; typedef uint8_t boolean; typedef uint8_t byte; -/* - * This has been renamed from init to arduino_init, the original - * function name is way too generic. The arduino compatibility framework - * makes sure the correct function is called. - */ -void arduino_init(void); - void pinMode(uint8_t, uint8_t); void digitalWrite(uint8_t, uint8_t); int digitalRead(uint8_t); -int analogRead(uint8_t); -void analogReference(uint8_t mode); unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout); diff --git a/platform/osd-merkur/dev/adc.c b/platform/osd-merkur/dev/adc.c index 82c66411f..7efde72e1 100644 --- a/platform/osd-merkur/dev/adc.c +++ b/platform/osd-merkur/dev/adc.c @@ -36,33 +36,28 @@ * Paulo Louro */ -#include +#include "adc.h" -#ifndef cbi -#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) -#endif -#ifndef sbi -#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) -#endif +static uint8_t analog_reference = ADC_DEFAULT; + +/* + * For arduino interface for setting external reference voltage + * Note that applying an external voltage *and* then setting the analog + * reference to something internal will short the internal and the + * external reference voltage and most likely destroy the processor. + */ +void analogReference(uint8_t mode) +{ + analog_reference = mode; +} int readADC(uint8_t pin) { int result = 0; - if ( pin >= 14 ) - pin -= 14; - - ADMUX = _BV(REFS1) | _BV(REFS0) | ( pin & 7 ) ; - ADCSRA = _BV(ADEN) | _BV(ADPS0) | _BV(ADPS2) ; - sbi(ADCSRA,ADSC); - loop_until_bit_is_clear(ADCSRA,ADSC); - - - result = ADC; - - ADCSRA=0; //disable ADC - ADMUX=0; //turn off internal vref - + adc_setup (analog_reference, pin); + result = adc_read (); + adc_fin (); return result; } @@ -77,13 +72,13 @@ int readInternalTemp(void) ADMUX = _BV(REFS1) | _BV(REFS0) | 0b1001 ; ADCSRA = _BV(ADEN) | _BV(ADPS0) | _BV(ADPS2) ; - sbi(ADCSRA,ADSC); + ADCSRA |= 1 << ADSC; loop_until_bit_is_clear(ADCSRA,ADSC); reading = ADC; + ADCSRB=0; //disable ADC, need to write B first for MUX5 bit ADCSRA=0; //disable ADC - ADCSRB=0; //disable ADC ADMUX=0; //turn off internal vref return reading * 113 - 27280; -} \ No newline at end of file +} diff --git a/platform/osd-merkur/dev/adc.h b/platform/osd-merkur/dev/adc.h index ea851f237..6ea4cf0ab 100644 --- a/platform/osd-merkur/dev/adc.h +++ b/platform/osd-merkur/dev/adc.h @@ -1,8 +1,52 @@ #ifndef __ADC_ARCH_H__ #define __ADC_ARCH_H__ +#include + +/* + * Reference voltage + * The default is 1.6V reference voltage + * The selected reference voltage is the maximum voltage that can be + * measured. + * Directly provide shifted variants so we don't need to shift. + */ +#define ADC_1_5 (2<<6) +#define ADC_1_6 (3<<6) +#define ADC_1_8 (1<<6) +#define ADC_EXTERNAL (0<<6) +#define ADC_DEFAULT ADC_1_6 + +/* sometimes it's desirable to decouple setup / finish from sampling */ + +static inline void adc_setup (uint8_t ref_volt, uint8_t pin) +{ + ADMUX = ref_volt | (pin & 0x7); + ADCSRA = _BV(ADEN) | _BV(ADPS0) | _BV(ADPS2); +} + +static inline int adc_read (void) +{ + ADCSRA |= (1 << ADSC); + loop_until_bit_is_clear (ADCSRA, ADSC); + return ADC; +} + +static inline void adc_fin (void) +{ + ADCSRA = 0; + ADMUX = 0; +} + +static inline void adc_init (void) +{ + ADCSRC = 0; + ADCSRB = 0; + adc_fin (); +} + int readADC(uint8_t pin); long readVcc(); int readInternalTemp(void); +void analogReference(uint8_t mode); -#endif /* __ADC_ARCH_H__ */ \ No newline at end of file +#endif /* __ADC_ARCH_H__ */ diff --git a/platform/osd-merkur/dev/hw-arduino.h b/platform/osd-merkur/dev/hw-arduino.h index f59f8daf2..1894d23cc 100644 --- a/platform/osd-merkur/dev/hw-arduino.h +++ b/platform/osd-merkur/dev/hw-arduino.h @@ -71,32 +71,6 @@ extern "C"{ #define arduino_pwm_timer_init() \ (hwtimer_ini (3, HWT_WGM_PWM_PHASE_8_BIT, HWT_CLOCK_PRESCALER_64, 0)) -/* - * micros on arduino takes timer overflows into account. - * We put in the seconds counter. To get a consistent seconds / ticks - * value we have to disable interrupts. - */ -static inline uint32_t micros (void) -{ - uint32_t ticks; - uint8_t sreg = SREG; - cli (); - ticks = clock_seconds () * 1000000L - + clock_time () * 1000L / CLOCK_SECOND; - SREG = sreg; - return ticks; -} -/* - * millis counts only internal timer ticks since start, not trying to do - * something about overflows. Note that we don't try to emulate overflow - * behaviour of arduino implementation. - */ -#define millis() (((uint32_t)clock_time())*1000L/CLOCK_SECOND) -#define micros() (clock_seconds()*1000L+ -#define delay(ms) clock_delay_msec(ms) -#define delayMicroseconds(us) clock_delay_usec(us) - - /* * VI settings, see coding style * ex:ts=8:et:sw=2 diff --git a/platform/osd-merkur/dev/wiring_analog.c b/platform/osd-merkur/dev/wiring_analog.c deleted file mode 100644 index 630e95721..000000000 --- a/platform/osd-merkur/dev/wiring_analog.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - wiring_analog.c - analog input and output - Part of Arduino - http://www.arduino.cc/ - - Copyright (c) 2005-2006 David A. Mellis - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA - - Modified 28 September 2010 by Mark Sproul - - $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ -*/ - -#include "wiring_private.h" -#include "pins_arduino.h" -#include "adc.h" - -uint8_t analog_reference = DEFAULT; - -void analogReference(uint8_t mode) -{ - // can't actually set the register here because the default setting - // will connect AVCC and the AREF pin, which would cause a short if - // there's something connected to AREF. - analog_reference = mode; -} - -int analogRead(uint8_t pin) -{ - return readADC(pin); -} - -/* - * analogWrite is now implemented in dev/arduino/arduino-compat.h - */ diff --git a/platform/osd-merkur/dev/wiring_digital.c b/platform/osd-merkur/dev/wiring_digital.c index cac0a7b12..75b6745d6 100644 --- a/platform/osd-merkur/dev/wiring_digital.c +++ b/platform/osd-merkur/dev/wiring_digital.c @@ -60,83 +60,6 @@ void pinMode(uint8_t pin, uint8_t mode) } } -// Forcing this inline keeps the callers from having to push their own stuff -// on the stack. It is a good performance win and only takes 1 more byte per -// user than calling. (It will take more bytes on the 168.) -// -// But shouldn't this be moved into pinMode? Seems silly to check and do on -// each digitalread or write. -// -// Mark Sproul: -// - Removed inline. Save 170 bytes on atmega1280 -// - changed to a switch statment; added 32 bytes but much easier to read and maintain. -// - Added more #ifdefs, now compiles for atmega645 -// -//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline)); -//static inline void turnOffPWM(uint8_t timer) -static void turnOffPWM(uint8_t timer) -{ - switch (timer) - { - #if defined(TCCR1A) && defined(COM1A1) - case TIMER1A: cbi(TCCR1A, COM1A1); break; - #endif - #if defined(TCCR1A) && defined(COM1B1) - case TIMER1B: cbi(TCCR1A, COM1B1); break; - #endif - #if defined(TCCR1A) && defined(COM1B1) - case TIMER1C: cbi(TCCR1A, COM1C1); break; - #endif - - #if defined(TCCR2) && defined(COM21) - case TIMER2: cbi(TCCR2, COM21); break; - #endif - - #if defined(TCCR0A) && defined(COM0A1) - case TIMER0A: cbi(TCCR0A, COM0A1); break; - #endif - - #if defined(TIMER0B) && defined(COM0B1) - case TIMER0B: cbi(TCCR0A, COM0B1); break; - #endif - #if defined(TCCR2A) && defined(COM2A1) - case TIMER2A: cbi(TCCR2A, COM2A1); break; - #endif - #if defined(TCCR2A) && defined(COM2B1) - case TIMER2B: cbi(TCCR2A, COM2B1); break; - #endif - - #if defined(TCCR3A) && defined(COM3A1) - case TIMER3A: cbi(TCCR3A, COM3A1); break; - #endif - #if defined(TCCR3A) && defined(COM3B1) - case TIMER3B: cbi(TCCR3A, COM3B1); break; - #endif - #if defined(TCCR3A) && defined(COM3C1) - case TIMER3C: cbi(TCCR3A, COM3C1); break; - #endif - - #if defined(TCCR4A) && defined(COM4A1) - case TIMER4A: cbi(TCCR4A, COM4A1); break; - #endif - #if defined(TCCR4A) && defined(COM4B1) - case TIMER4B: cbi(TCCR4A, COM4B1); break; - #endif - #if defined(TCCR4A) && defined(COM4C1) - case TIMER4C: cbi(TCCR4A, COM4C1); break; - #endif - #if defined(TCCR4C) && defined(COM4D1) - case TIMER4D: cbi(TCCR4C, COM4D1); break; - #endif - - #if defined(TCCR5A) - case TIMER5A: cbi(TCCR5A, COM5A1); break; - case TIMER5B: cbi(TCCR5A, COM5B1); break; - case TIMER5C: cbi(TCCR5A, COM5C1); break; - #endif - } -} - void digitalWrite(uint8_t pin, uint8_t val) { uint8_t timer = digitalPinToTimer(pin);