Add Arduino compatibility layer

We can now directly compile arduino sketches (.pde) files.
Arduino compatible analogWrite works now.
But there is still a long way to go, serial I/O and timer stuff (delay,
millis etc) currently don't work (not tested but I don't expect this to
work).
It can be used in an arduino sketch or in a normal contiki program.
We get a PWM frequency of 490.2 Hz (a period of 2.040 ms), that's
Arduino compatible. If you need different frequencies see native timer
usage in examples/osd/pwm-example
In a contiki program you have to call arduino_pwm_timer_init to
initialize the timer before pwm works. The arduino sketch wrapper
already does this.
For running a sketch, see examples/osd/arduino-sketch
This commit is contained in:
Ralf Schlatterbeck 2014-06-26 11:00:01 +02:00
parent 87903b2e89
commit e65dabb119
22 changed files with 999 additions and 361 deletions

View file

@ -0,0 +1,2 @@
arduino_src = arduino-process.c

View file

@ -0,0 +1,4 @@
%.cpp: %.pde
echo '#include "Arduino.h"' > $@
echo '#include "$<"' >> $@

13
apps/arduino/README.md Normal file
View file

@ -0,0 +1,13 @@
Arduino Compatibility
=====================
This application contains hardware-independent implementations of
arduino compatibilty libraries and include files to be used with
contiki.
The whole arduino compatibility library is work in progress. Note that
features having to do with timers like `millis` and `delay` are
currently untested. In Arduino they use timer 0 of the AVR
microcontroller. It should be investigated to use the hardware timer
already in use by contiki (on the OSD-merkur platform this is currently
timer 5).

View file

@ -0,0 +1,77 @@
/*
* 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 Arduino Process
*
* This wraps the Arduino-API entry points `loop` and `setup` in a
* contiki process.
*
* If the normal contiki includes are used and resources initialized in
* `setup`, Contiki resources can be used in an arduino sketch.
*
* @{
*/
/**
* \file
* Wrapper for Arduino sketches
* \author
* Ralf Schlatterbeck <rsc@runtux.com>
*
*/
#include "arduino-process.h"
PROCESS(arduino_sketch, "Arduino Sketch Wrapper");
PROCESS_THREAD(arduino_sketch, ev, data)
{
PROCESS_BEGIN();
arduino_init ();
setup ();
while (1) {
loop ();
/* Give other processes a chance to run */
process_post (&arduino_sketch, PROCESS_EVENT_CONTINUE, NULL);
PROCESS_WAIT_EVENT();
}
PROCESS_END();
}
/*
* VI settings, see coding style
* ex:ts=8:et:sw=2
*/
/** @} */

View file

@ -0,0 +1,65 @@
/*
* 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.
*/
/**
* \devgroup Arduino Process
*
* This wraps the Arduino-API entry points `loop` and `setup` in a
* contiki process.
*
* If the normal contiki includes are used and resources initialized in
* `setup`, Contiki resources can be used in an arduino sketch.
*
* @{
*/
/**
* \file
* Wrapper for Arduino sketches
* \author
* Ralf Schlatterbeck <rsc@runtux.com>
*
*/
#include "contiki.h"
extern void loop (void);
extern void setup (void);
extern void arduino_init (void);
extern struct process arduino_sketch;
/*
* VI settings, see coding style
* ex:ts=8:et:sw=2
*/
/** @} */

View file

@ -137,6 +137,8 @@
#define HWT_CHANNEL_A 0 #define HWT_CHANNEL_A 0
#define HWT_CHANNEL_B 1 #define HWT_CHANNEL_B 1
#define HWT_CHANNEL_C 2 #define HWT_CHANNEL_C 2
#define HWT_CHANNEL_D 3
#define HWT_CHANNEL_MASK 3
/* The following macros are defined for timer values 1,3,4,5 */ /* The following macros are defined for timer values 1,3,4,5 */
#define HWT_ICR(t) \ #define HWT_ICR(t) \

View file

