Initial implementation of avr hardware timer

Mainly for PWM use for now.
With example to set the LED to different brightness via COAP.
We switch the LED with 50 kHz (20µs) in this example.
This commit is contained in:
Ralf Schlatterbeck 2014-06-21 13:13:48 +02:00
parent d192553309
commit 5991c3e3db
12 changed files with 1171 additions and 1 deletions

View file

@ -13,7 +13,9 @@ CONTIKI_CPU=$(CONTIKI)/cpu/avr
### These directories will be searched for the specified source files ### These directories will be searched for the specified source files
### TARGETLIBS are platform-specific routines in the contiki library path ### TARGETLIBS are platform-specific routines in the contiki library path
CONTIKI_CPU_DIRS = . dev 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 ELFLOADER = elfloader.c elfloader-avr.c symtab-avr.c
TARGETLIBS = random.c leds.c TARGETLIBS = random.c leds.c

142
cpu/avr/hw_pwm_timer.c Normal file
View file

@ -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 <rsc@runtux.com>
*/
#include <avr/pgmspace.h>
#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
*/
/** @} */

103
cpu/avr/hw_timer.c Normal file
View file

@ -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 <rsc@runtux.com>
*/
#include <avr/pgmspace.h>
#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
*/
/** @} */

370
cpu/avr/hw_timer.h Normal file
View file

@ -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 <rsc@runtux.com>
*
*/
#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
*/
/** @} */

1
examples/osd/pwm-example/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.o

View file

@ -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

View file

@ -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 <kovatsch@inf.ethz.ch>
* Ralf Schlatterbeck <rsc@runtux.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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();
}

View file

@ -0,0 +1,2 @@
#!/bin/bash
make TARGET=osd-merkur flash

View file

@ -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 <rsc@tux.runtux.com>
*/
#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
/** @} */

View file

@ -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_ */

View file

@ -0,0 +1,174 @@
/**
* \file
* Resource for hardware timer handling
* \author
* Ralf Schlatterbeck <rsc@runtux.com>
*
* \brief get/put pwm for LED pin
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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<<PINE5);
}
RESOURCE \
( led_pwm, METHOD_GET | METHOD_PUT
, "led/pwm"
, "title=\"LED PWM\";rt=\"led pwm\""
);
void
led_pwm_handler
( void* request
, void* response
, uint8_t *buffer
, uint16_t preferred_size
, int32_t *offset
)
{
int success = 1;
int i;
char temp[100];
int index = 0;
int length = 0;
int tag = 0;
const uint8_t *bytes = NULL;
size_t len = 0;
int n_acc = 0;
const uint16_t *accept = NULL;
uint16_t a_ctype = REST.type.APPLICATION_JSON;
uint16_t c_ctype = REST.get_header_content_type (request);
/* Seems like accepted type is currently unsupported? */
n_acc = REST.get_header_accept (request, &accept);
for (i=0; i<n_acc; i++) {
if ( accept [i] == REST.type.TEXT_PLAIN
|| accept [i] == REST.type.APPLICATION_JSON
)
{
a_ctype = accept [i];
break;
}
}
switch(REST.get_method_type(request)) {
case METHOD_GET:
// TEXT format
if (a_ctype == REST.type.TEXT_PLAIN) {
index += sprintf (temp + index, "%d\n", pwm);
} else { // jSON Format
index += sprintf
( temp + index
,"{\n \"pwm\" : \"%d\"\n}\n"
, pwm
);
}
length = strlen(temp);
memcpy (buffer, temp, length);
REST.set_header_content_type (response, a_ctype);
REST.set_response_payload (response, buffer, length);
break;
case METHOD_PUT:
if ((len = coap_get_payload(request, &bytes))) {
PRINTF ("PUT: len: %d, %s\n", len, (char *)bytes);
if (c_ctype == REST.type.TEXT_PLAIN) {
temp [sizeof (temp) - 1] = 0;
strncpy (temp, (char *)bytes, MIN (len + 1, sizeof (temp) - 1));
} else { // jSON Format
struct jsonparse_state state;
struct jsonparse_state *parser = &state;
jsonparse_setup (parser, (char *)bytes, len);
if ((tag = jsonparse_next (parser)) != JSON_TYPE_OBJECT) {
BYE ("OBJECT", tag);
}
if ((tag = jsonparse_next (parser)) != JSON_TYPE_PAIR_NAME) {
BYE ("PAIR_NAME", tag);
}
while (jsonparse_strcmp_value (parser, "pwm") != 0) {
tag = jsonparse_next (parser);
if (tag != JSON_TYPE_PAIR) {
BYE ("PAIR", tag);
}
tag = jsonparse_next (parser);
tag = jsonparse_next (parser);
if (tag != ',') {
BYE (",", tag);
}
tag = jsonparse_next (parser);
if (tag != JSON_TYPE_PAIR_NAME) {
BYE ("PAIR_NAME", tag);
}
}
tag = jsonparse_next (parser);
if (tag != JSON_TYPE_PAIR) {
BYE ("PAIR", tag);
}
tag = jsonparse_next (parser);
if (tag != JSON_TYPE_STRING) {
BYE ("STRING", tag);
}
jsonparse_copy_value (parser, temp, sizeof (temp));
temp [sizeof (temp) - 1] = 0;
}
PRINTF ("GOT: %s\n", temp);
pwm = atoi (temp);
if (pwm > max_ticks) {
pwm = max_ticks;
}
PRINTF ("Setting: %d (max=%d)\n", pwm, max_ticks);
hwtimer_pwm_inverse (3, HWT_CHANNEL_C);
DDRE |= (1<<PINE5);
hwtimer_set_pwm (3, HWT_CHANNEL_C, pwm);
PRINTF
( "TCNT3: %04X TCCR3A: %04X TCCR3B: %04X TCCR3C: %04X OCR3C: %04X\n"
, TCNT3, TCCR3A, TCCR3B, TCCR3C, OCR3C
);
REST.set_response_status(response, REST.status.CHANGED);
} else {
PRINTF ("PUT: len: %d\n", len);
success = 0;
}
bye :
break;
default:
success = 0;
}
if (!success) {
REST.set_response_status(response, REST.status.BAD_REQUEST);
}
}

View file

@ -0,0 +1,5 @@
#!/bin/bash
# For the new bootloader (using a jump-table) you want to use
# BOOTLOADER_GET_MAC=0x0001ff80 (which is the current default)
make clean TARGET=osd-merkur
make TARGET=osd-merkur BOOTLOADER_GET_MAC=0x0001f3a0