diff --git a/cpu/avr/Makefile.avr b/cpu/avr/Makefile.avr index f1b09e82f..2656054a3 100644 --- a/cpu/avr/Makefile.avr +++ b/cpu/avr/Makefile.avr @@ -13,7 +13,9 @@ CONTIKI_CPU=$(CONTIKI)/cpu/avr ### These directories will be searched for the specified source files ### TARGETLIBS are platform-specific routines in the contiki library path CONTIKI_CPU_DIRS = . dev -AVR = clock.c mtarch.c eeprom.c flash.c rs232.c leds-arch.c watchdog.c rtimer-arch.c bootloader.c +AVR = clock.c mtarch.c eeprom.c flash.c rs232.c leds-arch.c \ + watchdog.c rtimer-arch.c bootloader.c hw_timer.c \ + hw_pwm_timer.c ELFLOADER = elfloader.c elfloader-avr.c symtab-avr.c TARGETLIBS = random.c leds.c diff --git a/cpu/avr/hw_pwm_timer.c b/cpu/avr/hw_pwm_timer.c new file mode 100644 index 000000000..2c45ce729 --- /dev/null +++ b/cpu/avr/hw_pwm_timer.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2014, Ralf Schlatterbeck Open Source Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \addgroup hardware timer + * + * @{ + */ + +/** + * \file + * Alternative initialisation with period in microseconds + * \author + * Ralf Schlatterbeck + */ + +#include +#include "contiki.h" +#include "rtimer-arch.h" +#include "hw_timer.h" + +/* one for each possible timer */ +uint16_t hwt_max_ticks [6]; + +#define PERIOD_MAX (0xFFFFFFFF / (F_CPU / 1000000)) +/* for 16-bit timer: */ +#define TICKS_MAX 0xFFFF +#define TICKS_MIN 0xFF + +int8_t +hwtimer_pwm_ini (uint8_t timer, uint32_t period_us, uint8_t pwm_type, uint8_t ocra) +{ + uint32_t ticks = 0; + uint8_t clock = HWT_CLOCK_PRESCALER_1024; + uint8_t wgm = HWT_WGM_NORMAL; + HWT_CHECK_TIMER (timer); + if (period_us > PERIOD_MAX) { + period_us = PERIOD_MAX; + } + ticks = (F_CPU / 1000000) * period_us; + /* Non-fast PWM modes have half the frequency */ + if (pwm_type != HWT_PWM_FAST) { + ticks >>= 1; + } + + /* + * Divisors are 1, 8, 64, 256, 1024, shifts between these are + * 3, 3, 2, 2, respectively. We modify `ticks` in place, the AVR can + * shift only one bit in one instruction, so shifting isn't cheap. + * We try to get the *maximum* prescaler that still permits a tick + * resolution of at least 8 bit. + */ + if (ticks <= (TICKS_MIN << 3)) { + clock = HWT_CLOCK_PRESCALER_1; + } + else if ((ticks >>= 3) <= (TICKS_MIN << 3)) { + clock = HWT_CLOCK_PRESCALER_8; + } + else if ((ticks >>= 3) <= (TICKS_MIN << 2)) { + clock = HWT_CLOCK_PRESCALER_64; + } + else if ((ticks >>= 2) <= (TICKS_MIN << 2)) { + clock = HWT_CLOCK_PRESCALER_256; + } + else if ((ticks >>= 2) > TICKS_MAX) { + ticks = TICKS_MAX; + } + hwt_max_ticks [timer] = ticks; + switch (pwm_type) { + case HWT_PWM_FAST: + wgm = ocra ? HWT_WGM_PWM_FAST_OCRA : HWT_WGM_PWM_FAST_ICR; + break; + case HWT_PWM_PHASE_CORRECT: + wgm = ocra ? HWT_WGM_PWM_PHASE_OCRA : HWT_WGM_PWM_PHASE_ICR; + break; + case HWT_PWM_PHASE_FRQ_CORRECT: + default: + wgm = ocra ? HWT_WGM_PWM_PHASE_FRQ_OCRA : HWT_WGM_PWM_PHASE_FRQ_ICR; + break; + } + /* Special 8- 9- 10-bit modes */ + if (pwm_type == HWT_PWM_FAST || pwm_type == HWT_PWM_PHASE_CORRECT) { + if (ticks == 0xFF) { + wgm = (pwm_type == HWT_PWM_FAST) + ? HWT_WGM_PWM_FAST_8_BIT + : HWT_WGM_PWM_PHASE_8_BIT; + } + else if (ticks == 0x1FF) { + wgm = (pwm_type == HWT_PWM_FAST) + ? HWT_WGM_PWM_FAST_9_BIT + : HWT_WGM_PWM_PHASE_9_BIT; + } + else if (ticks == 0x3FF) { + wgm = (pwm_type == HWT_PWM_FAST) + ? HWT_WGM_PWM_FAST_10_BIT + : HWT_WGM_PWM_PHASE_10_BIT; + } + } + return hwtimer_ini (timer, wgm, clock, ticks); +} + +uint32_t hwtimer_pwm_max_ticks (uint8_t timer) +{ + if (timer > 5) { + return 0; + } + return hwt_max_ticks [timer]; +} + +/* + * ex:ts=8:et:sw=2 + */ + +/** @} */ diff --git a/cpu/avr/hw_timer.c b/cpu/avr/hw_timer.c new file mode 100644 index 000000000..f3ec11930 --- /dev/null +++ b/cpu/avr/hw_timer.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014, Ralf Schlatterbeck Open Source Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \addgroup hardware timer + * + * @{ + */ + +/** + * \file + * Header file for hardware timer of AVR microcontrollers + * \author + * Ralf Schlatterbeck + */ + +#include +#include "contiki.h" +#include "rtimer-arch.h" +#include "hw_timer.h" + +#ifndef PLAT_TIMER +#define PLAT_TIMER 0xFF /* invalid timer for comparison */ +#endif + +int8_t hwtimer_ini (uint8_t timer, uint8_t wgm, uint8_t clock, uint16_t maxt) +{ + int8_t i; + HWT_CHECK_TIMER (timer); + if (wgm > HWT_WGM_MASK || wgm == HWT_WGM_RESERVED) { + return HWT_ERR_INVALID_WGM; + } + if (clock > HWT_CLOCK_MASK) { + return HWT_ERR_INVALID_CLOCK; + } + /* Turn off clock, no need to disable interrupt */ + *HWT_TCCRB (timer) &= ~HWT_CLOCK_MASK; + + *HWT_TCCRA (timer) &= ~(HWT_WGM_MASK_LOW << HWT_WGM_SHIFT_LOW); + *HWT_TCCRA (timer) |= ((wgm & HWT_WGM_MASK_LOW) << HWT_WGM_SHIFT_LOW); + *HWT_TCCRB (timer) &= ~(HWT_WGM_MASK_HIGH << HWT_WGM_SHIFT_HIGH); + *HWT_TCCRB (timer) |= ((wgm & HWT_WGM_MASK_HIGH) << HWT_WGM_SHIFT_HIGH); + + for (i=0; i<3; i++) { + HWT_SET_COM (timer, i, HWT_COM_NORMAL); + } + + if ( wgm == HWT_WGM_PWM_PHASE_FRQ_ICR + || wgm == HWT_WGM_PWM_PHASE_ICR + || wgm == HWT_WGM_CTC_ICR + || wgm == HWT_WGM_PWM_FAST_ICR + ) + { + *HWT_ICR (timer) = maxt; + } + + if ( wgm == HWT_WGM_CTC_OCRA + || wgm == HWT_WGM_PWM_PHASE_FRQ_OCRA + || wgm == HWT_WGM_PWM_PHASE_OCRA + || wgm == HWT_WGM_PWM_FAST_OCRA + ) + { + *HWT_OCRA (timer) = maxt; + } + + /* Set clock, finally */ + *HWT_TCCRB (timer) |= clock; + return 0; +} + +/* + * ex:ts=8:et:sw=2 + */ + +/** @} */ diff --git a/cpu/avr/hw_timer.h b/cpu/avr/hw_timer.h new file mode 100644 index 000000000..3b98566ce --- /dev/null +++ b/cpu/avr/hw_timer.h @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2014, Ralf Schlatterbeck Open Source Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \defgroup hardware timer + * + * This module wraps hardware timers of AVR microcontrollers. + * Currently we only support 16-bit timers. The main focus is currently + * on PWM generation. But input capture and interrupt routines are on + * the TODO list, see below. We currently support the AVR ATmega128RFA1 + * so this should be generalized to supported timers of other AVR + * microcontrollers. + * + * Datasheet references in the following refer to ATmega128RFA1 data sheet + * + * TODO: Allow input capture. + * TODO: Allow definition of interrupt routine; check if merkur board + * supports necessary pins. + * TODO: Generalize for 8-bit timers. + * TODO: Check other AVR microcontrollers and the supported timers. + * + * @{ + */ + +/** + * \file + * Header file for hardware timer of AVR microcontrollers + * \author + * Ralf Schlatterbeck + * + */ + +#ifndef hw_timer_h +#define hw_timer_h + +#include "contiki.h" +#include "rtimer-arch.h" + +#ifndef PLAT_TIMER +#define PLAT_TIMER -1 +#endif + +/* + * All routines return a negative number for error and 0 for success. + * The negative return value indicates the error. + */ +#define HWT_ERR_INVALID_TIMER (-1) +#define HWT_ERR_INVALID_WGM (-2) +#define HWT_ERR_INVALID_COM (-3) +#define HWT_ERR_INVALID_CLOCK (-4) +#define HWT_ERR_INVALID_CHANNEL (-5) + +/* + * Timer waveform generation modes (WGM), see data sheet + * chapter 18 "16-bit Timer/Counter (Timer/Counter 1,3,4, and 5) + * 18.9 "Modes of Operation", in particular Table 18-5 + */ +#define HWT_WGM_NORMAL 0 +#define HWT_WGM_PWM_PHASE_8_BIT 1 +#define HWT_WGM_PWM_PHASE_9_BIT 2 +#define HWT_WGM_PWM_PHASE_10_BIT 3 +#define HWT_WGM_CTC_OCRA 4 +#define HWT_WGM_PWM_FAST_8_BIT 5 +#define HWT_WGM_PWM_FAST_9_BIT 6 +#define HWT_WGM_PWM_FAST_10_BIT 7 +#define HWT_WGM_PWM_PHASE_FRQ_ICR 8 +#define HWT_WGM_PWM_PHASE_FRQ_OCRA 9 +#define HWT_WGM_PWM_PHASE_ICR 10 +#define HWT_WGM_PWM_PHASE_OCRA 11 +#define HWT_WGM_CTC_ICR 12 +#define HWT_WGM_RESERVED 13 +#define HWT_WGM_PWM_FAST_ICR 14 +#define HWT_WGM_PWM_FAST_OCRA 15 +#define HWT_WGM_MASK 15 +#define HWT_WGM_MASK_LOW 3 +#define HWT_WGM_MASK_HIGH (HWT_WGM_MASK - HWT_WGM_MASK_LOW) +#define HWT_WGM_SHIFT_LOW 0 +#define HWT_WGM_SHIFT_HIGH 1 + +/* + * Timer compare output modes (COM), + * chapter 18 "16-bit Timer/Counter (Timer/Counter 1,3,4, and 5) + * 18.8 "Compare Match Output Unit", in particular Tables 18-2,3,4 + */ +#define HWT_COM_NORMAL 0 +#define HWT_COM_TOGGLE 1 +#define HWT_COM_CLEAR 2 +#define HWT_COM_SET 3 +#define HWT_COM_MASK 3 + +/* + * Clock select, clock can be off, use prescaler or external clock + * source on Tn pin. See Table 18-11 (for Timer 1 but this is the same + * for all the timers). + */ +#define HWT_CLOCK_OFF 0 +#define HWT_CLOCK_PRESCALER_1 1 +#define HWT_CLOCK_PRESCALER_8 2 +#define HWT_CLOCK_PRESCALER_64 3 +#define HWT_CLOCK_PRESCALER_256 4 +#define HWT_CLOCK_PRESCALER_1024 5 +#define HWT_CLOCK_EXTERN_FALLING 6 +#define HWT_CLOCK_EXTERN_RISING 7 +#define HWT_CLOCK_MASK 7 + +/* + * Timer channels A B C + */ +#define HWT_CHANNEL_A 0 +#define HWT_CHANNEL_B 1 +#define HWT_CHANNEL_C 2 + +/* The following macros are defined for timer values 1,3,4,5 */ +#define HWT_ICR(t) \ + ((t)<4?((t)==1?(&ICR1) :(&ICR3)) :((t)==4?(&ICR4) :(&ICR5))) +#define HWT_OCRA(t) \ + ((t)<4?((t)==1?(&OCR1A):(&OCR3A)):((t)==4?(&OCR4A):(&OCR5A))) +#define HWT_OCRB(t) \ + ((t)<4?((t)==1?(&OCR1B):(&OCR3B)):((t)==4?(&OCR4B):(&OCR5B))) +#define HWT_OCRC(t) \ + ((t)<4?((t)==1?(&OCR1C):(&OCR3C)):((t)==4?(&OCR4C):(&OCR5C))) + +#define HWT_OCR(t,c) \ + ( (c)==HWT_CHANNEL_A \ + ? (HWT_OCRA(t)) \ + : ((c)==HWT_CHANNEL_B?HWT_OCRB(t):HWT_OCRC(t)) \ + ) + +#define HWT_TCCRA(t) \ + ( (t)<4 \ + ? ((t)==1?(&TCCR1A):(&TCCR3A)) \ + : ((t)==4?(&TCCR4A):(&TCCR5A)) \ + ) +#define HWT_TCCRB(t) \ + ( (t)<4 \ + ? ((t)==1?(&TCCR1B):(&TCCR3B)) \ + : ((t)==4?(&TCCR4B):(&TCCR5B)) \ + ) +#define HWT_TCCRC(t) \ + ( (t)<4 \ + ? ((t)==1?(&TCCR1C):(&TCCR3C)) \ + : ((t)==4?(&TCCR4C):(&TCCR5C)) \ + ) +#define HWT_TCNT(t) \ + ( (t)<4 \ + ? ((t)==1?(&TCNT1) :(&TCNT3)) \ + : ((t)==4?(&TCNT4) :(&TCNT5)) \ + ) + +#define HWT_SET_COM(timer, channel, com) \ + ((*HWT_TCCRA (timer) &= ~(HWT_COM_MASK << (6 - 2 * (channel)))) \ + ,(*HWT_TCCRA (timer) |= ((com) << (6 - 2 * (channel)))) \ + ) + +#define HWT_CHECK_TIMER(timer) \ + do { \ + if ((timer) == 0 || (timer) == 2 || (timer) == PLAT_TIMER || (timer) > 5) {\ + return HWT_ERR_INVALID_TIMER; \ + } \ + } while (0) + +#define HWT_CHECK_CHANNEL(chan) \ + do { \ + if ((chan) > HWT_CHANNEL_C) { \ + return HWT_ERR_INVALID_CHANNEL; \ + } \ + } while (0) + +#define HWT_PWM_FAST 0 +#define HWT_PWM_PHASE_CORRECT 1 +#define HWT_PWM_PHASE_FRQ_CORRECT 2 + +/** + * \brief Initialize the hardware timer with the given settings + * \param timer: Timer to use + * \param wgm: waveform generation mode to use, see definitions + * \param clock: Prescaler or external clock settings + * \param maxt: Maximum counter value, not used for fixed modes, this + * sets ICRn for the ICR modes and OCRnA for the OCR modes + * \return see HWT_ERR definitions for return codes, returns 0 if ok + * + * The initial compare output mode is set to HWT_COM_NORMAL (off) for + * all outputs (pwm disabled). + * + * Note that this sets the compare output mode COM registers to 0, + * turning off PWM on outputs. + */ +int8_t hwtimer_ini (uint8_t timer, uint8_t wgm, uint8_t clock, uint16_t maxt); + +/** + * \brief Convenience function to initialize hardware timer for PWM + * \param timer: Timer to use + * \param pwm_type: See HWT_PWM* macros + * \param period_us: Period of the timer in µs + * \param ocra: Use OCRnA register if set, ICRn otherwise + * \return see HWT_ERR definitions for return codes, returns 0 if ok + * + * This function can be called instead of hwtimer_ini and sets up the + * timer for one of the PWM modes. There are fast, phase-correct and + * phase- and frequency correct modes, refer to the datasheet for + * semantics. + * + * The function tries to initialize the timer to a mode that doesn't use + * one of the internal registers OCRnA or ICRn for specifying the upper + * bound of the counter. For fast PWM and phase-correct PWM there are + * fixed 8-, 9-, and 10-bit modes that can be used if the computed value + * fits one of these setups. + * + * We try to get the *maximum* prescaler that still permits a tick + * resolution of at least 8 bit. This will not work for very high + * frequencies. + * + * If the specified period is too large to fit into a 16-bit timer we + * take the maximum period that is still possible, this may be + * substatially higher than specified. + * + * Note that when using OCRnA for the upper bound of the counter, the + * pin associated with this register can not be used for PWM. Instead it + * can be used to change the period. + */ +int8_t +hwtimer_pwm_ini (uint8_t timer, uint32_t period_us, uint8_t pwm_type, uint8_t ocra); + +/* + * Simple init macro for sane default values + */ +#define hwtimer_pwm_ini_simple (timer, period_us) \ + hwtimer_pwm_ini ((timer), HWT_PWM_PHASE_CORRECT, (period_us), 0) + +/** + * \brief Maximum timer value usable in hwtimer_set_pwm + * \param timer: Timer to use + * \return + * + * + */ +uint32_t hwtimer_pwm_max_ticks (uint8_t timer); + +/* + * The following functions are defined inline to allow for compiler + * optimizations if some of the parameters are constant. + */ + +/** + * \brief Set PWM duty cycle + * \param timer: Timer to use + * \param channel: Channel to use, see HWT_CHANNEL definitions + * \param pwm: Duty cycle + * \return see HWT_ERR definitions for return codes, returns 0 if ok + * + * Note that the available range for the duty cycle depends on the timer + * setup and the chosen mode. + */ +static inline int8_t +hwtimer_set_pwm (uint8_t timer, uint8_t channel, uint16_t pwm) +{ + uint8_t sreg = 0; + HWT_CHECK_TIMER (timer); + HWT_CHECK_CHANNEL (channel); + sreg = SREG; + cli (); + *HWT_OCR (timer, channel) = pwm; + SREG = sreg; + return 0; +} + +/** + * \brief Set compare output mode + * \param timer: Timer to use + * \param channel: Channel to use, see HWT_CHANNEL definitions + * \param com: compare output mode for given channel + * \return see HWT_ERR definitions for return codes, returns 0 if ok + */ +static inline int8_t +hwtimer_set_com (uint8_t timer, uint8_t channel, uint8_t com) +{ + HWT_CHECK_TIMER (timer); + HWT_CHECK_CHANNEL (channel); + if (com > HWT_COM_MASK) { + return HWT_ERR_INVALID_COM; + } + HWT_SET_COM (timer, channel, com); + return 0; +} + +/** + * \brief Convenience function for setting compare output mode for PWM + * \param timer: Timer to use + * \param channel: Channel to use, see HWT_CHANNEL definitions + * \return see HWT_ERR definitions for return codes, returns 0 if ok + */ +static inline int8_t +hwtimer_pwm_enable (uint8_t timer, uint8_t channel) +{ + return hwtimer_set_com (timer, channel, HWT_COM_CLEAR); +} + +/** + * \brief Convenience function for inverse compare output mode for PWM + * \param timer: Timer to use + * \param channel: Channel to use, see HWT_CHANNEL definitions + * \return see HWT_ERR definitions for return codes, returns 0 if ok + */ +static inline int8_t +hwtimer_pwm_inverse (uint8_t timer, uint8_t channel) +{ + return hwtimer_set_com (timer, channel, HWT_COM_SET); +} + +/** + * \brief Convenience function for setting compare output mode to off + * \param timer: Timer to use + * \param channel: Channel to use, see HWT_CHANNEL definitions + * \return see HWT_ERR definitions for return codes, returns 0 if ok + */ +static inline int8_t +hwtimer_pwm_disable (uint8_t timer, uint8_t channel) +{ + return hwtimer_set_com (timer, channel, HWT_COM_NORMAL); +} + +/** + * \brief Turn off the clock + * \param timer: Timer to use + * \return see HWT_ERR definitions for return codes, returns 0 if ok + */ +static inline int8_t +hwtimer_fin (uint8_t timer) +{ + HWT_CHECK_TIMER (timer); + *HWT_TCCRB (timer) &= ~HWT_CLOCK_MASK; + *HWT_TCCRB (timer) |= HWT_CLOCK_OFF; /* technically not necessary this is 0 */ + return 0; +} + +#endif /* hw_timer_h */ + +/* + * ex:ts=8:et:sw=2 + */ + +/** @} */ diff --git a/examples/osd/pwm-example/.gitignore b/examples/osd/pwm-example/.gitignore new file mode 100644 index 000000000..5761abcfd --- /dev/null +++ b/examples/osd/pwm-example/.gitignore @@ -0,0 +1 @@ +*.o diff --git a/examples/osd/pwm-example/Makefile b/examples/osd/pwm-example/Makefile new file mode 100644 index 000000000..480983734 --- /dev/null +++ b/examples/osd/pwm-example/Makefile @@ -0,0 +1,99 @@ +all: er-example-server \ + er-example-server.osd-merkur.hex er-example-server.osd-merkur.eep +# use this target explicitly if requried: er-plugtest-server + +# variable for this Makefile +# configure CoAP implementation (3|7|12|13) (er-coap-07 also supports CoAP draft 08) +WITH_COAP=13 + +# for some platforms +UIP_CONF_IPV6=1 +# IPv6 make config disappeared completely +CFLAGS += -DUIP_CONF_IPV6=1 + +CONTIKI=../../.. +CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\" + +PROJECT_SOURCEFILES += resource_led_pwm.c + +# variable for Makefile.include +ifneq ($(TARGET), minimal-net) +CFLAGS += -DUIP_CONF_IPV6_RPL=1 +else +# minimal-net does not support RPL under Linux and is mostly used to test CoAP only +${info INFO: compiling without RPL} +CFLAGS += -DUIP_CONF_IPV6_RPL=0 +CFLAGS += -DHARD_CODED_ADDRESS=\"fdfd::10\" +${info INFO: compiling with large buffers} +CFLAGS += -DUIP_CONF_BUFFER_SIZE=2048 +CFLAGS += -DREST_MAX_CHUNK_SIZE=1024 +CFLAGS += -DCOAP_MAX_HEADER_SIZE=640 +endif + +# linker optimizations +SMALL=1 + +# REST framework, requires WITH_COAP +ifeq ($(WITH_COAP), 13) +${info INFO: compiling with CoAP-13} +CFLAGS += -DWITH_COAP=13 +CFLAGS += -DREST=coap_rest_implementation +CFLAGS += -DUIP_CONF_TCP=0 +APPS += er-coap-13 +else ifeq ($(WITH_COAP), 12) +${info INFO: compiling with CoAP-12} +CFLAGS += -DWITH_COAP=12 +CFLAGS += -DREST=coap_rest_implementation +CFLAGS += -DUIP_CONF_TCP=0 +APPS += er-coap-12 +else ifeq ($(WITH_COAP), 7) +${info INFO: compiling with CoAP-08} +CFLAGS += -DWITH_COAP=7 +CFLAGS += -DREST=coap_rest_implementation +CFLAGS += -DUIP_CONF_TCP=0 +APPS += er-coap-07 +else ifeq ($(WITH_COAP), 3) +${info INFO: compiling with CoAP-03} +CFLAGS += -DWITH_COAP=3 +CFLAGS += -DREST=coap_rest_implementation +CFLAGS += -DUIP_CONF_TCP=0 +APPS += er-coap-03 +else +${info INFO: compiling with HTTP} +CFLAGS += -DWITH_HTTP +CFLAGS += -DREST=http_rest_implementation +CFLAGS += -DUIP_CONF_TCP=1 +APPS += er-http-engine +endif + +APPS += erbium json + +include $(CONTIKI)/Makefile.include + +er-example-server.osd-merkur.hex: er-example-server.osd-merkur + avr-objcopy -j .text -j .data -O ihex er-example-server.osd-merkur \ + er-example-server.osd-merkur.hex + +er-example-server.osd-merkur.eep: er-example-server.osd-merkur + avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O ihex \ + er-example-server.osd-merkur er-example-server.osd-merkur.eep + +flash: er-example-server.osd-merkur.hex er-example-server.osd-merkur.eep + avrdude -pm128rfa1 -c arduino -P/dev/ttyUSB0 -b57600 -e -U \ + flash:w:er-example-server.osd-merkur.hex:a -U \ + eeprom:w:er-example-server.osd-merkur.eep:a + +.PHONY: flash + +$(CONTIKI)/tools/tunslip6: $(CONTIKI)/tools/tunslip6.c + (cd $(CONTIKI)/tools && $(MAKE) tunslip6) + +connect-router: $(CONTIKI)/tools/tunslip6 + sudo $(CONTIKI)/tools/tunslip6 aaaa::1/64 + +connect-router-cooja: $(CONTIKI)/tools/tunslip6 + sudo $(CONTIKI)/tools/tunslip6 -a 127.0.0.1 aaaa::1/64 + +connect-minimal: + sudo ip address add fdfd::1/64 dev tap0 diff --git a/examples/osd/pwm-example/er-example-server.c b/examples/osd/pwm-example/er-example-server.c new file mode 100644 index 000000000..6f6fddbbb --- /dev/null +++ b/examples/osd/pwm-example/er-example-server.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2011, Matthias Kovatsch and other contributors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Erbium (Er) PWM REST Engine example (with CoAP-specific code) + * \author + * Matthias Kovatsch + * Ralf Schlatterbeck + */ + +#include +#include +#include +#include "contiki.h" +#include "contiki-net.h" +#include "jsonparse.h" + +#include "erbium.h" +#include "er-coap-13.h" + +#include "led_pwm.h" + +#define DEBUG 1 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +/******************************************************************************/ + +/* + * Resources are defined by the RESOURCE macro. + * Signature: resource name, the RESTful methods it handles, and its URI + * path (omitting the leading slash). + */ +RESOURCE(info, METHOD_GET, "info", "title=\"Info\";rt=\"text\""); + +/* + * A handler function named [resource name]_handler must be implemented + * for each RESOURCE. A buffer for the response payload is provided + * through the buffer pointer. Simple resources can ignore + * preferred_size and offset, but must respect the REST_MAX_CHUNK_SIZE + * limit for the buffer. If a smaller block size is requested for CoAP, + * the REST framework automatically splits the data. + */ +void +info_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + char message[100]; + int index = 0; + int length = 0; /* |<-------->| */ + + /* + * Some data that has the length up to REST_MAX_CHUNK_SIZE. For more, + * see the chunk resource. + */ + // jSON Format + index += sprintf(message + index,"{\n \"Version\" : \"V1.0pre1\",\n"); + index += sprintf(message + index," \"name\" : \"PWM\"\n"); + index += sprintf(message + index,"}\n"); + + length = strlen(message); + memcpy(buffer, message,length ); + + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + REST.set_response_payload(response, buffer, length); +} + +void +hw_init() +{ + led_pwm_init (); +} + +PROCESS(rest_server_example, "Erbium Example Server"); + +AUTOSTART_PROCESSES(&rest_server_example); + +PROCESS_THREAD(rest_server_example, ev, data) +{ + PROCESS_BEGIN(); + PRINTF("Starting Erbium Example Server\n"); + +#ifdef RF_CHANNEL + PRINTF("RF channel: %u\n", RF_CHANNEL); +#endif +#ifdef IEEE802154_PANID + PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); +#endif + + PRINTF("uIP buffer: %u\n", UIP_BUFSIZE); + PRINTF("LL header: %u\n", UIP_LLH_LEN); + PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); + PRINTF("REST max chunk: %u\n", REST_MAX_CHUNK_SIZE); + +/* if static routes are used rather than RPL */ +#if !UIP_CONF_IPV6_RPL \ + && !defined (CONTIKI_TARGET_MINIMAL_NET) \ + && !defined (CONTIKI_TARGET_NATIVE) + set_global_address(); + configure_routing(); +#endif + + /* Initialize the OSD Hardware. */ + hw_init(); + /* Initialize the REST engine. */ + rest_init_engine(); + + /* Activate the application-specific resources. */ + rest_activate_resource(&resource_info); + rest_activate_resource(&resource_led_pwm); + + /* Define application-specific events here. */ + while(1) { + PROCESS_WAIT_EVENT(); + } /* while (1) */ + + PROCESS_END(); +} diff --git a/examples/osd/pwm-example/flash.sh b/examples/osd/pwm-example/flash.sh new file mode 100755 index 000000000..e9cb40bfc --- /dev/null +++ b/examples/osd/pwm-example/flash.sh @@ -0,0 +1,2 @@ +#!/bin/bash +make TARGET=osd-merkur flash diff --git a/examples/osd/pwm-example/led_pwm.h b/examples/osd/pwm-example/led_pwm.h new file mode 100644 index 000000000..b93008136 --- /dev/null +++ b/examples/osd/pwm-example/led_pwm.h @@ -0,0 +1,26 @@ +/** + * \defgroup LED PWM example + * + * Resource definition for LED PWM module + * + * @{ + */ + +/** + * \file + * Resource definitions for the LED PWM module + * + * \author + * Ralf Schlatterbeck + */ + +#ifndef led_pwm_h +#define led_pwm_h +#include "contiki.h" +#include "erbium.h" + +extern resource_t resource_led_pwm; +extern void led_pwm_init (void); + +#endif // led_pwm_h +/** @} */ diff --git a/examples/osd/pwm-example/project-conf.h b/examples/osd/pwm-example/project-conf.h new file mode 100644 index 000000000..0b651669e --- /dev/null +++ b/examples/osd/pwm-example/project-conf.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + */ + +#ifndef PROJECT_RPL_WEB_CONF_H_ +#define PROJECT_RPL_WEB_CONF_H_ + +#define SICSLOWPAN_CONF_FRAG 1 + +/* For Debug: Dont allow MCU sleeping between channel checks */ +#undef RDC_CONF_MCU_SLEEP +#define RDC_CONF_MCU_SLEEP 0 + +/* Disabling RDC for demo purposes. Core updates often require more memory. */ +/* For projects, optimize memory and enable RDC again. */ +// #undef NETSTACK_CONF_RDC +//#define NETSTACK_CONF_RDC nullrdc_driver + +/* Increase rpl-border-router IP-buffer when using more than 64. */ +#undef REST_MAX_CHUNK_SIZE +#define REST_MAX_CHUNK_SIZE 64 + +/* Estimate your header size, especially when using Proxy-Uri. */ +/* +#undef COAP_MAX_HEADER_SIZE +#define COAP_MAX_HEADER_SIZE 70 +*/ + +/* The IP buffer size must fit all other hops, in particular the border router. */ + +#undef UIP_CONF_BUFFER_SIZE +#define UIP_CONF_BUFFER_SIZE 256 + + +/* Multiplies with chunk size, be aware of memory constraints. */ +#undef COAP_MAX_OPEN_TRANSACTIONS +#define COAP_MAX_OPEN_TRANSACTIONS 4 + +/* Must be <= open transaction number, default is COAP_MAX_OPEN_TRANSACTIONS-1. */ +/* +#undef COAP_MAX_OBSERVERS +#define COAP_MAX_OBSERVERS 2 +*/ + +/* Filtering .well-known/core per query can be disabled to save space. */ +/* +#undef COAP_LINK_FORMAT_FILTERING +#define COAP_LINK_FORMAT_FILTERING 0 +*/ + +/* Save some memory for the sky platform. */ +/* +#undef NBR_TABLE_CONF_MAX_NEIGHBORS +#define NBR_TABLE_CONF_MAX_NEIGHBORS 10 +#undef UIP_CONF_MAX_ROUTES +#define UIP_CONF_MAX_ROUTES 10 +*/ + +/* Reduce 802.15.4 frame queue to save RAM. */ +/* +#undef QUEUEBUF_CONF_NUM +#define QUEUEBUF_CONF_NUM 4 +*/ + +/* +#undef SICSLOWPAN_CONF_FRAG +#define SICSLOWPAN_CONF_FRAG 1 +*/ + +#endif /* PROJECT_RPL_WEB_CONF_H_ */ diff --git a/examples/osd/pwm-example/resource_led_pwm.c b/examples/osd/pwm-example/resource_led_pwm.c new file mode 100644 index 000000000..a9b276e08 --- /dev/null +++ b/examples/osd/pwm-example/resource_led_pwm.c @@ -0,0 +1,174 @@ +/** + * \file + * Resource for hardware timer handling + * \author + * Ralf Schlatterbeck + * + * \brief get/put pwm for LED pin + */ + +#include +#include +#include +#include "contiki.h" +#include "jsonparse.h" +/* Only coap 13 for now */ +#include "er-coap-13.h" +#include "hw_timer.h" + +/* Error-handling macro */ +# define BYE(_exp, _tag) \ + do { \ + PRINTF("Expect "_exp": %d\n",_tag); \ + success=0; \ + goto bye; \ + } while(0) + +#define DEBUG 1 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +static uint16_t max_ticks = 0, pwm = 0; + +void led_pwm_init (void) +{ + int8_t result = hwtimer_pwm_ini (3, 20, HWT_PWM_PHASE_CORRECT, 0); + PRINTF ("HWTIMER init: %d\n", result); + max_ticks = hwtimer_pwm_max_ticks (3); + pwm = max_ticks / 2; + hwtimer_set_pwm (3, HWT_CHANNEL_C, pwm); + hwtimer_pwm_inverse (3, HWT_CHANNEL_C); + DDRE |= (1< max_ticks) { + pwm = max_ticks; + } + PRINTF ("Setting: %d (max=%d)\n", pwm, max_ticks); + hwtimer_pwm_inverse (3, HWT_CHANNEL_C); + DDRE |= (1<