@ -0,0 +1,157 @@
/*
* 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 independent Arduino compatibility
*
* This file is meant to be included into a compatible Arduino.h
*
* Arduino calls the combination of an AVR timer and the corresponding
* channel a timer. So Arduinos definition of timer is different from
* that of AVR documentation. Arduino defines arbitrary TIMERXX macros
* that are later parsed in a big switch statement.
*
* We use a better representation of timer values than arduino here:
* The AVRs have max. 6 (numbered 0-5) timers. For representing these we
* need 3 bits. In addition each timer can have channels A-D (or just
* one channel in which case there is no alphabetic suffix). We can
* represent this in 2 bits. We add one bit to each for future
* compatibility and come up with 7 bits, still easily represented in 8
* bit with room for a 'NOT_ON_TIMER' value. From these we can easily
* compute the channel and timer by shifting. No need for a big switch
* statement, and -- which is the common case -- when initializing with
* a constant for the pin, the compiler can compute everything at
* compile-time (that's why the analogWrite below is implemented as a
* static inline function).
*
* Note that Arduino also defines some TIMERX without an alphabetic
* suffix (e.g. TIMER2). I suspect this is for microcontrollers that
* only have one channel for a certain timer. So this is currently
* defined the same as TIMER2A because they are never used together.
* This may be wrong and may be a bug.
*
* Note that the hardware definition still has to define a
* digitalPinToTimer macro. We suggest to not implement this with a
* static table in program memory (as currently done by arduino) but
* instead as an if-cascade (as a C-macro). This allows the compiler to
* completely compute the if-cascade at compile-time if the used pin is
* a constant, resulting in *much* smaller code-footprint in the most
* common use-case.
*
* @{
*/
/**
* \file
* Header file for arduino compatibility
* \author
* Ralf Schlatterbeck <rsc@runtux.com>
*
*/
/* To be included by a compatible Arduino.h */
#ifdef __cplusplus
extern "C" {
#endif
#include "contiki.h"
#include "hw_timer.h"
#ifdef __cplusplus
} // extern "C"
#endif
#define HW_TIMER_SHIFT 3
#define NOT_ON_TIMER 0xFF
#define TIMER0A ((0 << HW_TIMER_SHIFT) | HWT_CHANNEL_A)
#define TIMER0B ((0 << HW_TIMER_SHIFT) | HWT_CHANNEL_B)
#define TIMER1A ((1 << HW_TIMER_SHIFT) | HWT_CHANNEL_A)
#define TIMER1B ((1 << HW_TIMER_SHIFT) | HWT_CHANNEL_B)
#define TIMER1C ((1 << HW_TIMER_SHIFT) | HWT_CHANNEL_C)
#define TIMER2 ((2 << HW_TIMER_SHIFT) | HWT_CHANNEL_A)
#define TIMER2A ((2 << HW_TIMER_SHIFT) | HWT_CHANNEL_A)
#define TIMER2B ((2 << HW_TIMER_SHIFT) | HWT_CHANNEL_B)
#define TIMER3A ((3 << HW_TIMER_SHIFT) | HWT_CHANNEL_A)
#define TIMER3B ((3 << HW_TIMER_SHIFT) | HWT_CHANNEL_B)
#define TIMER3C ((3 << HW_TIMER_SHIFT) | HWT_CHANNEL_C)
#define TIMER4A ((4 << HW_TIMER_SHIFT) | HWT_CHANNEL_A)
#define TIMER4B ((4 << HW_TIMER_SHIFT) | HWT_CHANNEL_B)
#define TIMER4C ((4 << HW_TIMER_SHIFT) | HWT_CHANNEL_C)
#define TIMER4D ((4 << HW_TIMER_SHIFT) | HWT_CHANNEL_D)
#define TIMER5A ((5 << HW_TIMER_SHIFT) | HWT_CHANNEL_A)
#define TIMER5B ((5 << HW_TIMER_SHIFT) | HWT_CHANNEL_B)
#define TIMER5C ((5 << HW_TIMER_SHIFT) | HWT_CHANNEL_C)
#ifdef __cplusplus
extern "C" {
#endif
static inline void analogWrite(uint8_t pin, int val)
{
/*
* Note on the timer usage: Arduino has code here that
* explicitly checks if the given val is 0 or 0xFF.
* The 16-bit timers on Arduino use the phase correct PWM
* waveform generation mode which already sets the output to
* continuous low for 0 or continuous high for 0xFF. When using
* an 8-bit timer, Arduino uses fast PWM which creates a tiny
* spike for 0, so to be Arduino-compatible in this mode we use
* digitalWrite in this case.
*/
uint8_t arduino_timer = digitalPinToTimer(pin);
pinMode(pin, OUTPUT);
if (val == 0 || arduino_timer == NOT_ON_TIMER) {
digitalWrite(pin, (val < 128) ? LOW : HIGH);
} else {
uint8_t t = arduino_timer >> HW_TIMER_SHIFT;
uint8_t c = arduino_timer & HWT_CHANNEL_MASK;
hwtimer_pwm_enable (t, c);
hwtimer_set_pwm (t, c, val);
}
}
#ifdef __cplusplus
} // extern "C"
#endif
/*
* VI settings, see coding style
* ex:ts=8:et:sw=2
*/
/** @} */

View file

@ -0,0 +1,102 @@
# Set this to the name of your sketch (without extension .pde)
SKETCH=sketch
all: arduino-example \
arduino-example.osd-merkur.hex arduino-example.osd-merkur.eep
# 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 ${SKETCH}.cpp
# 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 time json arduino
include $(CONTIKI)/Makefile.include
include $(CONTIKI)/apps/arduino/Makefile.include
arduino-example.osd-merkur.hex: arduino-example.osd-merkur
avr-objcopy -j .text -j .data -O ihex arduino-example.osd-merkur \
arduino-example.osd-merkur.hex
arduino-example.osd-merkur.eep: arduino-example.osd-merkur
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 -O ihex \
arduino-example.osd-merkur arduino-example.osd-merkur.eep
flash: arduino-example.osd-merkur.hex arduino-example.osd-merkur.eep
avrdude -pm128rfa1 -c arduino -P/dev/ttyUSB0 -b57600 -e -U \
flash:w:arduino-example.osd-merkur.hex:a -U \
eeprom:w:arduino-example.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,11 @@
Arduino compatibility example
=============================
This example shows that it is now possible to re-use arduino sketches in
Contiki. This example documents the necessary magic. Arduino specifies
two routines, `setup` and `loop`. Before `setup` is called, the
framework initializes hardware. In original Arduino, all this is done in
a `main` function (in C). For contiki we define a process that does the
same.
See the documentation file in apps/contiki-compat/README.md

View file

@ -0,0 +1,2 @@
#include <arduino-process.h>
AUTOSTART_PROCESSES(&arduino_sketch);

View file

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

View file

@ -0,0 +1,30 @@
/**
* \defgroup Arduino LED PWM example
*
* Resource definition for Arduino LED PWM module
*
* @{
*/
/**
* \file
* Resource definitions for the Arduino LED PWM module
*
* \author
* Ralf Schlatterbeck <rsc@tux.runtux.com>
*/
#ifndef led_pwm_h
#define led_pwm_h
#include "contiki.h"
#include "contiki-net.h"
#include "erbium.h"
#include "er-coap-13.h"
extern uint8_t pwm;
extern uint8_t period_100ms;
extern resource_t resource_led_pwm;
extern resource_t resource_led_period;
#endif // led_pwm_h
/** @} */

View file

@ -0,0 +1,101 @@
/*
* 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 PLATFORM_HAS_LEDS 1
//#define PLATFORM_HAS_BUTTON 1
#define PLATFORM_HAS_BATTERY 1
#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,273 @@
/**
* \file
* Resource for Arduino PWM
* \author
* Ralf Schlatterbeck <rsc@runtux.com>
*
* \brief get/put pwm and period for LED pin
*
* quick&dirty implementation, this should factor json parsing.
* But json format will probably change, there is a draft rfc.
*/
#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 "led_pwm.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
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);
PRINTF ("Setting: %d\n", pwm);
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);
}
}
RESOURCE \
( led_period, METHOD_GET | METHOD_PUT
, "led/period"
, "title=\"LED Period\";rt=\"led period\""
);
void
led_period_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", period_100ms * 100);
} else { // jSON Format
index += sprintf
( temp + index
,"{\n \"period\" : \"%d\"\n}\n"
, period_100ms * 100
);
}
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, "period") != 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);
period_100ms = (atoi (temp) + 50) / 100;
PRINTF ("Setting: %dms\n", period_100ms * 100);
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

View file

@ -0,0 +1,47 @@
/*
* Sample arduino sketch using contiki features.
* We turn the LED on and off and allow setting the interval and the
* brightness of the LED via coap.
* Unfortunately sleeping for long times in loop() isn't currently
* possible, something turns off the CPU (including PWM outputs) if a
* Proto-Thread is taking too long. We need to find out how to sleep in
* a Contiki-compatible way.
* Note that for a normal arduino sketch you won't have to include any
* of the contiki-specific files here, the sketch should just work.
*/
extern "C" {
#include <stdio.h>
#include "led_pwm.h"
#define LED_PIN 5
uint8_t pwm = 128;
uint8_t period_100ms = 10; /* one second */
}
void setup (void)
{
rest_init_engine ();
rest_activate_resource (&resource_led_pwm);
rest_activate_resource (&resource_led_period);
}
void loop (void)
{
static uint8_t last_pwm = 0;
if (last_pwm != pwm) {
last_pwm = pwm;
analogWrite (LED_PIN, pwm);
printf
( "TCNT3: %04X TCCR3A: %04X TCCR3B: %04X TCCR3C: %04X OCR3C: %04X\n"
, TCNT3, TCCR3A, TCCR3B, TCCR3C, OCR3C
);
}
// Originally I wanted to sleep here to make the LED blink.
// Sleeping currently doesn't work, something turns off the chip.
// Maybe a mechanism to guard agains proto-threads taking too long?
//clock_wait (CLOCK_SECOND * period_100ms / 10);
//analogWrite (LED_PIN, 0);
//printf ("After write\n");
}

View file

@ -27,7 +27,7 @@ CONTIKI_TARGET_SOURCEFILES += servo.c servo-sensor.c
#Needed for Relay 1 to 4 #Needed for Relay 1 to 4
CONTIKI_TARGET_SOURCEFILES += relay.c relay-sensor.c CONTIKI_TARGET_SOURCEFILES += relay.c relay-sensor.c
# Arduino # Arduino
CONTIKI_TARGET_SOURCEFILES += wiring_digital.c CONTIKI_TARGET_SOURCEFILES += wiring_digital.c wiring.c wiring_analog.c
CONTIKIBOARD=. CONTIKIBOARD=.
BOOTLOADER_START = 0x1F000 BOOTLOADER_START = 0x1F000

View file

@ -1,6 +1,7 @@
#ifndef Arduino_h #ifndef Arduino_h
#define Arduino_h #define Arduino_h
#include <hw-arduino.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
@ -88,14 +89,18 @@ typedef unsigned int word;
typedef uint8_t boolean; typedef uint8_t boolean;
typedef uint8_t byte; typedef uint8_t byte;
void init(void); /*
* 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 pinMode(uint8_t, uint8_t);
void digitalWrite(uint8_t, uint8_t); void digitalWrite(uint8_t, uint8_t);
int digitalRead(uint8_t); int digitalRead(uint8_t);
int analogRead(uint8_t); int analogRead(uint8_t);
void analogReference(uint8_t mode); void analogReference(uint8_t mode);
void analogWrite(uint8_t, int);
unsigned long millis(void); unsigned long millis(void);
unsigned long micros(void); unsigned long micros(void);
@ -126,7 +131,6 @@ extern const uint16_t PROGMEM port_to_output_PGM[];
extern const uint8_t PROGMEM digital_pin_to_port_PGM[]; extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[]; // extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
// Get the bit location within the hardware port of the given virtual pin. // Get the bit location within the hardware port of the given virtual pin.
// This comes from the pins_*.c file for the active board configuration. // This comes from the pins_*.c file for the active board configuration.
@ -135,7 +139,6 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
// //
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) ) #define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) ) #define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
#define analogInPinToBit(P) (P) #define analogInPinToBit(P) (P)
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) ) #define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) #define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
@ -158,35 +161,15 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
#define PL 12 #define PL 12
#endif #endif
#define NOT_ON_TIMER 0
#define TIMER0A 1
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
#define TIMER1C 5
#define TIMER2 6
#define TIMER2A 7
#define TIMER2B 8
#define TIMER3A 9
#define TIMER3B 10
#define TIMER3C 11
#define TIMER4A 12
#define TIMER4B 13
#define TIMER4C 14
#define TIMER4D 15
#define TIMER5A 16
#define TIMER5B 17
#define TIMER5C 18
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
#include "WCharacter.h" // look at this again when considering implementing serial
#include "WString.h" //#include "WCharacter.h"
#include "HardwareSerial.h" //#include "WString.h"
//#include "HardwareSerial.h"
uint16_t makeWord(uint16_t w); uint16_t makeWord(uint16_t w);
uint16_t makeWord(byte h, byte l); uint16_t makeWord(byte h, byte l);
@ -208,4 +191,6 @@ long map(long, long, long, long, long);
#include "pins_arduino.h" #include "pins_arduino.h"
#endif #include "dev/arduino/arduino-compat.h"
#endif

View file

@ -0,0 +1,73 @@
/*
* 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 compatibility Arduino - Contiki
*
* This defines contiki-compatible hardware definitions for running
* arduino sketches (or just to call arduino-compatible function).
* For now only for osd hardware, a similar file should exist for each
* arduino-compatible hardware.
*
* @{
*/
/**
* \file
* Header file for arduino compatibility
* \author
* Ralf Schlatterbeck <rsc@runtux.com>
*
*/
/*
* The OSD hardware only supports timer 3 for PWM, timer 2 is used by
* contiki for sleep/wakeup timing and is not usable for PWM.
*/
#define digitalPinToTimer(pin) \
( (pin) == 3 \
? TIMER3A \
: ( (pin) == 4 \
? TIMER3B \
: ((pin == 5) ? TIMER3C : NOT_ON_TIMER) \
) \
)
/* Only init timer 3 with phase correct pwm 8-bit and prescaler 64 */
#define arduino_pwm_timer_init() \
(hwtimer_ini (3, HWT_WGM_PWM_PHASE_8_BIT, HWT_CLOCK_PRESCALER_64, 0))
/*
* VI settings, see coding style
* ex:ts=8:et:sw=2
*/
/** @} */

View file

@ -215,48 +215,6 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
// _BV( 7 ) , // PB 7 ** 35 ** D35 / LED2 / PWM // _BV( 7 ) , // PB 7 ** 35 ** D35 / LED2 / PWM
}; };
// !!!
const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
// TIMERS
// -------------------------------------------
NOT_ON_TIMER , // PE 1 ** 0 ** USART0_TX
NOT_ON_TIMER , // PE 0 ** 1 ** USART0_RX
TIMER3A , // PE 3 ** 2 ** D3 / PWM
TIMER3B , // PE 4 ** 3 ** D4 / PWM
TIMER3C , // PE 5 ** 4 ** D5 / PWM
NOT_ON_TIMER , // PE 6 ** 5 ** D6
NOT_ON_TIMER , // PD 3 ** 6 ** D21 / USART1_TX
NOT_ON_TIMER , // PD 2 ** 7 ** D20 / USART1_RX
NOT_ON_TIMER , // PD 0 ** 8 ** D15 / I2C_SCL
NOT_ON_TIMER , // PD 1 ** 9 ** D14 / I2C_SDA
NOT_ON_TIMER , // PB 0 ** 10 ** D10 / SPI_SSN
NOT_ON_TIMER , // PB 2 ** 11 ** D11 / SPI_MOSI
NOT_ON_TIMER , // PB 1 ** 12 ** D13 / SPI_SCK
NOT_ON_TIMER , // PB 3 ** 13 ** D12 / SPI_MISO
TIMER2A , // PB 4 ** 14 ** D9 / PWM
NOT_ON_TIMER , // PF 7 ** 15 ** A0 / D33
NOT_ON_TIMER , // PF 6 ** 16 ** A1 / D32
NOT_ON_TIMER , // PF 5 ** 17 ** A2 / D31
NOT_ON_TIMER , // PF 4 ** 18 ** A3 / D30
NOT_ON_TIMER , // PF 0 ** 19 ** A4 / D26
NOT_ON_TIMER , // PF 1 ** 20 ** A5 / D27
// NOT_ON_TIMER , // PF 2 ** 28 ** A6 / D28
// NOT_ON_TIMER , // PF 3 ** 29 ** A7 / D29
// NOT_ON_TIMER , // PE 2 ** 2 ** D2
// NOT_ON_TIMER , // PE 7 ** 7 ** D7
// TIMER1A , // PB 5 ** 8 ** D8 / PWM
// NOT_ON_TIMER , // PG 0 ** 16 ** D16
// NOT_ON_TIMER , // PG 1 ** 17 ** D17
// NOT_ON_TIMER , // PG 2 ** 18 ** D18
// TIMER0B , // PG 5 ** 19 ** D19 / PWM
// NOT_ON_TIMER , // PD 4 ** 22 ** D22
// NOT_ON_TIMER , // PD 5 ** 23 ** D23
// NOT_ON_TIMER , // PD 6 ** 24 ** D24
// NOT_ON_TIMER , // PD 7 ** 25 ** D25
// TIMER1B , // PB 6 ** 34 ** D34/ PWM
// TIMER1C , // PB 7 ** 35 ** D35 / PWM
};
#endif #endif
#endif #endif

View file

@ -23,6 +23,7 @@
*/ */
#include "wiring_private.h" #include "wiring_private.h"
#include "hw-arduino.h"
// the prescaler is set so that timer0 ticks every 64 clock cycles, and the // the prescaler is set so that timer0 ticks every 64 clock cycles, and the
// the overflow handler is called every 256 ticks. // the overflow handler is called every 256 ticks.
@ -186,20 +187,23 @@ void delayMicroseconds(unsigned int us)
); );
} }
void init() void arduino_init()
{ {
// this needs to be called before setup() or some functions won't // this needs to be called before setup() or some functions won't
// work there // work there
sei();
// on the ATmega168, timer 0 is also used for fast hardware pwm // on the ATmega168, timer 0 is also used for fast hardware pwm
// (using phase-correct PWM would mean that timer 0 overflowed half as often // (using phase-correct PWM would mean that timer 0 overflowed half as often
// resulting in different millis() behavior on the ATmega8 and ATmega168) // resulting in different millis() behavior on the ATmega8 and ATmega168)
/*
* RSC: Keep timer0 for now, until we decide how to implement
* millis() etc in a contiki-compatible way
*/
#if defined(TCCR0A) && defined(WGM01) #if defined(TCCR0A) && defined(WGM01)
sbi(TCCR0A, WGM01); sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00); sbi(TCCR0A, WGM00);
#endif #endif
// set timer 0 prescale factor to 64 // set timer 0 prescale factor to 64
#if defined(__AVR_ATmega128__) #if defined(__AVR_ATmega128__)
// CPU specific: different values for the ATmega128 // CPU specific: different values for the ATmega128
@ -229,96 +233,13 @@ void init()
#error Timer 0 overflow interrupt not set correctly #error Timer 0 overflow interrupt not set correctly
#endif #endif
// timers 1 and 2 are used for phase-correct hardware pwm /*
// this is better for motors as it ensures an even waveform * All other PCM timers are initialized here in a
// note, however, that fast pwm mode can achieve a frequency of up * platform-specific way
// 8 MHz (with a 16 MHz clock) at 50% duty cycle */
arduino_pwm_timer_init ();
#if defined(TCCR1B) && defined(CS11) && defined(CS10) /*
TCCR1B = 0; * Removed the rest which manipulates the serial pins
*/
// set timer 1 prescale factor to 64
sbi(TCCR1B, CS11);
#if F_CPU >= 8000000L
sbi(TCCR1B, CS10);
#endif
#elif defined(TCCR1) && defined(CS11) && defined(CS10)
sbi(TCCR1, CS11);
#if F_CPU >= 8000000L
sbi(TCCR1, CS10);
#endif
#endif
// put timer 1 in 8-bit phase correct pwm mode
#if defined(TCCR1A) && defined(WGM10)
sbi(TCCR1A, WGM10);
#elif defined(TCCR1)
#warning this needs to be finished
#endif
// set timer 2 prescale factor to 64
#if defined(TCCR2) && defined(CS22)
sbi(TCCR2, CS22);
#elif defined(TCCR2B) && defined(CS22)
sbi(TCCR2B, CS22);
#else
#warning Timer 2 not finished (may not be present on this CPU)
#endif
// configure timer 2 for phase correct pwm (8-bit)
#if defined(TCCR2) && defined(WGM20)
sbi(TCCR2, WGM20);
#elif defined(TCCR2A) && defined(WGM20)
sbi(TCCR2A, WGM20);
#else
#warning Timer 2 not finished (may not be present on this CPU)
#endif
#if defined(TCCR3B) && defined(CS31) && defined(WGM30)
sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64
sbi(TCCR3B, CS30);
sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode
#endif
#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */
sbi(TCCR4B, CS42); // set timer4 prescale factor to 64
sbi(TCCR4B, CS41);
sbi(TCCR4B, CS40);
sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM mode
sbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4A
sbi(TCCR4C, PWM4D); // enable PWM mode for comparator OCR4D
#else /* beginning of timer4 block for ATMEGA1280 and ATMEGA2560 */
#if defined(TCCR4B) && defined(CS41) && defined(WGM40)
sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64
sbi(TCCR4B, CS40);
sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode
#endif
#endif /* end timer4 block for ATMEGA1280/2560 and similar */
#if defined(TCCR5B) && defined(CS51) && defined(WGM50)
sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64
sbi(TCCR5B, CS50);
sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode
#endif
#if defined(ADCSRA)
// set a2d prescale factor to 128
// 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
// XXX: this will not work properly for other clock speeds, and
// this code should use F_CPU to determine the prescale factor.
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
// enable a2d conversions
sbi(ADCSRA, ADEN);
#endif
// the bootloader connects pins 0 and 1 to the USART; disconnect them
// here so they can be used as normal digital i/o; they will be
// reconnected in Serial.begin()
#if defined(UCSRB)
UCSRB = 0;
#elif defined(UCSR0B)
UCSR0B = 0;
#endif
} }

View file

@ -43,198 +43,6 @@ int analogRead(uint8_t pin)
return readADC(pin); return readADC(pin);
} }
// Right now, PWM output only works on the pins with /*
// hardware support. These are defined in the appropriate * analogWrite is now implemented in dev/arduino/arduino-compat.h
// pins_*.c file. For the rest of the pins, we default */
// to digital output.
void analogWrite(uint8_t pin, int val)
{
// We need to make sure the PWM output is enabled for those pins
// that support it, as we turn it off when digitally reading or
// 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.
pinMode(pin, OUTPUT);
if (val == 0)
{
digitalWrite(pin, LOW);
}
else if (val == 255)
{
digitalWrite(pin, HIGH);
}
else
{
switch(digitalPinToTimer(pin))
{
// XXX fix needed for atmega8
#if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
case TIMER0A:
// connect pwm to pin on timer 0
sbi(TCCR0, COM00);
OCR0 = val; // set pwm duty
break;
#endif
#if defined(TCCR0A) && defined(COM0A1)
case TIMER0A:
// connect pwm to pin on timer 0, channel A
sbi(TCCR0A, COM0A1);
OCR0A = val; // set pwm duty
break;
#endif
#if defined(TCCR0A) && defined(COM0B1)
case TIMER0B:
// connect pwm to pin on timer 0, channel B
sbi(TCCR0A, COM0B1);
OCR0B = val; // set pwm duty
break;
#endif
#if defined(TCCR1A) && defined(COM1A1)
case TIMER1A:
// connect pwm to pin on timer 1, channel A
sbi(TCCR1A, COM1A1);
OCR1A = val; // set pwm duty
break;
#endif
#if defined(TCCR1A) && defined(COM1B1)
case TIMER1B:
// connect pwm to pin on timer 1, channel B
sbi(TCCR1A, COM1B1);
OCR1B = val; // set pwm duty
break;
#endif
#if defined(TCCR1A) && defined(COM1C1)
case TIMER1C:
// connect pwm to pin on timer 1, channel C
sbi(TCCR1A, COM1C1);
OCR1C = val; // set pwm duty
break;
#endif
#if defined(TCCR2) && defined(COM21)
case TIMER2:
// connect pwm to pin on timer 2
sbi(TCCR2, COM21);
OCR2 = val; // set pwm duty
break;
#endif
#if defined(TCCR2A) && defined(COM2A1)
case TIMER2A:
// connect pwm to pin on timer 2, channel A
sbi(TCCR2A, COM2A1);
OCR2A = val; // set pwm duty
break;
#endif
#if defined(TCCR2A) && defined(COM2B1)
case TIMER2B:
// connect pwm to pin on timer 2, channel B
sbi(TCCR2A, COM2B1);
OCR2B = val; // set pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3A1)
case TIMER3A:
// connect pwm to pin on timer 3, channel A
sbi(TCCR3A, COM3A1);
OCR3A = val; // set pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3B1)
case TIMER3B:
// connect pwm to pin on timer 3, channel B
sbi(TCCR3A, COM3B1);
OCR3B = val; // set pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3C1)
case TIMER3C:
// connect pwm to pin on timer 3, channel C
sbi(TCCR3A, COM3C1);
OCR3C = val; // set pwm duty
break;
#endif
#if defined(TCCR4A)
case TIMER4A:
//connect pwm to pin on timer 4, channel A
sbi(TCCR4A, COM4A1);
#if defined(COM4A0) // only used on 32U4
cbi(TCCR4A, COM4A0);
#endif
OCR4A = val; // set pwm duty
break;
#endif
#if defined(TCCR4A) && defined(COM4B1)
case TIMER4B:
// connect pwm to pin on timer 4, channel B
sbi(TCCR4A, COM4B1);
OCR4B = val; // set pwm duty
break;
#endif
#if defined(TCCR4A) && defined(COM4C1)
case TIMER4C:
// connect pwm to pin on timer 4, channel C
sbi(TCCR4A, COM4C1);
OCR4C = val; // set pwm duty
break;
#endif
#if defined(TCCR4C) && defined(COM4D1)
case TIMER4D:
// connect pwm to pin on timer 4, channel D
sbi(TCCR4C, COM4D1);
#if defined(COM4D0) // only used on 32U4
cbi(TCCR4C, COM4D0);
#endif
OCR4D = val; // set pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5A1)
case TIMER5A:
// connect pwm to pin on timer 5, channel A
sbi(TCCR5A, COM5A1);
OCR5A = val; // set pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5B1)
case TIMER5B:
// connect pwm to pin on timer 5, channel B
sbi(TCCR5A, COM5B1);
OCR5B = val; // set pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5C1)
case TIMER5C:
// connect pwm to pin on timer 5, channel C
sbi(TCCR5A, COM5C1);
OCR5C = val; // set pwm duty
break;
#endif
case NOT_ON_TIMER:
default:
if (val < 128) {
digitalWrite(pin, LOW);
} else {
digitalWrite(pin, HIGH);
}
}
}
}