Initial import of support files for all Digistump boards - Digispark, Pro, DigiX - including libraries, examples, tools, and other support files for the Arduino IDE

This commit is contained in:
Erik Tylek Kettenburg 2014-12-19 08:45:50 -08:00
parent 97abdbf157
commit 7e7473a2d6
3567 changed files with 722870 additions and 0 deletions

View File

@ -0,0 +1,65 @@
# See: http://code.google.com/p/arduino/wiki/Platforms
menu.cpu=Processor
##############################################################
digispark-tiny.name=Digispark (Default - 16.5mhz)
digispark-tiny.upload.using=micronucleusprog
digispark-tiny.upload.protocol=usb
digispark-tiny.upload.tool=micronucleus
digispark-tiny.upload.maximum_size=6012
digispark-tiny.build.mcu=attiny85
digispark-tiny.build.f_cpu=16500000L
digispark-tiny.build.board=AVR_DIGISPARK
digispark-tiny.build.core=tiny
digispark-tiny.build.variant=digispark
digispark-tiny.upload.wait_for_upload_port = false
digispark-tiny.upload.use_1200bps_touch = false
digispark-tiny.upload.disable_flushing = false
digispark-pro.name=Digispark Pro (Default 16 Mhz)
digispark-pro.upload.using=micronucleusprog
digispark-pro.upload.protocol=usb
digispark-pro.upload.tool=micronucleus
digispark-pro.upload.maximum_size=14844
digispark-pro.build.mcu=attiny167
digispark-pro.build.f_cpu=16000000L
digispark-pro.build.board=AVR_DIGISPARKPRO
digispark-pro.build.core=pro
digispark-pro.build.variant=pro
digispark-pro.upload.wait_for_upload_port = false
digispark-pro.upload.use_1200bps_touch = false
digispark-pro.upload.disable_flushing = false
digispark-pro32.name=Digispark Pro (16 Mhz) (32 byte buffer)
digispark-pro32.upload.using=micronucleusprog
digispark-pro32.upload.protocol=usb
digispark-pro32.upload.tool=micronucleus
digispark-pro32.upload.maximum_size=14844
digispark-pro32.build.mcu=attiny167
digispark-pro32.build.f_cpu=16000000L
digispark-pro32.build.board=AVR_DIGISPARKPRO
digispark-pro32.build.core=pro
digispark-pro32.build.variant=pro32buffer
digispark-pro32.upload.wait_for_upload_port = false
digispark-pro32.upload.use_1200bps_touch = false
digispark-pro32.upload.disable_flushing = false
digispark-pro64.name=Digispark Pro (16 Mhz) (64 byte buffer)
digispark-pro64.upload.using=micronucleusprog
digispark-pro64.upload.protocol=usb
digispark-pro64.upload.tool=micronucleus
digispark-pro64.upload.maximum_size=14844
digispark-pro64.build.mcu=attiny167
digispark-pro64.build.f_cpu=16000000L
digispark-pro64.build.board=AVR_DIGISPARKPRO
digispark-pro64.build.core=pro
digispark-pro64.build.variant=pro64buffer
digispark-pro64.upload.wait_for_upload_port = false
digispark-pro64.upload.use_1200bps_touch = false
digispark-pro64.upload.disable_flushing = false

View File

@ -0,0 +1,465 @@
.....................................................................
This file includes licensing information for Arduino-Tiny. The GNU
Lesser General Public License covers Arduino-Tiny.
.....................................................................
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
.....................................................................

View File

@ -0,0 +1,274 @@
#ifndef Arduino_h
#define Arduino_h
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <avr/pgmspace.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "binary.h"
#ifdef __cplusplus
extern "C"{
#endif
#define ATTINY_CORE 1
#define HIGH 0x1
#define LOW 0x0
#define INPUT 0x0
#define OUTPUT 0x1
#define INPUT_PULLUP 0x2
#define true 0x1
#define false 0x0
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
#define SERIAL 0x0
#define DISPLAY 0x1
#define LSBFIRST 0
#define MSBFIRST 1
#define CHANGE 1
#define FALLING 2
#define RISING 3
// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#if __AVR_LIBC_VERSION__ < 10701UL
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#endif
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))
#define interrupts() sei()
#define noInterrupts() cli()
#if F_CPU < 1000000L
//Prevent a divide by 0 is
#warning Clocks per microsecond < 1. To prevent divide by 0, it is rounded up to 1.
static inline unsigned long clockCyclesPerMicrosecond() __attribute__ ((always_inline));
static inline unsigned long clockCyclesPerMicrosecond()
{
//Inline function will be optimised out.
return 1;
}
#else
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#endif
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
typedef unsigned int word;
#define bit(b) (1UL << (b))
typedef uint8_t boolean;
typedef uint8_t byte;
void initToneTimer(void);
void init(void);
void pinMode(uint8_t, uint8_t);
void digitalWrite(uint8_t, uint8_t);
int digitalRead(uint8_t);
int analogRead(uint8_t);
void analogReference(uint8_t mode);
void analogWrite(uint8_t, int);
unsigned long millis(void);
unsigned long micros(void);
void delay(unsigned long);
void delayMicroseconds(unsigned int us);
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
void attachInterrupt(uint8_t, void (*)(void), int mode);
void detachInterrupt(uint8_t);
void setup(void);
void loop(void);
// 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.
#define analogInPinToBit(P) (P)
extern const uint16_t PROGMEM port_to_mode_PGM[];
extern const uint16_t PROGMEM port_to_input_PGM[];
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_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.
// This comes from the pins_*.c file for the active board configuration.
//
// These perform slightly better as macros compared to inline functions
//
#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 digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
#define analogInPinToBit(P) (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 portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
#define NOT_A_PIN 0
#define NOT_A_PORT 0
#define PA 1
#define PB 2
#define PC 3
#define PD 4
#define NOT_ON_TIMER 0
#define TIMER0A 1
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
#define TIMER1D 5
#include "pins_arduino.h"
#ifndef USE_SOFTWARE_SERIAL
//Default to hardware serial.
#define USE_SOFTWARE_SERIAL 0
#endif
/*=============================================================================
Allow the ADC to be optional for low-power applications
=============================================================================*/
#ifndef TIMER_TO_USE_FOR_MILLIS
#define TIMER_TO_USE_FOR_MILLIS 0
#endif
/*
Tone goes on whichever timer was not used for millis.
*/
#if TIMER_TO_USE_FOR_MILLIS == 1
#define TIMER_TO_USE_FOR_TONE 0
#else
#define TIMER_TO_USE_FOR_TONE 1
#endif
#if NUM_ANALOG_INPUTS > 0
#define HAVE_ADC 1
#ifndef INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER
#define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 1
#endif
#else
#define HAVE_ADC 0
#if defined(INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER)
#undef INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER
#endif
#define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 0
#endif
#if !HAVE_ADC
#undef INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER
#define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 0
#else
#ifndef INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER
#define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 1
#endif
#endif
/*=============================================================================
Allow the "secondary timers" to be optional for low-power applications
=============================================================================*/
#ifndef INITIALIZE_SECONDARY_TIMERS
#define INITIALIZE_SECONDARY_TIMERS 1
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#ifdef __cplusplus
#include "WCharacter.h"
#include "WString.h"
#include "HardwareSerial.h"
#include "TinySoftwareSerial.h"
uint16_t makeWord(uint16_t w);
uint16_t makeWord(byte h, byte l);
#define word(...) makeWord(__VA_ARGS__)
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
void noTone(uint8_t _pin = 255);
// WMath prototypes
long random(long);
long random(long, long);
void randomSeed(unsigned int);
long map(long, long, long, long, long);
#endif
/*=============================================================================
Aliases for the interrupt service routine vector numbers so the code
doesn't have to be riddled with #ifdefs.
=============================================================================*/
#if defined( TIM0_COMPA_vect ) && ! defined( TIMER0_COMPA_vect )
#define TIMER0_COMPA_vect TIM0_COMPA_vect
#endif
#if defined( TIM0_COMPB_vect ) && ! defined( TIMER0_COMPB_vect )
#define TIMER0_COMPB_vect TIM0_COMPB_vect
#endif
#if defined( TIM0_OVF_vect ) && ! defined( TIMER0_OVF_vect )
#define TIMER0_OVF_vect TIM0_OVF_vect
#endif
#if defined( TIM1_COMPA_vect ) && ! defined( TIMER1_COMPA_vect )
#define TIMER1_COMPA_vect TIM1_COMPA_vect
#endif
#if defined( TIM1_COMPB_vect ) && ! defined( TIMER1_COMPB_vect )
#define TIMER1_COMPB_vect TIM1_COMPB_vect
#endif
#if defined( TIM1_OVF_vect ) && ! defined( TIMER1_OVF_vect )
#define TIMER1_OVF_vect TIM1_OVF_vect
#endif
#endif

View File

@ -0,0 +1,411 @@
/*
HardwareSerial.cpp - Hardware serial library for Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
Modified 28 September 2010 by Mark Sproul
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"
#include "wiring_private.h"
// this next line disables the entire HardwareSerial.cpp,
// this is so I can support Attiny series and any other chip without a uart
#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(LINBRRH)) && !USE_SOFTWARE_SERIAL
#include "HardwareSerial.h"
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.
#ifndef SERIAL_BUFFER_SIZE
#if (RAMEND < 1000)
#define SERIAL_BUFFER_SIZE 16
#else
#define SERIAL_BUFFER_SIZE 64
#endif
#endif
struct ring_buffer
{
unsigned char buffer[SERIAL_BUFFER_SIZE];
byte head;
byte tail;
};
#if defined(UBRRH) || defined(UBRR0H) || defined(LINBRRH)
ring_buffer rx_buffer = { { 0 }, 0, 0 };
ring_buffer tx_buffer = { { 0 }, 0, 0 };
#endif
#if defined(UBRR1H)
ring_buffer rx_buffer1 = { { 0 }, 0, 0 };
ring_buffer tx_buffer1 = { { 0 }, 0, 0 };
#endif
inline void store_char(unsigned char c, ring_buffer *buffer)
{
byte i = (buffer->head + 1) % SERIAL_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != buffer->tail) {
buffer->buffer[buffer->head] = c;
buffer->head = i;
}
}
#if defined(USART_RX_vect)
SIGNAL(USART_RX_vect)
{
#if defined(UDR0)
unsigned char c = UDR0;
#elif defined(UDR)
unsigned char c = UDR; // atmega8535
#else
#error UDR not defined
#endif
store_char(c, &rx_buffer);
}
#elif defined(SIG_USART0_RECV) && defined(UDR0)
SIGNAL(SIG_USART0_RECV)
{
unsigned char c = UDR0;
store_char(c, &rx_buffer);
}
#elif defined(SIG_UART0_RECV) && defined(UDR0)
SIGNAL(SIG_UART0_RECV)
{
unsigned char c = UDR0;
store_char(c, &rx_buffer);
}
//#elif defined(SIG_USART_RECV)
#elif defined(USART0_RX_vect)
// fixed by Mark Sproul this is on the 644/644p
//SIGNAL(SIG_USART_RECV)
SIGNAL(USART0_RX_vect)
{
#if defined(UDR0)
unsigned char c = UDR0;
#elif defined(UDR)
unsigned char c = UDR; // atmega8, atmega32
#else
#error UDR not defined
#endif
store_char(c, &rx_buffer);
}
#elif defined(SIG_UART_RECV)
// this is for atmega8
SIGNAL(SIG_UART_RECV)
{
#if defined(UDR0)
unsigned char c = UDR0; // atmega645
#elif defined(UDR)
unsigned char c = UDR; // atmega8
#endif
store_char(c, &rx_buffer);
}
#elif defined(LIN_TC_vect)
// this is for attinyX7
SIGNAL(LIN_TC_vect)
{
if(LINSIR & _BV(LRXOK)) {
unsigned char c = LINDAT;
store_char(c, &rx_buffer);
}
if(LINSIR & _BV(LTXOK)){
PINA |= _BV(PINA5);
if (tx_buffer.head == tx_buffer.tail) {
// Buffer empty, so disable interrupts
cbi(LINENIR,LENTXOK);
} else {
// There is more data in the output buffer. Send the next byte
unsigned char c = tx_buffer.buffer[tx_buffer.tail];
tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE;
LINDAT = c;
}
}
}
#else
#error No interrupt handler for usart 0
#endif
//#if defined(SIG_USART1_RECV)
#if defined(USART1_RX_vect)
//SIGNAL(SIG_USART1_RECV)
SIGNAL(USART1_RX_vect)
{
unsigned char c = UDR1;
store_char(c, &rx_buffer1);
}
#elif defined(SIG_USART1_RECV)
#error SIG_USART1_RECV
#endif
#if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect) && !defined(LIN_TC_vect)
#error "Don't know what the Data Register Empty vector is called for the first UART"
#elif ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H))
#if defined(UART0_UDRE_vect)
ISR(UART0_UDRE_vect)
#elif defined(UART_UDRE_vect)
ISR(UART_UDRE_vect)
#elif defined(USART0_UDRE_vect)
ISR(USART0_UDRE_vect)
#elif defined(USART_UDRE_vect)
ISR(USART_UDRE_vect)
#endif
{
if (tx_buffer.head == tx_buffer.tail) {
// Buffer empty, so disable interrupts
#if defined(UCSR0B)
cbi(UCSR0B, UDRIE0);
#else
cbi(UCSRB, UDRIE);
#endif
}
else {
// There is more data in the output buffer. Send the next byte
unsigned char c = tx_buffer.buffer[tx_buffer.tail];
tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE;
#if defined(UDR0)
UDR0 = c;
#elif defined(UDR)
UDR = c;
#else
#error UDR not defined
#endif
}
}
#endif
#ifdef USART1_UDRE_vect
ISR(USART1_UDRE_vect)
{
if (tx_buffer1.head == tx_buffer1.tail) {
// Buffer empty, so disable interrupts
cbi(UCSR1B, UDRIE1);
}
else {
// There is more data in the output buffer. Send the next byte
unsigned char c = tx_buffer1.buffer[tx_buffer1.tail];
tx_buffer1.tail = (tx_buffer1.tail + 1) % SERIAL_BUFFER_SIZE;
UDR1 = c;
}
}
#endif
// Constructors ////////////////////////////////////////////////////////////////
HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer
#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H))
,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x
)
{
_rx_buffer = rx_buffer;
_tx_buffer = tx_buffer;
_ubrrh = ubrrh;
_ubrrl = ubrrl;
_ucsra = ucsra;
_ucsrb = ucsrb;
_udr = udr;
_rxen = rxen;
_txen = txen;
_rxcie = rxcie;
_udrie = udrie;
_u2x = u2x;
}
#else
)
{
_rx_buffer = rx_buffer;
_tx_buffer = tx_buffer;
}
#endif
// Public Methods //////////////////////////////////////////////////////////////
void HardwareSerial::begin(long baud)
{
#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H))
uint16_t baud_setting;
bool use_u2x = true;
#if F_CPU == 16000000UL
// hardcoded exception for compatibility with the bootloader shipped
// with the Duemilanove and previous boards and the firmware on the 8U2
// on the Uno and Mega 2560.
if (baud == 57600) {
use_u2x = false;
}
#endif
try_again:
if (use_u2x) {
*_ucsra = 1 << _u2x;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
} else {
*_ucsra = 0;
baud_setting = (F_CPU / 8 / baud - 1) / 2;
}
if ((baud_setting > 4095) && use_u2x)
{
use_u2x = false;
goto try_again;
}
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
*_ubrrh = baud_setting >> 8;
*_ubrrl = baud_setting;
sbi(*_ucsrb, _rxen);
sbi(*_ucsrb, _txen);
sbi(*_ucsrb, _rxcie);
cbi(*_ucsrb, _udrie);
#else
LINCR = (1 << LSWRES);
LINBRR = (((F_CPU * 10L / 16L / baud) + 5L) / 10L) - 1;
LINBTR = (1 << LDISR) | (16 << LBT0);
LINCR = _BV(LENA) | _BV(LCMD2) | _BV(LCMD1) | _BV(LCMD0);
sbi(LINENIR,LENRXOK);
#endif
}
void HardwareSerial::end()
{
while (_tx_buffer->head != _tx_buffer->tail)
;
#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H))
cbi(*_ucsrb, _rxen);
cbi(*_ucsrb, _txen);
cbi(*_ucsrb, _rxcie);
cbi(*_ucsrb, _udrie);
#else
cbi(LINENIR,LENTXOK);
cbi(LINENIR,LENRXOK);
cbi(LINCR,LENA);
cbi(LINCR,LCMD0);
cbi(LINCR,LCMD1);
cbi(LINCR,LCMD2);
#endif
_rx_buffer->head = _rx_buffer->tail;
}
int HardwareSerial::available(void)
{
return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE;
}
int HardwareSerial::peek(void)
{
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
return _rx_buffer->buffer[_rx_buffer->tail];
}
}
int HardwareSerial::read(void)
{
// if the head isn't ahead of the tail, we don't have any characters
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
_rx_buffer->tail = (_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE;
return c;
}
}
void HardwareSerial::flush()
{
while (_tx_buffer->head != _tx_buffer->tail)
;
}
unsigned int HardwareSerial::txfree()
{
if (_tx_buffer->head >= _tx_buffer->tail) return SERIAL_BUFFER_SIZE - 1 - _tx_buffer->head + _tx_buffer->tail;
return _tx_buffer->tail - _tx_buffer->head - 1;
}
size_t HardwareSerial::write(uint8_t c)
{
byte i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE;
// If the output buffer is full, there's nothing for it other than to
// wait for the interrupt handler to empty it a bit
// ???: return 0 here instead?
while (txfree() == 0);
_tx_buffer->buffer[_tx_buffer->head] = c;
_tx_buffer->head = i;
#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) )
sbi(*_ucsrb, _udrie);
#else
if(!(LINENIR & _BV(LENTXOK))){
//The buffer was previously empty, so enable TX Complete interrupt and load first byte.
sbi(LINENIR,LENTXOK);
unsigned char c = tx_buffer.buffer[tx_buffer.tail];
tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE;
LINDAT = c;
}
#endif
return 1;
}
HardwareSerial::operator bool() {
return true;
}
// Preinstantiate Objects //////////////////////////////////////////////////////
#if defined(UBRRH) && defined(UBRRL)
HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE, U2X);
#elif defined(UBRR0H) && defined(UBRR0L)
HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0);
#elif defined(LINBRRH)
HardwareSerial Serial(&rx_buffer, &tx_buffer);
#endif
#if defined(UBRR1H)
HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1, U2X1);
#endif
#elif !USE_SOFTWARE_SERIAL
#warning There is no Hardware UART, and Sofware Serial is not enabled. There will be no serial port.
#endif // whole file

View File

@ -0,0 +1,80 @@
/*
HardwareSerial.h - Hardware serial library for Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 28 September 2010 by Mark Sproul
*/
#ifndef HardwareSerial_h
#define HardwareSerial_h
#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(LINBRRH)) && !USE_SOFTWARE_SERIAL
#include <inttypes.h>
#include "Stream.h"
struct ring_buffer;
class HardwareSerial : public Stream
{
private:
ring_buffer *_rx_buffer;
ring_buffer *_tx_buffer;
#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H))
volatile uint8_t *_ubrrh;
volatile uint8_t *_ubrrl;
volatile uint8_t *_ucsra;
volatile uint8_t *_ucsrb;
volatile uint8_t *_udr;
uint8_t _rxen;
uint8_t _txen;
uint8_t _rxcie;
uint8_t _udrie;
uint8_t _u2x;
#endif
public:
HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer
#if ( defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H))
,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x);
#else
);
#endif
void begin(long);
void end();
virtual int available(void);
virtual int peek(void);
virtual unsigned int txfree(void);
virtual int read(void);
virtual void flush(void);
virtual size_t write(uint8_t);
using Print::write; // pull in write(str) and write(buf, size) from Print
operator bool();
};
#endif
#if (defined(UBRRH) || defined(UBRR0H) || defined(LINBRRH)) && !USE_SOFTWARE_SERIAL
extern HardwareSerial Serial;
#endif
#if defined(UBRR1H)
extern HardwareSerial Serial1;
#endif
#endif

View File

@ -0,0 +1,262 @@
/*
Print.cpp - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "Arduino.h"
#include "Print.h"
// Public Methods //////////////////////////////////////////////////////////////
/* default implementation: may be overridden */
size_t Print::write(const uint8_t *buffer, size_t size)
{
size_t n = 0;
while (size--) {
n += write(*buffer++);
}
return n;
}
size_t Print::print(const String &s)
{
size_t n = 0;
for (uint16_t i = 0; i < s.length(); i++) {
n += write(s[i]);
}
return n;
}
size_t Print::print(const char str[])
{
return write(str);
}
size_t Print::print(char c)
{
return write(c);
}
size_t Print::print(unsigned char b, int base)
{
return print((unsigned long) b, base);
}
size_t Print::print(int n, int base)
{
return print((long) n, base);
}
size_t Print::print(unsigned int n, int base)
{
return print((unsigned long) n, base);
}
size_t Print::print(long n, int base)
{
if (base == 0) {
return write(n);
} else if (base == 10) {
int t = 0;
if (n < 0) {
t = print('-');
n = -n;
}
return printNumber(n, 10) + t;
} else {
return printNumber(n, base);
}
}
size_t Print::print(unsigned long n, int base)
{
if (base == 0) return write(n);
else return printNumber(n, base);
}
size_t Print::print(double n, int digits)
{
return printFloat(n, digits);
}
size_t Print::print( fstr_t* s )
{
size_t n = 0;
char ch;
ch = pgm_read_byte( s );
while ( ch != 0 )
{
write( ch );
++s;
++n;
ch = pgm_read_byte( s );
}
return( n );
}
size_t Print::println(void)
{
size_t n = print('\r');
n += print('\n');
return n;
}
size_t Print::println(const String &s)
{
size_t n = print(s);
n += println();
return n;
}
size_t Print::println(const char c[])
{
size_t n = print(c);
n += println();
return n;
}
size_t Print::println(char c)
{
size_t n = print(c);
n += println();
return n;
}
size_t Print::println(unsigned char b, int base)
{
size_t n = print(b, base);
n += println();
return n;
}
size_t Print::println(int num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(unsigned int num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(long long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(unsigned long num, int base)
{
size_t n = print(num, base);
n += println();
return n;
}
size_t Print::println(double num, int digits)
{
size_t n = print(num, digits);
n += println();
return n;
}
size_t Print::println( fstr_t* s )
{
size_t n = print( s );
n += println();
return( n );
}
// Private Methods /////////////////////////////////////////////////////////////
size_t Print::printNumber(unsigned long n, uint8_t base) {
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
char *str = &buf[sizeof(buf) - 1];
*str = '\0';
// prevent crash if called with base == 1
if (base < 2) base = 10;
do {
unsigned long m = n;
n /= base;
char c = m - base * n;
*--str = c < 10 ? c + '0' : c + 'A' - 10;
} while(n);
return write(str);
}
size_t Print::printFloat(double number, uint8_t digits)
{
size_t n = 0;
// Handle negative numbers
if (number < 0.0)
{
n += print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for (uint8_t i=0; i<digits; ++i)
rounding /= 10.0;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
n += print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits > 0) {
n += print(".");
}
// Extract digits from the remainder one at a time
while (digits-- > 0)
{
remainder *= 10.0;
int toPrint = int(remainder);
n += print(toPrint);
remainder -= toPrint;
}
return n;
}

View File

@ -0,0 +1,108 @@
/*
Print.h - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 20-11-2010 by B.Cook ...
http://arduiniana.org/libraries/flash/
Printable support thanks to Mikal Hart
*/
#ifndef Print_h
#define Print_h
#include <inttypes.h>
#include <stdio.h> // for size_t
#include "WString.h"
#define DEC 10
#define HEX 16
#define OCT 8
#ifdef BIN
#define ABIN BIN
//One of the ATtiny84 registers has a bit called BIN, so rename it to avoid compiler warnings.
#undef BIN
#endif
#define BIN 2
#define ARDUINO_CORE_PRINTABLE_SUPPORT
class Print;
/* Printable...*/
class _Printable
{
public:
virtual void print(Print &stream) const = 0;
};
/* ...Printable */
typedef struct
{
char c;
}
fstr_t;
class Print
{
private:
int write_error;
size_t printNumber(unsigned long, uint8_t);
size_t printFloat(double, uint8_t);
protected:
void setWriteError(int err = 1) { write_error = err; }
public:
Print() : write_error(0) {}
int getWriteError() { return write_error; }
void clearWriteError() { setWriteError(0); }
virtual size_t write(uint8_t) = 0;
size_t write(const char *str) { return write((const uint8_t *)str, strlen(str)); }
virtual size_t write(const uint8_t *buffer, size_t size);
size_t print(fstr_t*);
size_t print(const String &);
size_t print(const char[]);
size_t print(char);
size_t print(unsigned char, int = DEC);
size_t print(int, int = DEC);
size_t print(unsigned int, int = DEC);
size_t print(long, int = DEC);
size_t print(long long, int = DEC);
size_t print(unsigned long, int = DEC);
size_t print(double, int = 2);
size_t println(fstr_t*);
size_t println(const String &s);
size_t println(const char[]);
size_t println(char);
size_t println(unsigned char, int = DEC);
size_t println(int, int = DEC);
size_t println(unsigned int, int = DEC);
size_t println(long, int = DEC);
size_t println(long long, int = DEC);
size_t println(unsigned long, int = DEC);
size_t println(double, int = 2);
size_t println(void);
};
#endif

View File

@ -0,0 +1,40 @@
/*
Printable.h - Interface class that allows printing of complex types
Copyright (c) 2011 Adrian McEwen. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef Printable_h
#define Printable_h
#include <new.h>
class Print;
/** The Printable class provides a way for new classes to allow themselves to be printed.
By deriving from Printable and implementing the printTo method, it will then be possible
for users to print out instances of this class by passing them into the usual
Print::print and Print::println methods.
*/
class Printable
{
public:
virtual size_t printTo(Print& p) const = 0;
};
#endif

View File

@ -0,0 +1,270 @@
/*
Stream.cpp - adds parsing methods to Stream class
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Created July 2011
parsing functions based on TextFinder library by Michael Margolis
*/
#include "Arduino.h"
#include "Stream.h"
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
// private method to read stream with timeout
int Stream::timedRead()
{
int c;
_startMillis = millis();
do {
c = read();
if (c >= 0) return c;
} while(millis() - _startMillis < _timeout);
return -1; // -1 indicates timeout
}
// private method to peek stream with timeout
int Stream::timedPeek()
{
int c;
_startMillis = millis();
do {
c = peek();
if (c >= 0) return c;
} while(millis() - _startMillis < _timeout);
return -1; // -1 indicates timeout
}
// returns peek of the next digit in the stream or -1 if timeout
// discards non-numeric characters
int Stream::peekNextDigit()
{
int c;
while (1) {
c = timedPeek();
if (c < 0) return c; // timeout
if (c == '-') return c;
if (c >= '0' && c <= '9') return c;
read(); // discard non-numeric
}
}
// Public Methods
//////////////////////////////////////////////////////////////
void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
{
_timeout = timeout;
}
// find returns true if the target string is found
bool Stream::find(char *target)
{
return findUntil(target, "");
}
// reads data from the stream until the target string of given length is found
// returns true if target string is found, false if timed out
bool Stream::find(char *target, size_t length)
{
return findUntil(target, length, NULL, 0);
}
// as find but search ends if the terminator string is found
bool Stream::findUntil(char *target, char *terminator)
{
return findUntil(target, strlen(target), terminator, strlen(terminator));
}
// reads data from the stream until the target string of the given length is found
// search terminated if the terminator string is found
// returns true if target string is found, false if terminated or timed out
bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen)
{
size_t index = 0; // maximum target string length is 64k bytes!
size_t termIndex = 0;
int c;
if( *target == 0)
return true; // return true if target is a null string
while( (c = timedRead()) > 0){
if(c != target[index])
index = 0; // reset index if any char does not match
if( c == target[index]){
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
if(++index >= targetLen){ // return true if all chars in the target match
return true;
}
}
if(termLen > 0 && c == terminator[termIndex]){
if(++termIndex >= termLen)
return false; // return false if terminate string found before target string
}
else
termIndex = 0;
}
return false;
}
// returns the first valid (long) integer value from the current position.
// initial characters that are not digits (or the minus sign) are skipped
// function is terminated by the first character that is not a digit.
long Stream::parseInt()
{
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
}
// as above but a given skipChar is ignored
// this allows format characters (typically commas) in values to be ignored
long Stream::parseInt(char skipChar)
{
boolean isNegative = false;
long value = 0;
int c;
c = peekNextDigit();
// ignore non numeric leading characters
if(c < 0)
return 0; // zero returned if timeout
do{
if(c == skipChar)
; // ignore this charactor
else if(c == '-')
isNegative = true;
else if(c >= '0' && c <= '9') // is c a digit?
value = value * 10 + c - '0';
read(); // consume the character we got with peek
c = timedPeek();
}
while( (c >= '0' && c <= '9') || c == skipChar );
if(isNegative)
value = -value;
return value;
}
// as parseInt but returns a floating point value
float Stream::parseFloat()
{
return parseFloat(NO_SKIP_CHAR);
}
// as above but the given skipChar is ignored
// this allows format characters (typically commas) in values to be ignored
float Stream::parseFloat(char skipChar){
boolean isNegative = false;
boolean isFraction = false;
long value = 0;
char c;
float fraction = 1.0;
c = peekNextDigit();
// ignore non numeric leading characters
if(c < 0)
return 0; // zero returned if timeout
do{
if(c == skipChar)
; // ignore
else if(c == '-')
isNegative = true;
else if (c == '.')
isFraction = true;
else if(c >= '0' && c <= '9') { // is c a digit?
value = value * 10 + c - '0';
if(isFraction)
fraction *= 0.1;
}
read(); // consume the character we got with peek
c = timedPeek();
}
while( (c >= '0' && c <= '9') || c == '.' || c == skipChar );
if(isNegative)
value = -value;
if(isFraction)
return value * fraction;
else
return value;
}
// read characters from stream into buffer
// terminates if length characters have been read, or timeout (see setTimeout)
// returns the number of characters placed in the buffer
// the buffer is NOT null terminated.
//
size_t Stream::readBytes(char *buffer, size_t length)
{
size_t count = 0;
while (count < length) {
int c = timedRead();
if (c < 0) break;
*buffer++ = (char)c;
count++;
}
return count;
}
// as readBytes with terminator character
// terminates if length characters have been read, timeout, or if the terminator character detected
// returns the number of characters placed in the buffer (0 means no valid data found)
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
{
if (length < 1) return 0;
size_t index = 0;
while (index < length) {
int c = timedRead();
if (c < 0 || c == terminator) break;
*buffer++ = (char)c;
index++;
}
return index; // return number of characters, not including null terminator
}
String Stream::readString()
{
String ret;
int c = timedRead();
while (c >= 0)
{
ret += (char)c;
c = timedRead();
}
return ret;
}
String Stream::readStringUntil(char terminator)
{
String ret;
int c = timedRead();
while (c >= 0 && c != terminator)
{
ret += (char)c;
c = timedRead();
}
return ret;
}

View File

@ -0,0 +1,96 @@
/*
Stream.h - base class for character-based streams.
Copyright (c) 2010 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
parsing functions based on TextFinder library by Michael Margolis
*/
#ifndef Stream_h
#define Stream_h
#include <inttypes.h>
#include "Print.h"
// compatability macros for testing
/*
#define getInt() parseInt()
#define getInt(skipChar) parseInt(skipchar)
#define getFloat() parseFloat()
#define getFloat(skipChar) parseFloat(skipChar)
#define getString( pre_string, post_string, buffer, length)
readBytesBetween( pre_string, terminator, buffer, length)
*/
class Stream : public Print
{
protected:
unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read
unsigned long _startMillis; // used for timeout measurement
int timedRead(); // private method to read stream with timeout
int timedPeek(); // private method to peek stream with timeout
int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout
public:
virtual int available() = 0;
virtual int read() = 0;
virtual int peek() = 0;
virtual void flush() = 0;
Stream() {_timeout=1000;}
// parsing methods
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
bool find(char *target); // reads data from the stream until the target string is found
// returns true if target string is found, false if timed out (see setTimeout)
bool find(char *target, size_t length); // reads data from the stream until the target string of given length is found
// returns true if target string is found, false if timed out
bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found
bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found
long parseInt(); // returns the first valid (long) integer value from the current position.
// initial characters that are not digits (or the minus sign) are skipped
// integer is terminated by the first character that is not a digit.
float parseFloat(); // float version of parseInt
size_t readBytes( char *buffer, size_t length); // read chars from stream into buffer
// terminates if length characters have been read or timeout (see setTimeout)
// returns the number of characters placed in the buffer (0 means no valid data found)
size_t readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character
// terminates if length characters have been read, timeout, or if the terminator character detected
// returns the number of characters placed in the buffer (0 means no valid data found)
// Arduino String functions to be added here
String readString();
String readStringUntil(char terminator);
protected:
long parseInt(char skipChar); // as above but the given skipChar is ignored
// as above but the given skipChar is ignored
// this allows format characters (typically commas) in values to be ignored
float parseFloat(char skipChar); // as above but the given skipChar is ignored
};
#endif

View File

@ -0,0 +1,35 @@
/*
Stream.h - base class for character-based streams.
Copyright (c) 2010 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef Stream_h
#define Stream_h
#include <inttypes.h>
#include "Print.h"
class Stream : public Print
{
public:
virtual int available() = 0;
virtual int read() = 0;
virtual int peek() = 0;
virtual void flush() = 0;
};
#endif

View File

@ -0,0 +1,218 @@
/*
* Copyright (c) 2012 by Thomas Carpenter
* Software based SPI Master Library for Tiny core.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*
* Currently, this runs at 125kHz on an 8MHz clock.
*/
#include "TinySoftwareSPI.h"
#include "Arduino.h"
SoftSPIClass::SoftSPIClass(){
_bitOrder = MSBFIRST;
_mode = SPI_MODE0;
_running = false;
transferType = &SoftSPIClass::noTransfer;
}
#if defined(SS) && defined(MOSI) && defined(MISO) && defined(SCK)
void SoftSPIClass::begin(){
begin(SCK,MOSI,MISO,SS);
}
#endif
void SoftSPIClass::writeSS(boolean state){
if (state) {
*_SS_PORT |= _SS_HIGH;
} else {
*_SS_PORT &= _SS_LOW;
}
}
void SoftSPIClass::begin(byte SCK_, byte MOSI_, byte MISO_, byte SS_){
_SS = SS_;
_SCK = SCK_;
_MISO = MISO_;
_MOSI = MOSI_;
byte MOSIport = digitalPinToPort(_MOSI);
byte SSport = digitalPinToPort(_SS);
byte SCKport = digitalPinToPort(_SCK);
byte MISOport = digitalPinToPort(_MISO);
if ((MOSIport == NOT_A_PIN) ||
( SSport == NOT_A_PIN) ||
( SCKport == NOT_A_PIN) ||
(MISOport == NOT_A_PIN) ){
end();
} else {
_running = true;
pinMode(_MOSI, OUTPUT);
pinMode(_MISO, INPUT);
pinMode(_SCK, OUTPUT);
pinMode(_SS, OUTPUT);
_MOSI_PORT = portOutputRegister(MOSIport);
_MOSI_HIGH = digitalPinToBitMask(_MOSI);
_MOSI_LOW = ~_MOSI_HIGH;
_SCK_PORT = portOutputRegister(SCKport);
_SCK_HIGH = digitalPinToBitMask(_SCK);
_SCK_LOW = ~_SCK_HIGH;
_SS_PORT = portOutputRegister(SSport);
_SS_HIGH = digitalPinToBitMask(_SS);
_SS_LOW = ~_SS_HIGH;
_MISO_PIN = portInputRegister(MISOport);
_MISO_MASK = digitalPinToBitMask(_MISO);
*_SS_PORT |= _SS_HIGH;
*_SCK_PORT &= _SCK_LOW;
*_MOSI_PORT &= _MOSI_LOW;
//Default to Mode0.
_mode = SPI_MODE0;
transferType = &SoftSPIClass::transferMode0;
}
}
byte SoftSPIClass::noTransfer(byte _data){
//This does nothing. If you call SPI.transfer() before calling begin() or after calling end(), the call will be redirected here to avoid crash.
return 0xFF;
}
byte SoftSPIClass::transferMode0(byte _data){
byte _newData = 0;
for (byte i = 0;i < 8; i++){
if(_data & 0x80){
*_MOSI_PORT |= _MOSI_HIGH;
} else {
*_MOSI_PORT &= _MOSI_LOW;
}
_data <<= 1;
*_SCK_PORT |= _SCK_HIGH;
_newData <<= 1;
_newData |= ((*_MISO_PIN & _MISO_MASK) ? 1 : 0);
*_SCK_PORT &= _SCK_LOW;
}
return _newData;
}
byte SoftSPIClass::transferMode1(byte _data){
byte _newData = 0;
for (byte i = 0;i < 8; i++){
*_SCK_PORT |= _SCK_HIGH;
if(_data & 0x80){
*_MOSI_PORT |= _MOSI_HIGH;
} else {
*_MOSI_PORT &= _MOSI_LOW;
}
_data <<= 1;
*_SCK_PORT &= _SCK_LOW;
_newData <<= 1;
_newData |= ((*_MISO_PIN & _MISO_MASK) ? 1 : 0);
}
return _newData;
}
byte SoftSPIClass::transferMode2(byte _data){
byte _newData = 0;
for (byte i = 0;i < 8; i++){
if(_data & 0x80){
*_MOSI_PORT |= _MOSI_HIGH;
} else {
*_MOSI_PORT &= _MOSI_LOW;
}
_data <<= 1;
*_SCK_PORT &= _SCK_LOW;
_newData <<= 1;
_newData |= ((*_MISO_PIN & _MISO_MASK) ? 1 : 0);
*_SCK_PORT |= _SCK_HIGH;
}
return _newData;
}
byte SoftSPIClass::transferMode3(byte _data){
byte _newData = 0;
for (byte i = 0;i < 8; i++){
*_SCK_PORT &= _SCK_LOW;
if(_data & 0x80){
*_MOSI_PORT |= _MOSI_HIGH;
} else {
*_MOSI_PORT &= _MOSI_LOW;
}
_data <<= 1;
*_SCK_PORT |= _SCK_HIGH;
_newData <<= 1;
_newData |= ((*_MISO_PIN & _MISO_MASK) ? 1 : 0);
}
return _newData;
}
byte SoftSPIClass::transfer(byte _data){
byte _newData = 0;
byte oldSREG = SREG;
cli();
if (_bitOrder == MSBFIRST){
//Send data
_newData = (*this.*transferType)(_data);
SREG = oldSREG;
return _newData;
} else {
//flip the data
for(byte i = 0; i < 8; i++){
_newData <<= 1;
_newData |= _data & 1;
_data >>= 1;
}
//SPI transfer
_newData = (*this.*transferType)(_newData);
SREG = oldSREG;
//flip data back.
_data = 0;
for(byte i = 0; i < 8; i++){
_data <<= 1;
_data |= _newData & 1;
_newData >>= 1;
}
return _data;
}
}
void SoftSPIClass::end(){
_running = false;
transferType = &SoftSPIClass::noTransfer;
}
void SoftSPIClass::setBitOrder(uint8_t bitOrder) {
_bitOrder = bitOrder;
}
void SoftSPIClass::setDataMode(uint8_t mode)
{
_mode = mode;
if(_mode == SPI_MODE0){
transferType = &SoftSPIClass::transferMode0;
} else if (_mode == SPI_MODE1){
transferType = &SoftSPIClass::transferMode1;
} else if (_mode == SPI_MODE2){
transferType = &SoftSPIClass::transferMode2;
} else if (_mode == SPI_MODE3){
transferType = &SoftSPIClass::transferMode3;
} else {
_mode = SPI_MODE0;
transferType = &SoftSPIClass::transferMode0;
}
if(_mode & 0x02){
*_SCK_PORT |= _SCK_HIGH;
} else {
*_SCK_PORT &= _SCK_LOW;
}
}
void SoftSPIClass::setClockDivider(uint8_t rate)
{
//does nothing as the speed cannot be changed - fixed at Fcpu/16
}
SoftSPIClass SPI;

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2012 by Thomas Carpenter
* Software based SPI Master Library for Tiny core.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either the GNU General Public License version 2
* or the GNU Lesser General Public License version 2.1, both as
* published by the Free Software Foundation.
*/
#ifndef _SPI_H_INCLUDED
//Uses the same guard as the SPI class as the two cannot be used together
#define _SPI_H_INCLUDED
#include <stdio.h>
#include <Arduino.h>
#define SPI_MODE0 0
#define SPI_MODE1 1
#define SPI_MODE2 2
#define SPI_MODE3 3
#define SPI_CLOCK_DIV4 0x00
#define SPI_CLOCK_DIV16 0x01
#define SPI_CLOCK_DIV64 0x02
#define SPI_CLOCK_DIV128 0x03
#define SPI_CLOCK_DIV2 0x04
#define SPI_CLOCK_DIV8 0x05
#define SPI_CLOCK_DIV32 0x06
class SoftSPIClass;
typedef byte (SoftSPIClass::*TransferFunction)(byte _data);
class SoftSPIClass {
public:
SoftSPIClass();
private:
TransferFunction transferType;
byte noTransfer(byte _data);
byte transferMode0(byte _data);
byte transferMode1(byte _data);
byte transferMode2(byte _data);
byte transferMode3(byte _data);
public:
byte transfer(byte _data);
// SPI Configuration methods
#if defined(SS) && defined(MOSI) && defined(MISO) && defined(SCK)
void begin(); // Default to the preset SPI pins
#endif
void begin(byte SCK_, byte MOSI_, byte MISO_, byte SS_); //No SS specified, so require pin designation
void end();
void setBitOrder(uint8_t);
void setDataMode(uint8_t);
void setClockDivider(uint8_t);
void writeSS(boolean state);
private:
byte _rate;
byte _bitOrder;
byte _mode;
boolean _running;
byte _SS;
byte _SCK;
byte _MISO;
byte _MOSI;
volatile uint8_t* _MOSI_PORT;
volatile uint8_t* _SS_PORT;
volatile uint8_t* _SCK_PORT;
volatile uint8_t* _MISO_PIN;
byte _SS_HIGH;
byte _MOSI_HIGH;
byte _SCK_HIGH;
byte _SS_LOW;
byte _MOSI_LOW;
byte _SCK_LOW;
byte _MISO_MASK;
};
extern SoftSPIClass SPI;
#endif

View File

@ -0,0 +1,266 @@
/*
TinySoftwareSerial.cpp - Hardware serial library for Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
Modified 28 September 2010 by Mark Sproul
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"
#include "wiring_private.h"
#if USE_SOFTWARE_SERIAL
#include "TinySoftwareSerial.h"
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.
extern "C"{
uint8_t getch() {
uint8_t ch = 0;
__asm__ __volatile__ (
" rcall uartDelay\n" // Get to 0.25 of start bit (our baud is too fast, so give room to correct)
"1: rcall uartDelay\n" // Wait 0.25 bit period
" rcall uartDelay\n" // Wait 0.25 bit period
" rcall uartDelay\n" // Wait 0.25 bit period
" rcall uartDelay\n" // Wait 0.25 bit period
" clc\n"
" in r23,%[pin]\n"
" and r23, %[mask]\n"
" breq 2f\n"
" sec\n"
"2: ror %0\n"
" dec %[count]\n"
" breq 3f\n"
" rjmp 1b\n"
"3: rcall uartDelay\n" // Wait 0.25 bit period
" rcall uartDelay\n" // Wait 0.25 bit period
:
"=r" (ch)
:
"0" ((uint8_t)0),
[count] "r" ((uint8_t)8),
[pin] "I" (_SFR_IO_ADDR(ANALOG_COMP_PIN)),
[mask] "r" (Serial._rxmask)
:
"r23",
"r24",
"r25"
);
return ch;
}
void uartDelay() {
__asm__ __volatile__ (
"mov r25,%[count]\n"
"1:dec r25\n"
"brne 1b\n"
"ret\n"
::[count] "r" ((uint8_t)Serial._delayCount)
);
}
#if !defined (ANALOG_COMP_vect) && defined(ANA_COMP_vect)
//rename the vector so we can use it.
#define ANALOG_COMP_vect ANA_COMP_vect
#elif !defined (ANALOG_COMP_vect)
#error Tiny Software Serial cant find the Analog comparator interrupt vector!
#endif
ISR(ANALOG_COMP_vect){
char ch = getch(); //read in the character softwarily - I know its not a word, but it sounded cool, so you know what: #define softwarily 1
store_char(ch, Serial._rx_buffer);
sbi(ACSR,ACI); //clear the flag.
}
}
soft_ring_buffer rx_buffer = { { 0 }, 0, 0 };
// Constructor ////////////////////////////////////////////////////////////////
TinySoftwareSerial::TinySoftwareSerial(soft_ring_buffer *rx_buffer, uint8_t txBit, uint8_t rxBit)
{
_rx_buffer = rx_buffer;
_rxmask = _BV(rxBit);
_txmask = _BV(txBit);
_txunmask = ~_txmask;
_delayCount = 0;
}
// Public Methods //////////////////////////////////////////////////////////////
void TinySoftwareSerial::begin(long baud)
{
long tempDelay = (((F_CPU/baud)-39)/12);
if ((tempDelay > 255) || (tempDelay <= 0)){
end(); //Cannot start as it would screw up uartDelay().
}
_delayCount = (uint8_t)tempDelay;
cbi(ACSR,ACIE); //turn off the comparator interrupt to allow change of ACD
#ifdef ACBG
sbi(ACSR,ACBG); //enable the internal bandgap reference - used instead of AIN0 to allow it to be used for TX.
#endif
cbi(ACSR,ACD); //turn on the comparator for RX
#ifdef ACIC
cbi(ACSR,ACIC); //prevent the comparator from affecting timer1 - just to be safe.
#endif
sbi(ACSR,ACIS1); //interrupt on rising edge (this means RX has gone from Mark state to Start bit state).
sbi(ACSR,ACIS0);
//Setup the pins in case someone messed with them.
ANALOG_COMP_DDR &= ~_rxmask; //set RX to an input
ANALOG_COMP_PORT |= _rxmask; //enable pullup on RX pin - to prevent accidental interrupt triggers.
ANALOG_COMP_DDR |= _txmask; //set TX to an output.
ANALOG_COMP_PORT |= _txmask; //set TX pin high
sbi(ACSR,ACI); //clear the flag.
sbi(ACSR,ACIE); //turn on the comparator interrupt to allow us to use it for RX
#ifdef ACSRB
ACSRB = 0; //Use AIN0 as +, AIN1 as -, no hysteresis - just like ones without this register.
#endif
}
void TinySoftwareSerial::end()
{
sbi(ACSR,ACI); //clear the flag.
cbi(ACSR,ACIE); //turn off the comparator interrupt to allow change of ACD, and because it needs to be turned off now too!
#ifdef ACBG
cbi(ACSR,ACBG); //disable the bandgap reference
#endif
sbi(ACSR,ACD); //turn off the comparator to save power
_delayCount = 0;
_rx_buffer->head = _rx_buffer->tail;
}
int TinySoftwareSerial::available(void)
{
return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE;
}
void store_char(unsigned char c, soft_ring_buffer *buffer)
{
int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != buffer->tail) {
buffer->buffer[buffer->head] = c;
buffer->head = i;
}
}
int TinySoftwareSerial::peek(void)
{
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
return _rx_buffer->buffer[_rx_buffer->tail];
}
}
int TinySoftwareSerial::read(void)
{
// if the head isn't ahead of the tail, we don't have any characters
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
_rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE;
return c;
}
}
size_t TinySoftwareSerial::write(uint8_t ch)
{
uint8_t oldSREG = SREG;
cli(); //Prevent interrupts from breaking the transmission. Note: TinySoftwareSerial is half duplex.
//it can either recieve or send, not both (because recieving requires an interrupt and would stall transmission
__asm__ __volatile__ (
" com %[ch]\n" // ones complement, carry set
" sec\n"
"1: brcc 2f\n"
" in r23,%[uartPort] \n"
" and r23,%[uartUnmask]\n"
" out %[uartPort],r23 \n"
" rjmp 3f\n"
"2: in r23,%[uartPort] \n"
" or r23,%[uartMask]\n"
" out %[uartPort],r23 \n"
" nop\n"
"3: rcall uartDelay\n"
" rcall uartDelay\n"
" rcall uartDelay\n"
" rcall uartDelay\n"
" lsr %[ch]\n"
" dec %[count]\n"
" brne 1b\n"
:
:
[ch] "r" (ch),
[count] "r" ((uint8_t)10),
[uartPort] "I" (_SFR_IO_ADDR(ANALOG_COMP_PORT)),
[uartMask] "r" (_txmask),
[uartUnmask] "r" (_txunmask)
: "r23",
"r24",
"r25"
);
SREG = oldSREG;
return 1;
}
void TinySoftwareSerial::flush()
{
}
TinySoftwareSerial::operator bool() {
return true;
}
// Preinstantiate Objects //////////////////////////////////////////////////////
#ifndef ANALOG_COMP_DDR
#error Please define ANALOG_COMP_DDR in the pins_arduino.h file!
#endif
#ifndef ANALOG_COMP_PORT
#error Please define ANALOG_COMP_PORT in the pins_arduino.h file!
#endif
#ifndef ANALOG_COMP_PIN
#error Please define ANALOG_COMP_PIN in the pins_arduino.h file!
#endif
#ifndef ANALOG_COMP_AIN0_BIT
#error Please define ANALOG_COMP_AIN0_BIT in the pins_arduino.h file!
#endif
#ifndef ANALOG_COMP_AIN1_BIT
#error Please define ANALOG_COMP_AIN1_BIT in the pins_arduino.h file!
#endif
TinySoftwareSerial Serial(&rx_buffer, ANALOG_COMP_AIN0_BIT, ANALOG_COMP_AIN1_BIT);
#endif // whole file

View File

@ -0,0 +1,61 @@
#if USE_SOFTWARE_SERIAL
#ifndef TinySoftwareSerial_h
#define TinySoftwareSerial_h
#include <inttypes.h>
#include "Stream.h"
#if !defined(ACSR) && defined(ACSRA)
#define ACSR ACSRA
#endif
#if (RAMEND < 250)
#define SERIAL_BUFFER_SIZE 8
#elif (RAMEND < 500)
#define SERIAL_BUFFER_SIZE 16
#elif (RAMEND < 1000)
#define SERIAL_BUFFER_SIZE 32
#else
#define SERIAL_BUFFER_SIZE 128
#endif
struct soft_ring_buffer
{
unsigned char buffer[SERIAL_BUFFER_SIZE];
int head;
int tail;
};
extern "C"{
void uartDelay() __attribute__ ((naked));
uint8_t getch();
void store_char(unsigned char c, soft_ring_buffer *buffer);
}
class TinySoftwareSerial : public Stream
{
public: //should be private but needed by extern "C" {} functions.
uint8_t _rxmask;
uint8_t _txmask;
uint8_t _txunmask;
soft_ring_buffer *_rx_buffer;
uint8_t _delayCount;
public:
TinySoftwareSerial(soft_ring_buffer *rx_buffer, uint8_t txBit, uint8_t rxBit);
void begin(long);
void end();
virtual int available(void);
virtual int peek(void);
virtual int read(void);
virtual void flush(void);
virtual size_t write(uint8_t);
using Print::write; // pull in write(str) and write(buf, size) from Print
operator bool();
};
#if (!defined(UBRRH) && !defined(UBRR0H)) || USE_SOFTWARE_SERIAL
extern TinySoftwareSerial Serial;
#endif
//extern void putch(uint8_t);
#endif
#endif

View File

@ -0,0 +1,546 @@
/* Tone.cpp
A Tone Generator Library
Written by Brett Hagman
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Version Modified By Date Comments
------- ----------- -------- --------
0001 B Hagman 09/08/02 Initial coding
0002 B Hagman 09/08/18 Multiple pins
0003 B Hagman 09/08/18 Moved initialization from constructor to begin()
0004 B Hagman 09/09/26 Fixed problems with ATmega8
0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers
09/11/25 Changed pin toggle method to XOR
09/11/25 Fixed timer0 from being excluded
0006 D Mellis 09/12/29 Replaced objects with functions
0007 B Cook 10/05/03 Rewritten to only work with Timer1 and support direct hardware output
0008 B Cook 10/05/03 Rewritten so the timer can be selected at compile time
0009 T Carpenter 12/08/06 Rewritten to remove requirement for all the wierd timer name creation macros.
*************************************************/
#include <avr/interrupt.h>
#include "Arduino.h"
#include "wiring_private.h"
#include "pins_arduino.h"
// timerx_toggle_count:
// > 0 - duration specified
// = 0 - stopped
// < 0 - infinitely (until stop() method called, or new play() called)
static volatile long tone_timer_toggle_count;
static volatile uint8_t *tone_timer_pin_register;
static volatile uint8_t tone_timer_pin_mask;
static uint8_t tone_pin = 255;
void tone( uint8_t _pin, unsigned int frequency, unsigned long duration )
{
if ( tone_pin == 255 )
{
/* Set the timer to power-up conditions so we start from a known state */
// Ensure the timer is in the same state as power-up
#if (TIMER_TO_USE_FOR_TONE == 0)
TCCR0B = (0<<FOC0A) | (0<<FOC0B) | (0<<WGM02) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCCR0A = (0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
// Reset the count to zero
TCNT0 = 0;
// Set the output compare registers to zero
OCR0A = 0;
OCR0B = 0;
#if defined(TIMSK)
// Disable all Timer0 interrupts
TIMSK &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
// Clear the Timer0 interrupt flags
TIFR |= ((1<<OCF0B) | (1<<OCF0A) | (1<<TOV0));
#elif defined(TIMSK1)
// Disable all Timer0 interrupts
TIMSK0 &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
// Clear the Timer0 interrupt flags
TIFR0 |= ((1<<OCF0B) | (1<<OCF0A) | (1<<TOV0));
#endif
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1)
// Turn off Clear on Compare Match, turn off PWM A, disconnect the timer from the output pin, stop the clock
TCCR1 = (0<<CTC1) | (0<<PWM1A) | (0<<COM1A1) | (0<<COM1A0) | (0<<CS13) | (0<<CS12) | (0<<CS11) | (0<<CS10);
// Turn off PWM A, disconnect the timer from the output pin, no Force Output Compare Match, no Prescaler Reset
GTCCR &= ~((1<<PWM1B) | (1<<COM1B1) | (1<<COM1B0) | (1<<FOC1B) | (1<<FOC1A) | (1<<PSR1));
// Reset the count to zero
TCNT1 = 0;
// Set the output compare registers to zero
OCR1A = 0;
OCR1B = 0;
OCR1C = 0;
// Disable all Timer1 interrupts
TIMSK &= ~((1<<OCIE1A) | (1<<OCIE1B) | (1<<TOIE1));
// Clear the Timer1 interrupt flags
TIFR |= ((1<<OCF1A) | (1<<OCF1B) | (1<<TOV1));
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1E)
TCCR1A = 0;
TCCR1B = 0;
TCCR1C = 0;
TCCR1D = 0;
TCCR1E = 0;
// Reset the count to zero
TCNT1 = 0;
// Set the output compare registers to zero
OCR1A = 0;
OCR1B = 0;
// Disable all Timer1 interrupts
TIMSK &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<OCIE1D));
// Clear the Timer1 interrupt flags
TIFR |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<OCF1D));
#elif (TIMER_TO_USE_FOR_TONE == 1)
// Turn off Input Capture Noise Canceler, Input Capture Edge Select on Falling, stop the clock
TCCR1B = (0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
// Disconnect the timer from the output pins, Set Waveform Generation Mode to Normal
TCCR1A = (0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
// Reset the count to zero
TCNT1 = 0;
// Set the output compare registers to zero
OCR1A = 0;
OCR1B = 0;
// Disable all Timer1 interrupts
#if defined(TIMSK)
TIMSK &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<ICIE1));
// Clear the Timer1 interrupt flags
TIFR |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<ICF1));
#elif defined(TIMSK1)
// Disable all Timer1 interrupts
TIMSK1 &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<ICIE1));
// Clear the Timer1 interrupt flags
TIFR1 |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<ICF1));
#endif
#endif
/*
Compare Output Mode = Normal port operation, OCxA/OCxB disconnected.
Waveform Generation Mode = 4; 0100; CTC; (Clear Timer on Compare); OCR1A; Immediate; MAX
Clock Select = No clock source (Timer/Counter stopped).
Note: Turn off the clock first to avoid ticks and scratches.
*/
#if TIMER_TO_USE_FOR_TONE == 1
#if defined(TCCR1)
sbi(TCCR1,CTC1);
cbi(TCCR1,PWM1A);
cbi(GTCCR,PWM1B);
#elif !defined(TCCR1E)
cbi(TCCR1A,WGM10);
cbi(TCCR1A,WGM11);
sbi(TCCR1B,WGM12);
cbi(TCCR1B,WGM13);
#endif
#elif TIMER_TO_USE_FOR_TONE == 0
cbi(TCCR0A,WGM00);
sbi(TCCR0A,WGM01);
cbi(TCCR0B,WGM02);
#endif
/* If the tone pin can be driven directly from the timer */
#if (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1E)
if ( (digitalPinToTimer(_pin) == TIMER1A) || (digitalPinToTimer(_pin) == TIMER1B) || (digitalPinToTimer(_pin) == TIMER1D) )
{
#elif (TIMER_TO_USE_FOR_TONE == 1)
if ( (digitalPinToTimer(_pin) == TIMER1A) || (digitalPinToTimer(_pin) == TIMER1B) )
{
#elif (TIMER_TO_USE_FOR_TONE == 0)
if ( (digitalPinToTimer(_pin) == TIMER0A) || (digitalPinToTimer(_pin) == TIMER0B) )
{
#else
if (0)
{ //unsupported, so only use software.
#endif
/* Pin toggling is handled by the hardware */
tone_timer_pin_register = NULL;
tone_timer_pin_mask = 0;
uint8_t timer = digitalPinToTimer(_pin);
#if defined(COM0A1)
//Just in case there are now pwm pins on timer0 (ATTiny861)
if (timer == TIMER0A)
{
/* Compare Output Mode = Toggle OC0A on Compare Match. */
cbi(TCCR0A,COM0A1);
sbi(TCCR0A,COM0A0);
}
else
#endif
if (timer == TIMER1A)
{
/* Compare Output Mode = Toggle OC1A on Compare Match. */
#if defined(TCCR1)
cbi(TCCR1,COM1A1);
sbi(TCCR1,COM1A0);
#elif defined(TCCR1E)
cbi(TCCR1C,COM1A1S);
sbi(TCCR1C,COM1A0S);
#else
cbi(TCCR1A,COM1A1);
sbi(TCCR1A,COM1A0);
#endif
}
#if defined(COM0B1)
//Just in case there are <2 pwm pins on timer0 (ATTiny861)
else if (timer == TIMER0B)
{
/* Compare Output Mode = Toggle OC0B on Compare Match. */
cbi(TCCR0A,COM0B1);
sbi(TCCR0A,COM0B0);
}
#endif
#if defined(COM1D1)
//in case there is a OCRD. (ATtiny861)
else if (timer == TIMER1D){
/* Compare Output Mode = Toggle OC1D on Compare Match. */
#if defined(TCCR1)
cbi(TCCR1,COM1D1);
sbi(TCCR1,COM1D0);
#elif defined(TCCR1E)
cbi(TCCR1C,COM1D1);
sbi(TCCR1C,COM1D0);
#else
cbi(TCCR1A,COM1D1);
sbi(TCCR1A,COM1D0);
#endif
}
#endif
else
{
/* Compare Output Mode = Toggle OC1B on Compare Match. */
#if defined(TCCR1)
cbi(GTCCR,COM1B1);
sbi(GTCCR,COM1B0);
#elif defined(TCCR1E)
cbi(TCCR1C,COM1B1S);
sbi(TCCR1C,COM1B0S);
#else
cbi(TCCR1A,COM1B1);
sbi(TCCR1A,COM1B0);
#endif
}
}
else
{
/* Save information needed by the interrupt service routine */
tone_timer_pin_register = portOutputRegister( digitalPinToPort( _pin ) );
tone_timer_pin_mask = digitalPinToBitMask( _pin );
/* Compare Output Mode = Normal port operation, OCxA disconnected. */
#if (TIMER_TO_USE_FOR_TONE == 0)
TCCR0A &= ~((1<<COM0A1)|(1<<COM0A0)|(1<<COM0B1)|(1<<COM0B0));
#elif (TIMER_TO_USE_FOR_TONE == 1) & defined(TCCR1)
TCCR1 &= ~((1<<COM1A1)|(1<<COM1A0));
GTCCR &= ~((1<<COM1B1)|(1<<COM1B0));
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1E)
TCCR1C &= ~((1<<COM1A1S)|(1<<COM1A0S)|(1<<COM1B1S)|(1<<COM1B0S)|(1<<COM1D1)|(1<<COM1D0));
#elif (TIMER_TO_USE_FOR_TONE == 1)
TCCR1A &= ~((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0));
#endif
}
/* Ensure the pin is configured for output */
pinMode( _pin, OUTPUT );
tone_pin = _pin;
}
if ( tone_pin == _pin )
{
/* Stop the clock while we make changes, then set the counter to zero to reduce ticks and scratches. */
// Millis timer is always processor clock divided by MillisTimer_Prescale_Value (64)
#if (TIMER_TO_USE_FOR_TONE == 0)
TCCR0B &= ~((1<<CS02)|(1<<CS01)|(1<<CS00));
TCNT0 = 0;
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1)
TCCR1 &= ~((1<<CS13)|(1<<CS12)|(1<<CS11)|(1<<CS10));
TCNT1 = 0;
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1E)
TCCR1B &= ~((1<<CS13)|(1<<CS12)|(1<<CS11)|(1<<CS10));
TCNT1 = 0;
#elif (TIMER_TO_USE_FOR_TONE == 1)
TCCR1B &= ~((1<<CS12)|(1<<CS11)|(1<<CS10));
TCNT1 = 0;
#endif
if ( frequency > 0 )
{
/* Determine which prescaler to use */
/* Set the Output Compare Register (rounding up) */
#if TIMER_TO_USE_FOR_TONE == 1
uint16_t ocr = F_CPU / frequency / 2;
#if defined(TCCR1E)
uint8_t prescalarbits = 0b0001;
if (ocr > 256)
{
ocr >>= 3; //divide by 8
prescalarbits = 0b0100; // ck/8
if (ocr > 256)
{
ocr >>= 3; //divide by a further 8
prescalarbits = 0b0111; //ck/64
if (ocr > 256)
{
ocr >>= 2; //divide by a further 4
prescalarbits = 0b1001; //ck/256
if (ocr > 256)
{
// can't do any better than /1024
ocr >>= 2; //divide by a further 4
prescalarbits = 0b1011; //ck/1024
}
}
}
}
#else
#if defined(TCCR1)
uint8_t prescalarbits = 0b0001;
#else
uint8_t prescalarbits = 0b001;
#endif
if (ocr > 0xffff)
{
ocr /= 64;
#if defined(TCCR1)
prescalarbits = 0b0111;
#else
prescalarbits = 0b011;
#endif
}
#endif
ocr -= 1; //Note we are doing the subtraction of 1 here to save repeatedly calculating ocr from just the frequency in the if tree above
OCR1A = ocr;
#elif TIMER_TO_USE_FOR_TONE == 0
uint16_t ocr = F_CPU / frequency / 2;
uint8_t prescalarbits = 0b001; // ck/1
if (ocr > 256)
{
ocr >>= 3; //divide by 8
prescalarbits = 0b010; // ck/8
if (ocr > 256)
{
ocr >>= 3; //divide by a further 8
prescalarbits = 0b011; //ck/64
if (ocr > 256)
{
ocr >>= 2; //divide by a further 4
prescalarbits = 0b100; //ck/256
if (ocr > 256)
{
// can't do any better than /1024
ocr >>= 2; //divide by a further 4
prescalarbits = 0b101; //ck/1024
}
}
}
}
ocr -= 1; //Note we are doing the subtraction of 1 here to save repeatedly calculating ocr from just the frequency in the if tree above
OCR0A = ocr;
#endif
/* Does the caller want a specific duration? */
if ( duration > 0 )
{
/* Determine how many times the value toggles */
tone_timer_toggle_count = (2 * frequency * duration) / 1000;
/* Output Compare A Match Interrupt Enable */
#if (TIMER_TO_USE_FOR_TONE == 1)
#if defined (TIMSK)
TIMSK |= (1<<OCIE1A);
#else
TIMSK1 |= (1<<OCIE1A);
#endif
#elif (TIMER_TO_USE_FOR_TONE == 0)
#if defined (TIMSK)
TIMSK |= (1<<OCIE0A);
#else
TIMSK0 |= (1<<OCIE0A);
#endif
#endif
}
else
{
/* Indicate to the interrupt service routine that we'll be running until further notice */
tone_timer_toggle_count = -1;
/* All pins but the OCxA / OCxB pins have to be driven by software */
#if (TIMER_TO_USE_FOR_TONE == 1)
#if defined(TCCR1E)
if ( (digitalPinToTimer(_pin) != TIMER1A) && (digitalPinToTimer(_pin) != TIMER1B) && (digitalPinToTimer(_pin) != TIMER1D) )
#else
if ( (digitalPinToTimer(_pin) != TIMER1A) && (digitalPinToTimer(_pin) != TIMER1B) )
#endif
{
/* Output Compare A Match Interrupt Enable (software control)*/
#if defined (TIMSK)
TIMSK |= (1<<OCIE1A);
#else
TIMSK1 |= (1<<OCIE1A);
#endif
}
#elif (TIMER_TO_USE_FOR_TONE == 0)
if ( (digitalPinToTimer(_pin) != TIMER0A) && (digitalPinToTimer(_pin) != TIMER0B) )
{
/* Output Compare A Match Interrupt Enable (software control)*/
#if defined (TIMSK)
TIMSK |= (1<<OCIE0A);
#else
TIMSK0 |= (1<<OCIE0A);
#endif
}
#endif
}
//Clock is always stopped before this point, which means all of CS[0..2] are already 0, so can just use a bitwise OR to set required bits
#if (TIMER_TO_USE_FOR_TONE == 0)
TCCR0B |= (prescalarbits << CS00);
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1)
TCCR1 |= (prescalarbits << CS10);
#elif (TIMER_TO_USE_FOR_TONE == 1)
TCCR1B |= (prescalarbits << CS10);
#endif
}
else
{
/* To be on the safe side, turn off all interrupts */
#if (TIMER_TO_USE_FOR_TONE == 1)
#if defined (TIMSK)
TIMSK |= (1<<OCIE1A);
TIMSK &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B));
#if defined(ICIE1)
TIMSK &= ~(1<<ICIE1);
#endif
#if defined(OCIE1D)
TIMSK &= ~(1<<OCIE1D);
#endif
#else
TIMSK1 |= (1<<OCIE1A);
TIMSK1 &= ~((1<<ICIE1) | (1<<OCIE1B) | (1<<OCIE1A) | (1<<TOIE1));
#endif
#elif (TIMER_TO_USE_FOR_TONE == 0)
#if defined (TIMSK)
TIMSK |= (1<<OCIE0A);
TIMSK &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
#else
TIMSK0 |= (1<<OCIE0A);
TIMSK0 &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
#endif
#endif
/* Clock is stopped. Counter is zero. The only thing left to do is turn off the output. */
digitalWrite( _pin, 0 );
}
}
}
void noTone( uint8_t _pin )
{
if ( (tone_pin != 255)
&& ((tone_pin == _pin) || (_pin == 255)) )
{
// Turn off all interrupts
#if (TIMER_TO_USE_FOR_TONE == 1)
#if defined (TIMSK)
TIMSK &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B));
#if defined(ICIE1)
TIMSK &= ~(1<<ICIE1);
#endif
#if defined(OCIE1D)
TIMSK &= ~(1<<OCIE1D);
#endif
#else
TIMSK1 &= ~((1<<ICIE1) | (1<<OCIE1B) | (1<<OCIE1A) | (1<<TOIE1));
#endif
#elif (TIMER_TO_USE_FOR_TONE == 0)
#if defined (TIMSK)
TIMSK &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
#else
TIMSK0 &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
#endif
#endif
// This just disables the tone. It doesn't reinitialise the PWM modules.
#if (TIMER_TO_USE_FOR_TONE == 0)
TCCR0B &= ~((1<<CS02) | (1<<CS01) | (1<<CS00)); //stop the clock
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1)
TCCR1 &= ~((1<<CS13) | (1<<CS12) | (1<<CS11) | (1<<CS10)); //stop the clock
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1E)
TCCR1B &= ~((1<<CS13) | (1<<CS12) | (1<<CS11) | (1<<CS10)); //stop the clock
#elif (TIMER_TO_USE_FOR_TONE == 1)
TCCR1B &= ~((1<<CS12) | (1<<CS11) | (1<<CS10)); //stop the clock
#endif
// Set the output low
if ( tone_timer_pin_register != NULL )
{
*tone_timer_pin_register &= ~(tone_timer_pin_mask);
}
else
{
digitalWrite( tone_pin, LOW );
}
tone_pin = 255;
}
}
#if (TIMER_TO_USE_FOR_TONE == 0)
ISR(TIMER0_COMPA_vect)
#elif (TIMER_TO_USE_FOR_TONE == 1)
ISR(TIMER1_COMPA_vect)
#else
#error Tone timer Overflow vector not defined!
#endif
{
if ( tone_timer_toggle_count != 0 )
{
if ( tone_timer_toggle_count > 0 )
{
--tone_timer_toggle_count;
if ( tone_timer_toggle_count == 0 )
{
// Shutdown the hardware
noTone( 255 );
// Skip the rest. We're finished.
return;
}
}
*tone_timer_pin_register ^= tone_timer_pin_mask;
}
else
{
// Shutdown the hardware
noTone( 255 );
}
}

View File

@ -0,0 +1,168 @@
/*
WCharacter.h - Character utility functions for Wiring & Arduino
Copyright (c) 2010 Hernando Barragan. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef Character_h
#define Character_h
#include <ctype.h>
// WCharacter.h prototypes
inline boolean isAlphaNumeric(int c) __attribute__((always_inline));
inline boolean isAlpha(int c) __attribute__((always_inline));
inline boolean isAscii(int c) __attribute__((always_inline));
inline boolean isWhitespace(int c) __attribute__((always_inline));
inline boolean isControl(int c) __attribute__((always_inline));
inline boolean isDigit(int c) __attribute__((always_inline));
inline boolean isGraph(int c) __attribute__((always_inline));
inline boolean isLowerCase(int c) __attribute__((always_inline));
inline boolean isPrintable(int c) __attribute__((always_inline));
inline boolean isPunct(int c) __attribute__((always_inline));
inline boolean isSpace(int c) __attribute__((always_inline));
inline boolean isUpperCase(int c) __attribute__((always_inline));
inline boolean isHexadecimalDigit(int c) __attribute__((always_inline));
inline int toAscii(int c) __attribute__((always_inline));
inline int toLowerCase(int c) __attribute__((always_inline));
inline int toUpperCase(int c)__attribute__((always_inline));
// Checks for an alphanumeric character.
// It is equivalent to (isalpha(c) || isdigit(c)).
inline boolean isAlphaNumeric(int c)
{
return ( isalnum(c) == 0 ? false : true);
}
// Checks for an alphabetic character.
// It is equivalent to (isupper(c) || islower(c)).
inline boolean isAlpha(int c)
{
return ( isalpha(c) == 0 ? false : true);
}
// Checks whether c is a 7-bit unsigned char value
// that fits into the ASCII character set.
inline boolean isAscii(int c)
{
return ( isascii (c) == 0 ? false : true);
}
// Checks for a blank character, that is, a space or a tab.
inline boolean isWhitespace(int c)
{
return ( isblank (c) == 0 ? false : true);
}
// Checks for a control character.
inline boolean isControl(int c)
{
return ( iscntrl (c) == 0 ? false : true);
}
// Checks for a digit (0 through 9).
inline boolean isDigit(int c)
{
return ( isdigit (c) == 0 ? false : true);
}
// Checks for any printable character except space.
inline boolean isGraph(int c)
{
return ( isgraph (c) == 0 ? false : true);
}
// Checks for a lower-case character.
inline boolean isLowerCase(int c)
{
return (islower (c) == 0 ? false : true);
}
// Checks for any printable character including space.
inline boolean isPrintable(int c)
{
return ( isprint (c) == 0 ? false : true);
}
// Checks for any printable character which is not a space
// or an alphanumeric character.
inline boolean isPunct(int c)
{
return ( ispunct (c) == 0 ? false : true);
}
// Checks for white-space characters. For the avr-libc library,
// these are: space, formfeed ('\f'), newline ('\n'), carriage
// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
inline boolean isSpace(int c)
{
return ( isspace (c) == 0 ? false : true);
}
// Checks for an uppercase letter.
inline boolean isUpperCase(int c)
{
return ( isupper (c) == 0 ? false : true);
}
// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
// 8 9 a b c d e f A B C D E F.
inline boolean isHexadecimalDigit(int c)
{
return ( isxdigit (c) == 0 ? false : true);
}
// Converts c to a 7-bit unsigned char value that fits into the
// ASCII character set, by clearing the high-order bits.
inline int toAscii(int c)
{
return toascii (c);
}
// Warning:
// Many people will be unhappy if you use this function.
// This function will convert accented letters into random
// characters.
// Converts the letter c to lower case, if possible.
inline int toLowerCase(int c)
{
return tolower (c);
}
// Converts the letter c to upper case, if possible.
inline int toUpperCase(int c)
{
return toupper (c);
}
#endif

View File

@ -0,0 +1,155 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.uniandes.edu.co
Copyright (c) 2004-05 Hernando Barragan
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 24 November 2006 by David A. Mellis
Modified 28-08-2009 for attiny84 R.Wiersma
Modified 09-10-2009 for attiny45 A.Saporetti
Modified 20-11-2010 - B.Cook - Correct a minor bug in attachInterrupt
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include "wiring_private.h"
volatile static voidFuncPtr intFunc[NUMBER_EXTERNAL_INTERRUPTS];
#if defined( MCUCR ) && ! defined( EICRA )
#define EICRA MCUCR
#endif
#if defined( GIMSK ) && ! defined( EIMSK )
#define EIMSK GIMSK
#endif
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)
{
if ( interruptNum < NUMBER_EXTERNAL_INTERRUPTS )
{
/*
If attachInterrupt is called in succession for the same
interruptNum but a different userFunc then the following line
is not safe. Changing intFunc is not atomic.
intFunc[interruptNum] = userFunc;
*/
{
// save interrupt flag
uint8_t SaveSREG = SREG;
// disable interrupts
cli();
// access the shared data
intFunc[interruptNum] = userFunc;
// restore the interrupt flag
SREG = SaveSREG;
}
// Configure the interrupt mode (trigger on low input, any change, rising
// edge, or falling edge). The mode constants were chosen to correspond
// to the configuration bits in the hardware register, so we simply shift
// the mode into place.
// Enable the interrupt.
switch ( interruptNum )
{
#if NUMBER_EXTERNAL_INTERRUPTS >= 1
case EXTERNAL_INTERRUPT_0:
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
break;
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 2 && !defined(ISC11)
//For ATtiny861, but interrupts share the same vector.
case EXTERNAL_INTERRUPT_1:
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT1);
break;
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 2 && defined(ISC11)
case EXTERNAL_INTERRUPT_1:
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
break;
#endif
#if NUMBER_EXTERNAL_INTERRUPTS > 2
#error Add handlers for the additional interrupts.
#endif
}
}
}
void detachInterrupt(uint8_t interruptNum)
{
if ( interruptNum < NUMBER_EXTERNAL_INTERRUPTS )
{
// Disable the interrupt. (We can't assume that interruptNum is equal
// to the number of the EIMSK bit to clear, as this isn't true on the
// ATmega8. There, INT0 is 6 and INT1 is 7.)
switch (interruptNum)
{
#if NUMBER_EXTERNAL_INTERRUPTS >= 1
case EXTERNAL_INTERRUPT_0:
EIMSK &= ~(1 << INT0);
break;;
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 2
case EXTERNAL_INTERRUPT_1:
EIMSK &= ~(1 << INT1);
break;;
#endif
#if NUMBER_EXTERNAL_INTERRUPTS > 2
#error Add handlers for the additional interrupts.
#endif
}
intFunc[interruptNum] = 0;
}
}
#if NUMBER_EXTERNAL_INTERRUPTS >= 1
ISR(EXTERNAL_INTERRUPT_0_vect)
{
if(intFunc[EXTERNAL_INTERRUPT_0])
intFunc[EXTERNAL_INTERRUPT_0]();
}
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 2
ISR(EXTERNAL_INTERRUPT_1_vect)
{
if(intFunc[EXTERNAL_INTERRUPT_1])
intFunc[EXTERNAL_INTERRUPT_1]();
}
#endif
#if NUMBER_EXTERNAL_INTERRUPTS > 2
#error Add handlers for the additional interrupts.
#endif

View File

@ -0,0 +1,60 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.org.co
Copyright (c) 2004-06 Hernando Barragan
Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
extern "C" {
#include "stdlib.h"
}
void randomSeed(unsigned int seed)
{
if (seed != 0) {
srandom(seed);
}
}
long random(long howbig)
{
if (howbig == 0) {
return 0;
}
return random() % howbig;
}
long random(long howsmall, long howbig)
{
if (howsmall >= howbig) {
return howsmall;
}
long diff = howbig - howsmall;
return random(diff) + howsmall;
}
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
unsigned int makeWord(unsigned int w) { return w; }
unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }

View File

@ -0,0 +1,2 @@
//For compatibility with older programs
#include "Arduino.h"

View File

@ -0,0 +1,744 @@
/*
WString.cpp - String library for Wiring & Arduino
...mostly rewritten by Paul Stoffregen...
Copyright (c) 2009-10 Hernando Barragan. All rights reserved.
Copyright 2011, Paul Stoffregen, paul@pjrc.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "WString.h"
/*********************************************/
/* Constructors */
/*********************************************/
String::String(const char *cstr)
{
init();
if (cstr) copy(cstr, strlen(cstr));
}
String::String(const String &value)
{
init();
*this = value;
}
String::String(const __FlashStringHelper *pstr)
{
init();
*this = pstr;
}
#ifdef __GXX_EXPERIMENTAL_CXX0X__
String::String(String &&rval)
{
init();
move(rval);
}
String::String(StringSumHelper &&rval)
{
init();
move(rval);
}
#endif
String::String(char c)
{
init();
char buf[2];
buf[0] = c;
buf[1] = 0;
*this = buf;
}
String::String(unsigned char value, unsigned char base)
{
init();
char buf[1 + 8 * sizeof(unsigned char)];
utoa(value, buf, base);
*this = buf;
}
String::String(int value, unsigned char base)
{
init();
char buf[2 + 8 * sizeof(int)];
itoa(value, buf, base);
*this = buf;
}
String::String(unsigned int value, unsigned char base)
{
init();
char buf[1 + 8 * sizeof(unsigned int)];
utoa(value, buf, base);
*this = buf;
}
String::String(long value, unsigned char base)
{
init();
char buf[2 + 8 * sizeof(long)];
ltoa(value, buf, base);
*this = buf;
}
String::String(unsigned long value, unsigned char base)
{
init();
char buf[1 + 8 * sizeof(unsigned long)];
ultoa(value, buf, base);
*this = buf;
}
String::String(float value, unsigned char decimalPlaces)
{
init();
char buf[33];
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
}
String::String(double value, unsigned char decimalPlaces)
{
init();
char buf[33];
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
}
String::~String()
{
free(buffer);
}
/*********************************************/
/* Memory Management */
/*********************************************/
inline void String::init(void)
{
buffer = NULL;
capacity = 0;
len = 0;
}
void String::invalidate(void)
{
if (buffer) free(buffer);
buffer = NULL;
capacity = len = 0;
}
unsigned char String::reserve(unsigned int size)
{
if (buffer && capacity >= size) return 1;
if (changeBuffer(size)) {
if (len == 0) buffer[0] = 0;
return 1;
}
return 0;
}
unsigned char String::changeBuffer(unsigned int maxStrLen)
{
char *newbuffer = (char *)realloc(buffer, maxStrLen + 1);
if (newbuffer) {
buffer = newbuffer;
capacity = maxStrLen;
return 1;
}
return 0;
}
/*********************************************/
/* Copy and Move */
/*********************************************/
String & String::copy(const char *cstr, unsigned int length)
{
if (!reserve(length)) {
invalidate();
return *this;
}
len = length;
strcpy(buffer, cstr);
return *this;
}
String & String::copy(const __FlashStringHelper *pstr, unsigned int length)
{
if (!reserve(length)) {
invalidate();
return *this;
}
len = length;
strcpy_P(buffer, (PGM_P)pstr);
return *this;
}
#ifdef __GXX_EXPERIMENTAL_CXX0X__
void String::move(String &rhs)
{
if (buffer) {
if (capacity >= rhs.len) {
strcpy(buffer, rhs.buffer);
len = rhs.len;
rhs.len = 0;
return;
} else {
free(buffer);
}
}
buffer = rhs.buffer;
capacity = rhs.capacity;
len = rhs.len;
rhs.buffer = NULL;
rhs.capacity = 0;
rhs.len = 0;
}
#endif
String & String::operator = (const String &rhs)
{
if (this == &rhs) return *this;
if (rhs.buffer) copy(rhs.buffer, rhs.len);
else invalidate();
return *this;
}
#ifdef __GXX_EXPERIMENTAL_CXX0X__
String & String::operator = (String &&rval)
{
if (this != &rval) move(rval);
return *this;
}
String & String::operator = (StringSumHelper &&rval)
{
if (this != &rval) move(rval);
return *this;
}
#endif
String & String::operator = (const char *cstr)
{
if (cstr) copy(cstr, strlen(cstr));
else invalidate();
return *this;
}
String & String::operator = (const __FlashStringHelper *pstr)
{
if (pstr) copy(pstr, strlen_P((PGM_P)pstr));
else invalidate();
return *this;
}
/*********************************************/
/* concat */
/*********************************************/
unsigned char String::concat(const String &s)
{
return concat(s.buffer, s.len);
}
unsigned char String::concat(const char *cstr, unsigned int length)
{
unsigned int newlen = len + length;
if (!cstr) return 0;
if (length == 0) return 1;
if (!reserve(newlen)) return 0;
strcpy(buffer + len, cstr);
len = newlen;
return 1;
}
unsigned char String::concat(const char *cstr)
{
if (!cstr) return 0;
return concat(cstr, strlen(cstr));
}
unsigned char String::concat(char c)
{
char buf[2];
buf[0] = c;
buf[1] = 0;
return concat(buf, 1);
}
unsigned char String::concat(unsigned char num)
{
char buf[1 + 3 * sizeof(unsigned char)];
itoa(num, buf, 10);
return concat(buf, strlen(buf));
}
unsigned char String::concat(int num)
{
char buf[2 + 3 * sizeof(int)];
itoa(num, buf, 10);
return concat(buf, strlen(buf));
}
unsigned char String::concat(unsigned int num)
{
char buf[1 + 3 * sizeof(unsigned int)];
utoa(num, buf, 10);
return concat(buf, strlen(buf));
}
unsigned char String::concat(long num)
{
char buf[2 + 3 * sizeof(long)];
ltoa(num, buf, 10);
return concat(buf, strlen(buf));
}
unsigned char String::concat(unsigned long num)
{
char buf[1 + 3 * sizeof(unsigned long)];
ultoa(num, buf, 10);
return concat(buf, strlen(buf));
}
unsigned char String::concat(float num)
{
char buf[20];
char* string = dtostrf(num, 4, 2, buf);
return concat(string, strlen(string));
}
unsigned char String::concat(double num)
{
char buf[20];
char* string = dtostrf(num, 4, 2, buf);
return concat(string, strlen(string));
}
unsigned char String::concat(const __FlashStringHelper * str)
{
if (!str) return 0;
int length = strlen_P((const char *) str);
if (length == 0) return 1;
unsigned int newlen = len + length;
if (!reserve(newlen)) return 0;
strcpy_P(buffer + len, (const char *) str);
len = newlen;
return 1;
}
/*********************************************/
/* Concatenate */
/*********************************************/
StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!a.concat(rhs.buffer, rhs.len)) a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, char c)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!a.concat(c)) a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!a.concat(num)) a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, int num)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!a.concat(num)) a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!a.concat(num)) a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, long num)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!a.concat(num)) a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!a.concat(num)) a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, float num)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!a.concat(num)) a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, double num)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!a.concat(num)) a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if (!a.concat(rhs)) a.invalidate();
return a;
}
/*********************************************/
/* Comparison */
/*********************************************/
int String::compareTo(const String &s) const
{
if (!buffer || !s.buffer) {
if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer;
if (buffer && len > 0) return *(unsigned char *)buffer;
return 0;
}
return strcmp(buffer, s.buffer);
}
unsigned char String::equals(const String &s2) const
{
return (len == s2.len && compareTo(s2) == 0);
}
unsigned char String::equals(const char *cstr) const
{
if (len == 0) return (cstr == NULL || *cstr == 0);
if (cstr == NULL) return buffer[0] == 0;
return strcmp(buffer, cstr) == 0;
}
unsigned char String::operator<(const String &rhs) const
{
return compareTo(rhs) < 0;
}
unsigned char String::operator>(const String &rhs) const
{
return compareTo(rhs) > 0;
}
unsigned char String::operator<=(const String &rhs) const
{
return compareTo(rhs) <= 0;
}
unsigned char String::operator>=(const String &rhs) const
{
return compareTo(rhs) >= 0;
}
unsigned char String::equalsIgnoreCase( const String &s2 ) const
{
if (this == &s2) return 1;
if (len != s2.len) return 0;
if (len == 0) return 1;
const char *p1 = buffer;
const char *p2 = s2.buffer;
while (*p1) {
if (tolower(*p1++) != tolower(*p2++)) return 0;
}
return 1;
}
unsigned char String::startsWith( const String &s2 ) const
{
if (len < s2.len) return 0;
return startsWith(s2, 0);
}
unsigned char String::startsWith( const String &s2, unsigned int offset ) const
{
if (offset > len - s2.len || !buffer || !s2.buffer) return 0;
return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0;
}
unsigned char String::endsWith( const String &s2 ) const
{
if ( len < s2.len || !buffer || !s2.buffer) return 0;
return strcmp(&buffer[len - s2.len], s2.buffer) == 0;
}
/*********************************************/
/* Character Access */
/*********************************************/
char String::charAt(unsigned int loc) const
{
return operator[](loc);
}
void String::setCharAt(unsigned int loc, char c)
{
if (loc < len) buffer[loc] = c;
}
char & String::operator[](unsigned int index)
{
static char dummy_writable_char;
if (index >= len || !buffer) {
dummy_writable_char = 0;
return dummy_writable_char;
}
return buffer[index];
}
char String::operator[]( unsigned int index ) const
{
if (index >= len || !buffer) return 0;
return buffer[index];
}
void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const
{
if (!bufsize || !buf) return;
if (index >= len) {
buf[0] = 0;
return;
}
unsigned int n = bufsize - 1;
if (n > len - index) n = len - index;
strncpy((char *)buf, buffer + index, n);
buf[n] = 0;
}
/*********************************************/
/* Search */
/*********************************************/
int String::indexOf(char c) const
{
return indexOf(c, 0);
}
int String::indexOf( char ch, unsigned int fromIndex ) const
{
if (fromIndex >= len) return -1;
const char* temp = strchr(buffer + fromIndex, ch);
if (temp == NULL) return -1;
return temp - buffer;
}
int String::indexOf(const String &s2) const
{
return indexOf(s2, 0);
}
int String::indexOf(const String &s2, unsigned int fromIndex) const
{
if (fromIndex >= len) return -1;
const char *found = strstr(buffer + fromIndex, s2.buffer);
if (found == NULL) return -1;
return found - buffer;
}
int String::lastIndexOf( char theChar ) const
{
return lastIndexOf(theChar, len - 1);
}
int String::lastIndexOf(char ch, unsigned int fromIndex) const
{
if (fromIndex >= len) return -1;
char tempchar = buffer[fromIndex + 1];
buffer[fromIndex + 1] = '\0';
char* temp = strrchr( buffer, ch );
buffer[fromIndex + 1] = tempchar;
if (temp == NULL) return -1;
return temp - buffer;
}
int String::lastIndexOf(const String &s2) const
{
return lastIndexOf(s2, len - s2.len);
}
int String::lastIndexOf(const String &s2, unsigned int fromIndex) const
{
if (s2.len == 0 || len == 0 || s2.len > len) return -1;
if (fromIndex >= len) fromIndex = len - 1;
int found = -1;
for (char *p = buffer; p <= buffer + fromIndex; p++) {
p = strstr(p, s2.buffer);
if (!p) break;
if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer;
}
return found;
}
String String::substring(unsigned int left, unsigned int right) const
{
if (left > right) {
unsigned int temp = right;
right = left;
left = temp;
}
String out;
if (left > len) return out;
if (right > len) right = len;
char temp = buffer[right]; // save the replaced character
buffer[right] = '\0';
out = buffer + left; // pointer arithmetic
buffer[right] = temp; //restore character
return out;
}
/*********************************************/
/* Modification */
/*********************************************/
void String::replace(char find, char replace)
{
if (!buffer) return;
for (char *p = buffer; *p; p++) {
if (*p == find) *p = replace;
}
}
void String::replace(const String& find, const String& replace)
{
if (len == 0 || find.len == 0) return;
int diff = replace.len - find.len;
char *readFrom = buffer;
char *foundAt;
if (diff == 0) {
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
memcpy(foundAt, replace.buffer, replace.len);
readFrom = foundAt + replace.len;
}
} else if (diff < 0) {
char *writeTo = buffer;
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
unsigned int n = foundAt - readFrom;
memcpy(writeTo, readFrom, n);
writeTo += n;
memcpy(writeTo, replace.buffer, replace.len);
writeTo += replace.len;
readFrom = foundAt + find.len;
len += diff;
}
strcpy(writeTo, readFrom);
} else {
unsigned int size = len; // compute size needed for result
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
readFrom = foundAt + find.len;
size += diff;
}
if (size == len) return;
if (size > capacity && !changeBuffer(size)) return; // XXX: tell user!
int index = len - 1;
while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) {
readFrom = buffer + index + find.len;
memmove(readFrom + diff, readFrom, len - (readFrom - buffer));
len += diff;
buffer[len] = 0;
memcpy(buffer + index, replace.buffer, replace.len);
index--;
}
}
}
void String::remove(unsigned int index){
if (index >= len) { return; }
int count = len - index;
remove(index, count);
}
void String::remove(unsigned int index, unsigned int count){
if (index >= len) { return; }
if (count <= 0) { return; }
if (index + count > len) { count = len - index; }
char *writeTo = buffer + index;
len = len - count;
strncpy(writeTo, buffer + index + count,len - index);
buffer[len] = 0;
}
void String::toLowerCase(void)
{
if (!buffer) return;
for (char *p = buffer; *p; p++) {
*p = tolower(*p);
}
}
void String::toUpperCase(void)
{
if (!buffer) return;
for (char *p = buffer; *p; p++) {
*p = toupper(*p);
}
}
void String::trim(void)
{
if (!buffer || len == 0) return;
char *begin = buffer;
while (isspace(*begin)) begin++;
char *end = buffer + len - 1;
while (isspace(*end) && end >= begin) end--;
len = end + 1 - begin;
if (begin > buffer) memcpy(buffer, begin, len);
buffer[len] = 0;
}
/*********************************************/
/* Parsing / Conversion */
/*********************************************/
long String::toInt(void) const
{
if (buffer) return atol(buffer);
return 0;
}
float String::toFloat(void) const
{
if (buffer) return float(atof(buffer));
return 0;
}

View File

@ -0,0 +1,224 @@
/*
WString.h - String library for Wiring & Arduino
...mostly rewritten by Paul Stoffregen...
Copyright (c) 2009-10 Hernando Barragan. All right reserved.
Copyright 2011, Paul Stoffregen, paul@pjrc.com
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef String_class_h
#define String_class_h
#ifdef __cplusplus
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <avr/pgmspace.h>
// When compiling programs with this class, the following gcc parameters
// dramatically increase performance and memory (RAM) efficiency, typically
// with little or no increase in code size.
// -felide-constructors
// -std=c++0x
class __FlashStringHelper;
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
// An inherited class for holding the result of a concatenation. These
// result objects are assumed to be writable by subsequent concatenations.
class StringSumHelper;
// The string class
class String
{
// use a function pointer to allow for "if (s)" without the
// complications of an operator bool(). for more information, see:
// http://www.artima.com/cppsource/safebool.html
typedef void (String::*StringIfHelperType)() const;
void StringIfHelper() const {}
public:
// constructors
// creates a copy of the initial value.
// if the initial value is null or invalid, or if memory allocation
// fails, the string will be marked as invalid (i.e. "if (s)" will
// be false).
String(const char *cstr = "");
String(const String &str);
String(const __FlashStringHelper *str);
#ifdef __GXX_EXPERIMENTAL_CXX0X__
String(String &&rval);
String(StringSumHelper &&rval);
#endif
explicit String(char c);
explicit String(unsigned char, unsigned char base=10);
explicit String(int, unsigned char base=10);
explicit String(unsigned int, unsigned char base=10);
explicit String(long, unsigned char base=10);
explicit String(unsigned long, unsigned char base=10);
explicit String(float, unsigned char decimalPlaces=2);
explicit String(double, unsigned char decimalPlaces=2);
~String(void);
// memory management
// return true on success, false on failure (in which case, the string
// is left unchanged). reserve(0), if successful, will validate an
// invalid string (i.e., "if (s)" will be true afterwards)
unsigned char reserve(unsigned int size);
inline unsigned int length(void) const {return len;}
// creates a copy of the assigned value. if the value is null or
// invalid, or if the memory allocation fails, the string will be
// marked as invalid ("if (s)" will be false).
String & operator = (const String &rhs);
String & operator = (const char *cstr);
String & operator = (const __FlashStringHelper *str);
#ifdef __GXX_EXPERIMENTAL_CXX0X__
String & operator = (String &&rval);
String & operator = (StringSumHelper &&rval);
#endif
// concatenate (works w/ built-in types)
// returns true on success, false on failure (in which case, the string
// is left unchanged). if the argument is null or invalid, the
// concatenation is considered unsucessful.
unsigned char concat(const String &str);
unsigned char concat(const char *cstr);
unsigned char concat(char c);
unsigned char concat(unsigned char c);
unsigned char concat(int num);
unsigned char concat(unsigned int num);
unsigned char concat(long num);
unsigned char concat(unsigned long num);
unsigned char concat(float num);
unsigned char concat(double num);
unsigned char concat(const __FlashStringHelper * str);
// if there's not enough memory for the concatenated value, the string
// will be left unchanged (but this isn't signalled in any way)
String & operator += (const String &rhs) {concat(rhs); return (*this);}
String & operator += (const char *cstr) {concat(cstr); return (*this);}
String & operator += (char c) {concat(c); return (*this);}
String & operator += (unsigned char num) {concat(num); return (*this);}
String & operator += (int num) {concat(num); return (*this);}
String & operator += (unsigned int num) {concat(num); return (*this);}
String & operator += (long num) {concat(num); return (*this);}
String & operator += (unsigned long num) {concat(num); return (*this);}
String & operator += (float num) {concat(num); return (*this);}
String & operator += (double num) {concat(num); return (*this);}
String & operator += (const __FlashStringHelper *str){concat(str); return (*this);}
friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs);
friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr);
friend StringSumHelper & operator + (const StringSumHelper &lhs, char c);
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, int num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, long num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, float num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, double num);
friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs);
// comparison (only works w/ Strings and "strings")
operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; }
int compareTo(const String &s) const;
unsigned char equals(const String &s) const;
unsigned char equals(const char *cstr) const;
unsigned char operator == (const String &rhs) const {return equals(rhs);}
unsigned char operator == (const char *cstr) const {return equals(cstr);}
unsigned char operator != (const String &rhs) const {return !equals(rhs);}
unsigned char operator != (const char *cstr) const {return !equals(cstr);}
unsigned char operator < (const String &rhs) const;
unsigned char operator > (const String &rhs) const;
unsigned char operator <= (const String &rhs) const;
unsigned char operator >= (const String &rhs) const;
unsigned char equalsIgnoreCase(const String &s) const;
unsigned char startsWith( const String &prefix) const;
unsigned char startsWith(const String &prefix, unsigned int offset) const;
unsigned char endsWith(const String &suffix) const;
// character acccess
char charAt(unsigned int index) const;
void setCharAt(unsigned int index, char c);
char operator [] (unsigned int index) const;
char& operator [] (unsigned int index);
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const;
void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const
{getBytes((unsigned char *)buf, bufsize, index);}
const char * c_str() const { return buffer; }
// search
int indexOf( char ch ) const;
int indexOf( char ch, unsigned int fromIndex ) const;
int indexOf( const String &str ) const;
int indexOf( const String &str, unsigned int fromIndex ) const;
int lastIndexOf( char ch ) const;
int lastIndexOf( char ch, unsigned int fromIndex ) const;
int lastIndexOf( const String &str ) const;
int lastIndexOf( const String &str, unsigned int fromIndex ) const;
String substring( unsigned int beginIndex ) const { return substring(beginIndex, len); };
String substring( unsigned int beginIndex, unsigned int endIndex ) const;
// modification
void replace(char find, char replace);
void replace(const String& find, const String& replace);
void remove(unsigned int index);
void remove(unsigned int index, unsigned int count);
void toLowerCase(void);
void toUpperCase(void);
void trim(void);
// parsing/conversion
long toInt(void) const;
float toFloat(void) const;
protected:
char *buffer; // the actual char array
unsigned int capacity; // the array length minus one (for the '\0')
unsigned int len; // the String length (not counting the '\0')
protected:
void init(void);
void invalidate(void);
unsigned char changeBuffer(unsigned int maxStrLen);
unsigned char concat(const char *cstr, unsigned int length);
// copy and move
String & copy(const char *cstr, unsigned int length);
String & copy(const __FlashStringHelper *pstr, unsigned int length);
#ifdef __GXX_EXPERIMENTAL_CXX0X__
void move(String &rhs);
#endif
};
class StringSumHelper : public String
{
public:
StringSumHelper(const String &s) : String(s) {}
StringSumHelper(const char *p) : String(p) {}
StringSumHelper(char c) : String(c) {}
StringSumHelper(unsigned char num) : String(num) {}
StringSumHelper(int num) : String(num) {}
StringSumHelper(unsigned int num) : String(num) {}
StringSumHelper(long num) : String(num) {}
StringSumHelper(unsigned long num) : String(num) {}
StringSumHelper(float num) : String(num) {}
StringSumHelper(double num) : String(num) {}
};
#endif // __cplusplus
#endif // String_class_h

View File

@ -0,0 +1,515 @@
#ifndef Binary_h
#define Binary_h
#define B0 0
#define B00 0
#define B000 0
#define B0000 0
#define B00000 0
#define B000000 0
#define B0000000 0
#define B00000000 0
#define B1 1
#define B01 1
#define B001 1
#define B0001 1
#define B00001 1
#define B000001 1
#define B0000001 1
#define B00000001 1
#define B10 2
#define B010 2
#define B0010 2
#define B00010 2
#define B000010 2
#define B0000010 2
#define B00000010 2
#define B11 3
#define B011 3
#define B0011 3
#define B00011 3
#define B000011 3
#define B0000011 3
#define B00000011 3
#define B100 4
#define B0100 4
#define B00100 4
#define B000100 4
#define B0000100 4
#define B00000100 4
#define B101 5
#define B0101 5
#define B00101 5
#define B000101 5
#define B0000101 5
#define B00000101 5
#define B110 6
#define B0110 6
#define B00110 6
#define B000110 6
#define B0000110 6
#define B00000110 6
#define B111 7
#define B0111 7
#define B00111 7
#define B000111 7
#define B0000111 7
#define B00000111 7
#define B1000 8
#define B01000 8
#define B001000 8
#define B0001000 8
#define B00001000 8
#define B1001 9
#define B01001 9
#define B001001 9
#define B0001001 9
#define B00001001 9
#define B1010 10
#define B01010 10
#define B001010 10
#define B0001010 10
#define B00001010 10
#define B1011 11
#define B01011 11
#define B001011 11
#define B0001011 11
#define B00001011 11
#define B1100 12
#define B01100 12
#define B001100 12
#define B0001100 12
#define B00001100 12
#define B1101 13
#define B01101 13
#define B001101 13
#define B0001101 13
#define B00001101 13
#define B1110 14
#define B01110 14
#define B001110 14
#define B0001110 14
#define B00001110 14
#define B1111 15
#define B01111 15
#define B001111 15
#define B0001111 15
#define B00001111 15
#define B10000 16
#define B010000 16
#define B0010000 16
#define B00010000 16
#define B10001 17
#define B010001 17
#define B0010001 17
#define B00010001 17
#define B10010 18
#define B010010 18
#define B0010010 18
#define B00010010 18
#define B10011 19
#define B010011 19
#define B0010011 19
#define B00010011 19
#define B10100 20
#define B010100 20
#define B0010100 20
#define B00010100 20
#define B10101 21
#define B010101 21
#define B0010101 21
#define B00010101 21
#define B10110 22
#define B010110 22
#define B0010110 22
#define B00010110 22
#define B10111 23
#define B010111 23
#define B0010111 23
#define B00010111 23
#define B11000 24
#define B011000 24
#define B0011000 24
#define B00011000 24
#define B11001 25
#define B011001 25
#define B0011001 25
#define B00011001 25
#define B11010 26
#define B011010 26
#define B0011010 26
#define B00011010 26
#define B11011 27
#define B011011 27
#define B0011011 27
#define B00011011 27
#define B11100 28
#define B011100 28
#define B0011100 28
#define B00011100 28
#define B11101 29
#define B011101 29
#define B0011101 29
#define B00011101 29
#define B11110 30
#define B011110 30
#define B0011110 30
#define B00011110 30
#define B11111 31
#define B011111 31
#define B0011111 31
#define B00011111 31
#define B100000 32
#define B0100000 32
#define B00100000 32
#define B100001 33
#define B0100001 33
#define B00100001 33
#define B100010 34
#define B0100010 34
#define B00100010 34
#define B100011 35
#define B0100011 35
#define B00100011 35
#define B100100 36
#define B0100100 36
#define B00100100 36
#define B100101 37
#define B0100101 37
#define B00100101 37
#define B100110 38
#define B0100110 38
#define B00100110 38
#define B100111 39
#define B0100111 39
#define B00100111 39
#define B101000 40
#define B0101000 40
#define B00101000 40
#define B101001 41
#define B0101001 41
#define B00101001 41
#define B101010 42
#define B0101010 42
#define B00101010 42
#define B101011 43
#define B0101011 43
#define B00101011 43
#define B101100 44
#define B0101100 44
#define B00101100 44
#define B101101 45
#define B0101101 45
#define B00101101 45
#define B101110 46
#define B0101110 46
#define B00101110 46
#define B101111 47
#define B0101111 47
#define B00101111 47
#define B110000 48
#define B0110000 48
#define B00110000 48
#define B110001 49
#define B0110001 49
#define B00110001 49
#define B110010 50
#define B0110010 50
#define B00110010 50
#define B110011 51
#define B0110011 51
#define B00110011 51
#define B110100 52
#define B0110100 52
#define B00110100 52
#define B110101 53
#define B0110101 53
#define B00110101 53
#define B110110 54
#define B0110110 54
#define B00110110 54
#define B110111 55
#define B0110111 55
#define B00110111 55
#define B111000 56
#define B0111000 56
#define B00111000 56
#define B111001 57
#define B0111001 57
#define B00111001 57
#define B111010 58
#define B0111010 58
#define B00111010 58
#define B111011 59
#define B0111011 59
#define B00111011 59
#define B111100 60
#define B0111100 60
#define B00111100 60
#define B111101 61
#define B0111101 61
#define B00111101 61
#define B111110 62
#define B0111110 62
#define B00111110 62
#define B111111 63
#define B0111111 63
#define B00111111 63
#define B1000000 64
#define B01000000 64
#define B1000001 65
#define B01000001 65
#define B1000010 66
#define B01000010 66
#define B1000011 67
#define B01000011 67
#define B1000100 68
#define B01000100 68
#define B1000101 69
#define B01000101 69
#define B1000110 70
#define B01000110 70
#define B1000111 71
#define B01000111 71
#define B1001000 72
#define B01001000 72
#define B1001001 73
#define B01001001 73
#define B1001010 74
#define B01001010 74
#define B1001011 75
#define B01001011 75
#define B1001100 76
#define B01001100 76
#define B1001101 77
#define B01001101 77
#define B1001110 78
#define B01001110 78
#define B1001111 79
#define B01001111 79
#define B1010000 80
#define B01010000 80
#define B1010001 81
#define B01010001 81
#define B1010010 82
#define B01010010 82
#define B1010011 83
#define B01010011 83
#define B1010100 84
#define B01010100 84
#define B1010101 85
#define B01010101 85
#define B1010110 86
#define B01010110 86
#define B1010111 87
#define B01010111 87
#define B1011000 88
#define B01011000 88
#define B1011001 89
#define B01011001 89
#define B1011010 90
#define B01011010 90
#define B1011011 91
#define B01011011 91
#define B1011100 92
#define B01011100 92
#define B1011101 93
#define B01011101 93
#define B1011110 94
#define B01011110 94
#define B1011111 95
#define B01011111 95
#define B1100000 96
#define B01100000 96
#define B1100001 97
#define B01100001 97
#define B1100010 98
#define B01100010 98
#define B1100011 99
#define B01100011 99
#define B1100100 100
#define B01100100 100
#define B1100101 101
#define B01100101 101
#define B1100110 102
#define B01100110 102
#define B1100111 103
#define B01100111 103
#define B1101000 104
#define B01101000 104
#define B1101001 105
#define B01101001 105
#define B1101010 106
#define B01101010 106
#define B1101011 107
#define B01101011 107
#define B1101100 108
#define B01101100 108
#define B1101101 109
#define B01101101 109
#define B1101110 110
#define B01101110 110
#define B1101111 111
#define B01101111 111
#define B1110000 112
#define B01110000 112
#define B1110001 113
#define B01110001 113
#define B1110010 114
#define B01110010 114
#define B1110011 115
#define B01110011 115
#define B1110100 116
#define B01110100 116
#define B1110101 117
#define B01110101 117
#define B1110110 118
#define B01110110 118
#define B1110111 119
#define B01110111 119
#define B1111000 120
#define B01111000 120
#define B1111001 121
#define B01111001 121
#define B1111010 122
#define B01111010 122
#define B1111011 123
#define B01111011 123
#define B1111100 124
#define B01111100 124
#define B1111101 125
#define B01111101 125
#define B1111110 126
#define B01111110 126
#define B1111111 127
#define B01111111 127
#define B10000000 128
#define B10000001 129
#define B10000010 130
#define B10000011 131
#define B10000100 132
#define B10000101 133
#define B10000110 134
#define B10000111 135
#define B10001000 136
#define B10001001 137
#define B10001010 138
#define B10001011 139
#define B10001100 140
#define B10001101 141
#define B10001110 142
#define B10001111 143
#define B10010000 144
#define B10010001 145
#define B10010010 146
#define B10010011 147
#define B10010100 148
#define B10010101 149
#define B10010110 150
#define B10010111 151
#define B10011000 152
#define B10011001 153
#define B10011010 154
#define B10011011 155
#define B10011100 156
#define B10011101 157
#define B10011110 158
#define B10011111 159
#define B10100000 160
#define B10100001 161
#define B10100010 162
#define B10100011 163
#define B10100100 164
#define B10100101 165
#define B10100110 166
#define B10100111 167
#define B10101000 168
#define B10101001 169
#define B10101010 170
#define B10101011 171
#define B10101100 172
#define B10101101 173
#define B10101110 174
#define B10101111 175
#define B10110000 176
#define B10110001 177
#define B10110010 178
#define B10110011 179
#define B10110100 180
#define B10110101 181
#define B10110110 182
#define B10110111 183
#define B10111000 184
#define B10111001 185
#define B10111010 186
#define B10111011 187
#define B10111100 188
#define B10111101 189
#define B10111110 190
#define B10111111 191
#define B11000000 192
#define B11000001 193
#define B11000010 194
#define B11000011 195
#define B11000100 196
#define B11000101 197
#define B11000110 198
#define B11000111 199
#define B11001000 200
#define B11001001 201
#define B11001010 202
#define B11001011 203
#define B11001100 204
#define B11001101 205
#define B11001110 206
#define B11001111 207
#define B11010000 208
#define B11010001 209
#define B11010010 210
#define B11010011 211
#define B11010100 212
#define B11010101 213
#define B11010110 214
#define B11010111 215
#define B11011000 216
#define B11011001 217
#define B11011010 218
#define B11011011 219
#define B11011100 220
#define B11011101 221
#define B11011110 222
#define B11011111 223
#define B11100000 224
#define B11100001 225
#define B11100010 226
#define B11100011 227
#define B11100100 228
#define B11100101 229
#define B11100110 230
#define B11100111 231
#define B11101000 232
#define B11101001 233
#define B11101010 234
#define B11101011 235
#define B11101100 236
#define B11101101 237
#define B11101110 238
#define B11101111 239
#define B11110000 240
#define B11110001 241
#define B11110010 242
#define B11110011 243
#define B11110100 244
#define B11110101 245
#define B11110110 246
#define B11110111 247
#define B11111000 248
#define B11111001 249
#define B11111010 250
#define B11111011 251
#define B11111100 252
#define B11111101 253
#define B11111110 254
#define B11111111 255
#endif

View File

@ -0,0 +1,15 @@
#include <Arduino.h>
int main(void)
{
//OSCCAL = TUNED_OSCCAL_VALUE; //set the oscillator calibration value based on the pins_arduino.h file. If this is not set, it will be optimised away - it would boil down to 1 = 1;
init();
setup();
for (;;)
loop();
return 0;
}

View File

@ -0,0 +1,692 @@
/*
wiring.c - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 970 2010-05-25 20:16:15Z dmellis $
Modified 28-08-2009 for attiny84 R.Wiersma
Modified 14-10-2009 for attiny45 Saposoft
Modified 20-11-2010 - B.Cook - Rewritten to use the various Veneers.
*/
#include "wiring_private.h"
#if F_CPU >= 3000000L
#if !defined(__AVR_ATtiny167__) && !defined(__AVR_ATtiny87__)
#define timer0Prescaler 0b011
#else
#define timer0Prescaler 0b100
#endif
//Timers with TCCR1 are slightly different.
#if defined(TCCR1) && (TIMER_TO_USE_FOR_MILLIS == 1)
#define MillisTimer_Prescale_Index (0b0111)
#define ToneTimer_Prescale_Index (timer0Prescaler)
#elif defined(TCCR1) && (TIMER_TO_USE_FOR_MILLIS == 0)
#define MillisTimer_Prescale_Index (timer0Prescaler)
#define ToneTimer_Prescale_Index (0b0111)
#elif defined(TCCR1E) && (TIMER_TO_USE_FOR_MILLIS == 1)
#define MillisTimer_Prescale_Index (0b0111)
#define ToneTimer_Prescale_Index (timer0Prescaler)
#elif defined(TCCR1E) && (TIMER_TO_USE_FOR_MILLIS == 0)
#define MillisTimer_Prescale_Index (timer0Prescaler)
#define ToneTimer_Prescale_Index (0b0111)
#elif (TIMER_TO_USE_FOR_MILLIS == 1)
#define MillisTimer_Prescale_Index (0b011)
#define ToneTimer_Prescale_Index (timer0Prescaler)
#else
#define MillisTimer_Prescale_Index (timer0Prescaler)
#define ToneTimer_Prescale_Index (0b011)
#endif
#define MillisTimer_Prescale_Value (64)
#define ToneTimer_Prescale_Value (64)
#else
#if defined(TCCR1) && (TIMER_TO_USE_FOR_MILLIS == 1)
#define MillisTimer_Prescale_Index (0b0100)
#define ToneTimer_Prescale_Index (0b010)
#elif defined(TCCR1) && (TIMER_TO_USE_FOR_MILLIS == 0)
#define MillisTimer_Prescale_Index (0b010)
#define ToneTimer_Prescale_Index (0b0100)
#elif defined(TCCR1E) && (TIMER_TO_USE_FOR_MILLIS == 1)
#define MillisTimer_Prescale_Index (0b0100)
#define ToneTimer_Prescale_Index (0b010)
#elif defined(TCCR1E) && (TIMER_TO_USE_FOR_MILLIS == 0)
#define MillisTimer_Prescale_Index (0b010)
#define ToneTimer_Prescale_Index (0b0100)
#else
#define MillisTimer_Prescale_Index (0b010)
#define ToneTimer_Prescale_Index (0b010)
#endif
#define MillisTimer_Prescale_Value (8)
#define ToneTimer_Prescale_Value (8)
#endif
// the prescaler is set so that the millis timer ticks every MillisTimer_Prescale_Value (64) clock cycles, and the
// the overflow handler is called every 256 ticks.
#define MICROSECONDS_PER_MILLIS_OVERFLOW (clockCyclesToMicroseconds(MillisTimer_Prescale_Value * 256))
// the whole number of milliseconds per millis timer overflow
#define MILLIS_INC (MICROSECONDS_PER_MILLIS_OVERFLOW / 1000)
// the fractional number of milliseconds per millis timer overflow. we shift right
// by three to fit these numbers into a byte. (for the clock speeds we care
// about - 8 and 16 MHz - this doesn't lose precision.)
#define FRACT_INC ((MICROSECONDS_PER_MILLIS_OVERFLOW % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)
volatile unsigned long millis_timer_overflow_count = 0;
volatile unsigned long millis_timer_millis = 0;
static unsigned char millis_timer_fract = 0;
#if (TIMER_TO_USE_FOR_MILLIS == 0)
#if defined(TIMER0_OVF_vect)
SIGNAL(TIMER0_OVF_vect)
#elif defined(TIM0_OVF_vect)
SIGNAL(TIM0_OVF_vect)
#else
#error cannot find Millis() timer overflow vector
#endif
#elif (TIMER_TO_USE_FOR_MILLIS == 1)
#if defined(TIMER1_OVF_vect)
SIGNAL(TIMER1_OVF_vect)
#elif defined(TIM1_OVF_vect)
SIGNAL(TIM1_OVF_vect)
#else
#error cannot find Millis() timer overflow vector
#endif
#else
#error Millis() timer not defined!
#endif
{
// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
unsigned long m = millis_timer_millis;
unsigned char f = millis_timer_fract;
/* rmv: The code below generates considerably less code (emtpy Sketch is 326 versus 304)...
m += MILLIS_INC;
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
m += 1;
}
...rmv */
f += FRACT_INC;
if (f >= FRACT_MAX)
{
f -= FRACT_MAX;
m += 1;
m += MILLIS_INC;
}
else
{
m += MILLIS_INC;
}
millis_timer_fract = f;
millis_timer_millis = m;
millis_timer_overflow_count++;
//MICROSECONDS_PER_MILLIS_OVERFLOW=2048
//MILLIS_INC=2
//FRACT_INC=6
//FRACT_MAX=125
}
unsigned long millis()
{
unsigned long m;
uint8_t oldSREG = SREG;
// disable interrupts while we read millis_timer_millis or we might get an
// inconsistent value (e.g. in the middle of a write to millis_timer_millis)
cli();
m = millis_timer_millis;
SREG = oldSREG;
return m;
}
unsigned long micros()
{
unsigned long m;
uint8_t oldSREG = SREG, t;
cli();
m = millis_timer_overflow_count;
#if defined(TCNT0) && (TIMER_TO_USE_FOR_MILLIS == 0) && !defined(TCW0)
t = TCNT0;
#elif defined(TCNT0L) && (TIMER_TO_USE_FOR_MILLIS == 0)
t = TCNT0L;
#elif defined(TCNT1) && (TIMER_TO_USE_FOR_MILLIS == 1)
t = TCNT1;
#elif defined(TCNT1L) && (TIMER_TO_USE_FOR_MILLIS == 1)
t = TCNT1L;
#else
#error Millis()/Micros() timer not defined
#endif
#if defined(TIFR0) && (TIMER_TO_USE_FOR_MILLIS == 0)
if ((TIFR0 & _BV(TOV0)) && (t < 255))
m++;
#elif defined(TIFR) && (TIMER_TO_USE_FOR_MILLIS == 0)
if ((TIFR & _BV(TOV0)) && (t < 255))
m++;
#elif defined(TIFR1) && (TIMER_TO_USE_FOR_MILLIS == 1)
if ((TIFR1 & _BV(TOV1)) && (t < 255))
m++;
#elif defined(TIFR) && (TIMER_TO_USE_FOR_MILLIS == 1)
if ((TIFR & _BV(TOV1)) && (t < 255))
m++;
#endif
SREG = oldSREG;
return ((m << 8) + t) * (MillisTimer_Prescale_Value / clockCyclesPerMicrosecond());
}
void delay(unsigned long ms)
{
uint16_t start = (uint16_t)micros();
while (ms > 0) {
if (((uint16_t)micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}
/* Delay for the given number of microseconds. Assumes a 1, 8, 12, 16, 20 or 24 MHz clock. */
void delayMicroseconds(unsigned int us)
{
// call = 4 cycles + 2 to 4 cycles to init us(2 for constant delay, 4 for variable)
// calling avrlib's delay_us() function with low values (e.g. 1 or
// 2 microseconds) gives delays longer than desired.
//delay_us(us);
#if F_CPU >= 24000000L
// for the 24 MHz clock for the aventurous ones, trying to overclock
// zero delay fix
if (!us) return; // = 3 cycles, (4 when true)
// the following loop takes a 1/6 of a microsecond (4 cycles)
// per iteration, so execute it six times for each microsecond of
// delay requested.
us *= 6; // x6 us, = 7 cycles
// account for the time taken in the preceeding commands.
// we just burned 22 (24) cycles above, remove 5, (5*4=20)
// us is at least 6 so we can substract 5
us -= 5; //=2 cycles
#elif F_CPU >= 20000000L
// for the 20 MHz clock on rare Arduino boards
// for a one-microsecond delay, simply return. the overhead
// of the function call takes 18 (20) cycles, which is 1us
__asm__ __volatile__ (
"nop" "\n\t"
"nop" "\n\t"
"nop" "\n\t"
"nop"); //just waiting 4 cycles
if (us <= 1) return; // = 3 cycles, (4 when true)
// the following loop takes a 1/5 of a microsecond (4 cycles)
// per iteration, so execute it five times for each microsecond of
// delay requested.
us = (us << 2) + us; // x5 us, = 7 cycles
// account for the time taken in the preceeding commands.
// we just burned 26 (28) cycles above, remove 7, (7*4=28)
// us is at least 10 so we can substract 7
us -= 7; // 2 cycles
#elif F_CPU >= 16000000L
// for the 16 MHz clock on most Arduino boards
// for a one-microsecond delay, simply return. the overhead
// of the function call takes 14 (16) cycles, which is 1us
if (us <= 1) return; // = 3 cycles, (4 when true)
// the following loop takes 1/4 of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2; // x4 us, = 4 cycles
// account for the time taken in the preceeding commands.
// we just burned 19 (21) cycles above, remove 5, (5*4=20)
// us is at least 8 so we can substract 5
us -= 5; // = 2 cycles,
#elif F_CPU >= 12000000L
// for the 12 MHz clock if somebody is working with USB
// for a 1 microsecond delay, simply return. the overhead
// of the function call takes 14 (16) cycles, which is 1.5us
if (us <= 1) return; // = 3 cycles, (4 when true)
// the following loop takes 1/3 of a microsecond (4 cycles)
// per iteration, so execute it three times for each microsecond of
// delay requested.
us = (us << 1) + us; // x3 us, = 5 cycles
// account for the time taken in the preceeding commands.
// we just burned 20 (22) cycles above, remove 5, (5*4=20)
// us is at least 6 so we can substract 5
us -= 5; //2 cycles
#elif F_CPU >= 8000000L
// for the 8 MHz internal clock
// for a 1 and 2 microsecond delay, simply return. the overhead
// of the function call takes 14 (16) cycles, which is 2us
if (us <= 2) return; // = 3 cycles, (4 when true)
// the following loop takes 1/2 of a microsecond (4 cycles)
// per iteration, so execute it twice for each microsecond of
// delay requested.
us <<= 1; //x2 us, = 2 cycles
// account for the time taken in the preceeding commands.
// we just burned 17 (19) cycles above, remove 4, (4*4=16)
// us is at least 6 so we can substract 4
us -= 4; // = 2 cycles
#else
// for the 1 MHz internal clock (default settings for common AVR microcontrollers)
// the overhead of the function calls is 14 (16) cycles
if (us <= 16) return; //= 3 cycles, (4 when true)
if (us <= 25) return; //= 3 cycles, (4 when true), (must be at least 25 if we want to substract 22)
// compensate for the time taken by the preceeding and next commands (about 22 cycles)
us -= 22; // = 2 cycles
// the following loop takes 4 microseconds (4 cycles)
// per iteration, so execute it us/4 times
// us is at least 4, divided by 4 gives us 1 (no zero delay bug)
us >>= 2; // us div 4, = 4 cycles
#endif
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
// return = 4 cycles
}
#if INITIALIZE_SECONDARY_TIMERS
static void initToneTimerInternal(void)
{
// Timer is processor clock divided by ToneTimer_Prescale_Index
#if (TIMER_TO_USE_FOR_TONE == 0)
TCCR0B &= ~((1<<CS02) | (1<<CS01) | (1<<CS00)); //stop the clock to configure
// Use the Tone Timer for phase correct PWM
sbi(TCCR0A, WGM00);
cbi(TCCR0A, WGM01);
cbi(TCCR0B, WGM02);
TCCR0B |= (ToneTimer_Prescale_Index << CS00);
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1)
TCCR1 &= ~((1<<CS13) | (1<<CS12) | (1<<CS11) | (1<<CS10)); //stop the clock to configure
// Use the Tone Timer for fast PWM as phase correct not supported by this timer
sbi(TCCR1, CTC1);
#if !defined(__AVR_ATtiny85__)
sbi(TCCR1, PWM1A); //for the tiny 85, Timer0 is used instead.
#endif
sbi(GTCCR, PWM1B);
OCR1C = 0xFF; //Use 255 as the top to match with the others as this module doesn't have a 8bit PWM mode.
TCCR1 |= (ToneTimer_Prescale_Index << CS10);
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1E)
TCCR1B &= ~((1<<CS13) | (1<<CS12) | (1<<CS11) | (1<<CS10)); //stop the clock to configure
// Use the Tone Timer for phase correct PWM
sbi(TCCR1A, PWM1A);
sbi(TCCR1A, PWM1B);
sbi(TCCR1C, PWM1D);
cbi(TCCR1D, WGM11);
sbi(TCCR1D, WGM10);
TCCR1B |= (ToneTimer_Prescale_Index << CS10);
#elif (TIMER_TO_USE_FOR_TONE == 1)
TCCR1B &= ~((1<<CS12) | (1<<CS11) | (1<<CS10)); //stop the clock to configure
// Use the Tone Timer for phase correct PWM
sbi(TCCR1A, WGM10);
cbi(TCCR1A, WGM11);
cbi(TCCR1B, WGM12);
cbi(TCCR1B, WGM13);
TCCR1B |= (ToneTimer_Prescale_Index << CS10); //set the clock
#endif
}
#endif
void initToneTimer(void)
{
// Ensure the timer is in the same state as power-up
#if (TIMER_TO_USE_FOR_TONE == 0)
TCCR0B = (0<<FOC0A) | (0<<FOC0B) | (0<<WGM02) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCCR0A = (0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
// Reset the count to zero
TCNT0 = 0;
// Set the output compare registers to zero
OCR0A = 0;
OCR0B = 0;
#if defined(TIMSK)
// Disable all Timer0 interrupts
TIMSK &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
// Clear the Timer0 interrupt flags
TIFR |= ((1<<OCF0B) | (1<<OCF0A) | (1<<TOV0));
#elif defined(TIMSK1)
// Disable all Timer0 interrupts
TIMSK0 &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
// Clear the Timer0 interrupt flags
TIFR0 |= ((1<<OCF0B) | (1<<OCF0A) | (1<<TOV0));
#endif
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1)
// Turn off Clear on Compare Match, turn off PWM A, disconnect the timer from the output pin, stop the clock
TCCR1 = (0<<CTC1) | (0<<PWM1A) | (0<<COM1A1) | (0<<COM1A0) | (0<<CS13) | (0<<CS12) | (0<<CS11) | (0<<CS10);
// Turn off PWM A, disconnect the timer from the output pin, no Force Output Compare Match, no Prescaler Reset
GTCCR &= ~((1<<PWM1B) | (1<<COM1B1) | (1<<COM1B0) | (1<<FOC1B) | (1<<FOC1A) | (1<<PSR1));
// Reset the count to zero
TCNT1 = 0;
// Set the output compare registers to zero
OCR1A = 0;
OCR1B = 0;
OCR1C = 0;
// Disable all Timer1 interrupts
TIMSK &= ~((1<<OCIE1A) | (1<<OCIE1B) | (1<<TOIE1));
// Clear the Timer1 interrupt flags
TIFR |= ((1<<OCF1A) | (1<<OCF1B) | (1<<TOV1));
#elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1E)
TCCR1A = 0;
TCCR1B = 0;
TCCR1C = 0;
TCCR1D = 0;
TCCR1E = 0;
// Reset the count to zero
TCNT1 = 0;
// Set the output compare registers to zero
OCR1A = 0;
OCR1B = 0;
OCR1C = 0;
OCR1D = 0;
// Disable all Timer1 interrupts
TIMSK &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<OCIE1D));
// Clear the Timer1 interrupt flags
TIFR |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<OCF1D));
#elif (TIMER_TO_USE_FOR_TONE == 1)
// Turn off Input Capture Noise Canceler, Input Capture Edge Select on Falling, stop the clock
TCCR1B = (0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
// Disconnect the timer from the output pins, Set Waveform Generation Mode to Normal
TCCR1A = (0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
// Reset the count to zero
TCNT1 = 0;
// Set the output compare registers to zero
OCR1A = 0;
OCR1B = 0;
// Disable all Timer1 interrupts
#if defined(TIMSK)
TIMSK &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<ICIE1));
// Clear the Timer1 interrupt flags
TIFR |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<ICF1));
#elif defined(TIMSK1)
// Disable all Timer1 interrupts
TIMSK1 &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<ICIE1));
// Clear the Timer1 interrupt flags
TIFR1 |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<ICF1));
#endif
#endif
#if INITIALIZE_SECONDARY_TIMERS
// Prepare the timer for PWM
initToneTimerInternal();
#endif
}
#if F_CPU == 20000000
// 20 MHz / 128 ~= 125 KHz
#define ADC_ARDUINO_PRESCALER B111
#elif F_CPU == 18432000
// 18.432 MHz / 128 ~= 125 KHz
#define ADC_ARDUINO_PRESCALER B111
#elif F_CPU == 16000000
// 16 MHz / 128 = 125 KHz
#define ADC_ARDUINO_PRESCALER B111
#elif F_CPU == 12000000
// 12 MHz / 64 ~= 125 KHz
#define ADC_ARDUINO_PRESCALER B110
#elif F_CPU == 8000000
// 8 MHz / 64 = 125 KHz
#define ADC_ARDUINO_PRESCALER B110
#elif F_CPU == 1000000
// 1 MHz / 8 = 125 KHz
#define ADC_ARDUINO_PRESCALER B011
#elif F_CPU == 128000
// 128 kHz / 2 = 64 KHz -> This is the closest you can get, the prescaler is 2
#define ADC_ARDUINO_PRESCALER B000
#else
#error Add an entry for the selected processor speed.
#endif
void init(void)
{
// In case the bootloader left our millis timer in a bad way
#if defined( HAVE_BOOTLOADER ) && HAVE_BOOTLOADER
// Ensure the timer is in the same state as power-up
#if (TIMER_TO_USE_FOR_MILLIS == 0) && defined(WGM01)
TCCR0B = 0;
TCCR0A = 0;
// Reset the count to zero
TCNT0 = 0;
// Set the output compare registers to zero
OCR0A = 0;
#ifdef OCR0B
OCR0B = 0;
#endif
#if defined(TIMSK)
// Disable all Timer0 interrupts
TIMSK &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
// Clear the Timer0 interrupt flags
TIFR |= ((1<<OCF0B) | (1<<OCF0A) | (1<<TOV0));
#elif defined(TIMSK1)
#ifdef OCIE0B
// Disable all Timer0 interrupts
TIMSK0 &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
// Clear the Timer0 interrupt flags
TIFR0 |= ((1<<OCF0B) | (1<<OCF0A) | (1<<TOV0));
#else
// Disable all Timer0 interrupts
TIMSK0 &= ~((1<<OCIE0A) | (1<<TOIE0));
// Clear the Timer0 interrupt flags
TIFR0 |= ((1<<OCF0A) | (1<<TOV0));
#endif
#endif
#elif (TIMER_TO_USE_FOR_MILLIS == 0) && defined(TCW0)
TCCR0A = 0;
TCCR0B = 0;
// Reset the count to zero
TCNT0 = 0;
#if defined(TIMSK)
// Disable all Timer0 interrupts
TIMSK &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
// Clear the Timer0 interrupt flags
TIFR |= ((1<<OCF0B) | (1<<OCF0A) | (1<<TOV0));
#if defined(TICIE0)
cbi(TIMSK,TICIE0);
sbi(TIFR0,ICF0);
#endif
#elif defined(TIMSK1)
// Disable all Timer0 interrupts
TIMSK0 &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
// Clear the Timer0 interrupt flags
TIFR0 |= ((1<<OCF0B) | (1<<OCF0A) | (1<<TOV0));
#if defined(TICIE0)
cbi(TIMSK0,TICIE0);
sbi(TIFR0,ICF0);
#endif
#endif
#elif (TIMER_TO_USE_FOR_MILLIS == 1) && defined(TCCR1)
// Turn off Clear on Compare Match, turn off PWM A, disconnect the timer from the output pin, stop the clock
TCCR1 = (0<<CTC1) | (0<<PWM1A) | (0<<COM1A1) | (0<<COM1A0) | (0<<CS13) | (0<<CS12) | (0<<CS11) | (0<<CS10);
// Turn off PWM A, disconnect the timer from the output pin, no Force Output Compare Match, no Prescaler Reset
GTCCR &= ~((1<<PWM1B) | (1<<COM1B1) | (1<<COM1B0) | (1<<FOC1B) | (1<<FOC1A) | (1<<PSR1));
// Reset the count to zero
TCNT1 = 0;
// Set the output compare registers to zero
OCR1A = 0;
OCR1B = 0;
OCR1C = 0;
// Disable all Timer1 interrupts
TIMSK = 0;
// Clear the Timer1 interrupt flags
TIFR |= ((1<<OCF1A) | (1<<OCF1B) | (1<<TOV1));
#elif (TIMER_TO_USE_FOR_MILLIS == 1) && defined(TCCR1E)
TCCR1A = 0;
TCCR1B = 0;
TCCR1C = 0;
TCCR1D = 0;
TCCR1E = 0;
// Reset the count to zero
TCNT1 = 0;
// Set the output compare registers to zero
OCR1A = 0;
OCR1B = 0;
// Disable all Timer1 interrupts
TIMSK &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<OCIE1D));
// Clear the Timer1 interrupt flags
TIFR |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<OCF1D));
#elif (TIMER_TO_USE_FOR_MILLIS == 1)
// Turn off Input Capture Noise Canceler, Input Capture Edge Select on Falling, stop the clock
TCCR1B = (0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
// Disconnect the timer from the output pins, Set Waveform Generation Mode to Normal
TCCR1A = (0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
// Reset the count to zero
TCNT1 = 0;
// Set the output compare registers to zero
OCR1A = 0;
OCR1B = 0;
// Disable all Timer1 interrupts
#if defined(TIMSK)
TIMSK &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<ICIE1));
// Clear the Timer1 interrupt flags
TIFR |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<ICF1));
#elif defined(TIMSK1)
// Disable all Timer1 interrupts
TIMSK1 &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<ICIE1));
// Clear the Timer1 interrupt flags
TIFR1 |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<ICF1));
#endif
#endif
#endif
// Use the Millis Timer for fast PWM (unless it doesn't have an output).
#if (TIMER_TO_USE_FOR_MILLIS == 0) && defined(WGM01)
sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00);
#elif (TIMER_TO_USE_FOR_MILLIS == 1) && defined(TCCR1)
sbi(TCCR1, CTC1);
//#if !defined(__AVR_ATtiny85__)
// sbi(TCCR1, PWM1A); //for the tiny 85, Timer0 is used instead.
//#endif
//sbi(GTCCR, PWM1B);
OCR1C = 0xFF; //Use 255 as the top to match with the others as this module doesn't have a 8bit PWM mode.
#elif (TIMER_TO_USE_FOR_MILLIS == 1) && defined(TCCR1E)
sbi(TCCR1C, PWM1D);
sbi(TCCR1A, PWM1A);
sbi(TCCR1A, PWM1B);
cbi(TCCR1E, WGM10); //fast pwm mode
cbi(TCCR1E, WGM11);
OCR1C = 0xFF; //Use 255 as the top to match with the others as this module doesn't have a 8bit PWM mode.
#elif (TIMER_TO_USE_FOR_MILLIS == 1)
sbi(TCCR1A, WGM10);
sbi(TCCR1B, WGM12);
#endif
// Millis timer is always processor clock divided by MillisTimer_Prescale_Value (64)
#if (TIMER_TO_USE_FOR_MILLIS == 0)
TCCR0B = (TCCR0B & ~((1<<CS02)|(1<<CS01)|(1<<CS00))) | (MillisTimer_Prescale_Index << CS00);
#elif (TIMER_TO_USE_FOR_MILLIS == 1) && defined(TCCR1)
TCCR1 = (TCCR1 & ~((1<<CS13)|(1<<CS12)|(1<<CS11)|(1<<CS10))) | (MillisTimer_Prescale_Index << CS10);
#elif (TIMER_TO_USE_FOR_MILLIS == 1) && defined(TCCR1E)
TCCR1B = (TCCR1B & ~((1<<CS13)|(1<<CS12)|(1<<CS11)|(1<<CS10))) | (MillisTimer_Prescale_Index << CS10);
#elif (TIMER_TO_USE_FOR_MILLIS == 1)
TCCR1B = (TCCR1B & ~((1<<CS12)|(1<<CS11)|(1<<CS10))) | (MillisTimer_Prescale_Index << CS10);
#endif
// this needs to be called before setup() or some functions won't work there
sei();
// Enable the overlow interrupt (this is the basic system tic-toc for millis)
#if defined(TIMSK) && defined(TOIE0) && (TIMER_TO_USE_FOR_MILLIS == 0)
sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0) && (TIMER_TO_USE_FOR_MILLIS == 0)
sbi(TIMSK0, TOIE0);
#elif defined(TIMSK) && defined(TOIE1) && (TIMER_TO_USE_FOR_MILLIS == 1)
sbi(TIMSK, TOIE1);
#elif defined(TIMSK1) && defined(TOIE1) && (TIMER_TO_USE_FOR_MILLIS == 1)
sbi(TIMSK1, TOIE1);
#else
#error Millis() Timer overflow interrupt not set correctly
#endif
// Initialize the timer used for Tone
#if INITIALIZE_SECONDARY_TIMERS
initToneTimerInternal();
#endif
// Initialize the ADC
#if defined( INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER ) && INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER
#if defined(ADCSRA)
// set a2d prescale factor
ADCSRA = (ADCSRA & ~((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0))) | (ADC_ARDUINO_PRESCALER << ADPS0) | (1<<ADEN);
// enable a2d conversions
sbi(ADCSRA, ADEN);
#endif
#endif
}

View File

@ -0,0 +1,175 @@
/*
wiring_analog.c - analog input and output
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
Modified 28-08-2009 for attiny84 R.Wiersma
Modified 14-10-2009 for attiny45 Saposoft
Corrected 17-05-2010 for ATtiny84 B.Cook
*/
#include "wiring_private.h"
#include "pins_arduino.h"
#ifndef DEFAULT
//For those with no ADC, need to define default.
#define DEFAULT (0)
#endif
uint8_t analog_reference = DEFAULT;
void analogReference(uint8_t mode)
{
// can't actually set the register here because the default setting
// will connect AVCC and the AREF pin, which would cause a short if
// there's something connected to AREF.
// fix? Validate the mode?
analog_reference = mode;
}
int analogRead(uint8_t pin)
{
#if defined( NUM_DIGITAL_PINS )
if ( pin >= NUM_DIGITAL_PINS ) pin -= NUM_DIGITAL_PINS; // allow for channel or pin numbers
#endif
// fix? Validate pin?
if(pin >= NUM_ANALOG_INPUTS) return 0; //Not a valid pin.
//if(pin < 4) return 9; //Not a valid pin.
#ifndef ADCSRA
return digitalRead(analogInputToDigitalPin(pin)) ? 1023 : 0; //No ADC, so read as a digital pin instead.
#endif
#if defined(ADMUX)
#if defined(MUX4)
ADMUX = ((analog_reference & 0x03) << REFS0) | ((pin & 0x1F) << MUX0); //select the channel and reference
#elif defined(MUX3)
ADMUX = ((analog_reference & 0x03) << REFS0) | ((pin & 0x0F) << MUX0); //select the channel and reference
#else
ADMUX = ((analog_reference & 0x03) << REFS0) | ((pin & 0x07) << MUX0); //select the channel and reference
#endif
#endif
#if defined(REFS2)
ADMUX |= (((analog_reference & 0x04) >> 2) << REFS2); //some have an extra reference bit in a weird position.
#endif
#if defined(HAVE_ADC) && HAVE_ADC
sbi(ADCSRA, ADSC); //Start conversion
while(ADCSRA & (1<<ADSC)); //Wait for conversion to complete.
uint8_t low = ADCL;
uint8_t high = ADCH;
return (high << 8) | low;
#else
return LOW;
#endif
}
// Right now, PWM output only works on the pins with
// hardware support. These are defined in the appropriate
// 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
{
uint8_t timer = digitalPinToTimer(pin);
/*
if( timer == TIMER0B){
// connect pwm to pin on timer 0, channel B
sbi(TCCR0A, COM0B1);
cbi(TCCR0A, COM0B0);
OCR0B = val; // set pwm duty
} else
*/
if( timer == TIMER1A){
// connect pwm to pin on timer 1, channel A
sbi(TCCR1A, COM1A1);
sbi(TCCR1A, WGM10);
cbi(TCCR1A, COM1A0);
sbi(TCCR1B, WGM10);
sbi(TCCR1B, CS11);
//sbi(TCCR1B, CS10);
cbi(TCCR1D, OC1AV);
sbi(TCCR1D, OC1AU);
cbi(TCCR1D, OC1AW);
cbi(TCCR1D, OC1AX);
OCR1A = val; // set pwm duty
} else
if( timer == TIMER1B){
// connect pwm to pin on timer 1, channel B
sbi(TCCR1A, COM1B1);
sbi(TCCR1A, WGM10);
cbi(TCCR1A, COM1B0);
sbi(TCCR1B, WGM10);
sbi(TCCR1B, CS11);
//sbi(TCCR1B, CS10);
cbi(TCCR1D, OC1BV);
sbi(TCCR1D, OC1BU);
cbi(TCCR1D, OC1BW);
cbi(TCCR1D, OC1BX);
OCR1B = val; // set pwm duty
} else
{
if (val < 128)
{
digitalWrite(pin, LOW);
}
else
{
digitalWrite(pin, HIGH);
}
}
}
}

View File

@ -0,0 +1,160 @@
/*
wiring_digital.c - digital input and output functions
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
Modified 28-08-2009 for attiny84 R.Wiersma
Modified 14-10-2009 for attiny45 Saposoft
*/
#define ARDUINO_MAIN
#include "wiring_private.h"
#include "pins_arduino.h"
void pinMode(uint8_t pin, uint8_t mode)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *reg, *out;
if (port == NOT_A_PIN) return;
reg = portModeRegister(port);
out = portOutputRegister(port);
if (mode == INPUT) {
uint8_t oldSREG = SREG;
cli();
*reg &= ~bit;
*out &= ~bit;
SREG = oldSREG;
} else if (mode == INPUT_PULLUP) {
uint8_t oldSREG = SREG;
cli();
*reg &= ~bit;
*out |= bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
cli();
*reg |= bit;
SREG = oldSREG;
}
}
static void turnOffPWM(uint8_t timer)
{
#if defined(TCCR0A) && defined(COM0A1)
if( timer == TIMER0A){
cbi(TCCR0A, COM0A1);
cbi(TCCR0A, COM0A0);
} else
#endif
#if defined(TCCR0A) && defined(COM0B1)
if( timer == TIMER0B){
cbi(TCCR0A, COM0B1);
cbi(TCCR0A, COM0B0);
} else
#endif
#if defined(TCCR1A) && defined(COM1A1)
if( timer == TIMER1A){
cbi(TCCR1A, COM1A1);
cbi(TCCR1A, COM1A0);
} else
#endif
#if defined(TCCR1) && defined(COM1A1)
if(timer == TIMER1A){
cbi(TCCR1, COM1A1);
cbi(TCCR1, COM1A0);
#ifdef OC1AX
cbi(TCCR1D, OC1AX);
#endif
} else
#endif
#if defined(TCCR1A) && defined(COM1B1)
if( timer == TIMER1B){
cbi(TCCR1A, COM1B1);
cbi(TCCR1A, COM1B0);
#ifdef OC1BV
cbi(TCCR1D, OC1BV);
#endif
} else
#endif
#if defined(TCCR1) && defined(COM1B1)
if( timer == TIMER1B){
cbi(GTCCR, COM1B1);
cbi(GTCCR, COM1B0);
} else
#endif
{
}
}
void digitalWrite(uint8_t pin, uint8_t val)
{
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *out;
if (port == NOT_A_PIN) return;
// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
out = portOutputRegister(port);
if (val == LOW) {
uint8_t oldSREG = SREG;
cli();
*out &= ~bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
cli();
*out |= bit;
SREG = oldSREG;
}
}
int digitalRead(uint8_t pin)
{
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
if (port == NOT_A_PIN) return LOW;
// If the pin that support PWM output, we need to turn it off
// before getting a digital reading.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
if (*portInputRegister(port) & bit) return HIGH;
return LOW;
}

View File

@ -0,0 +1,178 @@
/*
wiring_private.h - Internal header file.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.h 239 2007-01-12 17:58:39Z mellis $
Modified 28-08-2009 for attiny84 R.Wiersma
*/
#ifndef WiringPrivate_h
#define WiringPrivate_h
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdarg.h>
#include "Arduino.h"
#ifdef __cplusplus
extern "C"{
#endif
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#if defined( EXT_INT0_vect )
#define EXTERNAL_INTERRUPT_0_vect EXT_INT0_vect
#elif defined( INT0_vect )
#define EXTERNAL_INTERRUPT_0_vect INT0_vect
#endif
#if defined( EXT_INT1_vect )
#define EXTERNAL_INTERRUPT_1_vect EXT_INT1_vect
#elif defined( INT1_vect )
#define EXTERNAL_INTERRUPT_1_vect INT1_vect
#endif
#if defined( EXT_INT2_vect )
#define EXTERNAL_INTERRUPT_2_vect EXT_INT2_vect
#elif defined( INT2_vect )
#define EXTERNAL_INTERRUPT_2_vect INT2_vect
#endif
#if defined( EXT_INT3_vect )
#define EXTERNAL_INTERRUPT_3_vect EXT_INT3_vect
#elif defined( INT3_vect )
#define EXTERNAL_INTERRUPT_3_vect INT3_vect
#endif
#if defined( EXT_INT4_vect )
#define EXTERNAL_INTERRUPT_4_vect EXT_INT4_vect
#elif defined( INT4_vect )
#define EXTERNAL_INTERRUPT_4_vect INT4_vect
#endif
#if defined( EXT_INT5_vect )
#define EXTERNAL_INTERRUPT_5_vect EXT_INT5_vect
#elif defined( INT5_vect )
#define EXTERNAL_INTERRUPT_5_vect INT5_vect
#endif
#if defined( EXT_INT6_vect )
#define EXTERNAL_INTERRUPT_6_vect EXT_INT6_vect
#elif defined( INT6_vect )
#define EXTERNAL_INTERRUPT_6_vect INT6_vect
#endif
#if defined( EXT_INT7_vect )
#define EXTERNAL_INTERRUPT_7_vect EXT_INT7_vect
#elif defined( INT7_vect )
#define EXTERNAL_INTERRUPT_7_vect INT7_vect
#endif
#if defined( EXT_INT8_vect )
#define EXTERNAL_INTERRUPT_8_vect EXT_INT8_vect
#elif defined( INT8_vect )
#define EXTERNAL_INTERRUPT_8_vect INT8_vect
#endif
#if defined( EXT_INT9_vect )
#define EXTERNAL_INTERRUPT_9_vect EXT_INT9_vect
#elif defined( INT9_vect )
#define EXTERNAL_INTERRUPT_9_vect INT9_vect
#endif
#if defined( EXTERNAL_INTERRUPT_9_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (10)
#elif defined( EXTERNAL_INTERRUPT_8_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (9)
#elif defined( EXTERNAL_INTERRUPT_7_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (8)
#elif defined( EXTERNAL_INTERRUPT_6_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (7)
#elif defined( EXTERNAL_INTERRUPT_5_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (6)
#elif defined( EXTERNAL_INTERRUPT_4_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (5)
#elif defined( EXTERNAL_INTERRUPT_3_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (4)
#elif defined( EXTERNAL_INTERRUPT_2_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (3)
#elif defined( EXTERNAL_INTERRUPT_1_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (2)
#elif defined( EXTERNAL_INTERRUPT_0_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (1)
#else
#define NUMBER_EXTERNAL_INTERRUPTS (0)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 1
#define EXTERNAL_INTERRUPT_0 (0)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 2
#define EXTERNAL_INTERRUPT_1 (1)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 3
#define EXTERNAL_INTERRUPT_2 (2)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 4
#define EXTERNAL_INTERRUPT_3 (3)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 5
#define EXTERNAL_INTERRUPT_4 (4)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 6
#define EXTERNAL_INTERRUPT_5 (5)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 7
#define EXTERNAL_INTERRUPT_6 (6)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 8
#define EXTERNAL_INTERRUPT_7 (7)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 9
#define EXTERNAL_INTERRUPT_8 (8)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 10
#define EXTERNAL_INTERRUPT_9 (9)
#endif
typedef void (*voidFuncPtr)(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

View File

@ -0,0 +1,69 @@
/*
wiring_pulse.c - pulseIn() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
#include "pins_arduino.h"
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
* to 3 minutes in length, but must be called at least a few dozen microseconds
* before the start of the pulse. */
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
// cache the port and bit of the pin in order to speed up the
// pulse width measuring loop and achieve finer resolution. calling
// digitalRead() instead yields much coarser resolution.
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
uint8_t stateMask = (state ? bit : 0);
unsigned long width = 0; // keep initialization out of time critical area
// convert the timeout from microseconds to a number of times through
// the initial loop; it takes 16 clock cycles per iteration.
unsigned long numloops = 0;
unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
// wait for any previous pulse to end
while ((*portInputRegister(port) & bit) == stateMask)
if (numloops++ == maxloops)
return 0;
// wait for the pulse to start
while ((*portInputRegister(port) & bit) != stateMask)
if (numloops++ == maxloops)
return 0;
// wait for the pulse to stop
while ((*portInputRegister(port) & bit) == stateMask) {
if (numloops++ == maxloops)
return 0;
width++;
}
// convert the reading to microseconds. The loop has been determined
// to be 20 clock cycles long and have about 16 clocks between the edge
// and the start of the loop. There will be some error introduced by
// the interrupt handlers.
return clockCyclesToMicroseconds(width * 21 + 16);
}

View File

@ -0,0 +1,55 @@
/*
wiring_shift.c - shiftOut() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
uint8_t value = 0;
uint8_t i;
for (i = 0; i < 8; ++i) {
digitalWrite(clockPin, HIGH);
if (bitOrder == LSBFIRST)
value |= digitalRead(dataPin) << i;
else
value |= digitalRead(dataPin) << (7 - i);
digitalWrite(clockPin, LOW);
}
return value;
}
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
uint8_t i;
for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST)
digitalWrite(dataPin, !!(val & (1 << i)));
else
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
}
}

View File

@ -0,0 +1,6 @@
#ifndef Arduino_h
#define Arduino_h
#include <WProgram.h>
#endif

View File

@ -0,0 +1,308 @@
/*
HardwareSerial.cpp - Hardware serial library for Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
Modified 28 September 2010 by Mark Sproul
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "core_build_options.h"
#include "wiring.h"
#include "wiring_private.h"
// this next line disables the entire HardwareSerial.cpp,
// this is so I can support Attiny series and any other chip without a uart
#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)
#include "HardwareSerial.h"
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.
#if (RAMEND < 1000)
#define RX_BUFFER_SIZE 32
#else
#define RX_BUFFER_SIZE 128
#endif
struct ring_buffer
{
unsigned char buffer[RX_BUFFER_SIZE];
int head;
int tail;
};
#if defined(UBRRH) || defined(UBRR0H)
ring_buffer rx_buffer = { { 0 }, 0, 0 };
#endif
#if defined(UBRR1H)
ring_buffer rx_buffer1 = { { 0 }, 0, 0 };
#endif
#if defined(UBRR2H)
ring_buffer rx_buffer2 = { { 0 }, 0, 0 };
#endif
#if defined(UBRR3H)
ring_buffer rx_buffer3 = { { 0 }, 0, 0 };
#endif
inline void store_char(unsigned char c, ring_buffer *rx_buffer)
{
int i = (unsigned int)(rx_buffer->head + 1) % RX_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != rx_buffer->tail) {
rx_buffer->buffer[rx_buffer->head] = c;
rx_buffer->head = i;
}
}
#if defined(USART_RX_vect)
SIGNAL(USART_RX_vect)
{
#if defined(UDR0)
unsigned char c = UDR0;
#elif defined(UDR)
unsigned char c = UDR; // atmega8535
#else
#error UDR not defined
#endif
store_char(c, &rx_buffer);
}
#elif defined(SIG_USART0_RECV) && defined(UDR0)
SIGNAL(SIG_USART0_RECV)
{
unsigned char c = UDR0;
store_char(c, &rx_buffer);
}
#elif defined(SIG_UART0_RECV) && defined(UDR0)
SIGNAL(SIG_UART0_RECV)
{
unsigned char c = UDR0;
store_char(c, &rx_buffer);
}
//#elif defined(SIG_USART_RECV)
#elif defined(USART0_RX_vect)
// fixed by Mark Sproul this is on the 644/644p
//SIGNAL(SIG_USART_RECV)
SIGNAL(USART0_RX_vect)
{
#if defined(UDR0)
unsigned char c = UDR0;
#elif defined(UDR)
unsigned char c = UDR; // atmega8, atmega32
#else
#error UDR not defined
#endif
store_char(c, &rx_buffer);
}
#elif defined(SIG_UART_RECV)
// this is for atmega8
SIGNAL(SIG_UART_RECV)
{
#if defined(UDR0)
unsigned char c = UDR0; // atmega645
#elif defined(UDR)
unsigned char c = UDR; // atmega8
#endif
store_char(c, &rx_buffer);
}
#elif defined(USBCON)
#warning No interrupt handler for usart 0
#warning Serial(0) is on USB interface
#else
#error No interrupt handler for usart 0
#endif
//#if defined(SIG_USART1_RECV)
#if defined(USART1_RX_vect)
//SIGNAL(SIG_USART1_RECV)
SIGNAL(USART1_RX_vect)
{
unsigned char c = UDR1;
store_char(c, &rx_buffer1);
}
#elif defined(SIG_USART1_RECV)
#error SIG_USART1_RECV
#endif
#if defined(USART2_RX_vect) && defined(UDR2)
SIGNAL(USART2_RX_vect)
{
unsigned char c = UDR2;
store_char(c, &rx_buffer2);
}
#elif defined(SIG_USART2_RECV)
#error SIG_USART2_RECV
#endif
#if defined(USART3_RX_vect) && defined(UDR3)
SIGNAL(USART3_RX_vect)
{
unsigned char c = UDR3;
store_char(c, &rx_buffer3);
}
#elif defined(SIG_USART3_RECV)
#error SIG_USART3_RECV
#endif
// Constructors ////////////////////////////////////////////////////////////////
HardwareSerial::HardwareSerial(ring_buffer *rx_buffer,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x)
{
_rx_buffer = rx_buffer;
_ubrrh = ubrrh;
_ubrrl = ubrrl;
_ucsra = ucsra;
_ucsrb = ucsrb;
_udr = udr;
_rxen = rxen;
_txen = txen;
_rxcie = rxcie;
_udre = udre;
_u2x = u2x;
}
// Public Methods //////////////////////////////////////////////////////////////
void HardwareSerial::begin(long baud)
{
uint16_t baud_setting;
bool use_u2x = true;
#if F_CPU == 16000000UL
// hardcoded exception for compatibility with the bootloader shipped
// with the Duemilanove and previous boards and the firmware on the 8U2
// on the Uno and Mega 2560.
if (baud == 57600) {
use_u2x = false;
}
#endif
if (use_u2x) {
*_ucsra = 1 << _u2x;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
} else {
*_ucsra = 0;
baud_setting = (F_CPU / 8 / baud - 1) / 2;
}
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
*_ubrrh = baud_setting >> 8;
*_ubrrl = baud_setting;
sbi(*_ucsrb, _rxen);
sbi(*_ucsrb, _txen);
sbi(*_ucsrb, _rxcie);
}
void HardwareSerial::end()
{
cbi(*_ucsrb, _rxen);
cbi(*_ucsrb, _txen);
cbi(*_ucsrb, _rxcie);
}
int HardwareSerial::available(void)
{
return (unsigned int)(RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE;
}
int HardwareSerial::peek(void)
{
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
return _rx_buffer->buffer[_rx_buffer->tail];
}
}
int HardwareSerial::read(void)
{
// if the head isn't ahead of the tail, we don't have any characters
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
_rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % RX_BUFFER_SIZE;
return c;
}
}
void HardwareSerial::flush()
{
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
// may be written to rx_buffer_tail, making it appear as if the buffer
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
// may be written to rx_buffer_tail, making it appear as if the buffer
// were full, not empty.
_rx_buffer->head = _rx_buffer->tail;
}
size_t HardwareSerial::write(uint8_t c)
{
while (!((*_ucsra) & (1 << _udre)))
;
*_udr = c;
return( 1 );
}
// Preinstantiate Objects //////////////////////////////////////////////////////
#if ! DEFAULT_TO_TINY_DEBUG_SERIAL
#if defined(UBRRH) && defined(UBRRL)
HardwareSerial Serial(&rx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE, U2X);
#elif defined(UBRR0H) && defined(UBRR0L)
HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0);
#elif defined(USBCON)
#warning no serial port defined (port 0)
#else
#error no serial port defined (port 0)
#endif
#endif
#if defined(UBRR1H)
HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1, U2X1);
#endif
#if defined(UBRR2H)
HardwareSerial Serial2(&rx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRE2, U2X2);
#endif
#if defined(UBRR3H)
HardwareSerial Serial3(&rx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRE3, U2X3);
#endif
#endif // whole file

View File

@ -0,0 +1,77 @@
/*
HardwareSerial.h - Hardware serial library for Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 28 September 2010 by Mark Sproul
*/
#ifndef HardwareSerial_h
#define HardwareSerial_h
#include <inttypes.h>
#include "core_build_options.h"
#include "Stream.h"
struct ring_buffer;
class HardwareSerial : public Stream
{
private:
ring_buffer *_rx_buffer;
volatile uint8_t *_ubrrh;
volatile uint8_t *_ubrrl;
volatile uint8_t *_ucsra;
volatile uint8_t *_ucsrb;
volatile uint8_t *_udr;
uint8_t _rxen;
uint8_t _txen;
uint8_t _rxcie;
uint8_t _udre;
uint8_t _u2x;
public:
HardwareSerial(ring_buffer *rx_buffer,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x);
void begin(long);
void end();
virtual int available(void);
virtual int peek(void);
virtual int read(void);
virtual void flush(void);
virtual size_t write(uint8_t);
using Print::write; // pull in write(str) and write(buf, size) from Print
};
#if (defined(UBRRH) || defined(UBRR0H)) && ! DEFAULT_TO_TINY_DEBUG_SERIAL
extern HardwareSerial Serial;
#elif defined(USBCON)
#include "usb_api.h"
#endif
#if defined(UBRR1H)
extern HardwareSerial Serial1;
#endif
#if defined(UBRR2H)
extern HardwareSerial Serial2;
#endif
#if defined(UBRR3H)
extern HardwareSerial Serial3;
#endif
#endif

View File

@ -0,0 +1,247 @@
/*
Print.cpp - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "wiring.h"
#include "Print.h"
// Public Methods //////////////////////////////////////////////////////////////
/* default implementation: may be overridden */
void Print::write(const char *str)
{
while (*str)
write(*str++);
}
/* default implementation: may be overridden */
void Print::write(const uint8_t *buffer, size_t size)
{
while (size--)
write(*buffer++);
}
void Print::print(const String &s)
{
for (int i = 0; i < s.length(); i++) {
write(s[i]);
}
}
void Print::print(const char str[])
{
write(str);
}
void Print::print(char c, int base)
{
print((long) c, base);
}
void Print::print(unsigned char b, int base)
{
print((unsigned long) b, base);
}
void Print::print(int n, int base)
{
print((long) n, base);
}
void Print::print(unsigned int n, int base)
{
print((unsigned long) n, base);
}
void Print::print(long n, int base)
{
if (base == 0) {
write(n);
} else if (base == 10) {
if (n < 0) {
print('-');
n = -n;
}
printNumber(n, 10);
} else {
printNumber(n, base);
}
}
void Print::print(unsigned long n, int base)
{
if (base == 0) write(n);
else printNumber(n, base);
}
void Print::print(double n, int digits)
{
printFloat(n, digits);
}
int Print::print( fstr_t* s )
{
int rv;
char ch;
rv = 0;
ch = pgm_read_byte( s );
while ( ch != 0 )
{
write( ch );
++s;
++rv;
ch = pgm_read_byte( s );
}
return( rv );
}
int Print::println(void)
{
print('\r');
print('\n');
return( 2 );
}
void Print::println(const String &s)
{
print(s);
println();
}
void Print::println(const char c[])
{
print(c);
println();
}
void Print::println(char c, int base)
{
print(c, base);
println();
}
void Print::println(unsigned char b, int base)
{
print(b, base);
println();
}
void Print::println(int n, int base)
{
print(n, base);
println();
}
void Print::println(unsigned int n, int base)
{
print(n, base);
println();
}
void Print::println(long n, int base)
{
print(n, base);
println();
}
void Print::println(unsigned long n, int base)
{
print(n, base);
println();
}
void Print::println(double n, int digits)
{
print(n, digits);
println();
}
int Print::println( fstr_t* s )
{
int rv;
rv = print( s );
rv += println();
return( rv );
}
// Private Methods /////////////////////////////////////////////////////////////
void Print::printNumber(unsigned long n, uint8_t base)
{
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
unsigned long i = 0;
if (n == 0) {
print('0');
return;
}
while (n > 0) {
buf[i++] = n % base;
n /= base;
}
for (; i > 0; i--)
print((char) (buf[i - 1] < 10 ?
'0' + buf[i - 1] :
'A' + buf[i - 1] - 10));
}
void Print::printFloat(double number, uint8_t digits)
{
// Handle negative numbers
if (number < 0.0)
{
print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for (uint8_t i=0; i<digits; ++i)
rounding /= 10.0;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits > 0)
print(".");
// Extract digits from the remainder one at a time
while (digits-- > 0)
{
remainder *= 10.0;
int toPrint = int(remainder);
print(toPrint);
remainder -= toPrint;
}
}

View File

@ -0,0 +1,108 @@
/*
Print.h - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 20-11-2010 by B.Cook ...
http://arduiniana.org/libraries/flash/
Printable support thanks to Mikal Hart
*/
#ifndef Print_h
#define Print_h
#include <inttypes.h>
#include <stdio.h> // for size_t
#include <avr/pgmspace.h>
#include "WString.h"
#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2
#define BYTE 0
#define ARDUINO_CORE_PRINTABLE_SUPPORT
class Print;
/* Printable...*/
class _Printable
{
public:
virtual void print(Print &stream) const = 0;
};
/* ...Printable */
typedef struct
{
char c;
}
fstr_t;
/* rmv: Use the macro below in preparation for the next Arduino release.
# define FSTR(s) ((fstr_t*)PSTR(s))
*/
# define F(s) ((fstr_t*)PSTR(s))
class Print
{
private:
void printNumber(unsigned long, uint8_t);
void printFloat(double, uint8_t);
protected:
void setWriteError(int err = 1) { /*write_error = err;*/ }
public:
virtual size_t write(uint8_t) = 0;
virtual void write(const char *str);
virtual void write(const uint8_t *buffer, size_t size);
void print(const String &);
void print(const char[]);
void print(char, int = BYTE);
void print(unsigned char, int = BYTE);
void print(int, int = DEC);
void print(unsigned int, int = DEC);
void print(long, int = DEC);
void print(unsigned long, int = DEC);
void print(double, int = 2);
int print( fstr_t* );
void println(const String &s);
void println(const char[]);
void println(char, int = BYTE);
void println(unsigned char, int = BYTE);
void println(int, int = DEC);
void println(unsigned int, int = DEC);
void println(long, int = DEC);
void println(unsigned long, int = DEC);
void println(double, int = 2);
int println( fstr_t* );
int println(void);
public:
/* Printable...*/
void println(const _Printable &obj)
{ obj.print(*this); println(); }
void print(const _Printable &obj)
{ obj.print(*this); };
/* ...Printable */
};
#endif

View File

@ -0,0 +1,65 @@
/*==============================================================================
PwmTimer.h - Veneer for the PWM timers.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#ifndef PwmTimer_h
#define PwmTimer_h
#include "core_pins.h"
#include "core_timers.h"
#define PwmTimer3_(t,f,c) TIMER_PASTE_CHANNEL_A( Timer, t, f, c )
#define PwmTimer2_(t,f) TIMER_PASTE_A( Timer, t, f )
#if CORE_PWM_COUNT >= 1
#define Pwm0_SetCompareOutputMode PwmTimer3_( CORE_PWM0_TIMER, SetCompareOutputMode, CORE_PWM0_CHANNEL )
#define Pwm0_Disconnected PwmTimer2_( CORE_PWM0_TIMER, Disconnected )
#define Pwm0_Clear PwmTimer2_( CORE_PWM0_TIMER, Clear )
#define Pwm0_SetOutputCompareMatch PwmTimer3_( CORE_PWM0_TIMER, SetOutputCompareMatch, CORE_PWM0_CHANNEL )
#endif
#if CORE_PWM_COUNT >= 2
#define Pwm1_SetCompareOutputMode PwmTimer3_( CORE_PWM1_TIMER, SetCompareOutputMode, CORE_PWM1_CHANNEL )
#define Pwm1_Disconnected PwmTimer2_( CORE_PWM1_TIMER, Disconnected )
#define Pwm1_Clear PwmTimer2_( CORE_PWM1_TIMER, Clear )
#define Pwm1_SetOutputCompareMatch PwmTimer3_( CORE_PWM1_TIMER, SetOutputCompareMatch, CORE_PWM1_CHANNEL )
#endif
#if CORE_PWM_COUNT >= 3
#define Pwm2_SetCompareOutputMode PwmTimer3_( CORE_PWM2_TIMER, SetCompareOutputMode, CORE_PWM2_CHANNEL )
#define Pwm2_Disconnected PwmTimer2_( CORE_PWM2_TIMER, Disconnected )
#define Pwm2_Clear PwmTimer2_( CORE_PWM2_TIMER, Clear )
#define Pwm2_SetOutputCompareMatch PwmTimer3_( CORE_PWM2_TIMER, SetOutputCompareMatch, CORE_PWM2_CHANNEL )
#endif
#if CORE_PWM_COUNT >= 4
#define Pwm3_SetCompareOutputMode PwmTimer3_( CORE_PWM3_TIMER, SetCompareOutputMode, CORE_PWM3_CHANNEL )
#define Pwm3_Disconnected PwmTimer2_( CORE_PWM3_TIMER, Disconnected )
#define Pwm3_Clear PwmTimer2_( CORE_PWM3_TIMER, Clear )
#define Pwm3_SetOutputCompareMatch PwmTimer3_( CORE_PWM3_TIMER, SetOutputCompareMatch, CORE_PWM3_CHANNEL )
#endif
#if CORE_PWM_COUNT >= 5
#error Only 4 pins PWM are supported. Add more macro defintions.
#endif
#endif

View File

@ -0,0 +1,35 @@
/*
Stream.h - base class for character-based streams.
Copyright (c) 2010 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef Stream_h
#define Stream_h
#include <inttypes.h>
#include "Print.h"
class Stream : public Print
{
public:
virtual int available() = 0;
virtual int read() = 0;
virtual int peek() = 0;
virtual void flush() = 0;
};
#endif

View File

@ -0,0 +1,42 @@
/*==============================================================================
TinyDebugSerial.cpp - Tiny write-only software serial.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#include "core_build_options.h"
#include "TinyDebugSerial.h"
static TinyDebugSerialWriter stub;
void TinyDebugSerial::useStub( void )
{
_writer = &stub;
_writer->init();
}
TinyDebugSerial::TinyDebugSerial( void )
{
useStub();
}
#if defined( DEFAULT_TO_TINY_DEBUG_SERIAL ) && DEFAULT_TO_TINY_DEBUG_SERIAL
TinyDebugSerial Serial;
#endif

View File

@ -0,0 +1,749 @@
/*==============================================================================
TinyDebugSerial.h - Tiny write-only software serial.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#ifndef TinyDebugSerial_h
#define TinyDebugSerial_h
#include <inttypes.h>
#include "binary.h"
#include "core_build_options.h"
#include "Stream.h"
class TinyDebugSerialWriter;
class TinyDebugSerial;
class TinyDebugSerialWriter
{
protected:
virtual void init( void )
{
}
virtual void write( uint8_t )
{
}
friend class TinyDebugSerial;
};
void TinyDebugSerialWriterInternalBug( void ) __attribute__((error("Serial (TinyDebugSerial) has an internal problem. Contact the developer.")));
__attribute__((always_inline, unused)) static inline void TinyDebugSerialWriterBangOneByte( uint8_t value, uint8_t SER_REG, uint8_t SER_BIT, uint8_t lom, uint8_t him, uint8_t oloops, uint8_t iloops, uint8_t nops )
{
if ( __builtin_constant_p( SER_REG )
&& __builtin_constant_p( SER_BIT )
&& __builtin_constant_p( lom )
&& __builtin_constant_p( him )
&& __builtin_constant_p( oloops )
&& __builtin_constant_p( iloops )
&& __builtin_constant_p( nops ) )
{
uint8_t i;
uint8_t j;
uint8_t ol;
uint8_t il;
uint8_t b; // Initialized to the low bits
uint8_t hib;
uint8_t m;
b = ((value << 1) & 0x1F);
hib = ((value >> 4) & 0x1F) | 0x10;
asm volatile
(
"ldi %[j], 2" "\n\t"
"ldi %[i], 5" "\n\t"
"ldi %[m], %[lom]" "\n\t"
// Note: 8 MHz, 9600 baud ---> disabling interrupts does not appear to be necessary
"cli" "\n\t"
"rjmp L%=ntop" "\n\t"
"L%=btop: "
"nop" "\n\t" // ---> 7
"nop" "\n\t" //
"nop" "\n\t" //
"nop" "\n\t" //
"nop" "\n\t" //
"nop" "\n\t" //
"nop" "\n\t" //
"L%=ntop: "
"ror %[b]" "\n\t" // ---> 1
"brcs L%=bxh" "\n\t" // 1 (not taken)
"cbi %[serreg], %[serbit]" "\n\t" // 2
"rjmp L%=bxz" "\n\t" // 2
"L%=bxh: " // 2 (taken)
"sbi %[serreg], %[serbit]" "\n\t" // 2
"nop" "\n\t" // 1
// ---> 5
"L%=bxz: "
"ror %[m]" "\n\t" // ---> 3 or 4
"brcc L%=bnoe" "\n\t" //
"nop" "\n\t" //
"nop" "\n\t" //
"L%=bnoe: "
// ---> 1
".if %[oloops] >= 1" "\n\t" // if oloops >= 1 then...
"ldi %[ol], %[oloops]" "\n\t" // 4*oloops + oloops*(3*iloops) or oloops*((3*iloops)+4)
"L%=odelay: " "\n\t"
".endif" "\n\t"
"ldi %[il], %[iloops]" "\n\t" // if oloops == 0 then...
"L%=idelay: " "\n\t" // (3*iloops)
"dec %[il]" "\n\t"
"brne L%=idelay" "\n\t"
"nop" "\n\t"
".if %[oloops] >= 1" "\n\t"
"dec %[ol]" "\n\t"
"brne L%=odelay" "\n\t"
"nop" "\n\t"
".endif" "\n\t"
".if %[nops] >= 1" "\n\t"
"nop" "\n\t" //
".endif" "\n\t"
".if %[nops] >= 2" "\n\t"
"nop" "\n\t" //
".endif" "\n\t"
"dec %[i]" "\n\t" // ---> 3
"brne L%=btop" "\n\t" //
"nop" "\n\t" //
"dec %[j]" "\n\t" // ---> 7
"breq L%=bfin" "\n\t" //
"ldi %[i], 5" "\n\t" //
"mov %[b], %[hib]" "\n\t" //
"ldi %[m], %[him]" "\n\t" //
"rjmp L%=ntop" "\n\t" //
"L%=bfin: "
"sei" "\n\t"
:
[i] "=&r" ( i ),
[j] "=&r" ( j ),
[ol] "=&r" ( ol ),
[il] "=&r" ( il ),
[m] "=&r" ( m )
:
[b] "r" ( b ),
[hib] "r" ( hib ),
[serreg] "I" ( SER_REG ),
[serbit] "M" ( SER_BIT ),
[lom] "M" ( lom ),
[him] "M" ( him ),
[oloops] "M" ( oloops ),
[iloops] "M" ( iloops ),
[nops] "M" ( nops )
:
"r31",
"r30"
);
}
else
{
TinyDebugSerialWriterInternalBug();
}
}
template
<
uint8_t SER_REG,
uint8_t SER_BIT
>
class TinyDebugSerialWriter_1_9600 : public TinyDebugSerialWriter
{
protected:
virtual void init( void )
{
asm volatile
(
"sbi %[serreg]-1, %[serbit]" "\n\t"
"sbi %[serreg], %[serbit]" "\n\t"
:
:
[serreg] "I" ( SER_REG ),
[serbit] "I" ( SER_BIT )
:
);
}
virtual void write( uint8_t value )
{
TinyDebugSerialWriterBangOneByte( value, SER_REG, SER_BIT, B00100, B00010, 0, 28, 2 );
}
};
template
<
uint8_t SER_REG,
uint8_t SER_BIT
>
class TinyDebugSerialWriter_1_38400 : public TinyDebugSerialWriter
{
protected:
virtual void init( void )
{
asm volatile
(
"sbi %[serreg]-1, %[serbit]" "\n\t"
"sbi %[serreg], %[serbit]" "\n\t"
:
:
[serreg] "I" ( SER_REG ),
[serbit] "I" ( SER_BIT )
:
);
}
virtual void write( uint8_t value )
{
TinyDebugSerialWriterBangOneByte( value, SER_REG, SER_BIT, B00000, B00000, 0, 2, 0 );
}
};
template
<
uint8_t SER_REG,
uint8_t SER_BIT
>
class TinyDebugSerialWriter_1_115200 : public TinyDebugSerialWriter
{
protected:
virtual void init( void )
{
asm volatile
(
"sbi %[serreg]-1, %[serbit]" "\n\t"
"sbi %[serreg], %[serbit]" "\n\t"
:
:
[serreg] "I" ( SER_REG ),
[serbit] "I" ( SER_BIT )
:
);
}
virtual void write( uint8_t value )
{
asm volatile
(
"cli" "\n\t"
"cbi %[serreg], %[serbit]" "\n\t" /* 2 <--- 0 */
"ror %[value]" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"brcs L%=b0h" "\n\t" /* 1 (not taken) */
"nop" "\n\t" /* 1 */
"cbi %[serreg], %[serbit]" "\n\t" /* 2 <--- st is 9 cycles */
"rjmp L%=b0z" "\n\t" /* 2 */
"L%=b0h: " /* 2 (taken) */
"sbi %[serreg], %[serbit]" "\n\t" /* 2 <--- st is 9 cycles */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"L%=b0z: "
"ror %[value]" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"brcs L%=b1h" "\n\t" /* 1 (not taken) */
"nop" "\n\t" /* 1 */
"cbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b0 is 8 cycles */
"rjmp L%=b1z" "\n\t" /* 2 */
"L%=b1h: " /* 2 (taken) */
"sbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b0 is 8 cycles */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"L%=b1z: "
"ror %[value]" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"brcs L%=b2h" "\n\t" /* 1 (not taken) */
"nop" "\n\t" /* 1 */
"cbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b1 is 9 cycles */
"rjmp L%=b2z" "\n\t" /* 2 */
"L%=b2h: " /* 2 (taken) */
"sbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b1 is 9 cycles */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"L%=b2z: "
"ror %[value]" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"brcs L%=b3h" "\n\t" /* 1 (not taken) */
"nop" "\n\t" /* 1 */
"cbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b2 is 9 cycles */
"rjmp L%=b3z" "\n\t" /* 2 */
"L%=b3h: " /* 2 (taken) */
"sbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b2 is 9 cycles */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"L%=b3z: "
"ror %[value]" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"brcs L%=b4h" "\n\t" /* 1 (not taken) */
"nop" "\n\t" /* 1 */
"cbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b3 is 8 cycles */
"rjmp L%=b4z" "\n\t" /* 2 */
"L%=b4h: " /* 2 (taken) */
"sbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b3 is 8 cycles */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"L%=b4z: "
"ror %[value]" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"brcs L%=b5h" "\n\t" /* 1 (not taken) */
"nop" "\n\t" /* 1 */
"cbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b4 is 9 cycles */
"rjmp L%=b5z" "\n\t" /* 2 */
"L%=b5h: " /* 2 (taken) */
"sbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b4 is 9 cycles */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"L%=b5z: "
"ror %[value]" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"brcs L%=b6h" "\n\t" /* 1 (not taken) */
"nop" "\n\t" /* 1 */
"cbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b5 is 9 cycles */
"rjmp L%=b6z" "\n\t" /* 2 */
"L%=b6h: " /* 2 (taken) */
"sbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b5 is 9 cycles */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"L%=b6z: "
"ror %[value]" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"brcs L%=b7h" "\n\t" /* 1 (not taken) */
"nop" "\n\t" /* 1 */
"cbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b6 is 8 cycles */
"rjmp L%=b7z" "\n\t" /* 2 */
"L%=b7h: " /* 2 (taken) */
"sbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b6 is 8 cycles */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"L%=b7z: "
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"sbi %[serreg], %[serbit]" "\n\t" /* 2 <--- b7 is 9 cycles */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
"nop" "\n\t" /* 1 */
/* <---sp is 9 cycles */
"sei" "\n\t"
:
:
[value] "r" ( value ),
[serreg] "I" ( SER_REG ),
[serbit] "I" ( SER_BIT )
);
}
};
template
<
uint8_t SER_REG,
uint8_t SER_BIT
>
class TinyDebugSerialWriter_8_9600 : public TinyDebugSerialWriter
{
protected:
virtual void init( void )
{
asm volatile
(
"sbi %[serreg]-1, %[serbit]" "\n\t"
"sbi %[serreg], %[serbit]" "\n\t"
:
:
[serreg] "I" ( SER_REG ),
[serbit] "I" ( SER_BIT )
:
);
}
virtual void write( uint8_t value )
{
TinyDebugSerialWriterBangOneByte( value, SER_REG, SER_BIT, B01001, B00100, 3, 89, 0 );
}
};
template
<
uint8_t SER_REG,
uint8_t SER_BIT
>
class TinyDebugSerialWriter_8_38400 : public TinyDebugSerialWriter
{
protected:
virtual void init( void )
{
asm volatile
(
"sbi %[serreg]-1, %[serbit]" "\n\t"
"sbi %[serreg], %[serbit]" "\n\t"
:
:
[serreg] "I" ( SER_REG ),
[serbit] "I" ( SER_BIT )
:
);
}
virtual void write( uint8_t value )
{
TinyDebugSerialWriterBangOneByte( value, SER_REG, SER_BIT, B01001, B00100, 0, 62, 2 );
}
};
template
<
uint8_t SER_REG,
uint8_t SER_BIT
>
class TinyDebugSerialWriter_8_115200 : public TinyDebugSerialWriter
{
protected:
virtual void init( void )
{
asm volatile
(
"sbi %[serreg]-1, %[serbit]" "\n\t"
"sbi %[serreg], %[serbit]" "\n\t"
:
:
[serreg] "I" ( SER_REG ),
[serbit] "I" ( SER_BIT )
:
);
}
virtual void write( uint8_t value )
{
TinyDebugSerialWriterBangOneByte( value, SER_REG, SER_BIT, B01010, B10100, 0, 16, 1 );
}
};
template
<
uint8_t SER_REG,
uint8_t SER_BIT
>
class TinyDebugSerialWriter_16_9600 : public TinyDebugSerialWriter
{
protected:
virtual void init( void )
{
asm volatile
(
"sbi %[serreg]-1, %[serbit]" "\n\t"
"sbi %[serreg], %[serbit]" "\n\t"
:
:
[serreg] "I" ( SER_REG ),
[serbit] "I" ( SER_BIT )
:
);
}
virtual void write( uint8_t value )
{
TinyDebugSerialWriterBangOneByte( value, SER_REG, SER_BIT, B10110, B11011, 6, 90, 2 );
}
};
template
<
uint8_t SER_REG,
uint8_t SER_BIT
>
class TinyDebugSerialWriter_16_38400 : public TinyDebugSerialWriter
{
protected:
virtual void init( void )
{
asm volatile
(
"sbi %[serreg]-1, %[serbit]" "\n\t"
"sbi %[serreg], %[serbit]" "\n\t"
:
:
[serreg] "I" ( SER_REG ),
[serbit] "I" ( SER_BIT )
:
);
}
virtual void write( uint8_t value )
{
TinyDebugSerialWriterBangOneByte( value, SER_REG, SER_BIT, B10110, B11011, 5, 25, 1 );
}
};
template
<
uint8_t SER_REG,
uint8_t SER_BIT
>
class TinyDebugSerialWriter_16_115200 : public TinyDebugSerialWriter
{
protected:
virtual void init( void )
{
asm volatile
(
"sbi %[serreg]-1, %[serbit]" "\n\t"
"sbi %[serreg], %[serbit]" "\n\t"
:
:
[serreg] "I" ( SER_REG ),
[serbit] "I" ( SER_BIT )
:
);
}
virtual void write( uint8_t value )
{
TinyDebugSerialWriterBangOneByte( value, SER_REG, SER_BIT, B11110, B11111, 0, 39, 1 );
}
};
#if defined( __AVR_ATtinyX313__ )
#define TINY_DEBUG_SERIAL_REGISTER 0x1B
#define TINY_DEBUG_SERIAL_BIT 1
#elif defined( __AVR_ATtinyX4__ )
#if F_CPU <= 8000000L
// port B bit 0 (PB0)
#define TINY_DEBUG_SERIAL_REGISTER 0x18
#define TINY_DEBUG_SERIAL_BIT 0
#else
// port A bit 0 (PA0)
#define TINY_DEBUG_SERIAL_REGISTER 0x1B
#define TINY_DEBUG_SERIAL_BIT 0
#endif
#elif defined( __AVR_ATtinyX5__ )
#if F_CPU <= 8000000L
// port B bit 3 (PB3)
#define TINY_DEBUG_SERIAL_REGISTER 0x18
#define TINY_DEBUG_SERIAL_BIT 3
#else
// port B bit 2 (PB2)
#define TINY_DEBUG_SERIAL_REGISTER 0x18
#define TINY_DEBUG_SERIAL_BIT 2
#endif
#endif
#if F_CPU == 1000000L
typedef TinyDebugSerialWriter_1_9600<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_9600;
typedef TinyDebugSerialWriter_1_38400<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_38400;
typedef TinyDebugSerialWriter_1_115200<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_115200;
#define TINY_DEBUG_SERIAL_SUPPORTED 1
#elif F_CPU == 8000000L
typedef TinyDebugSerialWriter_8_9600<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_9600;
typedef TinyDebugSerialWriter_8_38400<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_38400;
typedef TinyDebugSerialWriter_8_115200<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_115200;
#define TINY_DEBUG_SERIAL_SUPPORTED 1
#elif F_CPU == 16000000L
typedef TinyDebugSerialWriter_16_9600<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_9600;
typedef TinyDebugSerialWriter_16_38400<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_38400;
typedef TinyDebugSerialWriter_16_115200<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_115200;
#define TINY_DEBUG_SERIAL_SUPPORTED 1
#elif F_CPU == 16500000L
typedef TinyDebugSerialWriter_16_9600<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_9600;
typedef TinyDebugSerialWriter_16_38400<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_38400;
typedef TinyDebugSerialWriter_16_115200<TINY_DEBUG_SERIAL_REGISTER,TINY_DEBUG_SERIAL_BIT> TinyDebugSerialWriter_115200;
#define TINY_DEBUG_SERIAL_SUPPORTED 1
/*
9600...
6, 90, 2
7, 77, 1
38400...
1, 130, 2
5, 25, 1
18, 6, 0
115200...
0, 39, 1
1, 38, 0
2, 18, 2
9, 3, 1
*/
#endif
#if TINY_DEBUG_SERIAL_SUPPORTED
extern TinyDebugSerialWriter_9600 tdsw9600;
extern TinyDebugSerialWriter_38400 tdsw38400;
extern TinyDebugSerialWriter_115200 tdsw115200;
void TinyDebugSerialBadBaud( void ) __attribute__((error("Serial (TinyDebugSerial) supports three baud rates: 9600, 38400, or 115200.")));
void TinyDebugSerialBaudMustBeConstant( void ) __attribute__((error("The baud rate for Serial (TinyDebugSerial) cannot be changed at run-time. Use 9600, 38400, or 115200.")));
class TinyDebugSerial : public Stream
{
protected:
TinyDebugSerialWriter* _writer;
void useStub( void );
public:
TinyDebugSerial( void );
inline void begin( long baud )
{
if ( __builtin_constant_p( baud ) )
{
if ( baud == 9600 )
{
_writer = &tdsw9600;
}
else if ( baud == 38400 )
{
_writer = &tdsw38400;
}
else if ( baud == 115200 )
{
_writer = &tdsw115200;
}
else
{
TinyDebugSerialBadBaud();
}
}
else
{
TinyDebugSerialBaudMustBeConstant();
}
_writer->init();
}
void end( void )
{
useStub();
}
virtual int available( void )
{
return( 0 );
}
virtual int peek( void )
{
return( -1 );
}
virtual int read( void )
{
return( -1 );
}
virtual void flush( void )
{
}
virtual size_t write( uint8_t c )
{
_writer->write( c );
return( 1 );
}
using Print::write; // pull in write(str) and write(buf, size) from Print
};
#if DEFAULT_TO_TINY_DEBUG_SERIAL
extern TinyDebugSerial Serial;
#endif
#endif
#endif

View File

@ -0,0 +1,26 @@
/*==============================================================================
TinyDebugSerial.cpp - Tiny write-only software serial.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#include "TinyDebugSerial.h"
TinyDebugSerialWriter_115200 tdsw115200;

View File

@ -0,0 +1,26 @@
/*==============================================================================
TinyDebugSerial.cpp - Tiny write-only software serial.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#include "TinyDebugSerial.h"
TinyDebugSerialWriter_38400 tdsw38400;

View File

@ -0,0 +1,26 @@
/*==============================================================================
TinyDebugSerial.cpp - Tiny write-only software serial.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#include "TinyDebugSerial.h"
TinyDebugSerialWriter_9600 tdsw9600;

View File

@ -0,0 +1,28 @@
/*==============================================================================
TinyDebugSerial.cpp - Tiny write-only software serial.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#include "TinyDebugSerial.h"
void TinyDebugSerialWriterInternalBug( void ) { }
void TinyDebugSerialBadBaud( void ) { }
void TinyDebugSerialBaudMustBeConstant( void ) { }

View File

@ -0,0 +1,504 @@
/* Tone.cpp
A Tone Generator Library
Written by Brett Hagman
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Version Modified By Date Comments
------- ----------- -------- --------
0001 B Hagman 09/08/02 Initial coding
0002 B Hagman 09/08/18 Multiple pins
0003 B Hagman 09/08/18 Moved initialization from constructor to begin()
0004 B Hagman 09/09/26 Fixed problems with ATmega8
0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers
09/11/25 Changed pin toggle method to XOR
09/11/25 Fixed timer0 from being excluded
0006 D Mellis 09/12/29 Replaced objects with functions
0007 B Cook 10/05/03 Rewritten to only work with Timer1 and support direct hardware output
0008 B Cook 10/05/03 Rewritten so the timer can be selected at compile time
*************************************************/
#define DEBUG_TONE 0
#include <avr/interrupt.h>
#include "core_build_options.h"
#include "ToneTimer.h"
#include "pins_arduino.h"
#include "wiring.h"
#if (TONETIMER_NUMBER_PRESCALERS != 5) && (TONETIMER_NUMBER_PRESCALERS != 15)
#error Only five or fifteen prescalers are supported. Update the code to support the number of actual prescalers.
#endif
#if TONETIMER_NUMBER_PRESCALERS == 15
#define TONETIMER_MAXIMUM_DIVISOR ( (unsigned long)(TONETIMER_(PRESCALER_VALUE_15)) * (1L + (unsigned long)(TONETIMER_(MAXIMUM_OCR))) )
#endif
#if TONETIMER_NUMBER_PRESCALERS == 5
#define TONETIMER_MAXIMUM_DIVISOR ( (unsigned long)(TONETIMER_(PRESCALER_VALUE_5)) * (1L + (unsigned long)(TONETIMER_(MAXIMUM_OCR))) )
#endif
const unsigned int Tone_Lowest_Frequency = (F_CPU + (2L * TONETIMER_MAXIMUM_DIVISOR - 1L)) / (2L * TONETIMER_MAXIMUM_DIVISOR);
#if (TONETIMER_(MAXIMUM_OCR) == 65535) && (TONETIMER_(PRESCALE_SET) == 1)
#if F_CPU <= 1000000
#define TONE_FREQUENCY_CUTOFF_2 (7)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#elif F_CPU <= 8000000
#define TONE_FREQUENCY_CUTOFF_3 (7)
#define TONE_FREQUENCY_CUTOFF_2 (61)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#elif F_CPU <= 16000000
#define TONE_FREQUENCY_CUTOFF_4 (1)
#define TONE_FREQUENCY_CUTOFF_3 (15)
#define TONE_FREQUENCY_CUTOFF_2 (122)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#elif F_CPU <= 16500000
#define TONE_FREQUENCY_CUTOFF_4 (1)
#define TONE_FREQUENCY_CUTOFF_3 (15)
#define TONE_FREQUENCY_CUTOFF_2 (122)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#endif
#endif
#if (TONETIMER_(MAXIMUM_OCR) == 255) && (TONETIMER_(PRESCALE_SET) == 1)
#if F_CPU <= 1000000
#define TONE_FREQUENCY_CUTOFF_5 (7)
#define TONE_FREQUENCY_CUTOFF_4 (30)
#define TONE_FREQUENCY_CUTOFF_3 (243)
#define TONE_FREQUENCY_CUTOFF_2 (1949)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#elif F_CPU <= 8000000
#define TONE_FREQUENCY_CUTOFF_5 (60)
#define TONE_FREQUENCY_CUTOFF_4 (243)
#define TONE_FREQUENCY_CUTOFF_3 (1949)
#define TONE_FREQUENCY_CUTOFF_2 (15594)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#elif F_CPU <= 16000000
#define TONE_FREQUENCY_CUTOFF_5 (121)
#define TONE_FREQUENCY_CUTOFF_4 (487)
#define TONE_FREQUENCY_CUTOFF_3 (3898)
#define TONE_FREQUENCY_CUTOFF_2 (31189)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#elif F_CPU <= 16500000
#define TONE_FREQUENCY_CUTOFF_5 (121)
#define TONE_FREQUENCY_CUTOFF_4 (487)
#define TONE_FREQUENCY_CUTOFF_3 (3898)
#define TONE_FREQUENCY_CUTOFF_2 (31189)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#endif
#endif
#if (TONETIMER_(MAXIMUM_OCR) == 255) && (TONETIMER_(PRESCALE_SET) == 2)
#if F_CPU <= 1000000
#define TONE_FREQUENCY_CUTOFF_12 (1)
#define TONE_FREQUENCY_CUTOFF_11 (3)
#define TONE_FREQUENCY_CUTOFF_10 (7)
#define TONE_FREQUENCY_CUTOFF_9 (15)
#define TONE_FREQUENCY_CUTOFF_8 (30)
#define TONE_FREQUENCY_CUTOFF_7 (60)
#define TONE_FREQUENCY_CUTOFF_6 (121)
#define TONE_FREQUENCY_CUTOFF_5 (243)
#define TONE_FREQUENCY_CUTOFF_4 (487)
#define TONE_FREQUENCY_CUTOFF_3 (974)
#define TONE_FREQUENCY_CUTOFF_2 (1949)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#elif F_CPU <= 8000000
#define TONE_FREQUENCY_CUTOFF_15 (1)
#define TONE_FREQUENCY_CUTOFF_14 (3)
#define TONE_FREQUENCY_CUTOFF_13 (7)
#define TONE_FREQUENCY_CUTOFF_12 (15)
#define TONE_FREQUENCY_CUTOFF_11 (30)
#define TONE_FREQUENCY_CUTOFF_10 (60)
#define TONE_FREQUENCY_CUTOFF_9 (121)
#define TONE_FREQUENCY_CUTOFF_8 (243)
#define TONE_FREQUENCY_CUTOFF_7 (487)
#define TONE_FREQUENCY_CUTOFF_6 (974)
#define TONE_FREQUENCY_CUTOFF_5 (1949)
#define TONE_FREQUENCY_CUTOFF_4 (3898)
#define TONE_FREQUENCY_CUTOFF_3 (7797)
#define TONE_FREQUENCY_CUTOFF_2 (15594)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#elif F_CPU <= 16000000
#define TONE_FREQUENCY_CUTOFF_15 (3)
#define TONE_FREQUENCY_CUTOFF_14 (7)
#define TONE_FREQUENCY_CUTOFF_13 (15)
#define TONE_FREQUENCY_CUTOFF_12 (30)
#define TONE_FREQUENCY_CUTOFF_11 (60)
#define TONE_FREQUENCY_CUTOFF_10 (121)
#define TONE_FREQUENCY_CUTOFF_9 (243)
#define TONE_FREQUENCY_CUTOFF_8 (487)
#define TONE_FREQUENCY_CUTOFF_7 (974)
#define TONE_FREQUENCY_CUTOFF_6 (1949)
#define TONE_FREQUENCY_CUTOFF_5 (3898)
#define TONE_FREQUENCY_CUTOFF_4 (7797)
#define TONE_FREQUENCY_CUTOFF_3 (15594)
#define TONE_FREQUENCY_CUTOFF_2 (31189)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#elif F_CPU <= 16500000
#define TONE_FREQUENCY_CUTOFF_15 (3)
#define TONE_FREQUENCY_CUTOFF_14 (7)
#define TONE_FREQUENCY_CUTOFF_13 (15)
#define TONE_FREQUENCY_CUTOFF_12 (30)
#define TONE_FREQUENCY_CUTOFF_11 (60)
#define TONE_FREQUENCY_CUTOFF_10 (121)
#define TONE_FREQUENCY_CUTOFF_9 (243)
#define TONE_FREQUENCY_CUTOFF_8 (487)
#define TONE_FREQUENCY_CUTOFF_7 (974)
#define TONE_FREQUENCY_CUTOFF_6 (1949)
#define TONE_FREQUENCY_CUTOFF_5 (3898)
#define TONE_FREQUENCY_CUTOFF_4 (7797)
#define TONE_FREQUENCY_CUTOFF_3 (15594)
#define TONE_FREQUENCY_CUTOFF_2 (31189)
#define TONE_FREQUENCY_CUTOFF_1 (65535)
#endif
#endif
#if DEBUG_TONE
uint16_t debug_tone_last_OCRxA;
uint16_t debug_tone_last_CSV;
#endif
// timerx_toggle_count:
// > 0 - duration specified
// = 0 - stopped
// < 0 - infinitely (until stop() method called, or new play() called)
static volatile long tone_timer_toggle_count;
static volatile uint8_t *tone_timer_pin_register;
static volatile uint8_t tone_timer_pin_mask;
static uint8_t tone_pin = 255;
void tone( uint8_t _pin, unsigned int frequency, unsigned long duration )
{
tonetimer_(ocr_t) ocr;
tonetimer_(prescale_value_t) csv;
tonetimer_(cs_t) csi;
if ( tone_pin == 255 )
{
/* Set the timer to power-up conditions so we start from a known state */
ToneTimer_SetToPowerup();
/*
Compare Output Mode = Normal port operation, OCxA/OCxB disconnected.
Waveform Generation Mode = 4; 0100; CTC; (Clear Timer on Compare); OCR1A; Immediate; MAX
Clock Select = No clock source (Timer/Counter stopped).
Note: Turn off the clock first to avoid ticks and scratches.
*/
ToneTimer_SetWaveformGenerationMode( ToneTimer_(CTC_OCR) );
/* If the tone pin can be driven directly from the timer */
if ( (_pin == ToneTimer_OutputComparePinA) || (_pin == ToneTimer_OutputComparePinB) )
{
/* Pin toggling is handled by the hardware */
tone_timer_pin_register = NULL;
tone_timer_pin_mask = 0;
if ( _pin == ToneTimer_OutputComparePinA )
{
/* Compare Output Mode = Toggle OCxA on Compare Match. */
ToneTimer_SetCompareOutputModeA( ToneTimer_(Toggle) );
}
else // if ( _pin == ToneTimer_OutputComparePinB )
{
/* Compare Output Mode = Toggle OCxA on Compare Match. */
ToneTimer_SetCompareOutputModeB( ToneTimer_(Toggle) );
}
}
else
{
/* Save information needed by the interrupt service routine */
tone_timer_pin_register = portOutputRegister( digitalPinToPort( _pin ) );
tone_timer_pin_mask = digitalPinToBitMask( _pin );
/* Compare Output Mode = Normal port operation, OCxA disconnected. */
ToneTimer_DisconnectOutputs();
}
/* Ensure the pin is configured for output */
pinMode( _pin, OUTPUT );
tone_pin = _pin;
}
if ( tone_pin == _pin )
{
/* Stop the clock while we make changes. */
ToneTimer_ClockSelect( ToneTimer_(Stopped) );
/* Start the counter at zero to reduce ticks and scratches. */
ToneTimer_SetCount( 0 );
if ( frequency > 0 )
{
if ( frequency < Tone_Lowest_Frequency )
{
frequency = Tone_Lowest_Frequency;
}
/* Determine which prescaler to use */
/* Set the Output Compare Register (rounding up) */
#if defined( TONE_FREQUENCY_CUTOFF_15 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_15 )
{
csv = TONETIMER_(PRESCALER_VALUE_15);
csi = ToneTimer_(Prescale_Index_15);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_14 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_14 )
{
csv = TONETIMER_(PRESCALER_VALUE_14);
csi = ToneTimer_(Prescale_Index_14);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_13 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_13 )
{
csv = TONETIMER_(PRESCALER_VALUE_13);
csi = ToneTimer_(Prescale_Index_13);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_12 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_12 )
{
csv = TONETIMER_(PRESCALER_VALUE_12);
csi = ToneTimer_(Prescale_Index_12);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_11 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_11 )
{
csv = TONETIMER_(PRESCALER_VALUE_11);
csi = ToneTimer_(Prescale_Index_11);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_10 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_10 )
{
csv = TONETIMER_(PRESCALER_VALUE_10);
csi = ToneTimer_(Prescale_Index_10);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_9 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_9 )
{
csv = TONETIMER_(PRESCALER_VALUE_9);
csi = ToneTimer_(Prescale_Index_9);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_8 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_8 )
{
csv = TONETIMER_(PRESCALER_VALUE_8);
csi = ToneTimer_(Prescale_Index_8);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_7 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_7 )
{
csv = TONETIMER_(PRESCALER_VALUE_7);
csi = ToneTimer_(Prescale_Index_7);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_6 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_6 )
{
csv = TONETIMER_(PRESCALER_VALUE_6);
csi = ToneTimer_(Prescale_Index_6);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_5 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_5 )
{
csv = TONETIMER_(PRESCALER_VALUE_5);
csi = ToneTimer_(Prescale_Index_5);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_4 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_4 )
{
csv = TONETIMER_(PRESCALER_VALUE_4);
csi = ToneTimer_(Prescale_Index_4);
}
else
#endif
#if defined( TONE_FREQUENCY_CUTOFF_3 )
if ( frequency <= TONE_FREQUENCY_CUTOFF_3 )
{
csv = TONETIMER_(PRESCALER_VALUE_3);
csi = ToneTimer_(Prescale_Index_3);
}
else
#endif
if ( frequency <= TONE_FREQUENCY_CUTOFF_2 )
{
csv = TONETIMER_(PRESCALER_VALUE_2);
csi = ToneTimer_(Prescale_Index_2);
}
else // if ( frequency <= TONE_FREQUENCY_CUTOFF_1 )
{
csv = TONETIMER_(PRESCALER_VALUE_1);
csi = ToneTimer_(Prescale_Index_1);
}
ocr = ( (2L * F_CPU) / (frequency * 2L * csv) + 1L ) / 2L - 1L;
ToneTimer_SetOutputCompareMatchAndClear( ocr );
#if DEBUG_TONE
debug_tone_last_OCRxA = ocr;
debug_tone_last_CSV = csv;
#endif
/* Does the caller want a specific duration? */
if ( duration > 0 )
{
/* Determine how many times the value toggles */
tone_timer_toggle_count = (2 * frequency * duration) / 1000;
/* Output Compare A Match Interrupt Enable */
ToneTimer_EnableOutputCompareInterruptA();
}
else
{
/* Indicate to the interrupt service routine that we'll be running until further notice */
tone_timer_toggle_count = -1;
/* All pins but the OCxA / OCxB pins have to be driven by software */
if ( (_pin != ToneTimer_OutputComparePinA) && (_pin != ToneTimer_OutputComparePinB) )
{
/* Output Compare A Match Interrupt Enable */
ToneTimer_EnableOutputCompareInterruptA();
}
}
/* Start the clock... */
ToneTimer_ClockSelect( csi );
}
else
{
/* To be on the safe side, turn off all interrupts */
ToneTimer_InterruptsOff();
/* Clock is stopped. Counter is zero. The only thing left to do is turn off the output. */
digitalWrite( _pin, 0 );
}
}
}
void noTone( uint8_t _pin )
{
if ( (tone_pin != 255)
&& ((tone_pin == _pin) || (_pin == 255)) )
{
// Turn off all interrupts
ToneTimer_InterruptsOff();
// Stop the clock while we make changes.
ToneTimer_ClockSelect( ToneTimer_(Stopped) );
// Set the Tone Timer exactly the same as init did...
initToneTimer();
//rmv ToneTimer_SetToPowerup();
/* rmv
// put timer 1 in 8-bit phase correct pwm mode
TCCR1A = (0<<COM1A1)|(0<<COM1A0) | (0<<COM1B1)|(0<<COM1B0) | (0<<WGM11)|(1<<WGM10);
// set timer 1 prescale factor to 64
// and start the timer
TCCR1B = (0<<ICNC1) | (0<<ICES1) | (0<<WGM13)|(0<<WGM12) | (0<<CS12)|(1<<CS11)|(1<<CS10);
*/
// Set the output low
if ( tone_timer_pin_register != NULL )
{
*tone_timer_pin_register &= ~(tone_timer_pin_mask);
}
else
{
digitalWrite( tone_pin, LOW );
}
tone_pin = 255;
}
}
ISR( TONETIMER_COMPA_vect, ISR_NOBLOCK )
{
if ( tone_timer_toggle_count != 0 )
{
if ( tone_timer_toggle_count > 0 )
{
--tone_timer_toggle_count;
if ( tone_timer_toggle_count == 0 )
{
// Shutdown the hardware
noTone( 255 );
// Skip the rest. We're finished.
return;
}
}
*tone_timer_pin_register ^= tone_timer_pin_mask;
}
else
{
// Shutdown the hardware
noTone( 255 );
}
}

View File

@ -0,0 +1,50 @@
/*==============================================================================
ToneTimer.h - Veneer for the Tone Timer.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#ifndef ToneTimer_h
#define ToneTimer_h
#include "core_build_options.h"
#include "core_timers.h"
#define tonetimer_(t) TIMER_PASTE_A( timer, TIMER_TO_USE_FOR_TONE, t )
#define ToneTimer_(f) TIMER_PASTE_A( Timer, TIMER_TO_USE_FOR_TONE, f )
#define TONETIMER_(c) TIMER_PASTE_A( TIMER, TIMER_TO_USE_FOR_TONE, c )
#define ToneTimer_SetToPowerup ToneTimer_(SetToPowerup)
#define ToneTimer_SetWaveformGenerationMode ToneTimer_(SetWaveformGenerationMode)
#define ToneTimer_OutputComparePinA ToneTimer_(OutputComparePinA)
#define ToneTimer_OutputComparePinB ToneTimer_(OutputComparePinB)
#define ToneTimer_SetCompareOutputModeA ToneTimer_(SetCompareOutputModeA)
#define ToneTimer_SetCompareOutputModeB ToneTimer_(SetCompareOutputModeB)
#define ToneTimer_DisconnectOutputs ToneTimer_(DisconnectOutputs)
#define ToneTimer_ClockSelect ToneTimer_(ClockSelect)
#define ToneTimer_SetCount ToneTimer_(SetCount)
#define TONETIMER_NUMBER_PRESCALERS TONETIMER_(NUMBER_PRESCALERS)
#define ToneTimer_SetOutputCompareMatchAndClear ToneTimer_(SetOutputCompareMatchAndClear)
#define ToneTimer_InterruptsOff ToneTimer_(InterruptsOff)
#define ToneTimer_EnableOutputCompareInterruptA ToneTimer_(EnableOutputCompareInterruptA)
#define TONETIMER_COMPA_vect TONETIMER_(COMPA_vect)
#define TONETIMER_SUPPORTS_PHASE_CORRECT_PWM TONETIMER_(SUPPORTS_PHASE_CORRECT_PWM)
#endif

View File

@ -0,0 +1,78 @@
/*==============================================================================
UserTimer.h - Veneer for the User Timer (same timer as the one used for
Tone)
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#ifndef UserTimer_h
#define UserTimer_h
#include "core_build_options.h"
#include "core_timers.h"
/*=============================================================================
Assume there are only two timers. One for millis and one for everything
else.
=============================================================================*/
#if TIMER_TO_USE_FOR_MILLIS == 0
#define TIMER_TO_USE_FOR_USER 1
#elif TIMER_TO_USE_FOR_MILLIS == 1
#define TIMER_TO_USE_FOR_USER 0
#else
#error Unexpected condition in UserTimer.h.
#endif
/*=============================================================================
Macros to help generate the macros below
=============================================================================*/
#define usertimer_(t) TIMER_PASTE_A( timer, TIMER_TO_USE_FOR_USER, t )
#define UserTimer_(f) TIMER_PASTE_A( Timer, TIMER_TO_USE_FOR_USER, f )
#define USERTIMER_(c) TIMER_PASTE_A( TIMER, TIMER_TO_USE_FOR_USER, c )
/*=============================================================================
Macros to provide a veneer over the data-types, functions, and constants in
core_timers.h
=============================================================================*/
#define UserTimer_SetToPowerup UserTimer_(SetToPowerup)
#define UserTimer_InterruptsOff UserTimer_(InterruptsOff)
#define UserTimer_ClockSelect UserTimer_(ClockSelect)
#define UserTimer_SetWaveformGenerationMode UserTimer_(SetWaveformGenerationMode)
#define UserTimer_SetCompareOutputModeA UserTimer_(SetCompareOutputModeA)
#define UserTimer_SetCompareOutputModeB UserTimer_(SetCompareOutputModeB)
#define UserTimer_SetOutputCompareMatchAndClear UserTimer_(SetOutputCompareMatchAndClear)
#define UserTimer_EnableOutputCompareInterruptA UserTimer_(EnableOutputCompareInterruptA)
#define UserTimer_EnableOverflowInterrupt UserTimer_(EnableOverflowInterrupt)
#define UserTimer_GetCount UserTimer_(GetCount)
#define UserTimer_SetCount UserTimer_(SetCount)
#define UserTimer_IsOverflowSet UserTimer_(IsOverflowSet)
#define USERTIMER_OVF_vect USERTIMER_(OVF_vect)
#define USERTIMER_COMPA_vect USERTIMER_(COMPA_vect)
#define USERTIMER_COMPB_vect USERTIMER_(COMPB_vect)
#endif

View File

@ -0,0 +1,168 @@
/*
WCharacter.h - Character utility functions for Wiring & Arduino
Copyright (c) 2010 Hernando Barragan. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef Character_h
#define Character_h
#include <ctype.h>
// WCharacter.h prototypes
inline boolean isAlphaNumeric(int c) __attribute__((always_inline));
inline boolean isAlpha(int c) __attribute__((always_inline));
inline boolean isAscii(int c) __attribute__((always_inline));
inline boolean isWhitespace(int c) __attribute__((always_inline));
inline boolean isControl(int c) __attribute__((always_inline));
inline boolean isDigit(int c) __attribute__((always_inline));
inline boolean isGraph(int c) __attribute__((always_inline));
inline boolean isLowerCase(int c) __attribute__((always_inline));
inline boolean isPrintable(int c) __attribute__((always_inline));
inline boolean isPunct(int c) __attribute__((always_inline));
inline boolean isSpace(int c) __attribute__((always_inline));
inline boolean isUpperCase(int c) __attribute__((always_inline));
inline boolean isHexadecimalDigit(int c) __attribute__((always_inline));
inline int toAscii(int c) __attribute__((always_inline));
inline int toLowerCase(int c) __attribute__((always_inline));
inline int toUpperCase(int c)__attribute__((always_inline));
// Checks for an alphanumeric character.
// It is equivalent to (isalpha(c) || isdigit(c)).
inline boolean isAlphaNumeric(int c)
{
return ( isalnum(c) == 0 ? false : true);
}
// Checks for an alphabetic character.
// It is equivalent to (isupper(c) || islower(c)).
inline boolean isAlpha(int c)
{
return ( isalpha(c) == 0 ? false : true);
}
// Checks whether c is a 7-bit unsigned char value
// that fits into the ASCII character set.
inline boolean isAscii(int c)
{
return ( isascii (c) == 0 ? false : true);
}
// Checks for a blank character, that is, a space or a tab.
inline boolean isWhitespace(int c)
{
return ( isblank (c) == 0 ? false : true);
}
// Checks for a control character.
inline boolean isControl(int c)
{
return ( iscntrl (c) == 0 ? false : true);
}
// Checks for a digit (0 through 9).
inline boolean isDigit(int c)
{
return ( isdigit (c) == 0 ? false : true);
}
// Checks for any printable character except space.
inline boolean isGraph(int c)
{
return ( isgraph (c) == 0 ? false : true);
}
// Checks for a lower-case character.
inline boolean isLowerCase(int c)
{
return (islower (c) == 0 ? false : true);
}
// Checks for any printable character including space.
inline boolean isPrintable(int c)
{
return ( isprint (c) == 0 ? false : true);
}
// Checks for any printable character which is not a space
// or an alphanumeric character.
inline boolean isPunct(int c)
{
return ( ispunct (c) == 0 ? false : true);
}
// Checks for white-space characters. For the avr-libc library,
// these are: space, formfeed ('\f'), newline ('\n'), carriage
// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
inline boolean isSpace(int c)
{
return ( isspace (c) == 0 ? false : true);
}
// Checks for an uppercase letter.
inline boolean isUpperCase(int c)
{
return ( isupper (c) == 0 ? false : true);
}
// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
// 8 9 a b c d e f A B C D E F.
inline boolean isHexadecimalDigit(int c)
{
return ( isxdigit (c) == 0 ? false : true);
}
// Converts c to a 7-bit unsigned char value that fits into the
// ASCII character set, by clearing the high-order bits.
inline int toAscii(int c)
{
return toascii (c);
}
// Warning:
// Many people will be unhappy if you use this function.
// This function will convert accented letters into random
// characters.
// Converts the letter c to lower case, if possible.
inline int toLowerCase(int c)
{
return tolower (c);
}
// Converts the letter c to upper case, if possible.
inline int toUpperCase(int c)
{
return toupper (c);
}
#endif

View File

@ -0,0 +1 @@
#include "wiring.h"

View File

@ -0,0 +1,148 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.uniandes.edu.co
Copyright (c) 2004-05 Hernando Barragan
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 24 November 2006 by David A. Mellis
Modified 28-08-2009 for attiny84 R.Wiersma
Modified 09-10-2009 for attiny45 A.Saporetti
Modified 20-11-2010 - B.Cook - Correct a minor bug in attachInterrupt
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include "WConstants.h"
#include "wiring_private.h"
volatile static voidFuncPtr intFunc[NUMBER_EXTERNAL_INTERRUPTS];
#if defined( MCUCR ) && ! defined( EICRA )
#define EICRA MCUCR
#endif
#if defined( GIMSK ) && ! defined( EIMSK )
#define EIMSK GIMSK
#endif
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)
{
if ( interruptNum < NUMBER_EXTERNAL_INTERRUPTS )
{
/*
If attachInterrupt is called in succession for the same
interruptNum but a different userFunc then the following line
is not safe. Changing intFunc is not atomic.
intFunc[interruptNum] = userFunc;
*/
{
// save interrupt flag
uint8_t SaveSREG = SREG;
// disable interrupts
cli();
// access the shared data
intFunc[interruptNum] = userFunc;
// restore the interrupt flag
SREG = SaveSREG;
}
// Configure the interrupt mode (trigger on low input, any change, rising
// edge, or falling edge). The mode constants were chosen to correspond
// to the configuration bits in the hardware register, so we simply shift
// the mode into place.
// Enable the interrupt.
switch ( interruptNum )
{
#if NUMBER_EXTERNAL_INTERRUPTS >= 1
case EXTERNAL_INTERRUPT_0:
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
break;
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 2
case EXTERNAL_INTERRUPT_1:
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
break;
#endif
#if NUMBER_EXTERNAL_INTERRUPTS > 2
#error Add handlers for the additional interrupts.
#endif
}
}
}
void detachInterrupt(uint8_t interruptNum)
{
if ( interruptNum < NUMBER_EXTERNAL_INTERRUPTS )
{
// Disable the interrupt. (We can't assume that interruptNum is equal
// to the number of the EIMSK bit to clear, as this isn't true on the
// ATmega8. There, INT0 is 6 and INT1 is 7.)
switch (interruptNum)
{
#if NUMBER_EXTERNAL_INTERRUPTS >= 1
case EXTERNAL_INTERRUPT_0:
EIMSK &= ~(1 << INT0);
break;;
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 2
case EXTERNAL_INTERRUPT_1:
EIMSK &= ~(1 << INT1);
break;;
#endif
#if NUMBER_EXTERNAL_INTERRUPTS > 2
#error Add handlers for the additional interrupts.
#endif
}
intFunc[interruptNum] = 0;
}
}
#if NUMBER_EXTERNAL_INTERRUPTS >= 1
ISR(EXTERNAL_INTERRUPT_0_vect, ISR_NOBLOCK)
{
if(intFunc[EXTERNAL_INTERRUPT_0])
intFunc[EXTERNAL_INTERRUPT_0]();
}
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 2
ISR(EXTERNAL_INTERRUPT_1_vect, ISR_NOBLOCK)
{
if(intFunc[EXTERNAL_INTERRUPT_1])
intFunc[EXTERNAL_INTERRUPT_1]();
}
#endif
#if NUMBER_EXTERNAL_INTERRUPTS > 2
#error Add handlers for the additional interrupts.
#endif

View File

@ -0,0 +1,60 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.org.co
Copyright (c) 2004-06 Hernando Barragan
Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
extern "C" {
#include "stdlib.h"
}
void randomSeed(unsigned int seed)
{
if (seed != 0) {
srandom(seed);
}
}
long random(long howbig)
{
if (howbig == 0) {
return 0;
}
return random() % howbig;
}
long random(long howsmall, long howbig)
{
if (howsmall >= howbig) {
return howsmall;
}
long diff = howbig - howsmall;
return random(diff) + howsmall;
}
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
unsigned int makeWord(unsigned int w) { return w; }
unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }

View File

@ -0,0 +1,83 @@
#ifndef WProgram_h
#define WProgram_h
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <avr/interrupt.h>
#include "core_build_options.h"
#include "core_pins.h"
#include "wiring.h"
#include "pins_arduino.h"
#ifdef __cplusplus
#include "WCharacter.h"
#include "WString.h"
#include "TinyDebugSerial.h"
#include "HardwareSerial.h"
uint16_t makeWord(uint16_t w);
uint16_t makeWord(byte h, byte l);
#define word(...) makeWord(__VA_ARGS__)
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
void noTone(uint8_t _pin = 255);
// WMath prototypes
long random(long);
long random(long, long);
void randomSeed(unsigned int);
long map(long, long, long, long, long);
/*
fix? On the Mega processors, the analogs are also "extended" digital pins.
To (sort of) work the same way with this core, the following constants
would have to be valid arguments to digitalRead, digitalWrite, and pinMode
("the digitals"). Which means the digitals would have to check for pins
over A0 and then subtract A0. The current plan is to wait until someone
wants this feature.
*/
#if CORE_ANALOG_COUNT >= 1
const static uint8_t A0 = CORE_ANALOG_FIRST + 0;
#endif
#if CORE_ANALOG_COUNT >= 2
const static uint8_t A1 = CORE_ANALOG_FIRST + 1;
#endif
#if CORE_ANALOG_COUNT >= 3
const static uint8_t A2 = CORE_ANALOG_FIRST + 2;
#endif
#if CORE_ANALOG_COUNT >= 4
const static uint8_t A3 = CORE_ANALOG_FIRST + 3;
#endif
#if CORE_ANALOG_COUNT >= 5
const static uint8_t A4 = CORE_ANALOG_FIRST + 4;
#endif
#if CORE_ANALOG_COUNT >= 6
const static uint8_t A5 = CORE_ANALOG_FIRST + 5;
#endif
#if CORE_ANALOG_COUNT >= 7
const static uint8_t A6 = CORE_ANALOG_FIRST + 6;
#endif
#if CORE_ANALOG_COUNT >= 8
const static uint8_t A7 = CORE_ANALOG_FIRST + 7;
#endif
#if CORE_ANALOG_COUNT >= 9
#error Update the A* definitions for the selected processor.
#endif
#endif
#endif

View File

@ -0,0 +1,443 @@
/*
WString.cpp - String library for Wiring & Arduino
Copyright (c) 2009-10 Hernando Barragan. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include "WProgram.h"
#include "WString.h"
String::String( const char *value )
{
if ( value == NULL )
value = "";
getBuffer( _length = strlen( value ) );
if ( _buffer != NULL )
strcpy( _buffer, value );
}
String::String( const String &value )
{
getBuffer( _length = value._length );
if ( _buffer != NULL )
strcpy( _buffer, value._buffer );
}
String::String( const char value )
{
_length = 1;
getBuffer(1);
if ( _buffer != NULL ) {
_buffer[0] = value;
_buffer[1] = 0;
}
}
String::String( const unsigned char value )
{
_length = 1;
getBuffer(1);
if ( _buffer != NULL) {
_buffer[0] = value;
_buffer[1] = 0;
}
}
String::String( const int value, const int base )
{
char buf[33];
itoa((signed long)value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const unsigned int value, const int base )
{
char buf[33];
ultoa((unsigned long)value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const long value, const int base )
{
char buf[33];
ltoa(value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const unsigned long value, const int base )
{
char buf[33];
ultoa(value, buf, 10);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
char String::charAt( unsigned int loc ) const
{
return operator[]( loc );
}
void String::setCharAt( unsigned int loc, const char aChar )
{
if(_buffer == NULL) return;
if(_length > loc) {
_buffer[loc] = aChar;
}
}
int String::compareTo( const String &s2 ) const
{
return strcmp( _buffer, s2._buffer );
}
const String & String::concat( const String &s2 )
{
return (*this) += s2;
}
const String & String::operator=( const String &rhs )
{
if ( this == &rhs )
return *this;
if ( rhs._length > _length )
{
free(_buffer);
getBuffer( rhs._length );
}
if ( _buffer != NULL ) {
_length = rhs._length;
strcpy( _buffer, rhs._buffer );
}
return *this;
}
//const String & String::operator+=( const char aChar )
//{
// if ( _length == _capacity )
// doubleBuffer();
//
// _buffer[ _length++ ] = aChar;
// _buffer[ _length ] = '\0';
// return *this;
//}
const String & String::operator+=( const String &other )
{
_length += other._length;
if ( _length > _capacity )
{
char *temp = (char *)realloc(_buffer, _length + 1);
if ( temp != NULL ) {
_buffer = temp;
_capacity = _length;
} else {
_length -= other._length;
return *this;
}
}
strcat( _buffer, other._buffer );
return *this;
}
int String::operator==( const String &rhs ) const
{
return ( _length == rhs._length && strcmp( _buffer, rhs._buffer ) == 0 );
}
int String::operator!=( const String &rhs ) const
{
return ( _length != rhs.length() || strcmp( _buffer, rhs._buffer ) != 0 );
}
int String::operator<( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) < 0;
}
int String::operator>( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) > 0;
}
int String::operator<=( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) <= 0;
}
int String::operator>=( const String & rhs ) const
{
return strcmp( _buffer, rhs._buffer ) >= 0;
}
char & String::operator[]( unsigned int index )
{
static char dummy_writable_char;
if (index >= _length || !_buffer) {
dummy_writable_char = 0;
return dummy_writable_char;
}
return _buffer[ index ];
}
char String::operator[]( unsigned int index ) const
{
// need to check for valid index, to do later
return _buffer[ index ];
}
boolean String::endsWith( const String &s2 ) const
{
if ( _length < s2._length )
return 0;
return strcmp( &_buffer[ _length - s2._length], s2._buffer ) == 0;
}
boolean String::equals( const String &s2 ) const
{
return ( _length == s2._length && strcmp( _buffer,s2._buffer ) == 0 );
}
boolean String::equalsIgnoreCase( const String &s2 ) const
{
if ( this == &s2 )
return true; //1;
else if ( _length != s2._length )
return false; //0;
return strcmp(toLowerCase()._buffer, s2.toLowerCase()._buffer) == 0;
}
String String::replace( char findChar, char replaceChar )
{
if ( _buffer == NULL ) return *this;
String theReturn = _buffer;
char* temp = theReturn._buffer;
while( (temp = strchr( temp, findChar )) != 0 )
*temp = replaceChar;
return theReturn;
}
String String::replace( const String& match, const String& replace )
{
if ( _buffer == NULL ) return *this;
String temp = _buffer, newString;
int loc;
while ( (loc = temp.indexOf( match )) != -1 )
{
newString += temp.substring( 0, loc );
newString += replace;
temp = temp.substring( loc + match._length );
}
newString += temp;
return newString;
}
int String::indexOf( char temp ) const
{
return indexOf( temp, 0 );
}
int String::indexOf( char ch, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
const char* temp = strchr( &_buffer[fromIndex], ch );
if ( temp == NULL )
return -1;
return temp - _buffer;
}
int String::indexOf( const String &s2 ) const
{
return indexOf( s2, 0 );
}
int String::indexOf( const String &s2, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
const char *theFind = strstr( &_buffer[ fromIndex ], s2._buffer );
if ( theFind == NULL )
return -1;
return theFind - _buffer; // pointer subtraction
}
int String::lastIndexOf( char theChar ) const
{
return lastIndexOf( theChar, _length - 1 );
}
int String::lastIndexOf( char ch, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
char tempchar = _buffer[fromIndex + 1];
_buffer[fromIndex + 1] = '\0';
char* temp = strrchr( _buffer, ch );
_buffer[fromIndex + 1] = tempchar;
if ( temp == NULL )
return -1;
return temp - _buffer;
}
int String::lastIndexOf( const String &s2 ) const
{
return lastIndexOf( s2, _length - s2._length );
}
int String::lastIndexOf( const String &s2, unsigned int fromIndex ) const
{
// check for empty strings
if ( s2._length == 0 || s2._length - 1 > fromIndex || fromIndex >= _length )
return -1;
// matching first character
char temp = s2[ 0 ];
for ( int i = fromIndex; i >= 0; i-- )
{
if ( _buffer[ i ] == temp && (*this).substring( i, i + s2._length ).equals( s2 ) )
return i;
}
return -1;
}
boolean String::startsWith( const String &s2 ) const
{
if ( _length < s2._length )
return 0;
return startsWith( s2, 0 );
}
boolean String::startsWith( const String &s2, unsigned int offset ) const
{
if ( offset > _length - s2._length )
return 0;
return strncmp( &_buffer[offset], s2._buffer, s2._length ) == 0;
}
String String::substring( unsigned int left ) const
{
return substring( left, _length );
}
String String::substring( unsigned int left, unsigned int right ) const
{
if ( left > right )
{
int temp = right;
right = left;
left = temp;
}
if ( right > _length )
{
right = _length;
}
char temp = _buffer[ right ]; // save the replaced character
_buffer[ right ] = '\0';
String outPut = ( _buffer + left ); // pointer arithmetic
_buffer[ right ] = temp; //restore character
return outPut;
}
String String::toLowerCase() const
{
String temp = _buffer;
for ( unsigned int i = 0; i < _length; i++ )
temp._buffer[ i ] = (char)tolower( temp._buffer[ i ] );
return temp;
}
String String::toUpperCase() const
{
String temp = _buffer;
for ( unsigned int i = 0; i < _length; i++ )
temp._buffer[ i ] = (char)toupper( temp._buffer[ i ] );
return temp;
}
String String::trim() const
{
if ( _buffer == NULL ) return *this;
String temp = _buffer;
unsigned int i,j;
for ( i = 0; i < _length; i++ )
{
if ( !isspace(_buffer[i]) )
break;
}
for ( j = temp._length - 1; j > i; j-- )
{
if ( !isspace(_buffer[j]) )
break;
}
return temp.substring( i, j + 1);
}
void String::getBytes(unsigned char *buf, unsigned int bufsize)
{
if (!bufsize || !buf) return;
unsigned int len = bufsize - 1;
if (len > _length) len = _length;
strncpy((char *)buf, _buffer, len);
buf[len] = 0;
}
void String::toCharArray(char *buf, unsigned int bufsize)
{
if (!bufsize || !buf) return;
unsigned int len = bufsize - 1;
if (len > _length) len = _length;
strncpy(buf, _buffer, len);
buf[len] = 0;
}
long String::toInt() {
return atol(_buffer);
}

View File

@ -0,0 +1,112 @@
/*
WString.h - String library for Wiring & Arduino
Copyright (c) 2009-10 Hernando Barragan. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef String_h
#define String_h
//#include "WProgram.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
class String
{
public:
// constructors
String( const char *value = "" );
String( const String &value );
String( const char );
String( const unsigned char );
String( const int, const int base=10);
String( const unsigned int, const int base=10 );
String( const long, const int base=10 );
String( const unsigned long, const int base=10 );
~String() { free(_buffer); _length = _capacity = 0;} //added _length = _capacity = 0;
// operators
const String & operator = ( const String &rhs );
const String & operator +=( const String &rhs );
//const String & operator +=( const char );
int operator ==( const String &rhs ) const;
int operator !=( const String &rhs ) const;
int operator < ( const String &rhs ) const;
int operator > ( const String &rhs ) const;
int operator <=( const String &rhs ) const;
int operator >=( const String &rhs ) const;
char operator []( unsigned int index ) const;
char& operator []( unsigned int index );
//operator const char *() const { return _buffer; }
// general methods
char charAt( unsigned int index ) const;
int compareTo( const String &anotherString ) const;
unsigned char endsWith( const String &suffix ) const;
unsigned char equals( const String &anObject ) const;
unsigned char equalsIgnoreCase( const String &anotherString ) const;
int indexOf( char ch ) const;
int indexOf( char ch, unsigned int fromIndex ) const;
int indexOf( const String &str ) const;
int indexOf( const String &str, unsigned int fromIndex ) const;
int lastIndexOf( char ch ) const;
int lastIndexOf( char ch, unsigned int fromIndex ) const;
int lastIndexOf( const String &str ) const;
int lastIndexOf( const String &str, unsigned int fromIndex ) const;
const unsigned int length( ) const { return _length; }
void setCharAt(unsigned int index, const char ch);
unsigned char startsWith( const String &prefix ) const;
unsigned char startsWith( const String &prefix, unsigned int toffset ) const;
String substring( unsigned int beginIndex ) const;
String substring( unsigned int beginIndex, unsigned int endIndex ) const;
String toLowerCase( ) const;
String toUpperCase( ) const;
String trim( ) const;
void getBytes(unsigned char *buf, unsigned int bufsize);
void toCharArray(char *buf, unsigned int bufsize);
long toInt( );
const String& concat( const String &str );
String replace( char oldChar, char newChar );
String replace( const String& match, const String& replace );
friend String operator + ( String lhs, const String &rhs );
protected:
char *_buffer; // the actual char array
unsigned int _capacity; // the array length minus one (for the '\0')
unsigned int _length; // the String length (not counting the '\0')
void getBuffer(unsigned int maxStrLen);
private:
};
// allocate buffer space
inline void String::getBuffer(unsigned int maxStrLen)
{
_capacity = maxStrLen;
_buffer = (char *) malloc(_capacity + 1);
if (_buffer == NULL) _length = _capacity = 0;
}
inline String operator+( String lhs, const String &rhs )
{
return lhs += rhs;
}
#endif

View File

@ -0,0 +1,515 @@
#ifndef Binary_h
#define Binary_h
#define B0 0
#define B00 0
#define B000 0
#define B0000 0
#define B00000 0
#define B000000 0
#define B0000000 0
#define B00000000 0
#define B1 1
#define B01 1
#define B001 1
#define B0001 1
#define B00001 1
#define B000001 1
#define B0000001 1
#define B00000001 1
#define B10 2
#define B010 2
#define B0010 2
#define B00010 2
#define B000010 2
#define B0000010 2
#define B00000010 2
#define B11 3
#define B011 3
#define B0011 3
#define B00011 3
#define B000011 3
#define B0000011 3
#define B00000011 3
#define B100 4
#define B0100 4
#define B00100 4
#define B000100 4
#define B0000100 4
#define B00000100 4
#define B101 5
#define B0101 5
#define B00101 5
#define B000101 5
#define B0000101 5
#define B00000101 5
#define B110 6
#define B0110 6
#define B00110 6
#define B000110 6
#define B0000110 6
#define B00000110 6
#define B111 7
#define B0111 7
#define B00111 7
#define B000111 7
#define B0000111 7
#define B00000111 7
#define B1000 8
#define B01000 8
#define B001000 8
#define B0001000 8
#define B00001000 8
#define B1001 9
#define B01001 9
#define B001001 9
#define B0001001 9
#define B00001001 9
#define B1010 10
#define B01010 10
#define B001010 10
#define B0001010 10
#define B00001010 10
#define B1011 11
#define B01011 11
#define B001011 11
#define B0001011 11
#define B00001011 11
#define B1100 12
#define B01100 12
#define B001100 12
#define B0001100 12
#define B00001100 12
#define B1101 13
#define B01101 13
#define B001101 13
#define B0001101 13
#define B00001101 13
#define B1110 14
#define B01110 14
#define B001110 14
#define B0001110 14
#define B00001110 14
#define B1111 15
#define B01111 15
#define B001111 15
#define B0001111 15
#define B00001111 15
#define B10000 16
#define B010000 16
#define B0010000 16
#define B00010000 16
#define B10001 17
#define B010001 17
#define B0010001 17
#define B00010001 17
#define B10010 18
#define B010010 18
#define B0010010 18
#define B00010010 18
#define B10011 19
#define B010011 19
#define B0010011 19
#define B00010011 19
#define B10100 20
#define B010100 20
#define B0010100 20
#define B00010100 20
#define B10101 21
#define B010101 21
#define B0010101 21
#define B00010101 21
#define B10110 22
#define B010110 22
#define B0010110 22
#define B00010110 22
#define B10111 23
#define B010111 23
#define B0010111 23
#define B00010111 23
#define B11000 24
#define B011000 24
#define B0011000 24
#define B00011000 24
#define B11001 25
#define B011001 25
#define B0011001 25
#define B00011001 25
#define B11010 26
#define B011010 26
#define B0011010 26
#define B00011010 26
#define B11011 27
#define B011011 27
#define B0011011 27
#define B00011011 27
#define B11100 28
#define B011100 28
#define B0011100 28
#define B00011100 28
#define B11101 29
#define B011101 29
#define B0011101 29
#define B00011101 29
#define B11110 30
#define B011110 30
#define B0011110 30
#define B00011110 30
#define B11111 31
#define B011111 31
#define B0011111 31
#define B00011111 31
#define B100000 32
#define B0100000 32
#define B00100000 32
#define B100001 33
#define B0100001 33
#define B00100001 33
#define B100010 34
#define B0100010 34
#define B00100010 34
#define B100011 35
#define B0100011 35
#define B00100011 35
#define B100100 36
#define B0100100 36
#define B00100100 36
#define B100101 37
#define B0100101 37
#define B00100101 37
#define B100110 38
#define B0100110 38
#define B00100110 38
#define B100111 39
#define B0100111 39
#define B00100111 39
#define B101000 40
#define B0101000 40
#define B00101000 40
#define B101001 41
#define B0101001 41
#define B00101001 41
#define B101010 42
#define B0101010 42
#define B00101010 42
#define B101011 43
#define B0101011 43
#define B00101011 43
#define B101100 44
#define B0101100 44
#define B00101100 44
#define B101101 45
#define B0101101 45
#define B00101101 45
#define B101110 46
#define B0101110 46
#define B00101110 46
#define B101111 47
#define B0101111 47
#define B00101111 47
#define B110000 48
#define B0110000 48
#define B00110000 48
#define B110001 49
#define B0110001 49
#define B00110001 49
#define B110010 50
#define B0110010 50
#define B00110010 50
#define B110011 51
#define B0110011 51
#define B00110011 51
#define B110100 52
#define B0110100 52
#define B00110100 52
#define B110101 53
#define B0110101 53
#define B00110101 53
#define B110110 54
#define B0110110 54
#define B00110110 54
#define B110111 55
#define B0110111 55
#define B00110111 55
#define B111000 56
#define B0111000 56
#define B00111000 56
#define B111001 57
#define B0111001 57
#define B00111001 57
#define B111010 58
#define B0111010 58
#define B00111010 58
#define B111011 59
#define B0111011 59
#define B00111011 59
#define B111100 60
#define B0111100 60
#define B00111100 60
#define B111101 61
#define B0111101 61
#define B00111101 61
#define B111110 62
#define B0111110 62
#define B00111110 62
#define B111111 63
#define B0111111 63
#define B00111111 63
#define B1000000 64
#define B01000000 64
#define B1000001 65
#define B01000001 65
#define B1000010 66
#define B01000010 66
#define B1000011 67
#define B01000011 67
#define B1000100 68
#define B01000100 68
#define B1000101 69
#define B01000101 69
#define B1000110 70
#define B01000110 70
#define B1000111 71
#define B01000111 71
#define B1001000 72
#define B01001000 72
#define B1001001 73
#define B01001001 73
#define B1001010 74
#define B01001010 74
#define B1001011 75
#define B01001011 75
#define B1001100 76
#define B01001100 76
#define B1001101 77
#define B01001101 77
#define B1001110 78
#define B01001110 78
#define B1001111 79
#define B01001111 79
#define B1010000 80
#define B01010000 80
#define B1010001 81
#define B01010001 81
#define B1010010 82
#define B01010010 82
#define B1010011 83
#define B01010011 83
#define B1010100 84
#define B01010100 84
#define B1010101 85
#define B01010101 85
#define B1010110 86
#define B01010110 86
#define B1010111 87
#define B01010111 87
#define B1011000 88
#define B01011000 88
#define B1011001 89
#define B01011001 89
#define B1011010 90
#define B01011010 90
#define B1011011 91
#define B01011011 91
#define B1011100 92
#define B01011100 92
#define B1011101 93
#define B01011101 93
#define B1011110 94
#define B01011110 94
#define B1011111 95
#define B01011111 95
#define B1100000 96
#define B01100000 96
#define B1100001 97
#define B01100001 97
#define B1100010 98
#define B01100010 98
#define B1100011 99
#define B01100011 99
#define B1100100 100
#define B01100100 100
#define B1100101 101
#define B01100101 101
#define B1100110 102
#define B01100110 102
#define B1100111 103
#define B01100111 103
#define B1101000 104
#define B01101000 104
#define B1101001 105
#define B01101001 105
#define B1101010 106
#define B01101010 106
#define B1101011 107
#define B01101011 107
#define B1101100 108
#define B01101100 108
#define B1101101 109
#define B01101101 109
#define B1101110 110
#define B01101110 110
#define B1101111 111
#define B01101111 111
#define B1110000 112
#define B01110000 112
#define B1110001 113
#define B01110001 113
#define B1110010 114
#define B01110010 114
#define B1110011 115
#define B01110011 115
#define B1110100 116
#define B01110100 116
#define B1110101 117
#define B01110101 117
#define B1110110 118
#define B01110110 118
#define B1110111 119
#define B01110111 119
#define B1111000 120
#define B01111000 120
#define B1111001 121
#define B01111001 121
#define B1111010 122
#define B01111010 122
#define B1111011 123
#define B01111011 123
#define B1111100 124
#define B01111100 124
#define B1111101 125
#define B01111101 125
#define B1111110 126
#define B01111110 126
#define B1111111 127
#define B01111111 127
#define B10000000 128
#define B10000001 129
#define B10000010 130
#define B10000011 131
#define B10000100 132
#define B10000101 133
#define B10000110 134
#define B10000111 135
#define B10001000 136
#define B10001001 137
#define B10001010 138
#define B10001011 139
#define B10001100 140
#define B10001101 141
#define B10001110 142
#define B10001111 143
#define B10010000 144
#define B10010001 145
#define B10010010 146
#define B10010011 147
#define B10010100 148
#define B10010101 149
#define B10010110 150
#define B10010111 151
#define B10011000 152
#define B10011001 153
#define B10011010 154
#define B10011011 155
#define B10011100 156
#define B10011101 157
#define B10011110 158
#define B10011111 159
#define B10100000 160
#define B10100001 161
#define B10100010 162
#define B10100011 163
#define B10100100 164
#define B10100101 165
#define B10100110 166
#define B10100111 167
#define B10101000 168
#define B10101001 169
#define B10101010 170
#define B10101011 171
#define B10101100 172
#define B10101101 173
#define B10101110 174
#define B10101111 175
#define B10110000 176
#define B10110001 177
#define B10110010 178
#define B10110011 179
#define B10110100 180
#define B10110101 181
#define B10110110 182
#define B10110111 183
#define B10111000 184
#define B10111001 185
#define B10111010 186
#define B10111011 187
#define B10111100 188
#define B10111101 189
#define B10111110 190
#define B10111111 191
#define B11000000 192
#define B11000001 193
#define B11000010 194
#define B11000011 195
#define B11000100 196
#define B11000101 197
#define B11000110 198
#define B11000111 199
#define B11001000 200
#define B11001001 201
#define B11001010 202
#define B11001011 203
#define B11001100 204
#define B11001101 205
#define B11001110 206
#define B11001111 207
#define B11010000 208
#define B11010001 209
#define B11010010 210
#define B11010011 211
#define B11010100 212
#define B11010101 213
#define B11010110 214
#define B11010111 215
#define B11011000 216
#define B11011001 217
#define B11011010 218
#define B11011011 219
#define B11011100 220
#define B11011101 221
#define B11011110 222
#define B11011111 223
#define B11100000 224
#define B11100001 225
#define B11100010 226
#define B11100011 227
#define B11100100 228
#define B11100101 229
#define B11100110 230
#define B11100111 231
#define B11101000 232
#define B11101001 233
#define B11101010 234
#define B11101011 235
#define B11101100 236
#define B11101101 237
#define B11101110 238
#define B11101111 239
#define B11110000 240
#define B11110001 241
#define B11110010 242
#define B11110011 243
#define B11110100 244
#define B11110101 245
#define B11110110 246
#define B11110111 247
#define B11111000 248
#define B11111001 249
#define B11111010 250
#define B11111011 251
#define B11111100 252
#define B11111101 253
#define B11111110 254
#define B11111111 255
#endif

View File

@ -0,0 +1,320 @@
/*==============================================================================
core_adc.h - Veneer for the analog-to-digital converter.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#ifndef core_adc_h
#define core_adc_h
#include <avr/io.h>
#include <binary.h>
#include "core_build_options.h"
#include "core_macros.h"
/*=============================================================================
Some common things
=============================================================================*/
#if defined( __AVR_ATtinyX4__ ) || defined( __AVR_ATtinyX5__ )
/*
From the '84 and '85 datasheets... By default, the successive approximation
circuitry requires an input clock frequency between 50 kHz and 200 kHz to
get maximum resolution.
*/
#if F_CPU == 16000000
// 16 MHz / 128 = 125 KHz
#define ADC_ARDUINO_PRESCALER ADC_Prescaler_Value_128
#elif F_CPU == 16500000
// 8 MHz / 64 = 125 KHz
#define ADC_ARDUINO_PRESCALER ADC_Prescaler_Value_128
#elif F_CPU == 8000000
// 8 MHz / 64 = 125 KHz
#define ADC_ARDUINO_PRESCALER ADC_Prescaler_Value_64
#elif F_CPU == 1000000
// 1 MHz / 8 = 125 KHz
#define ADC_ARDUINO_PRESCALER ADC_Prescaler_Value_8
#else
#error Add an entry for the selected processor speed.
#endif
typedef enum
{
ADC_Prescaler_Value_2 = B001,
ADC_Prescaler_Value_4 = B010,
ADC_Prescaler_Value_8 = B011,
ADC_Prescaler_Value_16 = B100,
ADC_Prescaler_Value_32 = B101,
ADC_Prescaler_Value_64 = B110,
ADC_Prescaler_Value_128 = B111,
ADC_Prescaler_Index_1 = B001,
ADC_Prescaler_Index_2 = B010,
ADC_Prescaler_Index_3 = B011,
ADC_Prescaler_Index_4 = B100,
ADC_Prescaler_Index_5 = B101,
ADC_Prescaler_Index_6 = B110,
ADC_Prescaler_Index_7 = B111
}
adc_ps_t;
__attribute__((always_inline)) static inline void ADC_PrescalerSelect( adc_ps_t ps )
{
ADCSRA = (ADCSRA & ~MASK3(ADPS2,ADPS1,ADPS0)) | (ps << ADPS0);
}
__attribute__((always_inline)) static inline void ADC_Enable( void )
{
ADCSRA |= MASK1( ADEN );
}
#endif
/*=============================================================================
Veneer for the ATtiny84 ADC
=============================================================================*/
#if defined( __AVR_ATtinyX4__ )
typedef enum
{
ADC_Reference_VCC = B00,
ADC_Reference_External = B01,
ADC_Reference_Internal_1p1 = B10,
ADC_Reference_Reserved_1 = B11
}
adc_vr_t;
__attribute__((always_inline)) static inline void ADC_SetVoltageReference( adc_vr_t vr )
{
ADMUX = (ADMUX & ~MASK2(REFS1,REFS0)) | (((vr & B11) >> 0) << REFS0);
}
typedef enum
{
ADC_Input_ADC0 = B000000,
ADC_Input_ADC1 = B000001,
ADC_Input_ADC2 = B000010,
ADC_Input_ADC3 = B000011,
ADC_Input_ADC4 = B000100,
ADC_Input_ADC5 = B000101,
ADC_Input_ADC6 = B000110,
ADC_Input_ADC7 = B000111,
ADC_Input_GND = B100000, // 0V (AGND)
ADC_Input_1p1 = B100001, // 1.1V (I Ref)
ADC_Input_ADC8 = B100010, // For temperature sensor.
ADC_Input_Pos0_Neg0_20x = B100011, // For offset calibration, only.
ADC_Input_Pos0_Neg1_1x = B001000,
ADC_Input_Pos0_Neg1_20x = B001001,
ADC_Input_Pos0_Neg3_1x = B001010,
ADC_Input_Pos0_Neg3_20x = B001011,
ADC_Input_Pos1_Neg0_1x = B101000,
ADC_Input_Pos1_Neg0_20x = B101001,
ADC_Input_Pos1_Neg2_1x = B001100,
ADC_Input_Pos1_Neg2_20x = B001101,
ADC_Input_Pos1_Neg3_1x = B001110,
ADC_Input_Pos1_Neg3_20x = B001111,
ADC_Input_Pos2_Neg1_1x = B101100,
ADC_Input_Pos2_Neg1_20x = B101101,
ADC_Input_Pos2_Neg3_1x = B010000,
ADC_Input_Pos2_Neg3_20x = B010001,
ADC_Input_Pos3_Neg0_1x = B101010,
ADC_Input_Pos3_Neg0_20x = B101011,
ADC_Input_Pos3_Neg1_1x = B101110,
ADC_Input_Pos3_Neg1_20x = B101111,
ADC_Input_Pos3_Neg2_1x = B110000,
ADC_Input_Pos3_Neg2_20x = B110001,
ADC_Input_Pos3_Neg3_1x = B100100, // For offset calibration, only.
ADC_Input_Pos3_Neg3_20x = B100101, // For offset calibration, only.
ADC_Input_Pos3_Neg4_1x = B010010,
ADC_Input_Pos3_Neg4_20x = B010011,
ADC_Input_Pos3_Neg5_1x = B010100,
ADC_Input_Pos3_Neg5_20x = B010101,
ADC_Input_Pos3_Neg6_1x = B010110,
ADC_Input_Pos3_Neg6_20x = B010111,
ADC_Input_Pos3_Neg7_1x = B011000,
ADC_Input_Pos3_Neg7_20x = B011001,
ADC_Input_Pos4_Neg3_1x = B110010,
ADC_Input_Pos4_Neg3_20x = B110011,
ADC_Input_Pos4_Neg5_1x = B011010,
ADC_Input_Pos4_Neg5_20x = B011011,
ADC_Input_Pos5_Neg3_1x = B110100,
ADC_Input_Pos5_Neg3_20x = B110101,
ADC_Input_Pos5_Neg4_1x = B111010,
ADC_Input_Pos5_Neg4_20x = B111011,
ADC_Input_Pos5_Neg6_1x = B011100,
ADC_Input_Pos5_Neg6_20x = B011101,
ADC_Input_Pos6_Neg3_1x = B110110,
ADC_Input_Pos6_Neg3_20x = B110111,
ADC_Input_Pos6_Neg5_1x = B111100,
ADC_Input_Pos6_Neg5_20x = B111101,
ADC_Input_Pos6_Neg7_1x = B011110,
ADC_Input_Pos6_Neg7_20x = B011111,
ADC_Input_Pos7_Neg3_1x = B111000,
ADC_Input_Pos7_Neg3_20x = B111001,
ADC_Input_Pos7_Neg6_1x = B111110,
ADC_Input_Pos7_Neg6_20x = B111111,
ADC_Input_Pos7_Neg7_1x = B100110, // For offset calibration, only.
ADC_Input_Pos7_Neg7_20x = B100111 // For offset calibration, only.
}
adc_ic_t;
__attribute__((always_inline)) static inline void ADC_SetInputChannel( adc_ic_t ic )
{
ADMUX = (ADMUX & ~MASK6(MUX5,MUX4,MUX3,MUX2,MUX1,MUX0)) | (ic << MUX0);
}
__attribute__((always_inline)) static inline void ADC_StartConversion( void )
{
ADCSRA |= MASK1( ADSC );
}
__attribute__((always_inline)) static inline uint8_t ADC_ConversionInProgress( void )
{
return( (ADCSRA & (1<<ADSC)) != 0 );
}
__attribute__((always_inline)) static inline uint16_t ADC_GetDataRegister( void )
{
return( ADC );
}
#endif
/*=============================================================================
Veneer for the ATtiny85 ADC
=============================================================================*/
#if defined( __AVR_ATtinyX5__ )
typedef enum
{
ADC_Reference_VCC = B000,
ADC_Reference_External = B001,
ADC_Reference_Internal_1p1 = B010,
ADC_Reference_Reserved_1 = B011,
ADC_Reference_Internal_2p56 = B110,
ADC_Reference_Internal_2p56_Bypass_Capacitor = B111
}
adc_vr_t;
__attribute__((always_inline)) static inline void ADC_SetVoltageReference( adc_vr_t vr )
{
ADMUX = (ADMUX & ~MASK3(REFS1,REFS0,REFS2))
| (((vr & B011) >> 0) << REFS0)
| (((vr & B100) >> 2) << REFS2);
}
typedef enum
{
ADC_Input_ADC0 = B0000,
ADC_Input_ADC1 = B0001,
ADC_Input_ADC2 = B0010,
ADC_Input_ADC3 = B0011,
ADC_Input_Pos2_Neg2_1x = B0100, // For offset calibration, only.
ADC_Input_Pos2_Neg2_20x = B0101, // For offset calibration, only.
ADC_Input_Pos2_Neg3_1x = B0110,
ADC_Input_Pos2_Neg3_20x = B0111,
ADC_Input_Pos0_Neg0_1x = B1000,
ADC_Input_Pos0_Neg0_20x = B1001,
ADC_Input_Pos0_Neg1_1x = B1010,
ADC_Input_Pos0_Neg1_20x = B1011,
ADC_Input_VBG = B1100,
ADC_Input_GND = B1101,
ADC_Input_NA = B1110,
ADC_Input_ADC4 = B1111 // For temperature sensor.
}
adc_ic_t;
__attribute__((always_inline)) static inline void ADC_SetInputChannel( adc_ic_t ic )
{
ADMUX = (ADMUX & ~MASK4(MUX3,MUX2,MUX1,MUX0)) | (ic << MUX0);
}
__attribute__((always_inline)) static inline void ADC_StartConversion( void )
{
ADCSRA |= MASK1( ADSC );
}
__attribute__((always_inline)) static inline uint8_t ADC_ConversionInProgress( void )
{
return( (ADCSRA & (1<<ADSC)) != 0 );
}
__attribute__((always_inline)) static inline uint16_t ADC_GetDataRegister( void )
{
return( ADC );
}
#endif
/*=============================================================================
Veneer for the (non-existant) ATtinyX313 ADC
=============================================================================*/
#if defined( __AVR_ATtinyX313__ )
typedef enum
{
ADC_No_Reference = 0
}
adc_vr_t;
__attribute__((always_inline)) static inline void ADC_SetVoltageReference( adc_vr_t vr )
{
}
typedef enum
{
ADC_No_Input = 0
}
adc_ic_t;
__attribute__((always_inline)) static inline void ADC_SetInputChannel( adc_ic_t ic )
{
}
__attribute__((always_inline)) static inline void ADC_StartConversion( void )
{
}
__attribute__((always_inline)) static inline uint8_t ADC_ConversionInProgress( void )
{
return( 0 );
}
__attribute__((always_inline)) static inline uint16_t ADC_GetDataRegister( void )
{
return( 0 );
}
#endif
#endif

View File

@ -0,0 +1,174 @@
/*==============================================================================
core_build_options.h - Various options for mapping functionality to hardware.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#ifndef core_build_options_h
#define core_build_options_h
/*=============================================================================
Low power / smaller code options
=============================================================================*/
#define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 1
#define INITIALIZE_SECONDARY_TIMERS 1
/*=============================================================================
Build options for the ATtinyX313 processor
=============================================================================*/
#if defined( __AVR_ATtiny2313__ ) || defined( __AVR_ATtiny4313__ )
#define __AVR_ATtinyX313__
#endif
#if defined( __AVR_ATtinyX313__ )
/*
The old standby ... millis on Timer 0.
*/
#define TIMER_TO_USE_FOR_MILLIS 0
/*
Tone goes on whichever timer was not used for millis.
*/
#if TIMER_TO_USE_FOR_MILLIS == 1
#define TIMER_TO_USE_FOR_TONE 0
#else
#define TIMER_TO_USE_FOR_TONE 1
#endif
#define HAVE_ADC 0
#define DEFAULT_TO_TINY_DEBUG_SERIAL 0
#endif
/*=============================================================================
Build options for the ATtiny84 processor
=============================================================================*/
#if defined( __AVR_ATtiny24__ ) || defined( __AVR_ATtiny44__ ) || defined( __AVR_ATtiny84__ )
#define __AVR_ATtinyX4__
#endif
#if defined( __AVR_ATtinyX4__ )
/*
The old standby ... millis on Timer 0.
*/
#define TIMER_TO_USE_FOR_MILLIS 0
/*
Tone goes on whichever timer was not used for millis.
*/
#if TIMER_TO_USE_FOR_MILLIS == 1
#define TIMER_TO_USE_FOR_TONE 0
#else
#define TIMER_TO_USE_FOR_TONE 1
#endif
#define HAVE_ADC 1
#define DEFAULT_TO_TINY_DEBUG_SERIAL 1
#endif
/*=============================================================================
Build options for the ATtiny85 processor
=============================================================================*/
#if defined( __AVR_ATtiny25__ ) || defined( __AVR_ATtiny45__ ) || defined( __AVR_ATtiny85__ )
#define __AVR_ATtinyX5__
#endif
#if defined( __AVR_ATtinyX5__ )
/*
For various reasons, Timer 1 is a better choice for the millis timer on the
'85 processor.
*/
#define TIMER_TO_USE_FOR_MILLIS 1
/*
If the following is true (non-zero) there will be two phase-correct PWM
pins and one fast PWM pin. If false there will be one phase-correct PWM
pin and two fast PWM pins.
*/
#define FAVOR_PHASE_CORRECT_PWM 1
/*
Tone goes on whichever timer was not used for millis.
*/
#if TIMER_TO_USE_FOR_MILLIS == 1
#define TIMER_TO_USE_FOR_TONE 0
#else
#define TIMER_TO_USE_FOR_TONE 1
#endif
#define HAVE_ADC 1
#define DEFAULT_TO_TINY_DEBUG_SERIAL 1
#endif
/*=============================================================================
There doesn't seem to be many people using a bootloader so we'll assume
there isn't one. If the following is true (non-zero), the timers are
reinitialized to their power-up state in init just in case the bootloader
left them in a bad way.
=============================================================================*/
#define HAVE_BOOTLOADER 0
/*=============================================================================
Allow the ADC to be optional for low-power applications
=============================================================================*/
#if ! defined( HAVE_ADC )
#define HAVE_ADC 0
#endif
#if ! HAVE_ADC
#undef INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER
#define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 0
#else
#if ! defined( INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER )
#define INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER 1
#endif
#endif
/*=============================================================================
Allow the "secondary timers" to be optional for low-power applications
=============================================================================*/
#if ! defined( INITIALIZE_SECONDARY_TIMERS )
#define INITIALIZE_SECONDARY_TIMERS 1
#endif
#endif

View File

@ -0,0 +1,42 @@
/*==============================================================================
core_macros.h - Simple but handy macros.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#ifndef core_macros_h
#define core_macros_h
/*=============================================================================
Bitmask macros
=============================================================================*/
#define MASK1(b1) ( (1<<b1) )
#define MASK2(b1,b2) ( (1<<b1) | (1<<b2) )
#define MASK3(b1,b2,b3) ( (1<<b1) | (1<<b2) | (1<<b3) )
#define MASK4(b1,b2,b3,b4) ( (1<<b1) | (1<<b2) | (1<<b3) | (1<<b4) )
#define MASK5(b1,b2,b3,b4,b5) ( (1<<b1) | (1<<b2) | (1<<b3) | (1<<b4) | (1<<b5) )
#define MASK6(b1,b2,b3,b4,b5,b6) ( (1<<b1) | (1<<b2) | (1<<b3) | (1<<b4) | (1<<b5) | (1<<b6) )
#define MASK7(b1,b2,b3,b4,b5,b6,b7) ( (1<<b1) | (1<<b2) | (1<<b3) | (1<<b4) | (1<<b5) | (1<<b6) | (1<<b7) )
#define MASK8(b1,b2,b3,b4,b5,b6,b7,b8) ( (1<<b1) | (1<<b2) | (1<<b3) | (1<<b4) | (1<<b5) | (1<<b6) | (1<<b7) | (1<<b8) )
#endif

View File

@ -0,0 +1,204 @@
/*==============================================================================
core_pins.h - Pin definitions.
Copyright 2010 Rowdy Dog Software.
This file is part of Arduino-Tiny.
Arduino-Tiny is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
Arduino-Tiny is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Arduino-Tiny. If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/
#ifndef core_pins_h
#define core_pins_h
#include "core_build_options.h"
/*=============================================================================
Pin definitions for the ATtinyX313
=============================================================================*/
#if defined( __AVR_ATtinyX313__ )
#define PIN_D0 ( 0)
#define PIN_D1 ( 1)
#define PIN_A1 ( 2)
#define PIN_A0 ( 3)
#define PIN_D2 ( 4)
#define PIN_D3 ( 5)
#define PIN_D4 ( 6)
#define PIN_D5 ( 7)
#define PIN_D6 ( 8)
#define PIN_B0 ( 9)
#define PIN_B1 (10)
#define PIN_B2 (11)
#define PIN_B3 (12)
#define PIN_B4 (13)
#define PIN_B5 (14)
#define PIN_B6 (15)
#define PIN_B7 (16)
#define PIN_A2 (17) /* RESET */
#define CORE_DIGITAL_FIRST (0)
#define CORE_DIGITAL_LAST (17)
#define CORE_DIGITAL_COUNT (CORE_DIGITAL_LAST-CORE_DIGITAL_FIRST+1)
#define CORE_RESET_INCLUDED (1)
#define CORE_ANALOG_COUNT (0)
#define CORE_INT0_PIN PIN_D2
#define CORE_INT1_PIN PIN_D3
#define CORE_OC0A_PIN PIN_B2
#define CORE_OC0B_PIN PIN_D5
#define CORE_OC1A_PIN PIN_B3
#define CORE_OC1B_PIN PIN_B4
#define CORE_PWM0_PIN CORE_OC0A_PIN
#define CORE_PWM0_TIMER 0
#define CORE_PWM0_CHANNEL A
#define CORE_PWM1_PIN CORE_OC0B_PIN
#define CORE_PWM1_TIMER 0
#define CORE_PWM1_CHANNEL B
#define CORE_PWM2_PIN CORE_OC1A_PIN
#define CORE_PWM2_TIMER 1
#define CORE_PWM2_CHANNEL A
#define CORE_PWM3_PIN CORE_OC1B_PIN
#define CORE_PWM3_TIMER 1
#define CORE_PWM3_CHANNEL B
#define CORE_PWM_COUNT (4)
#endif
/*=============================================================================
Pin definitions for the ATtiny84
=============================================================================*/
#if defined( __AVR_ATtinyX4__ )
#define PIN_A0 (10)
#define PIN_A1 ( 9)
#define PIN_A2 ( 8)
#define PIN_A3 ( 7)
#define PIN_A4 ( 6)
#define PIN_A5 ( 5)
#define PIN_A6 ( 4)
#define PIN_A7 ( 3)
#define PIN_B0 ( 0)
#define PIN_B1 ( 1)
#define PIN_B2 ( 2)
#define PIN_B3 (11) /* RESET */
#define CORE_DIGITAL_FIRST (0)
#define CORE_DIGITAL_LAST (11)
#define CORE_DIGITAL_COUNT (CORE_DIGITAL_LAST-CORE_DIGITAL_FIRST+1)
#define CORE_RESET_INCLUDED (1)
#define CORE_ANALOG_FIRST (CORE_DIGITAL_LAST+1)
#define CORE_ANALOG_COUNT (8)
#define CORE_ANALOG_LAST (CORE_ANALOG_FIRST+CORE_ANALOG_COUNT-1)
#define CORE_INT0_PIN PIN_B2
#define CORE_OC0A_PIN PIN_B2
#define CORE_OC0B_PIN PIN_A7
#define CORE_OC1A_PIN PIN_A6
#define CORE_OC1B_PIN PIN_A5
#define CORE_PWM0_PIN CORE_OC0A_PIN
#define CORE_PWM0_TIMER 0
#define CORE_PWM0_CHANNEL A
#define CORE_PWM1_PIN CORE_OC0B_PIN
#define CORE_PWM1_TIMER 0
#define CORE_PWM1_CHANNEL B
#define CORE_PWM2_PIN CORE_OC1A_PIN
#define CORE_PWM2_TIMER 1
#define CORE_PWM2_CHANNEL A
#define CORE_PWM3_PIN CORE_OC1B_PIN
#define CORE_PWM3_TIMER 1
#define CORE_PWM3_CHANNEL B
#define CORE_PWM_COUNT (4)
#endif
/*=============================================================================
Pin definitions for the ATtiny85
=============================================================================*/
#if defined( __AVR_ATtinyX5__ )
#define PIN_B0 ( 0)
#define PIN_B1 ( 1)
#define PIN_B2 ( 2)
#define PIN_B3 ( 3)
#define PIN_B4 ( 4)
#define PIN_B5 ( 5) /* RESET */
#define CORE_DIGITAL_FIRST (0)
#define CORE_DIGITAL_LAST (5)
#define CORE_DIGITAL_COUNT (CORE_DIGITAL_LAST-CORE_DIGITAL_FIRST+1)
#define CORE_RESET_INCLUDED (1)
#define CORE_ANALOG_FIRST (CORE_DIGITAL_LAST+1)
#define CORE_ANALOG_COUNT (4)
#define CORE_ANALOG_LAST (CORE_ANALOG_FIRST+CORE_ANALOG_COUNT-1)
#define CORE_INT0_PIN PIN_B2
#define CORE_OC0A_PIN PIN_B0
#define CORE_OC0B_PIN PIN_B1
#define CORE_OC1A_PIN PIN_B1
#define CORE_OC1B_PIN PIN_B4
/* Note: By default, CORE_OC1A_PIN is not used for PWM. It overlaps with
CORE_OC0B_PIN. CORE_OC0B_PIN was used because it supports phase-correct PWM.
There is a build option in "core_build_options.h" to determine which channel
to use */
#define CORE_PWM0_PIN CORE_OC0A_PIN
#define CORE_PWM0_TIMER 0
#define CORE_PWM0_CHANNEL A
#if FAVOR_PHASE_CORRECT_PWM
#define CORE_PWM1_PIN CORE_OC0B_PIN
#define CORE_PWM1_TIMER 0
#define CORE_PWM1_CHANNEL B
#else
#define CORE_PWM1_PIN CORE_OC1A_PIN
#define CORE_PWM1_TIMER 1
#define CORE_PWM1_CHANNEL A
#endif
#define CORE_PWM2_PIN CORE_OC1B_PIN
#define CORE_PWM2_TIMER 1
#define CORE_PWM2_CHANNEL B
#define CORE_PWM_COUNT (3)
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
#include <WProgram.h>
int main(void)
{
init();
setup();
for (;;)
loop();
return 0;
}

View File

@ -0,0 +1,18 @@
#include <new.h>
void * operator new(size_t size)
{
return malloc(size);
}
void operator delete(void * ptr)
{
free(ptr);
}
int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);};
void __cxa_guard_release (__guard *g) {*(char *)g = 1;};
void __cxa_guard_abort (__guard *) {};
void __cxa_pure_virtual(void) {};

View File

@ -0,0 +1,22 @@
/* Header to define new/delete operators as they aren't provided by avr-gcc by default
Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453
*/
#ifndef NEW_H
#define NEW_H
#include <stdlib.h>
void * operator new(size_t size);
void operator delete(void * ptr);
__extension__ typedef int __guard __attribute__((mode (__DI__)));
extern "C" int __cxa_guard_acquire(__guard *);
extern "C" void __cxa_guard_release (__guard *);
extern "C" void __cxa_guard_abort (__guard *);
extern "C" void __cxa_pure_virtual(void);
#endif

View File

@ -0,0 +1,321 @@
/*
pins_arduino.c - pin definitions for the Arduino board
Part of Arduino / Wiring Lite
Copyright (c) 2005 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: pins_arduino.c 565 2009-03-25 10:50:00Z dmellis $
Modified 28-08-2009 for attiny84 R.Wiersma
Modified 09-10-2009 for attiny45 A.Saporetti
Modified for Atmel ATTiny2313 mcu by René Bohne
Corrected 17-05-2010 for ATtiny84 B.Cook ...
The default analog_reference leaves chip pin 13 (digital pin 10; PA0)
unconnected. So the pin can be set to a non-floating state and so the
pin can be used as another digital pin, support for digital pin 10 was
added.
*/
#include <avr/io.h>
#include "pins_arduino.h"
#include "wiring_private.h"
#if defined( __AVR_ATtinyX313__ )
// On the Arduino board, digital pins are also used
// for the analog output (software PWM). Analog input
// pins are a separate set.
// ATMEL ATTINY2313
//
// +-\/-+
// (D 17) PA2 1| |29 VCC
// RX (D 0) PD0 2| |19 PB7 (D 16)
// TX (D 1) PD1 3| |18 PB6 (D 15)
// (D 2) PA1 4| |17 PB5 (D 14)
// (D 3) PA0 5| |16 PB4 (D 13)*
// INT0 (D 4) PD2 6| |15 PB3 (D 12)*
// INT1 (D 5) PD3 7| |14 PB2 (D 11)*
// (D 6) PD4 8| |13 PB1 (D 10)
// *(D 7) PD5 9| |12 PB0 (D 9)
// GND 10| |11 PD6 (D 8)
// +----+
//
// * indicates PWM port
// these arrays map port names (e.g. port B) to the
// appropriate addresses for various functions (e.g. reading
// and writing)
const uint8_t PROGMEM port_to_mode_PGM[] =
{
NOT_A_PORT,
&DDRA,
&DDRB,
NOT_A_PORT,
&DDRD,
};
const uint8_t PROGMEM port_to_output_PGM[] =
{
NOT_A_PORT,
&PORTA,
&PORTB,
NOT_A_PORT,
&PORTD,
};
const uint8_t PROGMEM port_to_input_PGM[] =
{
NOT_A_PORT,
&PINA,
&PINB,
NOT_A_PORT,
&PIND,
};
const uint8_t PROGMEM digital_pin_to_port_PGM[] =
{
PORT_D_ID, /* 0 */
PORT_D_ID,
PORT_A_ID,
PORT_A_ID,
PORT_D_ID,
PORT_D_ID,
PORT_D_ID,
PORT_D_ID,
PORT_D_ID, /* 8 */
PORT_B_ID,
PORT_B_ID,
PORT_B_ID,
PORT_B_ID,
PORT_B_ID,
PORT_B_ID, /* 14 */
PORT_B_ID,
PORT_B_ID,
PORT_A_ID,
};
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] =
{
_BV(0), /* 0 */
_BV(1),
_BV(1),
_BV(0),
_BV(2),
_BV(3),
_BV(4),
_BV(5),
_BV(6), /* 8 */
_BV(0),
_BV(1),
_BV(2),
_BV(3),
_BV(4),
_BV(5), /* 14 */
_BV(6),
_BV(7),
_BV(2),
};
const uint8_t PROGMEM digital_pin_to_timer_PGM[] =
{
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
TIMER0B,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
TIMER0A,
TIMER1A,
TIMER1B,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
};
#endif
#if defined( __AVR_ATtinyX4__ )
// ATMEL ATTINY84 / ARDUINO
//
// +-\/-+
// VCC 1| |14 GND
// (D 0) PB0 2| |13 AREF (D 10)
// (D 1) PB1 3| |12 PA1 (D 9)
// PB3 4| |11 PA2 (D 8)
// PWM INT0 (D 2) PB2 5| |10 PA3 (D 7)
// PWM (D 3) PA7 6| |9 PA4 (D 6)
// PWM (D 4) PA6 7| |8 PA5 (D 5) PWM
// +----+
// these arrays map port names (e.g. port B) to the
// appropriate addresses for various functions (e.g. reading
// and writing)
const uint8_t PROGMEM port_to_mode_PGM[] =
{
NOT_A_PORT,
&DDRA,
&DDRB,
};
const uint8_t PROGMEM port_to_output_PGM[] =
{
NOT_A_PORT,
&PORTA,
&PORTB,
};
const uint8_t PROGMEM port_to_input_PGM[] =
{
NOT_A_PORT,
&PINA,
&PINB,
};
const uint8_t PROGMEM port_to_pcmask_PGM[] =
{
NOT_A_PORT,
&PCMSK0,
&PCMSK1,
};
const uint8_t PROGMEM digital_pin_to_port_PGM[] =
{
PORT_B_ID, /* 0 */
PORT_B_ID,
PORT_B_ID,
PORT_A_ID,
PORT_A_ID,
PORT_A_ID,
PORT_A_ID,
PORT_A_ID,
PORT_A_ID, /* 8 */
PORT_A_ID,
PORT_A_ID,
};
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] =
{
_BV(0), /* 0, port B */
_BV(1),
_BV(2),
_BV(7), /* 3 port B */
_BV(6),
_BV(5),
_BV(4),
_BV(3),
_BV(2),
_BV(1),
_BV(0),
};
const uint8_t PROGMEM digital_pin_to_timer_PGM[] =
{
NOT_ON_TIMER,
NOT_ON_TIMER,
TIMER0A, /* OC0A */
TIMER0B, /* OC0B */
TIMER1A, /* OC1A */
TIMER1B, /* OC1B */
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
};
#endif
#if defined( __AVR_ATtinyX5__ )
// ATMEL ATTINY45 / ARDUINO
//
// +-\/-+
// Ain0 (D 5) PB5 1| |8 VCC
// Ain3 (D 3) PB3 2| |7 PB2 (D 2) INT0 Ain1
// Ain2 (D 4) PB4 3| |6 PB1 (D 1) pwm1
// GND 4| |5 PB0 (D 0) pwm0
// +----+
// these arrays map port names (e.g. port B) to the
// appropriate addresses for various functions (e.g. reading
// and writing) tiny45 only port B
const uint8_t PROGMEM port_to_mode_PGM[] =
{
NOT_A_PORT,
&DDRB,
};
const uint8_t PROGMEM port_to_output_PGM[] =
{
NOT_A_PORT,
&PORTB,
};
const uint8_t PROGMEM port_to_input_PGM[] =
{
NOT_A_PIN,
&PINB,
};
const uint8_t PROGMEM digital_pin_to_port_PGM[] =
{
PORT_B_ID, /* 0 */
PORT_B_ID,
PORT_B_ID,
PORT_B_ID,
PORT_B_ID,
PORT_B_ID, /* 5 */
};
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] =
{
_BV(0), /* 0, port B */
_BV(1),
_BV(2),
_BV(3), /* 3 port B */
_BV(4),
_BV(5),
};
const uint8_t PROGMEM digital_pin_to_timer_PGM[] =
{
TIMER0A, /* OC0A */
TIMER1A, /* OC1A? */
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
NOT_ON_TIMER,
};
#endif

View File

@ -0,0 +1,115 @@
/*
pins_arduino.h - Pin definition functions for Arduino
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2007 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
Modified 28-08-2009 for attiny84 R.Wiersma
Modified 14-10-2009 for attiny45 Saposoft
*/
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <avr/pgmspace.h>
#include "core_build_options.h"
#if defined( __AVR_ATtinyX313__ )
#define PORT_A_ID 1
#define PORT_B_ID 2
#define PORT_D_ID 4
#endif
#if defined( __AVR_ATtinyX4__ )
#define PORT_A_ID 1
#define PORT_B_ID 2
#endif
#if defined( __AVR_ATtinyX5__ )
#define PORT_B_ID 1
#endif
#define NOT_A_PIN 0
#define NOT_A_PORT 0
#define NOT_ON_TIMER 0
#define TIMER0A 1
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
//changed it to uint16_t to uint8_t
extern const uint8_t PROGMEM port_to_mode_PGM[];
extern const uint8_t PROGMEM port_to_input_PGM[];
extern const uint8_t PROGMEM port_to_output_PGM[];
extern const uint8_t PROGMEM port_to_pcmask_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_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.
// This comes from the pins_*.c file for the active board configuration.
//
// These perform slightly better as macros compared to inline functions
//
#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 digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
#define analogInPinToBit(P) (P)
// in the following lines modified pgm_read_word in pgm_read_byte, word doesn't work on attiny45
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_output_PGM + (P))) )
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_input_PGM + (P))) )
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_mode_PGM + (P))) )
#define portPcMaskRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_pcmask_PGM + (P))) )
#if defined(__AVR_ATtinyX5__)
#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 5) ? (&GIMSK) : ((uint8_t *)NULL))
#define digitalPinToPCICRbit(p) (PCIE)
#define digitalPinToPCMSK(p) (((p) >= 0 && (p) <= 5) ? (&PCMSK) : ((uint8_t *)NULL))
#define digitalPinToPCMSKbit(p) (p)
#endif
#if defined(__AVR_ATtinyX4__)
#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 10) ? (&GIMSK) : ((uint8_t *)NULL))
#define digitalPinToPCICRbit(p) (((p) <= 2) ? PCIE1 : PCIE0)
#define digitalPinToPCMSK(p) (((p) <= 2) ? (&PCMSK1) : (((p) <= 10) ? (&PCMSK0) : ((uint8_t *)NULL)))
#define digitalPinToPCMSKbit(p) (((p) <= 2) ? (p) : (10 - (p)))
#endif
#if defined(__AVR_ATtiny4313__)
#define digitalPinToPCX(p,s1,s2,s3,s4,s5) \
(((p) >= 0) \
? (((p) <= 1) ? (s1) /* 0 - 1 ==> D0 - D1 */ \
: (((p) <= 3) ? (s2) /* 2 - 3 ==> A1 - A0 */ \
: (((p) <= 8) ? (s3) /* 4 - 8 ==> D2 - D6 */ \
: (((p) <= 16) ? (s4) /* 9 - 16 ==> B0 - B7 */ \
: (s5))))) \
: (s5))
// s1 D s2 A s3 D s4 B
#define digitalPinToPCICR(p) digitalPinToPCX( p, &GIMSK, &GIMSK, &GIMSK, &GIMSK, NULL )
#define digitalPinToPCICRbit(p) digitalPinToPCX( p, PCIE2, PCIE1, PCIE2, PCIE0, 0 )
#define digitalPinToPCMSK(p) digitalPinToPCX( p, &PCMSK2, &PCMSK1, &PCMSK2, &PCMSK0, NULL )
#define digitalPinToPCMSKbit(p) digitalPinToPCX( p, p, 3-p, p-2, p-9, 0 )
#endif
#endif

View File

@ -0,0 +1,366 @@
/*
wiring.c - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 970 2010-05-25 20:16:15Z dmellis $
Modified 28-08-2009 for attiny84 R.Wiersma
Modified 14-10-2009 for attiny45 Saposoft
Modified 20-11-2010 - B.Cook - Rewritten to use the various Veneers.
*/
#include "core_build_options.h"
#include "core_adc.h"
#include "core_timers.h"
#include "wiring_private.h"
#include "ToneTimer.h"
#if F_CPU != 16500000L
#include <avr/boot.h>
#endif
#define millistimer_(t) TIMER_PASTE_A( timer, TIMER_TO_USE_FOR_MILLIS, t )
#define MillisTimer_(f) TIMER_PASTE_A( Timer, TIMER_TO_USE_FOR_MILLIS, f )
#define MILLISTIMER_(c) TIMER_PASTE_A( TIMER, TIMER_TO_USE_FOR_MILLIS, c )
#define MillisTimer_SetToPowerup MillisTimer_(SetToPowerup)
#define MillisTimer_SetWaveformGenerationMode MillisTimer_(SetWaveformGenerationMode)
#define MillisTimer_GetCount MillisTimer_(GetCount)
#define MillisTimer_IsOverflowSet MillisTimer_(IsOverflowSet)
#define MillisTimer_ClockSelect MillisTimer_(ClockSelect)
#define MillisTimer_EnableOverflowInterrupt MillisTimer_(EnableOverflowInterrupt)
#define MILLISTIMER_OVF_vect MILLISTIMER_(OVF_vect)
#define MS_TIMER_TICK_EVERY_X_CYCLES 64 /* Shall be a within 1, 8, 64, 256 or 1024. (default = 64) If set to 1, HW PWM is around 64.5KHz@16.5MHz with Digispark */
#if F_CPU >= 3000000L
#if !defined(MS_TIMER_TICK_EVERY_X_CYCLES)
#define MillisTimer_Prescale_Index MillisTimer_(Prescale_Value_64)
#define MillisTimer_Prescale_Value (64)
#define ToneTimer_Prescale_Index ToneTimer_(Prescale_Value_64)
#define ToneTimer_Prescale_Value (64)
#else
#define Prescaler_Value(Val) PRESCALER_VALUE(Val)
#define PRESCALER_VALUE(Val) Prescale_Value_##Val
#define MillisTimer_Prescale_Index MillisTimer_(Prescaler_Value(MS_TIMER_TICK_EVERY_X_CYCLES))
#define MillisTimer_Prescale_Value (MS_TIMER_TICK_EVERY_X_CYCLES)
#define ToneTimer_Prescale_Index ToneTimer_(Prescaler_Value(MS_TIMER_TICK_EVERY_X_CYCLES))
#define ToneTimer_Prescale_Value (MS_TIMER_TICK_EVERY_X_CYCLES)
#endif
#else
#define MillisTimer_Prescale_Index MillisTimer_(Prescale_Value_8)
#define MillisTimer_Prescale_Value (8)
#define ToneTimer_Prescale_Index ToneTimer_(Prescale_Value_8)
#define ToneTimer_Prescale_Value (8)
#endif
// the prescaler is set so that the millis timer ticks every MillisTimer_Prescale_Value (64) clock cycles, and the
// the overflow handler is called every 256 ticks.
#define MICROSECONDS_PER_MILLIS_OVERFLOW (clockCyclesToMicroseconds(MillisTimer_Prescale_Value * 256))
// the whole number of milliseconds per millis timer overflow
#define MILLIS_INC (MICROSECONDS_PER_MILLIS_OVERFLOW / 1000)
// the fractional number of milliseconds per millis timer overflow. we shift right
// by three to fit these numbers into a byte. (for the clock speeds we care
// about - 8 and 16 MHz - this doesn't lose precision.)
#define FRACT_INC ((MICROSECONDS_PER_MILLIS_OVERFLOW % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)
volatile unsigned long millis_timer_overflow_count = 0;
volatile unsigned long millis_timer_millis = 0;
static unsigned char millis_timer_fract = 0;
// bluebie changed isr to noblock so it wouldn't mess up USB libraries
ISR(MILLISTIMER_OVF_vect, ISR_NOBLOCK)
{
// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
unsigned long m = millis_timer_millis;
unsigned char f = millis_timer_fract;
/* rmv: The code below generates considerably less code (emtpy Sketch is 326 versus 304)...
m += MILLIS_INC;
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
m += 1;
}
...rmv */
f += FRACT_INC;
if (f >= FRACT_MAX)
{
f -= FRACT_MAX;
m = m + MILLIS_INC + 1;
}
else
{
m += MILLIS_INC;
}
millis_timer_fract = f;
millis_timer_millis = m;
millis_timer_overflow_count++;
}
unsigned long millis()
{
unsigned long m;
uint8_t oldSREG = SREG;
// disable interrupts while we read millis_timer_millis or we might get an
// inconsistent value (e.g. in the middle of a write to millis_timer_millis)
cli();
m = millis_timer_millis;
SREG = oldSREG;
return m;
}
unsigned long micros()
{
unsigned long m;
uint8_t oldSREG = SREG, t;
cli();
m = millis_timer_overflow_count;
t = MillisTimer_GetCount();
if (MillisTimer_IsOverflowSet() && (t < 255))
m++;
SREG = oldSREG;
#if (MillisTimer_Prescale_Value >= clockCyclesPerMicrosecond())
return ((m << 8) + t) * (MillisTimer_Prescale_Value / clockCyclesPerMicrosecond());
#else
return ((m << 8) + t) / (clockCyclesPerMicrosecond() / MillisTimer_Prescale_Value);
#endif
}
void delay(unsigned long ms)
{
uint16_t start = (uint16_t)micros();
while (ms > 0) {
if (((uint16_t)micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}
#if F_CPU == 16500000L
// optimised delay loop from Bluebie contributed to Digispark project
// deals accurately with half-mhz clock speed, but can only delay in increments of 2us rounded down
// this loop has been tuned empirically with an oscilloscope and works in avr-gcc 4.5.1
void delayMicroseconds(unsigned int us){
us &= ((unsigned int) 0) - ((unsigned int) 2); // remove least signifficant bit
while (us > 1) {
// 16 nops
asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
// 11 nops
asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");
asm("NOP");asm("NOP");asm("NOP");
us -= 2;
}
}
#else
/* Improved delayMicroseconds function
* Copyright (c) 2011, Paul Stoffregen, paul at pjrc dot com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// modified by Bluebie in 2013 for Digispark project
// #include <stdint.h>
// #include <avr/io.h>
void delayMicroseconds(uint16_t usec) {
asm volatile(
#if F_CPU == 16000000L
"sbiw %A0, 2" "\n\t" // 2
"brcs L_%=_end" "\n\t" // 1
"breq L_%=_end" "\n\t" // 1
"lsl %A0" "\n\t" // 1
"rol %B0" "\n\t" // 1
"lsl %A0" "\n\t" // 1
"rol %B0" "\n\t" // 1 overhead: (8)/4 = 2us
#elif F_CPU == 8000000L
"sbiw %A0, 3" "\n\t" // 2
"brcs L_%=_end" "\n\t" // 1
"breq L_%=_end" "\n\t" // 1
"lsl %A0" "\n\t" // 1
"rol %B0" "\n\t" // 1 overhead: (6)/2 = 3 us
#elif F_CPU == 4000000L
"sbiw %A0, 4" "\n\t" // 2
"brcs L_%=_end" "\n\t" // 1
"breq L_%=_end" "\n\t" // 1 overhead: (4) = 4 us
#elif F_CPU == 2000000L
"sbiw %A0, 12" "\n\t" // 2
"brcs L_%=_end" "\n\t" // 1
"breq L_%=_end" "\n\t" // 1
"lsr %B0" "\n\t" // 1
"ror %A0" "\n\t" // 1 overhead: (6)*2 = 12 us
#elif F_CPU == 1000000L
"sbiw %A0, 32" "\n\t" // 2
"brcs L_%=_end" "\n\t" // 1
"breq L_%=_end" "\n\t" // 1
"lsr %B0" "\n\t" // 1
"ror %A0" "\n\t" // 1
"lsr %B0" "\n\t" // 1
"ror %A0" "\n\t" // 1 overhead: (8)*4 = 32 us
#endif
"L_%=_loop:"
"sbiw %A0, 1" "\n\t" // 2
"brne L_%=_loop" "\n\t" // 2
"L_%=_end:"
: "+w" (usec)
: "0" (usec)
);
}
#endif
static void initToneTimerInternal(void)
{
// Stop the clock while we make changes
ToneTimer_ClockSelect( ToneTimer_(Stopped) );
// Set the timer to phase-correct PWM
#if defined( TONETIMER_SUPPORTS_PHASE_CORRECT_PWM ) && TONETIMER_SUPPORTS_PHASE_CORRECT_PWM
ToneTimer_SetWaveformGenerationMode( ToneTimer_(Phase_Correct_PWM_FF) );
#else
ToneTimer_SetWaveformGenerationMode( ToneTimer_(Fast_PWM_FF) );
#endif
// Timer is processor clock divided by ToneTimer_Prescale_Index (64)
ToneTimer_ClockSelect( ToneTimer_Prescale_Index );
}
void initToneTimer(void)
{
// Ensure the timer is in the same state as power-up
ToneTimer_SetToPowerup();
#if defined( INITIALIZE_SECONDARY_TIMERS ) && INITIALIZE_SECONDARY_TIMERS
// Prepare the timer for PWM
initToneTimerInternal();
#endif
}
#if F_CPU != 16500000L
// used to detect bootloader applying calibration in init
byte read_factory_calibration(void)
{
byte SIGRD = 5; // for some reason this isn't defined...
byte value = boot_signature_byte_get(1);
return value;
}
#endif
void init(void)
{
// clock calibration stuff
// recalibrate clock if it was calibrated by bootloader (like micronucleus)
#if F_CPU != 16500000L
if (OSCCAL != read_factory_calibration()) {
// adjust the calibration down from 16.5mhz to 16.0mhz
if (OSCCAL >= 128) {
// maybe 8 is better? oh well - only about 0.3% out anyway
OSCCAL -= 7;
} else {
OSCCAL -= 5;
}
}
#endif
// TODO: detect if fuses set to PLL, regular internal oscillator or external and change behaviour in this next section...
#if F_CPU < 16000000L
cli();
CLKPR = 0b10000000;
#if F_CPU == 8000000L
CLKPR = 1; // div 2
#elif F_CPU == 4000000L
CLKPR = 2 // div 4
#elif F_CPU == 2000000L
CLKPR = 3; // div 8
#elif F_CPU == 1000000L
CLKPR = 4; // div 16
#elif F_CPU == 500000L
CLKPR = 5; // div 32 = 500khz
#elif F_CPU == 250000L
CLKPR = 6; // div 64 = 250khz
#elif F_CPU == 125000L
CLKPR = 7; // div 128 = 125khz cpu clock
#else
#warning "Cannot prescale chip to specified F_CPU speed"
#endif
#endif
// this needs to be called before setup() or some functions won't work there
sei();
// In case the bootloader left our millis timer in a bad way
#if defined( HAVE_BOOTLOADER ) && HAVE_BOOTLOADER
MillisTimer_SetToPowerup();
#endif
// Use the Millis Timer for fast PWM
MillisTimer_SetWaveformGenerationMode( MillisTimer_(Fast_PWM_FF) );
// Millis timer is always processor clock divided by MillisTimer_Prescale_Value (64)
MillisTimer_ClockSelect( MillisTimer_Prescale_Index );
// Enable the overlow interrupt (this is the basic system tic-toc for millis)
MillisTimer_EnableOverflowInterrupt();
// Initialize the timer used for Tone
#if defined( INITIALIZE_SECONDARY_TIMERS ) && INITIALIZE_SECONDARY_TIMERS
initToneTimerInternal();
#endif
// Initialize the ADC
#if defined( INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER ) && INITIALIZE_ANALOG_TO_DIGITAL_CONVERTER
ADC_PrescalerSelect( ADC_ARDUINO_PRESCALER );
ADC_Enable();
#endif
}

View File

@ -0,0 +1,194 @@
/*
wiring.h - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.h 1073 2010-08-17 21:50:41Z dmellis $
Modified 28-08-2009 for attiny84 R.Wiersma
Modified 14-108-2009 for attiny45 Saposoft
*/
#ifndef Wiring_h
#define Wiring_h
#include <avr/io.h>
#include <stdlib.h>
#include "binary.h"
#include "core_build_options.h"
#ifdef __cplusplus
extern "C"{
#endif
#define HIGH 0x1
#define LOW 0x0
#define INPUT 0x0
#define OUTPUT 0x1
#define true 0x1
#define false 0x0
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
#define SERIAL 0x0
#define DISPLAY 0x1
#define LSBFIRST 0
#define MSBFIRST 1
#define CHANGE 1
#define FALLING 2
#define RISING 3
/* rmv or fix
#if defined(__AVR_ATmega1280__)
#define INTERNAL1V1 2
#define INTERNAL2V56 3
#else
#define INTERNAL 3
#endif
#define DEFAULT 1
#define EXTERNAL 0
*/
/* rmv
analogReference constants for ATmega168. These are NOT correct for the ATtiny84 nor for the ATtiny85. The correct values are below.
// Internal 1.1V Voltage Reference with external capacitor at AREF pin
#define INTERNAL 3
// AVCC with external capacitor at AREF pin
#define DEFAULT 1
// AREF, Internal Vref turned off
#define EXTERNAL 0
*/
#if defined( __AVR_ATtinyX313__ )
#define DEFAULT (0)
#elif defined( __AVR_ATtinyX4__ )
// VCC used as analog reference, disconnected from PA0 (AREF)
#define DEFAULT (0)
// External voltage reference at PA0 (AREF) pin, internal reference turned off
#define EXTERNAL (1)
// Internal 1.1V voltage reference
#define INTERNAL (2)
#elif defined( __AVR_ATtinyX5__ )
// X 0 0 VCC used as Voltage Reference, disconnected from PB0 (AREF).
#define DEFAULT (0)
// X 0 1 External Voltage Reference at PB0 (AREF) pin, Internal Voltage Reference turned off.
#define EXTERNAL (1)
// 0 1 0 Internal 1.1V Voltage Reference.
#define INTERNAL (2)
#define INTERNAL1V1 INTERNAL
// 1 1 1 Internal 2.56V Voltage Reference with external bypass capacitor at PB0 (AREF) pin(1).
#define INTERNAL2V56 (7)
// An alternative for INTERNAL2V56 is (6) ...
// 1 1 0 Internal 2.56V Voltage Reference without external bypass capacitor, disconnected from PB0 (AREF)(1).
#endif
// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#if __AVR_LIBC_VERSION__ < 10701UL
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#endif
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))
#define interrupts() sei()
#define noInterrupts() cli()
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
typedef unsigned int word;
#define bit(b) (1UL << (b))
typedef uint8_t boolean;
typedef uint8_t byte;
void initToneTimer(void);
void init(void);
void pinMode(uint8_t, uint8_t);
void digitalWrite(uint8_t, uint8_t);
int digitalRead(uint8_t);
int analogRead(uint8_t);
void analogReference(uint8_t mode);
void analogWrite(uint8_t, int);
unsigned long millis(void);
unsigned long micros(void);
void delay(unsigned long);
void delayMicroseconds(unsigned int us);
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
void attachInterrupt(uint8_t, void (*)(void), int mode);
void detachInterrupt(uint8_t);
void setup(void);
void loop(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

View File

@ -0,0 +1,140 @@
/*
wiring_analog.c - analog input and output
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
Modified 28-08-2009 for attiny84 R.Wiersma
Modified 14-10-2009 for attiny45 Saposoft
Corrected 17-05-2010 for ATtiny84 B.Cook
*/
#include "wiring_private.h"
#include "pins_arduino.h"
#include "core_adc.h"
#include "core_pins.h"
#include "core_timers.h"
#include "PwmTimer.h"
uint8_t analog_reference = DEFAULT;
void analogReference(uint8_t mode)
{
// can't actually set the register here because the default setting
// will connect AVCC and the AREF pin, which would cause a short if
// there's something connected to AREF.
// fix? Validate the mode?
analog_reference = mode;
}
int analogRead(uint8_t pin)
{
#if defined( CORE_ANALOG_FIRST )
if ( pin >= CORE_ANALOG_FIRST ) pin -= CORE_ANALOG_FIRST; // allow for channel or pin numbers
#endif
// fix? Validate pin?
ADC_SetVoltageReference( analog_reference );
ADC_SetInputChannel( pin );
ADC_StartConversion();
while( ADC_ConversionInProgress() );
return( ADC_GetDataRegister() );
}
// Right now, PWM output only works on the pins with
// hardware support. These are defined in the appropriate
// 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
{
#if CORE_PWM_COUNT >= 1
if ( pin == CORE_PWM0_PIN )
{
Pwm0_SetCompareOutputMode( Pwm0_Clear );
Pwm0_SetOutputCompareMatch( val );
}
else
#endif
#if CORE_PWM_COUNT >= 2
if ( pin == CORE_PWM1_PIN )
{
Pwm1_SetCompareOutputMode( Pwm1_Clear );
Pwm1_SetOutputCompareMatch( val );
}
else
#endif
#if CORE_PWM_COUNT >= 3
if ( pin == CORE_PWM2_PIN )
{
Pwm2_SetCompareOutputMode( Pwm2_Clear );
Pwm2_SetOutputCompareMatch( val );
}
else
#endif
#if CORE_PWM_COUNT >= 4
if ( pin == CORE_PWM3_PIN )
{
Pwm3_SetCompareOutputMode( Pwm3_Clear );
Pwm3_SetOutputCompareMatch( val );
}
else
#endif
#if CORE_PWM_COUNT >= 5
#error Only 4 PWM pins are supported. Add more conditions.
#endif
{
if (val < 128)
{
digitalWrite(pin, LOW);
}
else
{
digitalWrite(pin, HIGH);
}
}
}
}

View File

@ -0,0 +1,148 @@
/*
wiring_digital.c - digital input and output functions
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
Modified 28-08-2009 for attiny84 R.Wiersma
Modified 14-10-2009 for attiny45 Saposoft
*/
#include "wiring_private.h"
#include "pins_arduino.h"
#include "core_pins.h"
#include "core_timers.h"
#include "PwmTimer.h"
void pinMode(uint8_t pin, uint8_t mode)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *reg;
if (port == NOT_A_PIN) return;
// JWS: can I let the optimizer do this?
reg = portModeRegister(port);
if (mode == INPUT) {
uint8_t oldSREG = SREG;
cli();
*reg &= ~bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
cli();
*reg |= bit;
SREG = oldSREG;
}
}
// Forcing this inline keeps the callers from having to push their own stuff
// on the stack. It is a good performance win and only takes 1 more byte per
// user than calling. (It will take more bytes on the 168.)
//
// But shouldn't this be moved into pinMode? Seems silly to check and do on
// each digitalread or write.
//
__attribute__((always_inline)) static inline void turnOffPWM( uint8_t pin )
{
#if CORE_PWM_COUNT >= 1
if ( pin == CORE_PWM0_PIN )
{
Pwm0_SetCompareOutputMode( Pwm0_Disconnected );
}
else
#endif
#if CORE_PWM_COUNT >= 2
if ( pin == CORE_PWM1_PIN )
{
Pwm1_SetCompareOutputMode( Pwm1_Disconnected );
}
else
#endif
#if CORE_PWM_COUNT >= 3
if ( pin == CORE_PWM2_PIN )
{
Pwm2_SetCompareOutputMode( Pwm2_Disconnected );
}
else
#endif
#if CORE_PWM_COUNT >= 4
if ( pin == CORE_PWM3_PIN )
{
Pwm3_SetCompareOutputMode( Pwm3_Disconnected );
}
else
#endif
#if CORE_PWM_COUNT >= 5
#error Only 4 PWM pins are supported. Add more conditions.
#endif
{
}
}
void digitalWrite(uint8_t pin, uint8_t val)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *out;
if (port == NOT_A_PIN) return;
// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
turnOffPWM( pin );
out = portOutputRegister(port);
if (val == LOW) {
uint8_t oldSREG = SREG;
cli();
*out &= ~bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
cli();
*out |= bit;
SREG = oldSREG;
}
}
int digitalRead(uint8_t pin)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
if (port == NOT_A_PIN) return LOW;
// If the pin that support PWM output, we need to turn it off
// before getting a digital reading.
turnOffPWM( pin );
if (*portInputRegister(port) & bit) return HIGH;
return LOW;
}

View File

@ -0,0 +1,179 @@
/*
wiring_private.h - Internal header file.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.h 239 2007-01-12 17:58:39Z mellis $
Modified 28-08-2009 for attiny84 R.Wiersma
*/
#ifndef WiringPrivate_h
#define WiringPrivate_h
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#include <stdio.h>
#include <stdarg.h>
#include "wiring.h"
#ifdef __cplusplus
extern "C"{
#endif
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#if defined( EXT_INT0_vect )
#define EXTERNAL_INTERRUPT_0_vect EXT_INT0_vect
#elif defined( INT0_vect )
#define EXTERNAL_INTERRUPT_0_vect INT0_vect
#endif
#if defined( EXT_INT1_vect )
#define EXTERNAL_INTERRUPT_1_vect EXT_INT1_vect
#elif defined( INT1_vect )
#define EXTERNAL_INTERRUPT_1_vect INT1_vect
#endif
#if defined( EXT_INT2_vect )
#define EXTERNAL_INTERRUPT_2_vect EXT_INT2_vect
#elif defined( INT2_vect )
#define EXTERNAL_INTERRUPT_2_vect INT2_vect
#endif
#if defined( EXT_INT3_vect )
#define EXTERNAL_INTERRUPT_3_vect EXT_INT3_vect
#elif defined( INT3_vect )
#define EXTERNAL_INTERRUPT_3_vect INT3_vect
#endif
#if defined( EXT_INT4_vect )
#define EXTERNAL_INTERRUPT_4_vect EXT_INT4_vect
#elif defined( INT4_vect )
#define EXTERNAL_INTERRUPT_4_vect INT4_vect
#endif
#if defined( EXT_INT5_vect )
#define EXTERNAL_INTERRUPT_5_vect EXT_INT5_vect
#elif defined( INT5_vect )
#define EXTERNAL_INTERRUPT_5_vect INT5_vect
#endif
#if defined( EXT_INT6_vect )
#define EXTERNAL_INTERRUPT_6_vect EXT_INT6_vect
#elif defined( INT6_vect )
#define EXTERNAL_INTERRUPT_6_vect INT6_vect
#endif
#if defined( EXT_INT7_vect )
#define EXTERNAL_INTERRUPT_7_vect EXT_INT7_vect
#elif defined( INT7_vect )
#define EXTERNAL_INTERRUPT_7_vect INT7_vect
#endif
#if defined( EXT_INT8_vect )
#define EXTERNAL_INTERRUPT_8_vect EXT_INT8_vect
#elif defined( INT8_vect )
#define EXTERNAL_INTERRUPT_8_vect INT8_vect
#endif
#if defined( EXT_INT9_vect )
#define EXTERNAL_INTERRUPT_9_vect EXT_INT9_vect
#elif defined( INT9_vect )
#define EXTERNAL_INTERRUPT_9_vect INT9_vect
#endif
#if defined( EXTERNAL_INTERRUPT_9_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (10)
#elif defined( EXTERNAL_INTERRUPT_8_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (9)
#elif defined( EXTERNAL_INTERRUPT_7_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (8)
#elif defined( EXTERNAL_INTERRUPT_6_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (7)
#elif defined( EXTERNAL_INTERRUPT_5_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (6)
#elif defined( EXTERNAL_INTERRUPT_4_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (5)
#elif defined( EXTERNAL_INTERRUPT_3_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (4)
#elif defined( EXTERNAL_INTERRUPT_2_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (3)
#elif defined( EXTERNAL_INTERRUPT_1_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (2)
#elif defined( EXTERNAL_INTERRUPT_0_vect )
#define NUMBER_EXTERNAL_INTERRUPTS (1)
#else
#define NUMBER_EXTERNAL_INTERRUPTS (0)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 1
#define EXTERNAL_INTERRUPT_0 (0)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 2
#define EXTERNAL_INTERRUPT_1 (1)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 3
#define EXTERNAL_INTERRUPT_2 (2)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 4
#define EXTERNAL_INTERRUPT_3 (3)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 5
#define EXTERNAL_INTERRUPT_4 (4)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 6
#define EXTERNAL_INTERRUPT_5 (5)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 7
#define EXTERNAL_INTERRUPT_6 (6)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 8
#define EXTERNAL_INTERRUPT_7 (7)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 9
#define EXTERNAL_INTERRUPT_8 (8)
#endif
#if NUMBER_EXTERNAL_INTERRUPTS >= 10
#define EXTERNAL_INTERRUPT_9 (9)
#endif
typedef void (*voidFuncPtr)(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

View File

@ -0,0 +1,69 @@
/*
wiring_pulse.c - pulseIn() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
#include "pins_arduino.h"
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
* to 3 minutes in length, but must be called at least a few dozen microseconds
* before the start of the pulse. */
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
// cache the port and bit of the pin in order to speed up the
// pulse width measuring loop and achieve finer resolution. calling
// digitalRead() instead yields much coarser resolution.
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
uint8_t stateMask = (state ? bit : 0);
unsigned long width = 0; // keep initialization out of time critical area
// convert the timeout from microseconds to a number of times through
// the initial loop; it takes 16 clock cycles per iteration.
unsigned long numloops = 0;
unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
// wait for any previous pulse to end
while ((*portInputRegister(port) & bit) == stateMask)
if (numloops++ == maxloops)
return 0;
// wait for the pulse to start
while ((*portInputRegister(port) & bit) != stateMask)
if (numloops++ == maxloops)
return 0;
// wait for the pulse to stop
while ((*portInputRegister(port) & bit) == stateMask) {
if (numloops++ == maxloops)
return 0;
width++;
}
// convert the reading to microseconds. The loop has been determined
// to be 20 clock cycles long and have about 16 clocks between the edge
// and the start of the loop. There will be some error introduced by
// the interrupt handlers.
return clockCyclesToMicroseconds(width * 21 + 16);
}

View File

@ -0,0 +1,55 @@
/*
wiring_shift.c - shiftOut() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
uint8_t value = 0;
uint8_t i;
for (i = 0; i < 8; ++i) {
digitalWrite(clockPin, HIGH);
if (bitOrder == LSBFIRST)
value |= digitalRead(dataPin) << i;
else
value |= digitalRead(dataPin) << (7 - i);
digitalWrite(clockPin, LOW);
}
return value;
}
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
uint8_t i;
for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST)
digitalWrite(dataPin, !!(val & (1 << i)));
else
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
}
}

View File

@ -0,0 +1,937 @@
/*-------------------------------------------------------------------------
Arduino library to control a wide variety of WS2811- and WS2812-based RGB
LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips.
Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega
MCUs, with LEDs wired for RGB or GRB color order. 8 MHz MCUs provide
output on PORTB and PORTD, while 16 MHz chips can handle most output pins
(possible exception with upper PORT registers on the Arduino Mega).
Written by Phil Burgess / Paint Your Dragon for Adafruit Industries,
contributions by PJRC and other members of the open source community.
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing products
from Adafruit!
-------------------------------------------------------------------------
This file is part of the Adafruit NeoPixel library.
NeoPixel is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoPixel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#include "Adafruit_NeoPixel.h"
Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint8_t p, uint8_t t) : numLEDs(n), numBytes(n * 3), pin(p), pixels(NULL)
,type(t), brightness(0), endTime(0)
#ifdef __AVR__
,port(portOutputRegister(digitalPinToPort(p))),
pinMask(digitalPinToBitMask(p))
#endif
{
if((pixels = (uint8_t *)malloc(numBytes))) {
memset(pixels, 0, numBytes);
}
if(t & NEO_GRB) { // GRB vs RGB; might add others if needed
rOffset = 1;
gOffset = 0;
bOffset = 2;
} else if (t & NEO_BRG) {
rOffset = 1;
gOffset = 2;
bOffset = 0;
} else {
rOffset = 0;
gOffset = 1;
bOffset = 2;
}
}
Adafruit_NeoPixel::~Adafruit_NeoPixel() {
if(pixels) free(pixels);
pinMode(pin, INPUT);
}
void Adafruit_NeoPixel::begin(void) {
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
}
void Adafruit_NeoPixel::show(void) {
if(!pixels) return;
// Data latch = 50+ microsecond pause in the output stream. Rather than
// put a delay at the end of the function, the ending time is noted and
// the function will simply hold off (if needed) on issuing the
// subsequent round of data until the latch time has elapsed. This
// allows the mainline code to start generating the next frame of data
// rather than stalling for the latch.
while(!canShow());
// endTime is a private member (rather than global var) so that mutliple
// instances on different pins can be quickly issued in succession (each
// instance doesn't delay the next).
// In order to make this code runtime-configurable to work with any pin,
// SBI/CBI instructions are eschewed in favor of full PORT writes via the
// OUT or ST instructions. It relies on two facts: that peripheral
// functions (such as PWM) take precedence on output pins, so our PORT-
// wide writes won't interfere, and that interrupts are globally disabled
// while data is being issued to the LEDs, so no other code will be
// accessing the PORT. The code takes an initial 'snapshot' of the PORT
// state, computes 'pin high' and 'pin low' values, and writes these back
// to the PORT register as needed.
noInterrupts(); // Need 100% focus on instruction timing
#ifdef __AVR__
volatile uint16_t
i = numBytes; // Loop counter
volatile uint8_t
*ptr = pixels, // Pointer to next byte
b = *ptr++, // Current byte value
hi, // PORT w/output bit set high
lo; // PORT w/output bit set low
// Hand-tuned assembly code issues data to the LED drivers at a specific
// rate. There's separate code for different CPU speeds (8, 12, 16 MHz)
// for both the WS2811 (400 KHz) and WS2812 (800 KHz) drivers. The
// datastream timing for the LED drivers allows a little wiggle room each
// way (listed in the datasheets), so the conditions for compiling each
// case are set up for a range of frequencies rather than just the exact
// 8, 12 or 16 MHz values, permitting use with some close-but-not-spot-on
// devices (e.g. 16.5 MHz DigiSpark). The ranges were arrived at based
// on the datasheet figures and have not been extensively tested outside
// the canonical 8/12/16 MHz speeds; there's no guarantee these will work
// close to the extremes (or possibly they could be pushed further).
// Keep in mind only one CPU speed case actually gets compiled; the
// resulting program isn't as massive as it might look from source here.
// 8 MHz(ish) AVR ---------------------------------------------------------
#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL)
#ifdef NEO_KHZ400
if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream
#endif
volatile uint8_t n1, n2 = 0; // First, next bits out
// Squeezing an 800 KHz stream out of an 8 MHz chip requires code
// specific to each PORT register. At present this is only written
// to work with pins on PORTD or PORTB, the most likely use case --
// this covers all the pins on the Adafruit Flora and the bulk of
// digital pins on the Arduino Pro 8 MHz (keep in mind, this code
// doesn't even get compiled for 16 MHz boards like the Uno, Mega,
// Leonardo, etc., so don't bother extending this out of hand).
// Additional PORTs could be added if you really need them, just
// duplicate the else and loop and change the PORT. Each add'l
// PORT will require about 150(ish) bytes of program space.
// 10 instruction clocks per bit: HHxxxxxLLL
// OUT instructions: ^ ^ ^ (T=0,2,7)
#ifdef PORTD // PORTD isn't present on ATtiny85, etc.
if(port == &PORTD) {
hi = PORTD | pinMask;
lo = PORTD & ~pinMask;
n1 = lo;
if(b & 0x80) n1 = hi;
// Dirty trick: RJMPs proceeding to the next instruction are used
// to delay two clock cycles in one instruction word (rather than
// using two NOPs). This was necessary in order to squeeze the
// loop down to exactly 64 words -- the maximum possible for a
// relative branch.
asm volatile(
"headD:" "\n\t" // Clk Pseudocode
// Bit 7:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 6:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 5:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 4:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 3:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 2:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"rjmp .+0" "\n\t" // 2 nop nop
// Bit 1:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo
"out %[port] , %[n1]" "\n\t" // 1 PORT = n1
"rjmp .+0" "\n\t" // 2 nop nop
"sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01)
"mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet)
// Bit 0:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi
"mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo
"out %[port] , %[n2]" "\n\t" // 1 PORT = n2
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80)
"mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo
"brne headD" "\n" // 2 while(i) (Z flag set above)
: [byte] "+r" (b),
[n1] "+r" (n1),
[n2] "+r" (n2),
[count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTD)),
[ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo));
} else if(port == &PORTB) {
#endif // PORTD
// Same as above, just switched to PORTB and stripped of comments.
hi = PORTB | pinMask;
lo = PORTB & ~pinMask;
n1 = lo;
if(b & 0x80) n1 = hi;
asm volatile(
"headB:" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 6" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 5" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 4" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 3" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 2" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 1" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"rjmp .+0" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n2] , %[lo]" "\n\t"
"out %[port] , %[n1]" "\n\t"
"rjmp .+0" "\n\t"
"sbrc %[byte] , 0" "\n\t"
"mov %[n2] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"sbiw %[count], 1" "\n\t"
"out %[port] , %[hi]" "\n\t"
"mov %[n1] , %[lo]" "\n\t"
"out %[port] , %[n2]" "\n\t"
"ld %[byte] , %a[ptr]+" "\n\t"
"sbrc %[byte] , 7" "\n\t"
"mov %[n1] , %[hi]" "\n\t"
"out %[port] , %[lo]" "\n\t"
"brne headB" "\n"
: [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi),
[lo] "r" (lo));
#ifdef PORTD
} // endif PORTB
#endif
#ifdef NEO_KHZ400
} else { // end 800 KHz, do 400 KHz
// Timing is more relaxed; unrolling the inner loop for each bit is
// not necessary. Still using the peculiar RJMPs as 2X NOPs, not out
// of need but just to trim the code size down a little.
// This 400-KHz-datastream-on-8-MHz-CPU code is not quite identical
// to the 800-on-16 code later -- the hi/lo timing between WS2811 and
// WS2812 is not simply a 2:1 scale!
// 20 inst. clocks per bit: HHHHxxxxxxLLLLLLLLLL
// ST instructions: ^ ^ ^ (T=0,4,10)
volatile uint8_t next, bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile(
"head20:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7)
"dec %[bit]" "\n\t" // 1 bit-- (T = 8)
"breq nextbyte20" "\n\t" // 1-2 if(bit == 0)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12)
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
"rjmp .+0" "\n\t" // 2 nop nop (T = 16)
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
"rjmp head20" "\n\t" // 2 -> head20 (next bit out)
"nextbyte20:" "\n\t" // (T = 10)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12)
"nop" "\n\t" // 1 nop (T = 13)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 18)
"brne head20" "\n" // 2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [hi] "r" (hi),
[lo] "r" (lo),
[ptr] "e" (ptr));
}
#endif
// 12 MHz(ish) AVR --------------------------------------------------------
#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL)
#ifdef NEO_KHZ400
if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream
#endif
// In the 12 MHz case, an optimized 800 KHz datastream (no dead time
// between bytes) requires a PORT-specific loop similar to the 8 MHz
// code (but a little more relaxed in this case).
// 15 instruction clocks per bit: HHHHxxxxxxLLLLL
// OUT instructions: ^ ^ ^ (T=0,4,10)
volatile uint8_t next;
#ifdef PORTD
if(port == &PORTD) {
hi = PORTD | pinMask;
lo = PORTD & ~pinMask;
next = lo;
if(b & 0x80) next = hi;
// Don't "optimize" the OUT calls into the bitTime subroutine;
// we're exploiting the RCALL and RET as 3- and 4-cycle NOPs!
asm volatile(
"headD:" "\n\t" // (T = 0)
"out %[port], %[hi]" "\n\t" // (T = 1)
"rcall bitTimeD" "\n\t" // Bit 7 (T = 15)
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 6
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 5
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 4
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 3
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 2
"out %[port], %[hi]" "\n\t"
"rcall bitTimeD" "\n\t" // Bit 1
// Bit 0:
"out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1)
"rjmp .+0" "\n\t" // 2 nop nop (T = 3)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5)
"out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8)
"mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9)
"nop" "\n\t" // 1 (T = 10)
"out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 13)
"brne headD" "\n\t" // 2 if(i != 0) -> (next byte)
"rjmp doneD" "\n\t"
"bitTimeD:" "\n\t" // nop nop nop (T = 4)
"out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5)
"mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7)
"sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9)
"nop" "\n\t" // 1 (T = 10)
"out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11)
"ret" "\n\t" // 4 nop nop nop nop (T = 15)
"doneD:" "\n"
: [byte] "+r" (b),
[next] "+r" (next),
[count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTD)),
[ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo));
} else if(port == &PORTB) {
#endif // PORTD
hi = PORTB | pinMask;
lo = PORTB & ~pinMask;
next = lo;
if(b & 0x80) next = hi;
// Same as above, just set for PORTB & stripped of comments
asm volatile(
"headB:" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port], %[hi]" "\n\t"
"rcall bitTimeB" "\n\t"
"out %[port] , %[hi]" "\n\t"
"rjmp .+0" "\n\t"
"ld %[byte] , %a[ptr]+" "\n\t"
"out %[port] , %[next]" "\n\t"
"mov %[next] , %[lo]" "\n\t"
"sbrc %[byte] , 7" "\n\t"
"mov %[next] , %[hi]" "\n\t"
"nop" "\n\t"
"out %[port] , %[lo]" "\n\t"
"sbiw %[count], 1" "\n\t"
"brne headB" "\n\t"
"rjmp doneB" "\n\t"
"bitTimeB:" "\n\t"
"out %[port], %[next]" "\n\t"
"mov %[next], %[lo]" "\n\t"
"rol %[byte]" "\n\t"
"sbrc %[byte], 7" "\n\t"
"mov %[next], %[hi]" "\n\t"
"nop" "\n\t"
"out %[port], %[lo]" "\n\t"
"ret" "\n\t"
"doneB:" "\n"
: [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i)
: [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi),
[lo] "r" (lo));
#ifdef PORTD
}
#endif
#ifdef NEO_KHZ400
} else { // 400 KHz
// 30 instruction clocks per bit: HHHHHHxxxxxxxxxLLLLLLLLLLLLLLL
// ST instructions: ^ ^ ^ (T=0,6,15)
volatile uint8_t next, bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile(
"head30:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"rjmp .+0" "\n\t" // 2 nop nop (T = 6)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8)
"rjmp .+0" "\n\t" // 2 nop nop (T = 10)
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
"nop" "\n\t" // 1 nop (T = 15)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17)
"rjmp .+0" "\n\t" // 2 nop nop (T = 19)
"dec %[bit]" "\n\t" // 1 bit-- (T = 20)
"breq nextbyte30" "\n\t" // 1-2 if(bit == 0)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22)
"rjmp .+0" "\n\t" // 2 nop nop (T = 24)
"rjmp .+0" "\n\t" // 2 nop nop (T = 26)
"rjmp .+0" "\n\t" // 2 nop nop (T = 28)
"rjmp head30" "\n\t" // 2 -> head30 (next bit out)
"nextbyte30:" "\n\t" // (T = 22)
"nop" "\n\t" // 1 nop (T = 23)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 28)
"brne head30" "\n" // 1-2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [hi] "r" (hi),
[lo] "r" (lo),
[ptr] "e" (ptr));
}
#endif
// 16 MHz(ish) AVR --------------------------------------------------------
#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L)
#ifdef NEO_KHZ400
if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream
#endif
// WS2811 and WS2812 have different hi/lo duty cycles; this is
// similar but NOT an exact copy of the prior 400-on-8 code.
// 20 inst. clocks per bit: HHHHHxxxxxxxxLLLLLLL
// ST instructions: ^ ^ ^ (T=0,5,13)
volatile uint8_t next, bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile(
"head20:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128)
"mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"dec %[bit]" "\n\t" // 1 bit-- (T = 5)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8)
"breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10)
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
"nop" "\n\t" // 1 nop (T = 13)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15)
"nop" "\n\t" // 1 nop (T = 16)
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
"rjmp head20" "\n\t" // 2 -> head20 (next bit out)
"nextbyte20:" "\n\t" // (T = 10)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15)
"nop" "\n\t" // 1 nop (T = 16)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 18)
"brne head20" "\n" // 2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo));
#ifdef NEO_KHZ400
} else { // 400 KHz
// The 400 KHz clock on 16 MHz MCU is the most 'relaxed' version.
// 40 inst. clocks per bit: HHHHHHHHxxxxxxxxxxxxLLLLLLLLLLLLLLLLLLLL
// ST instructions: ^ ^ ^ (T=0,8,20)
volatile uint8_t next, bit;
hi = *port | pinMask;
lo = *port & ~pinMask;
next = lo;
bit = 8;
asm volatile(
"head40:" "\n\t" // Clk Pseudocode (T = 0)
"st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2)
"sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128)
"mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4)
"rjmp .+0" "\n\t" // 2 nop nop (T = 6)
"rjmp .+0" "\n\t" // 2 nop nop (T = 8)
"st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10)
"rjmp .+0" "\n\t" // 2 nop nop (T = 12)
"rjmp .+0" "\n\t" // 2 nop nop (T = 14)
"rjmp .+0" "\n\t" // 2 nop nop (T = 16)
"rjmp .+0" "\n\t" // 2 nop nop (T = 18)
"rjmp .+0" "\n\t" // 2 nop nop (T = 20)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22)
"nop" "\n\t" // 1 nop (T = 23)
"mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24)
"dec %[bit]" "\n\t" // 1 bit-- (T = 25)
"breq nextbyte40" "\n\t" // 1-2 if(bit == 0)
"rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27)
"nop" "\n\t" // 1 nop (T = 28)
"rjmp .+0" "\n\t" // 2 nop nop (T = 30)
"rjmp .+0" "\n\t" // 2 nop nop (T = 32)
"rjmp .+0" "\n\t" // 2 nop nop (T = 34)
"rjmp .+0" "\n\t" // 2 nop nop (T = 36)
"rjmp .+0" "\n\t" // 2 nop nop (T = 38)
"rjmp head40" "\n\t" // 2 -> head40 (next bit out)
"nextbyte40:" "\n\t" // (T = 27)
"ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28)
"ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30)
"rjmp .+0" "\n\t" // 2 nop nop (T = 32)
"st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34)
"rjmp .+0" "\n\t" // 2 nop nop (T = 36)
"sbiw %[count], 1" "\n\t" // 2 i-- (T = 38)
"brne head40" "\n" // 1-2 if(i != 0) -> (next byte)
: [port] "+e" (port),
[byte] "+r" (b),
[bit] "+r" (bit),
[next] "+r" (next),
[count] "+w" (i)
: [ptr] "e" (ptr),
[hi] "r" (hi),
[lo] "r" (lo));
}
#endif
#else
#error "CPU SPEED NOT SUPPORTED"
#endif
#elif defined(__arm__)
#if defined(__MK20DX128__) || defined(__MK20DX256__) // Teensy 3.0 & 3.1
#define CYCLES_800_T0H (F_CPU / 2500000)
#define CYCLES_800_T1H (F_CPU / 1250000)
#define CYCLES_800 (F_CPU / 800000)
#define CYCLES_400_T0H (F_CPU / 2000000)
#define CYCLES_400_T1H (F_CPU / 833333)
#define CYCLES_400 (F_CPU / 400000)
uint8_t *p = pixels,
*end = p + numBytes, pix, mask;
volatile uint8_t *set = portSetRegister(pin),
*clr = portClearRegister(pin);
uint32_t cyc;
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
#ifdef NEO_KHZ400
if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream
#endif
cyc = ARM_DWT_CYCCNT + CYCLES_800;
while(p < end) {
pix = *p++;
for(mask = 0x80; mask; mask >>= 1) {
while(ARM_DWT_CYCCNT - cyc < CYCLES_800);
cyc = ARM_DWT_CYCCNT;
*set = 1;
if(pix & mask) {
while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H);
} else {
while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H);
}
*clr = 1;
}
}
while(ARM_DWT_CYCCNT - cyc < CYCLES_800);
#ifdef NEO_KHZ400
} else { // 400 kHz bitstream
cyc = ARM_DWT_CYCCNT + CYCLES_400;
while(p < end) {
pix = *p++;
for(mask = 0x80; mask; mask >>= 1) {
while(ARM_DWT_CYCCNT - cyc < CYCLES_400);
cyc = ARM_DWT_CYCCNT;
*set = 1;
if(pix & mask) {
while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H);
} else {
while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H);
}
*clr = 1;
}
}
while(ARM_DWT_CYCCNT - cyc < CYCLES_400);
}
#endif
#else // Arduino Due
#define SCALE VARIANT_MCK / 2UL / 1000000UL
#define INST (2UL * F_CPU / VARIANT_MCK)
#define TIME_800_0 ((int)(0.40 * SCALE + 0.5) - (5 * INST))
#define TIME_800_1 ((int)(0.80 * SCALE + 0.5) - (5 * INST))
#define PERIOD_800 ((int)(1.25 * SCALE + 0.5) - (5 * INST))
#define TIME_400_0 ((int)(0.50 * SCALE + 0.5) - (5 * INST))
#define TIME_400_1 ((int)(1.20 * SCALE + 0.5) - (5 * INST))
#define PERIOD_400 ((int)(2.50 * SCALE + 0.5) - (5 * INST))
int pinMask, time0, time1, period, t;
Pio *port;
volatile WoReg *portSet, *portClear, *timeValue, *timeReset;
uint8_t *p, *end, pix, mask;
pmc_set_writeprotect(false);
pmc_enable_periph_clk((uint32_t)TC3_IRQn);
TC_Configure(TC1, 0,
TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1);
TC_Start(TC1, 0);
pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into
port = g_APinDescription[pin].pPort; // declarations above. Want to
portSet = &(port->PIO_SODR); // burn a few cycles after
portClear = &(port->PIO_CODR); // starting timer to minimize
timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'.
timeReset = &(TC1->TC_CHANNEL[0].TC_CCR);
p = pixels;
end = p + numBytes;
pix = *p++;
mask = 0x80;
#ifdef NEO_KHZ400
if((type & NEO_SPDMASK) == NEO_KHZ800) { // 800 KHz bitstream
#endif
time0 = TIME_800_0;
time1 = TIME_800_1;
period = PERIOD_800;
#ifdef NEO_KHZ400
} else { // 400 KHz bitstream
time0 = TIME_400_0;
time1 = TIME_400_1;
period = PERIOD_400;
}
#endif
for(t = time0;; t = time0) {
if(pix & mask) t = time1;
while(*timeValue < period);
*portSet = pinMask;
*timeReset = TC_CCR_CLKEN | TC_CCR_SWTRG;
while(*timeValue < t);
*portClear = pinMask;
if(!(mask >>= 1)) { // This 'inside-out' loop logic utilizes
if(p >= end) break; // idle time to minimize inter-byte delays.
pix = *p++;
mask = 0x80;
}
}
while(*timeValue < period); // Wait for last bit
TC_Stop(TC1, 0);
#endif // end Arduino Due
#endif // end Architecture select
interrupts();
endTime = micros(); // Save EOD time for latch on next call
}
// Set the output pin number
void Adafruit_NeoPixel::setPin(uint8_t p) {
pinMode(pin, INPUT);
pin = p;
pinMode(p, OUTPUT);
digitalWrite(p, LOW);
#ifdef __AVR__
port = portOutputRegister(digitalPinToPort(p));
pinMask = digitalPinToBitMask(p);
#endif
}
// Set pixel color from separate R,G,B components:
void Adafruit_NeoPixel::setPixelColor(
uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
if(n < numLEDs) {
if(brightness) { // See notes in setBrightness()
r = (r * brightness) >> 8;
g = (g * brightness) >> 8;
b = (b * brightness) >> 8;
}
uint8_t *p = &pixels[n * 3];
p[rOffset] = r;
p[gOffset] = g;
p[bOffset] = b;
}
}
// Set pixel color from 'packed' 32-bit RGB color:
void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) {
if(n < numLEDs) {
uint8_t
r = (uint8_t)(c >> 16),
g = (uint8_t)(c >> 8),
b = (uint8_t)c;
if(brightness) { // See notes in setBrightness()
r = (r * brightness) >> 8;
g = (g * brightness) >> 8;
b = (b * brightness) >> 8;
}
uint8_t *p = &pixels[n * 3];
p[rOffset] = r;
p[gOffset] = g;
p[bOffset] = b;
}
}
// Convert separate R,G,B into packed 32-bit RGB color.
// Packed format is always RGB, regardless of LED strand color order.
uint32_t Adafruit_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) {
return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
}
// Query color from previously-set pixel (returns packed 32-bit RGB value)
uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) const {
if(n >= numLEDs) {
// Out of bounds, return no color.
return 0;
}
uint8_t *p = &pixels[n * 3];
uint32_t c = ((uint32_t)p[rOffset] << 16) |
((uint32_t)p[gOffset] << 8) |
(uint32_t)p[bOffset];
// Adjust this back up to the true color, as setting a pixel color will
// scale it back down again.
if(brightness) { // See notes in setBrightness()
//Cast the color to a byte array
uint8_t * c_ptr =reinterpret_cast<uint8_t*>(&c);
c_ptr[0] = (c_ptr[0] << 8)/brightness;
c_ptr[1] = (c_ptr[1] << 8)/brightness;
c_ptr[2] = (c_ptr[2] << 8)/brightness;
}
return c; // Pixel # is out of bounds
}
// Returns pointer to pixels[] array. Pixel data is stored in device-
// native format and is not translated here. Application will need to be
// aware whether pixels are RGB vs. GRB and handle colors appropriately.
uint8_t *Adafruit_NeoPixel::getPixels(void) const {
return pixels;
}
uint16_t Adafruit_NeoPixel::numPixels(void) const {
return numLEDs;
}
// Adjust output brightness; 0=darkest (off), 255=brightest. This does
// NOT immediately affect what's currently displayed on the LEDs. The
// next call to show() will refresh the LEDs at this level. However,
// this process is potentially "lossy," especially when increasing
// brightness. The tight timing in the WS2811/WS2812 code means there
// aren't enough free cycles to perform this scaling on the fly as data
// is issued. So we make a pass through the existing color data in RAM
// and scale it (subsequent graphics commands also work at this
// brightness level). If there's a significant step up in brightness,
// the limited number of steps (quantization) in the old data will be
// quite visible in the re-scaled version. For a non-destructive
// change, you'll need to re-render the full strip data. C'est la vie.
void Adafruit_NeoPixel::setBrightness(uint8_t b) {
// Stored brightness value is different than what's passed.
// This simplifies the actual scaling math later, allowing a fast
// 8x8-bit multiply and taking the MSB. 'brightness' is a uint8_t,
// adding 1 here may (intentionally) roll over...so 0 = max brightness
// (color values are interpreted literally; no scaling), 1 = min
// brightness (off), 255 = just below max brightness.
uint8_t newBrightness = b + 1;
if(newBrightness != brightness) { // Compare against prior value
// Brightness has changed -- re-scale existing data in RAM
uint8_t c,
*ptr = pixels,
oldBrightness = brightness - 1; // De-wrap old brightness value
uint16_t scale;
if(oldBrightness == 0) scale = 0; // Avoid /0
else if(b == 255) scale = 65535 / oldBrightness;
else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness;
for(uint16_t i=0; i<numBytes; i++) {
c = *ptr;
*ptr++ = (c * scale) >> 8;
}
brightness = newBrightness;
}
}
//Return the brightness value
uint8_t Adafruit_NeoPixel::getBrightness(void) const {
return brightness - 1;
}
void Adafruit_NeoPixel::clear() {
memset(pixels, 0, numBytes);
}

View File

@ -0,0 +1,97 @@
/*--------------------------------------------------------------------
This file is part of the Adafruit NeoPixel library.
NeoPixel is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoPixel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------*/
#ifndef ADAFRUIT_NEOPIXEL_H
#define ADAFRUIT_NEOPIXEL_H
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#include <pins_arduino.h>
#endif
// 'type' flags for LED pixels (third parameter to constructor):
#define NEO_RGB 0x00 // Wired for RGB data order
#define NEO_GRB 0x01 // Wired for GRB data order
#define NEO_BRG 0x04
#define NEO_COLMASK 0x01
#define NEO_KHZ800 0x02 // 800 KHz datastream
#define NEO_SPDMASK 0x02
// Trinket flash space is tight, v1 NeoPixels aren't handled by default.
// Remove the ifndef/endif to add support -- but code will be bigger.
// Conversely, can comment out the #defines to save space on other MCUs.
#ifndef __AVR_ATtiny85__
#define NEO_KHZ400 0x00 // 400 KHz datastream
#endif
class Adafruit_NeoPixel {
public:
// Constructor: number of LEDs, pin number, LED type
Adafruit_NeoPixel(uint16_t n, uint8_t p=6, uint8_t t=NEO_GRB + NEO_KHZ800);
~Adafruit_NeoPixel();
void
begin(void),
show(void),
setPin(uint8_t p),
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b),
setPixelColor(uint16_t n, uint32_t c),
setBrightness(uint8_t),
clear();
uint8_t
*getPixels(void) const,
getBrightness(void) const;
uint16_t
numPixels(void) const;
static uint32_t
Color(uint8_t r, uint8_t g, uint8_t b);
uint32_t
getPixelColor(uint16_t n) const;
inline bool
canShow(void) { return (micros() - endTime) >= 50L; }
private:
const uint16_t
numLEDs, // Number of RGB LEDs in strip
numBytes; // Size of 'pixels' buffer below
uint8_t
pin, // Output pin number
brightness,
*pixels, // Holds LED color values (3 bytes each)
rOffset, // Index of red byte within each 3-byte pixel
gOffset, // Index of green byte
bOffset; // Index of blue byte
const uint8_t
type; // Pixel flags (400 vs 800 KHz, RGB vs GRB color)
uint32_t
endTime; // Latch timing reference
#ifdef __AVR__
const volatile uint8_t
*port; // Output PORT register
uint8_t
pinMask; // Output PORT bitmask
#endif
};
#endif // ADAFRUIT_NEOPIXEL_H

View File

@ -0,0 +1,794 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
LGPL ADDENDUM:
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@ -0,0 +1,12 @@
Adafruit NeoPixel library
=========================
Arduino library for controlling single-wire-based LED pixels and strip such as the [Adafruit 60 LED/meter Digital LED strip][strip], the [Adafruit FLORA RGB Smart Pixel][flora], the [Adafruit Breadboard-friendly RGB Smart Pixel][pixel], the [Adafruit NeoPixel Stick][stick], and the [Adafruit NeoPixel Shield][shield].
After downloading, rename folder to 'Adafruit_NeoPixel' and install in Arduino Libraries folder. Restart Arduino IDE, then open File->Sketchbook->Library->Adafruit_NeoPixel->strandtest sketch.
[flora]: http://adafruit.com/products/1060
[strip]: http://adafruit.com/products/1138
[pixel]: http://adafruit.com/products/1312
[stick]: http://adafruit.com/products/1426
[shield]: http://adafruit.com/products/1430

View File

@ -0,0 +1,165 @@
// This is a demonstration on how to use an input device to trigger changes on your neo pixels.
// You should wire a momentary push button to connect from ground to a digital IO pin. When you
// press the button it will change to a new pixel animation. Note that you need to press the
// button once to start the first animation!
#include <Adafruit_NeoPixel.h>
#define BUTTON_PIN 2 // Digital IO pin connected to the button. This will be
// driven with a pull-up resistor so the switch should
// pull the pin to ground momentarily. On a high -> low
// transition the button press logic will execute.
#define PIXEL_PIN 6 // Digital IO pin connected to the NeoPixels.
#define PIXEL_COUNT 16
// Parameter 1 = number of pixels in strip, neopixel stick has 8
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_RGB Pixels are wired for RGB bitstream
// NEO_GRB Pixels are wired for GRB bitstream, correct for neopixel stick
// NEO_KHZ400 400 KHz bitstream (e.g. FLORA pixels)
// NEO_KHZ800 800 KHz bitstream (e.g. High Density LED strip), correct for neopixel stick
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
bool oldState = HIGH;
int showType = 0;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
void loop() {
// Get current button state.
bool newState = digitalRead(BUTTON_PIN);
// Check if state changed from high to low (button press).
if (newState == LOW && oldState == HIGH) {
// Short delay to debounce button.
delay(20);
// Check if button is still low after debounce.
newState = digitalRead(BUTTON_PIN);
if (newState == LOW) {
showType++;
if (showType > 9)
showType=0;
startShow(showType);
}
}
// Set the last button state to the old state.
oldState = newState;
}
void startShow(int i) {
switch(i){
case 0: colorWipe(strip.Color(0, 0, 0), 50); // Black/off
break;
case 1: colorWipe(strip.Color(255, 0, 0), 50); // Red
break;
case 2: colorWipe(strip.Color(0, 255, 0), 50); // Green
break;
case 3: colorWipe(strip.Color(0, 0, 255), 50); // Blue
break;
case 4: theaterChase(strip.Color(127, 127, 127), 50); // White
break;
case 5: theaterChase(strip.Color(127, 0, 0), 50); // Red
break;
case 6: theaterChase(strip.Color( 0, 0, 127), 50); // Blue
break;
case 7: rainbow(20);
break;
case 8: rainbowCycle(20);
break;
case 9: theaterChaseRainbow(50);
break;
}
}
// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
void rainbow(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256; j++) {
for(i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i+j) & 255));
}
strip.show();
delay(wait);
}
}
// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
for(i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
delay(wait);
}
}
//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
for (int j=0; j<10; j++) { //do 10 cycles of chasing
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, c); //turn every third pixel on
}
strip.show();
delay(wait);
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}
//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, Wheel( (i+j) % 255)); //turn every third pixel on
}
strip.show();
delay(wait);
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}

View File

@ -0,0 +1,30 @@
// NeoPixel Ring simple sketch (c) 2013 Shae Erisson
// released under the GPLv3 license to match the rest of the AdaFruit NeoPixel library
#include <Adafruit_NeoPixel.h>
// Which pin on the Arduino is connected to the NeoPixels?
#define PIN 1
// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 1
// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
// example for more information on possible values.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800);
int delayval = 500; // delay for half a second
void setup() {
pixels.begin(); // This initializes the NeoPixel library.
}
void loop() {
// For a set of NeoPixels the first NeoPixel is 0, second is 1, all the way up to the count of pixels minus one.
for(int i=0;i<NUMPIXELS;i++){
// pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
pixels.setPixelColor(i, pixels.Color(0,150,0)); // Moderately bright green color.
pixels.show(); // This sends the updated pixel color to the hardware.
delay(delayval); // Delay for a period of time (in milliseconds).
}
}

View File

@ -0,0 +1,30 @@
// NeoPixel Ring simple sketch (c) 2013 Shae Erisson
// released under the GPLv3 license to match the rest of the AdaFruit NeoPixel library
#include <Adafruit_NeoPixel.h>
// Which pin on the Arduino is connected to the NeoPixels?
#define PIN 6
// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 16
// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
// example for more information on possible values.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
int delayval = 500; // delay for half a second
void setup() {
pixels.begin(); // This initializes the NeoPixel library.
}
void loop() {
// For a set of NeoPixels the first NeoPixel is 0, second is 1, all the way up to the count of pixels minus one.
for(int i=0;i<NUMPIXELS;i++){
// pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
pixels.setPixelColor(i, pixels.Color(0,150,0)); // Moderately bright green color.
pixels.show(); // This sends the updated pixel color to the hardware.
delay(delayval); // Delay for a period of time (in milliseconds).
}
}

View File

@ -0,0 +1,123 @@
#include <Adafruit_NeoPixel.h>
#define PIN 6
// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);
// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel. Avoid connecting
// on a live circuit...if you must, connect GND first.
void setup() {
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
void loop() {
// Some example procedures showing how to display to the pixels:
colorWipe(strip.Color(255, 0, 0), 50); // Red
colorWipe(strip.Color(0, 255, 0), 50); // Green
colorWipe(strip.Color(0, 0, 255), 50); // Blue
// Send a theater pixel chase in...
theaterChase(strip.Color(127, 127, 127), 50); // White
theaterChase(strip.Color(127, 0, 0), 50); // Red
theaterChase(strip.Color( 0, 0, 127), 50); // Blue
rainbow(20);
rainbowCycle(20);
theaterChaseRainbow(50);
}
// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
void rainbow(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256; j++) {
for(i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i+j) & 255));
}
strip.show();
delay(wait);
}
}
// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
for(i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
delay(wait);
}
}
//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
for (int j=0; j<10; j++) { //do 10 cycles of chasing
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, c); //turn every third pixel on
}
strip.show();
delay(wait);
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}
//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, Wheel( (i+j) % 255)); //turn every third pixel on
}
strip.show();
delay(wait);
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}

View File

@ -0,0 +1,29 @@
#######################################
# Syntax Coloring Map For Adafruit_NeoPixel
#######################################
# Class
#######################################
Adafruit_NeoPixel KEYWORD1
#######################################
# Methods and Functions
#######################################
setPixelColor KEYWORD2
setPin KEYWORD2
setBrightness KEYWORD2
numPixels KEYWORD2
getPixelColor KEYWORD2
Color KEYWORD2
#######################################
# Constants
#######################################
NEO_GRB LITERAL1
NEO_COLMASK LITERAL1
NEO_KHZ800 LITERAL1
NEO_SPDMASK LITERAL1
NEO_RGB LITERAL1
NEO_KHZ400 LITERAL1

View File

@ -0,0 +1,308 @@
This file documents changes in the firmware-only USB driver for atmel's AVR
microcontrollers. New entries are always appended to the end of the file.
Scroll down to the bottom to see the most recent changes.
2005-04-01:
- Implemented endpoint 1 as interrupt-in endpoint.
- Moved all configuration options to usbconfig.h which is not part of the
driver.
- Changed interface for usbVendorSetup().
- Fixed compatibility with ATMega8 device.
- Various minor optimizations.
2005-04-11:
- Changed interface to application: Use usbFunctionSetup(), usbFunctionRead()
and usbFunctionWrite() now. Added configuration options to choose which
of these functions to compile in.
- Assembler module delivers receive data non-inverted now.
- Made register and bit names compatible with more AVR devices.
2005-05-03:
- Allow address of usbRxBuf on any memory page as long as the buffer does
not cross 256 byte page boundaries.
- Better device compatibility: works with Mega88 now.
- Code optimization in debugging module.
- Documentation updates.
2006-01-02:
- Added (free) default Vendor- and Product-IDs bought from voti.nl.
- Added USBID-License.txt file which defines the rules for using the free
shared VID/PID pair.
- Added Readme.txt to the usbdrv directory which clarifies administrative
issues.
2006-01-25:
- Added "configured state" to become more standards compliant.
- Added "HALT" state for interrupt endpoint.
- Driver passes the "USB Command Verifier" test from usb.org now.
- Made "serial number" a configuration option.
- Minor optimizations, we now recommend compiler option "-Os" for best
results.
- Added a version number to usbdrv.h
2006-02-03:
- New configuration variable USB_BUFFER_SECTION for the memory section where
the USB rx buffer will go. This defaults to ".bss" if not defined. Since
this buffer MUST NOT cross 256 byte pages (not even touch a page at the
end), the user may want to pass a linker option similar to
"-Wl,--section-start=.mybuffer=0x800060".
- Provide structure for usbRequest_t.
- New defines for USB constants.
- Prepared for HID implementations.
- Increased data size limit for interrupt transfers to 8 bytes.
- New macro usbInterruptIsReady() to query interrupt buffer state.
2006-02-18:
- Ensure that the data token which is sent as an ack to an OUT transfer is
always zero sized. This fixes a bug where the host reports an error after
sending an out transfer to the device, although all data arrived at the
device.
- Updated docs in usbdrv.h to reflect changed API in usbFunctionWrite().
* Release 2006-02-20
- Give a compiler warning when compiling with debugging turned on.
- Added Oleg Semyonov's changes for IAR-cc compatibility.
- Added new (optional) functions usbDeviceConnect() and usbDeviceDisconnect()
(also thanks to Oleg!).
- Rearranged tests in usbPoll() to save a couple of instructions in the most
likely case that no actions are pending.
- We need a delay between the SET ADDRESS request until the new address
becomes active. This delay was handled in usbPoll() until now. Since the
spec says that the delay must not exceed 2ms, previous versions required
aggressive polling during the enumeration phase. We have now moved the
handling of the delay into the interrupt routine.
- We must not reply with NAK to a SETUP transaction. We can only achieve this
by making sure that the rx buffer is empty when SETUP tokens are expected.
We therefore don't pass zero sized data packets from the status phase of
a transfer to usbPoll(). This change MAY cause troubles if you rely on
receiving a less than 8 bytes long packet in usbFunctionWrite() to
identify the end of a transfer. usbFunctionWrite() will NEVER be called
with a zero length.
* Release 2006-03-14
- Improved IAR C support: tiny memory model, more devices
- Added template usbconfig.h file under the name usbconfig-prototype.h
* Release 2006-03-26
- Added provision for one more interrupt-in endpoint (endpoint 3).
- Added provision for one interrupt-out endpoint (endpoint 1).
- Added flowcontrol macros for USB.
- Added provision for custom configuration descriptor.
- Allow ANY two port bits for D+ and D-.
- Merged (optional) receive endpoint number into global usbRxToken variable.
- Use USB_CFG_IOPORTNAME instead of USB_CFG_IOPORT. We now construct the
variable name from the single port letter instead of computing the address
of related ports from the output-port address.
* Release 2006-06-26
- Updated documentation in usbdrv.h and usbconfig-prototype.h to reflect the
new features.
- Removed "#warning" directives because IAR does not understand them. Use
unused static variables instead to generate a warning.
- Do not include <avr/io.h> when compiling with IAR.
- Introduced USB_CFG_DESCR_PROPS_* in usbconfig.h to configure how each
USB descriptor should be handled. It is now possible to provide descriptor
data in Flash, RAM or dynamically at runtime.
- STALL is now a status in usbTxLen* instead of a message. We can now conform
to the spec and leave the stall status pending until it is cleared.
- Made usbTxPacketCnt1 and usbTxPacketCnt3 public. This allows the
application code to reset data toggling on interrupt pipes.
* Release 2006-07-18
- Added an #if !defined __ASSEMBLER__ to the warning in usbdrv.h. This fixes
an assembler error.
- usbDeviceDisconnect() takes pull-up resistor to high impedance now.
* Release 2007-02-01
- Merged in some code size improvements from usbtiny (thanks to Dick
Streefland for these optimizations!)
- Special alignment requirement for usbRxBuf not required any more. Thanks
again to Dick Streefland for this hint!
- Reverted to "#warning" instead of unused static variables -- new versions
of IAR CC should handle this directive.
- Changed Open Source license to GNU GPL v2 in order to make linking against
other free libraries easier. We no longer require publication of the
circuit diagrams, but we STRONGLY encourage it. If you improve the driver
itself, PLEASE grant us a royalty free license to your changes for our
commercial license.
* Release 2007-03-29
- New configuration option "USB_PUBLIC" in usbconfig.h.
- Set USB version number to 1.10 instead of 1.01.
- Code used USB_CFG_DESCR_PROPS_STRING_DEVICE and
USB_CFG_DESCR_PROPS_STRING_PRODUCT inconsistently. Changed all occurrences
to USB_CFG_DESCR_PROPS_STRING_PRODUCT.
- New assembler module for 16.5 MHz RC oscillator clock with PLL in receiver
code.
- New assembler module for 16 MHz crystal.
- usbdrvasm.S contains common code only, clock-specific parts have been moved
to usbdrvasm12.S, usbdrvasm16.S and usbdrvasm165.S respectively.
* Release 2007-06-25
- 16 MHz module: Do SE0 check in stuffed bits as well.
* Release 2007-07-07
- Define hi8(x) for IAR compiler to limit result to 8 bits. This is necessary
for negative values.
- Added 15 MHz module contributed by V. Bosch.
- Interrupt vector name can now be configured. This is useful if somebody
wants to use a different hardware interrupt than INT0.
* Release 2007-08-07
- Moved handleIn3 routine in usbdrvasm16.S so that relative jump range is
not exceeded.
- More config options: USB_RX_USER_HOOK(), USB_INITIAL_DATATOKEN,
USB_COUNT_SOF
- USB_INTR_PENDING can now be a memory address, not just I/O
* Release 2007-09-19
- Split out common parts of assembler modules into separate include file
- Made endpoint numbers configurable so that given interface definitions
can be matched. See USB_CFG_EP3_NUMBER in usbconfig-prototype.h.
- Store endpoint number for interrupt/bulk-out so that usbFunctionWriteOut()
can handle any number of endpoints.
- Define usbDeviceConnect() and usbDeviceDisconnect() even if no
USB_CFG_PULLUP_IOPORTNAME is defined. Directly set D+ and D- to 0 in this
case.
* Release 2007-12-01
- Optimize usbDeviceConnect() and usbDeviceDisconnect() for less code size
when USB_CFG_PULLUP_IOPORTNAME is not defined.
* Release 2007-12-13
- Renamed all include-only assembler modules from *.S to *.inc so that
people don't add them to their project sources.
- Distribute leap bits in tx loop more evenly for 16 MHz module.
- Use "macro" and "endm" instead of ".macro" and ".endm" for IAR
- Avoid compiler warnings for constant expr range by casting some values in
USB descriptors.
* Release 2008-01-21
- Fixed bug in 15 and 16 MHz module where the new address set with
SET_ADDRESS was already accepted at the next NAK or ACK we send, not at
the next data packet we send. This caused problems when the host polled
too fast. Thanks to Alexander Neumann for his help and patience debugging
this issue!
* Release 2008-02-05
- Fixed bug in 16.5 MHz module where a register was used in the interrupt
handler before it was pushed. This bug was introduced with version
2007-09-19 when common parts were moved to a separate file.
- Optimized CRC routine (thanks to Reimar Doeffinger).
* Release 2008-02-16
- Removed outdated IAR compatibility stuff (code sections).
- Added hook macros for USB_RESET_HOOK() and USB_SET_ADDRESS_HOOK().
- Added optional routine usbMeasureFrameLength() for calibration of the
internal RC oscillator.
* Release 2008-02-28
- USB_INITIAL_DATATOKEN defaults to USBPID_DATA1 now, which means that we
start with sending USBPID_DATA0.
- Changed defaults in usbconfig-prototype.h
- Added free USB VID/PID pair for MIDI class devices
- Restructured AVR-USB as separate package, not part of PowerSwitch any more.
* Release 2008-04-18
- Restructured usbdrv.c so that it is easier to read and understand.
- Better code optimization with gcc 4.
- If a second interrupt in endpoint is enabled, also add it to config
descriptor.
- Added config option for long transfers (above 254 bytes), see
USB_CFG_LONG_TRANSFERS in usbconfig.h.
- Added 20 MHz module contributed by Jeroen Benschop.
* Release 2008-05-13
- Fixed bug in libs-host/hiddata.c function usbhidGetReport(): length
was not incremented, pointer to length was incremented instead.
- Added code to command line tool(s) which claims an interface. This code
is disabled by default, but may be necessary on newer Linux kernels.
- Added usbconfig.h option "USB_CFG_CHECK_DATA_TOGGLING".
- New header "usbportability.h" prepares ports to other development
environments.
- Long transfers (above 254 bytes) did not work when usbFunctionRead() was
used to supply the data. Fixed this bug. [Thanks to Alexander Neumann!]
- In hiddata.c (example code for sending/receiving data over HID), use
USB_RECIP_DEVICE instead of USB_RECIP_INTERFACE for control transfers so
that we need not claim the interface.
- in usbPoll() loop 20 times polling for RESET state instead of 10 times.
This accounts for the higher clock rates we now support.
- Added a module for 12.8 MHz RC oscillator with PLL in receiver loop.
- Added hook to SOF code so that oscillator can be tuned to USB frame clock.
- Added timeout to waitForJ loop. Helps preventing unexpected hangs.
- Added example code for oscillator tuning to libs-device (thanks to
Henrik Haftmann for the idea to this routine).
- Implemented option USB_CFG_SUPPRESS_INTR_CODE.
* Release 2008-10-22
- Fixed libs-device/osctune.h: OSCCAL is memory address on ATMega88 and
similar, not offset of 0x20 needs to be added.
- Allow distribution under GPLv3 for those who have to link against other
code distributed under GPLv3.
* Release 2008-11-26
- Removed libusb-win32 dependency for hid-data example in Makefile.windows.
It was never required and confused many people.
- Added extern uchar usbRxToken to usbdrv.h.
- Integrated a module with CRC checks at 18 MHz by Lukas Schrittwieser.
* Release 2009-03-23
- Hid-mouse example used settings from hid-data example, fixed that.
- Renamed project to V-USB due to a trademark issue with Atmel(r).
- Changed CommercialLicense.txt and USBID-License.txt to make the
background of USB ID registration clearer.
* Release 2009-04-15
- Changed CommercialLicense.txt to reflect the new range of PIDs from
Jason Kotzin.
- Removed USBID-License.txt in favor of USB-IDs-for-free.txt and
USB-ID-FAQ.txt
- Fixed a bug in the 12.8 MHz module: End Of Packet decection was made in
the center between bit 0 and 1 of each byte. This is where the data lines
are expected to change and the sampled data may therefore be nonsense.
We therefore check EOP ONLY if bits 0 AND 1 have both been read as 0 on D-.
- Fixed a bitstuffing problem in the 16 MHz module: If bit 6 was stuffed,
the unstuffing code in the receiver routine was 1 cycle too long. If
multiple bytes had the unstuffing in bit 6, the error summed up until the
receiver was out of sync.
- Included option for faster CRC routine.
Thanks to Slawomir Fras (BoskiDialer) for this code!
- Updated bits in Configuration Descriptor's bmAttributes according to
USB 1.1 (in particular bit 7, it is a must-be-set bit now).
* Release 2009-08-22
- Moved first DBG1() after odDebugInit() in all examples.
- Use vector INT0_vect instead of SIG_INTERRUPT0 if defined. This makes
V-USB compatible with the new "p" suffix devices (e.g. ATMega328p).
- USB_CFG_CLOCK_KHZ setting is now required in usbconfig.h (no default any
more).
- New option USB_CFG_DRIVER_FLASH_PAGE allows boot loaders on devices with
more than 64 kB flash.
- Built-in configuration descriptor allows custom definition for second
endpoint now.
* Release 2010-07-15

View File

@ -0,0 +1,166 @@
V-USB Driver Software License Agreement
Version 2009-08-03
THIS LICENSE AGREEMENT GRANTS YOU CERTAIN RIGHTS IN A SOFTWARE. YOU CAN
ENTER INTO THIS AGREEMENT AND ACQUIRE THE RIGHTS OUTLINED BELOW BY PAYING
THE AMOUNT ACCORDING TO SECTION 4 ("PAYMENT") TO OBJECTIVE DEVELOPMENT.
1 DEFINITIONS
1.1 "OBJECTIVE DEVELOPMENT" shall mean OBJECTIVE DEVELOPMENT Software GmbH,
Grosse Schiffgasse 1A/7, 1020 Wien, AUSTRIA.
1.2 "You" shall mean the Licensee.
1.3 "V-USB" shall mean all files included in the package distributed under
the name "vusb" by OBJECTIVE DEVELOPMENT (http://www.obdev.at/vusb/)
unless otherwise noted. This includes the firmware-only USB device
implementation for Atmel AVR microcontrollers, some simple device examples
and host side software examples and libraries.
2 LICENSE GRANTS
2.1 Source Code. OBJECTIVE DEVELOPMENT shall furnish you with the source
code of V-USB.
2.2 Distribution and Use. OBJECTIVE DEVELOPMENT grants you the
non-exclusive right to use, copy and distribute V-USB with your hardware
product(s), restricted by the limitations in section 3 below.
2.3 Modifications. OBJECTIVE DEVELOPMENT grants you the right to modify
the source code and your copy of V-USB according to your needs.
2.4 USB IDs. OBJECTIVE DEVELOPMENT furnishes you with one or two USB
Product ID(s), sent to you in e-mail. These Product IDs are reserved
exclusively for you. OBJECTIVE DEVELOPMENT has obtained USB Product ID
ranges under the Vendor ID 5824 from Wouter van Ooijen (Van Ooijen
Technische Informatica, www.voti.nl) and under the Vendor ID 8352 from
Jason Kotzin (Clay Logic, www.claylogic.com). Both owners of the Vendor IDs
have obtained these IDs from the USB Implementers Forum, Inc.
(www.usb.org). OBJECTIVE DEVELOPMENT disclaims all liability which might
arise from the assignment of USB IDs.
2.5 USB Certification. Although not part of this agreement, we want to make
it clear that you cannot become USB certified when you use V-USB or a USB
Product ID assigned by OBJECTIVE DEVELOPMENT. AVR microcontrollers don't
meet the electrical specifications required by the USB specification and
the USB Implementers Forum certifies only members who bought a Vendor ID of
their own.
3 LICENSE RESTRICTIONS
3.1 Number of Units. Only one of the following three definitions is
applicable. Which one is determined by the amount you pay to OBJECTIVE
DEVELOPMENT, see section 4 ("Payment") below.
Hobby License: You may use V-USB according to section 2 above in no more
than 5 hardware units. These units must not be sold for profit.
Entry Level License: You may use V-USB according to section 2 above in no
more than 150 hardware units.
Professional License: You may use V-USB according to section 2 above in
any number of hardware units, except for large scale production ("unlimited
fair use"). Quantities below 10,000 units are not considered large scale
production. If your reach quantities which are obviously large scale
production, you must pay a license fee of 0.10 EUR per unit for all units
above 10,000.
3.2 Rental. You may not rent, lease, or lend V-USB or otherwise encumber
any copy of V-USB, or any of the rights granted herein.
3.3 Transfer. You may not transfer your rights under this Agreement to
another party without OBJECTIVE DEVELOPMENT's prior written consent. If
such consent is obtained, you may permanently transfer this License to
another party. The recipient of such transfer must agree to all terms and
conditions of this Agreement.
3.4 Reservation of Rights. OBJECTIVE DEVELOPMENT retains all rights not
expressly granted.
3.5 Non-Exclusive Rights. Your license rights under this Agreement are
non-exclusive.
3.6 Third Party Rights. This Agreement cannot grant you rights controlled
by third parties. In particular, you are not allowed to use the USB logo or
other trademarks owned by the USB Implementers Forum, Inc. without their
consent. Since such consent depends on USB certification, it should be
noted that V-USB will not pass certification because it does not
implement checksum verification and the microcontroller ports do not meet
the electrical specifications.
4 PAYMENT
The payment amount depends on the variation of this agreement (according to
section 3.1) into which you want to enter. Concrete prices are listed on
OBJECTIVE DEVELOPMENT's web site, usually at
http://www.obdev.at/vusb/license.html. You agree to pay the amount listed
there to OBJECTIVE DEVELOPMENT or OBJECTIVE DEVELOPMENT's payment processor
or reseller.
5 COPYRIGHT AND OWNERSHIP
V-USB is protected by copyright laws and international copyright
treaties, as well as other intellectual property laws and treaties. V-USB
is licensed, not sold.
6 TERM AND TERMINATION
6.1 Term. This Agreement shall continue indefinitely. However, OBJECTIVE
DEVELOPMENT may terminate this Agreement and revoke the granted license and
USB-IDs if you fail to comply with any of its terms and conditions.
6.2 Survival of Terms. All provisions regarding secrecy, confidentiality
and limitation of liability shall survive termination of this agreement.
7 DISCLAIMER OF WARRANTY AND LIABILITY
LIMITED WARRANTY. V-USB IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, OBJECTIVE
DEVELOPMENT AND ITS SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
NON-INFRINGEMENT, WITH REGARD TO V-USB, AND THE PROVISION OF OR FAILURE
TO PROVIDE SUPPORT SERVICES. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL
RIGHTS. YOU MAY HAVE OTHERS, WHICH VARY FROM STATE/JURISDICTION TO
STATE/JURISDICTION.
LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW,
IN NO EVENT SHALL OBJECTIVE DEVELOPMENT OR ITS SUPPLIERS BE LIABLE FOR ANY
SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER
(INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY
LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE V-USB OR THE
PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, EVEN IF OBJECTIVE
DEVELOPMENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY
CASE, OBJECTIVE DEVELOPMENT'S ENTIRE LIABILITY UNDER ANY PROVISION OF THIS
AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID BY YOU FOR V-USB.
8 MISCELLANEOUS TERMS
8.1 Marketing. OBJECTIVE DEVELOPMENT has the right to mention for marketing
purposes that you entered into this agreement.
8.2 Entire Agreement. This document represents the entire agreement between
OBJECTIVE DEVELOPMENT and you. It may only be modified in writing signed by
an authorized representative of both, OBJECTIVE DEVELOPMENT and you.
8.3 Severability. In case a provision of these terms and conditions should
be or become partly or entirely invalid, ineffective, or not executable,
the validity of all other provisions shall not be affected.
8.4 Applicable Law. This agreement is governed by the laws of the Republic
of Austria.
8.5 Responsible Courts. The responsible courts in Vienna/Austria will have
exclusive jurisdiction regarding all disputes in connection with this
agreement.

View File

@ -0,0 +1,380 @@
/*
CDC Arduino Library by Ihsan Kehribar (kehribar.me)
and Digistump LLC (digistump.com)
- all changes made under the same license as V-USB
*/
#include "DigiCDC.h"
#include <stdint.h>
#include <Arduino.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/delay.h>
uchar sendEmptyFrame;
static uchar intr3Status; /* used to control interrupt endpoint transmissions */
DigiCDCDevice::DigiCDCDevice(void){}
void DigiCDCDevice::delay(long milli) {
unsigned long last = millis();
while (milli > 0) {
unsigned long now = millis();
milli -= now - last;
last = now;
refresh();
}
}
void DigiCDCDevice::flush(){
cli();
RingBuffer_InitBuffer(&rxBuf,rxBuf_Data,sizeof(rxBuf_Data));
sei();
}
void DigiCDCDevice::begin(){
usbBegin();
}
size_t DigiCDCDevice::write(uint8_t chr)
{
if(RingBuffer_IsFull(&txBuf))
{
return 0;
}
else
{
RingBuffer_Insert(&txBuf,chr);
return 1;
}
}
int DigiCDCDevice::available()
{
return RingBuffer_GetCount(&rxBuf);
}
int DigiCDCDevice::read()
{
if(RingBuffer_IsEmpty(&rxBuf))
{
return 0;
}
else
{
return RingBuffer_Remove(&rxBuf);
}
}
int DigiCDCDevice::peek()
{
if(RingBuffer_IsEmpty(&rxBuf))
{
return 0;
}
else
{
return RingBuffer_Peek(&rxBuf);
}
}
void DigiCDCDevice::task(void)
{
usbPollWrapper();
}
void DigiCDCDevice::refresh(void)
{
usbPollWrapper();
}
void DigiCDCDevice::end(void)
{
// drive both USB pins low to disconnect
usbDeviceDisconnect();
cli();
RingBuffer_InitBuffer(&rxBuf,rxBuf_Data,sizeof(rxBuf_Data));
sei();
}
DigiCDCDevice::operator bool() {
usbPollWrapper();
return true;
}
void DigiCDCDevice::usbBegin()
{
cli();
PORTB &= ~(_BV(USB_CFG_DMINUS_BIT) | _BV(USB_CFG_DPLUS_BIT));
usbDeviceDisconnect();
_delay_ms(250);
usbDeviceConnect();
usbInit();
RingBuffer_InitBuffer(&txBuf,txBuf_Data,sizeof(txBuf_Data));
RingBuffer_InitBuffer(&rxBuf,rxBuf_Data,sizeof(rxBuf_Data));
intr3Status = 0;
sendEmptyFrame = 0;
sei();
}
void DigiCDCDevice::usbPollWrapper()
{
usbPoll();
while((!(RingBuffer_IsEmpty(&txBuf)))&&(index<9))
{
tmp[index++] = RingBuffer_Remove(&txBuf);
}
if(usbInterruptIsReady())
{
if(sendEmptyFrame)
{
usbSetInterrupt(tmp,0);
sendEmptyFrame = 0;
}
else if(index>0)
{
usbSetInterrupt(tmp,index);
usbEnableAllRequests();
sendEmptyFrame = 1;
index = 0;
}
}
/* We need to report rx and tx carrier after open attempt */
if(intr3Status != 0 && usbInterruptIsReady3()){
static uchar serialStateNotification[10] = {0xa1, 0x20, 0, 0, 0, 0, 2, 0, 3, 0};
if(intr3Status == 2){
usbSetInterrupt3(serialStateNotification, 8);
}else{
usbSetInterrupt3(serialStateNotification+8, 2);
}
intr3Status--;
}
}
#ifdef __cplusplus
extern "C"{
#endif
enum {
SEND_ENCAPSULATED_COMMAND = 0,
GET_ENCAPSULATED_RESPONSE,
SET_COMM_FEATURE,
GET_COMM_FEATURE,
CLEAR_COMM_FEATURE,
SET_LINE_CODING = 0x20,
GET_LINE_CODING,
SET_CONTROL_LINE_STATE,
SEND_BREAK
};
static const PROGMEM char configDescrCDC[] = { /* USB configuration descriptor */
9, /* sizeof(usbDescrConfig): length of descriptor in bytes */
USBDESCR_CONFIG, /* descriptor type */
67,
0, /* total length of data returned (including inlined descriptors) */
2, /* number of interfaces in this configuration */
1, /* index of this configuration */
0, /* configuration name string index */
#if USB_CFG_IS_SELF_POWERED
(1 << 7) | USBATTR_SELFPOWER, /* attributes */
#else
(1 << 7), /* attributes */
#endif
USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */
/* interface descriptor follows inline: */
9, /* sizeof(usbDescrInterface): length of descriptor in bytes */
USBDESCR_INTERFACE, /* descriptor type */
0, /* index of this interface */
0, /* alternate setting for this interface */
USB_CFG_HAVE_INTRIN_ENDPOINT, /* endpoints excl 0: number of endpoint descriptors to follow */
USB_CFG_INTERFACE_CLASS,
USB_CFG_INTERFACE_SUBCLASS,
USB_CFG_INTERFACE_PROTOCOL,
0, /* string index for interface */
/* CDC Class-Specific descriptor */
5, /* sizeof(usbDescrCDC_HeaderFn): length of descriptor in bytes */
0x24, /* descriptor type */
0, /* header functional descriptor */
0x10, 0x01,
4, /* sizeof(usbDescrCDC_AcmFn): length of descriptor in bytes */
0x24, /* descriptor type */
2, /* abstract control management functional descriptor */
0x02, /* SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE */
5, /* sizeof(usbDescrCDC_UnionFn): length of descriptor in bytes */
0x24, /* descriptor type */
6, /* union functional descriptor */
0, /* CDC_COMM_INTF_ID */
1, /* CDC_DATA_INTF_ID */
5, /* sizeof(usbDescrCDC_CallMgtFn): length of descriptor in bytes */
0x24, /* descriptor type */
1, /* call management functional descriptor */
3, /* allow management on data interface, handles call management by itself */
1, /* CDC_DATA_INTF_ID */
/* Endpoint Descriptor */
7, /* sizeof(usbDescrEndpoint) */
USBDESCR_ENDPOINT, /* descriptor type = endpoint */
0x80|USB_CFG_EP3_NUMBER, /* IN endpoint number 3 */
0x03, /* attrib: Interrupt endpoint */
8, 0, /* maximum packet size */
USB_CFG_INTR_POLL_INTERVAL, /* in ms */
/* Interface Descriptor */
9, /* sizeof(usbDescrInterface): length of descriptor in bytes */
USBDESCR_INTERFACE, /* descriptor type */
1, /* index of this interface */
0, /* alternate setting for this interface */
2, /* endpoints excl 0: number of endpoint descriptors to follow */
0x0A, /* Data Interface Class Codes */
0,
0, /* Data Interface Class Protocol Codes */
0, /* string index for interface */
/* Endpoint Descriptor */
7, /* sizeof(usbDescrEndpoint) */
USBDESCR_ENDPOINT, /* descriptor type = endpoint */
0x01, /* OUT endpoint number 1 */
0x02, /* attrib: Bulk endpoint */
HW_CDC_BULK_OUT_SIZE, 0, /* maximum packet size */
0, /* in ms */
/* Endpoint Descriptor */
7, /* sizeof(usbDescrEndpoint) */
USBDESCR_ENDPOINT, /* descriptor type = endpoint */
0x81, /* IN endpoint number 1 */
0x02, /* attrib: Bulk endpoint */
HW_CDC_BULK_IN_SIZE, 0, /* maximum packet size */
0, /* in ms */
};
uchar usbFunctionDescriptor(usbRequest_t *rq)
{
if(rq->wValue.bytes[1] == USBDESCR_DEVICE){
usbMsgPtr = (uchar *)usbDescriptorDevice;
return usbDescriptorDevice[0];
}else{ /* must be config descriptor */
usbMsgPtr = (uchar *)configDescrCDC;
return sizeof(configDescrCDC);
}
}
/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */
uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (usbRequest_t*)((void *)data);
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */
if( rq->bRequest==GET_LINE_CODING || rq->bRequest==SET_LINE_CODING ){
return 0xff;
/* GET_LINE_CODING -> usbFunctionRead() */
/* SET_LINE_CODING -> usbFunctionWrite() */
}
if(rq->bRequest == SET_CONTROL_LINE_STATE){
/* Report serial state (carrier detect). On several Unix platforms,
* tty devices can only be opened when carrier detect is set.
*/
if( intr3Status==0 )
intr3Status = 2;
}
/* Prepare bulk-in endpoint to respond to early termination */
if((rq->bmRequestType & USBRQ_DIR_MASK) == USBRQ_DIR_HOST_TO_DEVICE)
sendEmptyFrame = 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
/* usbFunctionRead */
/*---------------------------------------------------------------------------*/
uchar usbFunctionRead( uchar *data, uchar len )
{
// data[0] = 0;
// data[1] = 0;
// data[2] = 0;
// data[3] = 0;
// data[4] = 0;
// data[5] = 0;
// data[6] = 8;
return 7;
}
/*---------------------------------------------------------------------------*/
/* usbFunctionWrite */
/*---------------------------------------------------------------------------*/
uchar usbFunctionWrite( uchar *data, uchar len )
{
// baud.bytes[0] = data[0];
// baud.bytes[1] = data[1];
return 1;
}
void usbFunctionWriteOut( uchar *data, uchar len )
{
uint8_t qw = 0;
for(qw=0;qw<len;qw++)
{
if(!RingBuffer_IsFull(&rxBuf))
{
RingBuffer_Insert(&rxBuf,data[qw]);
}
}
/* postpone receiving next data */
if(RingBuffer_GetCount(&rxBuf) >= HW_CDC_BULK_OUT_SIZE)
{
usbDisableAllRequests();
}
}
#ifdef __cplusplus
} // extern "C"
#endif
DigiCDCDevice SerialUSB;

View File

@ -0,0 +1,65 @@
/*
CDC Arduino Library by Ihsan Kehribar (kehribar.me)
and Digistump LLC (digistump.com)
- all changes made under the same license as V-USB
*/
#ifndef __DigiCDC_h__
#define __DigiCDC_h__
#include "usbdrv.h"
#include "Stream.h"
#include "ringBuffer.h"
#define HW_CDC_TX_BUF_SIZE 32
#define HW_CDC_RX_BUF_SIZE 32
#define HW_CDC_BULK_OUT_SIZE 8
#define HW_CDC_BULK_IN_SIZE 8
/* library functions and variables start */
static uint8_t tmp[HW_CDC_BULK_IN_SIZE];
static uint8_t index = 0;
static RingBuffer_t rxBuf;
static uint8_t rxBuf_Data[HW_CDC_RX_BUF_SIZE];
static RingBuffer_t txBuf;
static uint8_t txBuf_Data[HW_CDC_TX_BUF_SIZE];
class DigiCDCDevice : public Stream {
public:
DigiCDCDevice();
void begin(), begin(unsigned long x);
void end();
void refresh();
void task();
void delay(long milli);
virtual int available(void);
virtual int peek(void);
virtual int read(void);
virtual void flush(void);
virtual size_t write(uint8_t);
inline size_t write(unsigned long n) { return write((uint8_t)n); }
inline size_t write(long n) { return write((uint8_t)n); }
inline size_t write(unsigned int n) { return write((uint8_t)n); }
inline size_t write(int n) { return write((uint8_t)n); }
using Print::write;
operator bool();
private:
void usbBegin();
void usbPollWrapper();
};
extern DigiCDCDevice SerialUSB;
#endif // __DigiCDC_h__

View File

@ -0,0 +1,361 @@
OBJECTIVE DEVELOPMENT GmbH's V-USB driver software is distributed under the
terms and conditions of the GNU GPL version 2 or the GNU GPL version 3. It is
your choice whether you apply the terms of version 2 or version 3. The full
text of GPLv2 is included below. In addition to the requirements in the GPL,
we STRONGLY ENCOURAGE you to do the following:
(1) Publish your entire project on a web site and drop us a note with the URL.
Use the form at http://www.obdev.at/vusb/feedback.html for your submission.
(2) Adhere to minimum publication standards. Please include AT LEAST:
- a circuit diagram in PDF, PNG or GIF format
- full source code for the host software
- a Readme.txt file in ASCII format which describes the purpose of the
project and what can be found in which directories and which files
- a reference to http://www.obdev.at/vusb/
(3) If you improve the driver firmware itself, please give us a free license
to your modifications for our commercial license offerings.
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -0,0 +1,172 @@
This is the Readme file to Objective Development's firmware-only USB driver
for Atmel AVR microcontrollers. For more information please visit
http://www.obdev.at/vusb/
This directory contains the USB firmware only. Copy it as-is to your own
project and add all .c and .S files to your project (these files are marked
with an asterisk in the list below). Then copy usbconfig-prototype.h as
usbconfig.h to your project and edit it according to your configuration.
TECHNICAL DOCUMENTATION
=======================
The technical documentation (API) for the firmware driver is contained in the
file "usbdrv.h". Please read all of it carefully! Configuration options are
documented in "usbconfig-prototype.h".
The driver consists of the following files:
Readme.txt ............. The file you are currently reading.
Changelog.txt .......... Release notes for all versions of the driver.
usbdrv.h ............... Driver interface definitions and technical docs.
* usbdrv.c ............... High level language part of the driver. Link this
module to your code!
* usbdrvasm.S ............ Assembler part of the driver. This module is mostly
a stub and includes one of the usbdrvasm*.S files
depending on processor clock. Link this module to
your code!
usbdrvasm*.inc ......... Assembler routines for particular clock frequencies.
Included by usbdrvasm.S, don't link it directly!
asmcommon.inc .......... Common assembler routines. Included by
usbdrvasm*.inc, don't link it directly!
usbconfig-prototype.h .. Prototype for your own usbdrv.h file.
* oddebug.c .............. Debug functions. Only used when DEBUG_LEVEL is
defined to a value greater than 0. Link this module
to your code!
oddebug.h .............. Interface definitions of the debug module.
usbportability.h ....... Header with compiler-dependent stuff.
usbdrvasm.asm .......... Compatibility stub for IAR-C-compiler. Use this
module instead of usbdrvasm.S when you assembler
with IAR's tools.
License.txt ............ Open Source license for this driver.
CommercialLicense.txt .. Optional commercial license for this driver.
USB-ID-FAQ.txt ......... General infos about USB Product- and Vendor-IDs.
USB-IDs-for-free.txt ... List and terms of use for free shared PIDs.
(*) ... These files should be linked to your project.
CPU CORE CLOCK FREQUENCY
========================
We supply assembler modules for clock frequencies of 12 MHz, 12.8 MHz, 15 MHz,
16 MHz, 16.5 MHz 18 MHz and 20 MHz. Other clock rates are not supported. The
actual clock rate must be configured in usbconfig.h.
12 MHz Clock
This is the traditional clock rate of V-USB because it's the lowest clock
rate where the timing constraints of the USB spec can be met.
15 MHz Clock
Similar to 12 MHz, but some NOPs inserted. On the other hand, the higher clock
rate allows for some loops which make the resulting code size somewhat smaller
than the 12 MHz version.
16 MHz Clock
This clock rate has been added for users of the Arduino board and other
ready-made boards which come with a fixed 16 MHz crystal. It's also an option
if you need the slightly higher clock rate for performance reasons. Since
16 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code
is somewhat tricky and has to insert a leap cycle every third byte.
12.8 MHz and 16.5 MHz Clock
The assembler modules for these clock rates differ from the other modules
because they have been built for an RC oscillator with only 1% precision. The
receiver code inserts leap cycles to compensate for clock deviations. 1% is
also the precision which can be achieved by calibrating the internal RC
oscillator of the AVR. Please note that only AVRs with internal 64 MHz PLL
oscillator can reach 16.5 MHz with the RC oscillator. This includes the very
popular ATTiny25, ATTiny45, ATTiny85 series as well as the ATTiny26. Almost
all AVRs can reach 12.8 MHz, although this is outside the specified range.
See the EasyLogger example at http://www.obdev.at/vusb/easylogger.html for
code which calibrates the RC oscillator based on the USB frame clock.
18 MHz Clock
This module is closer to the USB specification because it performs an on the
fly CRC check for incoming packets. Packets with invalid checksum are
discarded as required by the spec. If you also implement checks for data
PID toggling on application level (see option USB_CFG_CHECK_DATA_TOGGLING
in usbconfig.h for more info), this ensures data integrity. Due to the CRC
tables and alignment requirements, this code is bigger than modules for other
clock rates. To activate this module, you must define USB_CFG_CHECK_CRC to 1
and USB_CFG_CLOCK_KHZ to 18000 in usbconfig.h.
20 MHz Clock
This module is for people who won't do it with less than the maximum. Since
20 MHz is not divisible by the USB low speed bit clock of 1.5 MHz, the code
uses similar tricks as the 16 MHz module to insert leap cycles.
USB IDENTIFIERS
===============
Every USB device needs a vendor- and a product-identifier (VID and PID). VIDs
are obtained from usb.org for a price of 1,500 USD. Once you have a VID, you
can assign PIDs at will.
Since an entry level cost of 1,500 USD is too high for most small companies
and hobbyists, we provide some VID/PID pairs for free. See the file
USB-IDs-for-free.txt for details.
Objective Development also has some license offerings which include product
IDs. See http://www.obdev.at/vusb/ for details.
DEVELOPMENT SYSTEM
==================
This driver has been developed and optimized for the GNU compiler version 3
and 4. We recommend that you use the GNU compiler suite because it is freely
available. V-USB has also been ported to the IAR compiler and assembler. It
has been tested with IAR 4.10B/W32 and 4.12A/W32 on an ATmega8 with the
"small" and "tiny" memory model. Not every release is tested with IAR CC and
the driver may therefore fail to compile with IAR. Please note that gcc is
more efficient for usbdrv.c because this module has been deliberately
optimized for gcc.
Gcc version 3 produces smaller code than version 4 due to new optimizing
capabilities which don't always improve things on 8 bit CPUs. The code size
generated by gcc 4 can be reduced with the compiler options
-fno-move-loop-invariants, -fno-tree-scev-cprop and
-fno-inline-small-functions in addition to -Os. On devices with more than
8k of flash memory, we also recommend the linker option --relax (written as
-Wl,--relax for gcc) to convert absolute calls into relative where possible.
For more information about optimizing options see:
http://www.tty1.net/blog/2008-04-29-avr-gcc-optimisations_en.html
These optimizations are good for gcc 4.x. Version 3.x of gcc does not support
most of these options and produces good code anyway.
USING V-USB FOR FREE
====================
The AVR firmware driver is published under the GNU General Public License
Version 2 (GPL2) and the GNU General Public License Version 3 (GPL3). It is
your choice whether you apply the terms of version 2 or version 3.
If you decide for the free GPL2 or GPL3, we STRONGLY ENCOURAGE you to do the
following things IN ADDITION to the obligations from the GPL:
(1) Publish your entire project on a web site and drop us a note with the URL.
Use the form at http://www.obdev.at/vusb/feedback.html for your submission.
If you don't have a web site, you can publish the project in obdev's
documentation wiki at
http://www.obdev.at/goto.php?t=vusb-wiki&p=hosted-projects.
(2) Adhere to minimum publication standards. Please include AT LEAST:
- a circuit diagram in PDF, PNG or GIF format
- full source code for the host software
- a Readme.txt file in ASCII format which describes the purpose of the
project and what can be found in which directories and which files
- a reference to http://www.obdev.at/vusb/
(3) If you improve the driver firmware itself, please give us a free license
to your modifications for our commercial license offerings.
COMMERCIAL LICENSES FOR V-USB
=============================
If you don't want to publish your source code under the terms of the GPL,
you can simply pay money for V-USB. As an additional benefit you get
USB PIDs for free, reserved exclusively to you. See the file
"CommercialLicense.txt" for details.

View File

@ -0,0 +1,188 @@
/* Name: asmcommon.inc
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Christian Starkjohann
* Creation Date: 2007-11-05
* Tabsize: 4
* Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* Revision: $Id$
*/
/* Do not link this file! Link usbdrvasm.S instead, which includes the
* appropriate implementation!
*/
/*
General Description:
This file contains assembler code which is shared among the USB driver
implementations for different CPU cocks. Since the code must be inserted
in the middle of the module, it's split out into this file and #included.
Jump destinations called from outside:
sofError: Called when no start sequence was found.
se0: Called when a package has been successfully received.
overflow: Called when receive buffer overflows.
doReturn: Called after sending data.
Outside jump destinations used by this module:
waitForJ: Called to receive an already arriving packet.
sendAckAndReti:
sendNakAndReti:
sendCntAndReti:
usbSendAndReti:
The following macros must be defined before this file is included:
.macro POP_STANDARD
.endm
.macro POP_RETI
.endm
*/
#define token x1
overflow:
ldi x2, 1<<USB_INTR_PENDING_BIT
USB_STORE_PENDING(x2) ; clear any pending interrupts
ignorePacket:
clr token
rjmp storeTokenAndReturn
;----------------------------------------------------------------------------
; Processing of received packet (numbers in brackets are cycles after center of SE0)
;----------------------------------------------------------------------------
;This is the only non-error exit point for the software receiver loop
;we don't check any CRCs here because there is no time left.
se0:
subi cnt, USB_BUFSIZE ;[5]
neg cnt ;[6]
sub YL, cnt ;[7]
sbci YH, 0 ;[8]
ldi x2, 1<<USB_INTR_PENDING_BIT ;[9]
USB_STORE_PENDING(x2) ;[10] clear pending intr and check flag later. SE0 should be over.
ld token, y ;[11]
cpi token, USBPID_DATA0 ;[13]
breq handleData ;[14]
cpi token, USBPID_DATA1 ;[15]
breq handleData ;[16]
lds shift, usbDeviceAddr;[17]
ldd x2, y+1 ;[19] ADDR and 1 bit endpoint number
lsl x2 ;[21] shift out 1 bit endpoint number
cpse x2, shift ;[22]
rjmp ignorePacket ;[23]
/* only compute endpoint number in x3 if required later */
#if USB_CFG_HAVE_INTRIN_ENDPOINT || USB_CFG_IMPLEMENT_FN_WRITEOUT
ldd x3, y+2 ;[24] endpoint number + crc
rol x3 ;[26] shift in LSB of endpoint
#endif
cpi token, USBPID_IN ;[27]
breq handleIn ;[28]
cpi token, USBPID_SETUP ;[29]
breq handleSetupOrOut ;[30]
cpi token, USBPID_OUT ;[31]
brne ignorePacket ;[32] must be ack, nak or whatever
; rjmp handleSetupOrOut ; fallthrough
;Setup and Out are followed by a data packet two bit times (16 cycles) after
;the end of SE0. The sync code allows up to 40 cycles delay from the start of
;the sync pattern until the first bit is sampled. That's a total of 56 cycles.
handleSetupOrOut: ;[32]
#if USB_CFG_IMPLEMENT_FN_WRITEOUT /* if we have data for endpoint != 0, set usbCurrentTok to address */
andi x3, 0xf ;[32]
breq storeTokenAndReturn ;[33]
mov token, x3 ;[34] indicate that this is endpoint x OUT
#endif
storeTokenAndReturn:
sts usbCurrentTok, token;[35]
doReturn:
POP_STANDARD ;[37] 12...16 cycles
USB_LOAD_PENDING(YL) ;[49]
sbrc YL, USB_INTR_PENDING_BIT;[50] check whether data is already arriving
rjmp waitForJ ;[51] save the pops and pushes -- a new interrupt is already pending
sofError:
POP_RETI ;macro call
reti
handleData:
#if USB_CFG_CHECK_CRC
CRC_CLEANUP_AND_CHECK ; jumps to ignorePacket if CRC error
#endif
lds shift, usbCurrentTok;[18]
tst shift ;[20]
breq doReturn ;[21]
lds x2, usbRxLen ;[22]
tst x2 ;[24]
brne sendNakAndReti ;[25]
; 2006-03-11: The following two lines fix a problem where the device was not
; recognized if usbPoll() was called less frequently than once every 4 ms.
cpi cnt, 4 ;[26] zero sized data packets are status phase only -- ignore and ack
brmi sendAckAndReti ;[27] keep rx buffer clean -- we must not NAK next SETUP
#if USB_CFG_CHECK_DATA_TOGGLING
sts usbCurrentDataToken, token ; store for checking by C code
#endif
sts usbRxLen, cnt ;[28] store received data, swap buffers
sts usbRxToken, shift ;[30]
lds x2, usbInputBufOffset;[32] swap buffers
ldi cnt, USB_BUFSIZE ;[34]
sub cnt, x2 ;[35]
sts usbInputBufOffset, cnt;[36] buffers now swapped
rjmp sendAckAndReti ;[38] 40 + 17 = 57 until SOP
handleIn:
;We don't send any data as long as the C code has not processed the current
;input data and potentially updated the output data. That's more efficient
;in terms of code size than clearing the tx buffers when a packet is received.
lds x1, usbRxLen ;[30]
cpi x1, 1 ;[32] negative values are flow control, 0 means "buffer free"
brge sendNakAndReti ;[33] unprocessed input packet?
ldi x1, USBPID_NAK ;[34] prepare value for usbTxLen
#if USB_CFG_HAVE_INTRIN_ENDPOINT
andi x3, 0xf ;[35] x3 contains endpoint
#if USB_CFG_SUPPRESS_INTR_CODE
brne sendNakAndReti ;[36]
#else
brne handleIn1 ;[36]
#endif
#endif
lds cnt, usbTxLen ;[37]
sbrc cnt, 4 ;[39] all handshake tokens have bit 4 set
rjmp sendCntAndReti ;[40] 42 + 16 = 58 until SOP
sts usbTxLen, x1 ;[41] x1 == USBPID_NAK from above
ldi YL, lo8(usbTxBuf) ;[43]
ldi YH, hi8(usbTxBuf) ;[44]
rjmp usbSendAndReti ;[45] 57 + 12 = 59 until SOP
; Comment about when to set usbTxLen to USBPID_NAK:
; We should set it back when we receive the ACK from the host. This would
; be simple to implement: One static variable which stores whether the last
; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
; ACK. However, we set it back immediately when we send the package,
; assuming that no error occurs and the host sends an ACK. We save one byte
; RAM this way and avoid potential problems with endless retries. The rest of
; the driver assumes error-free transfers anyway.
#if !USB_CFG_SUPPRESS_INTR_CODE && USB_CFG_HAVE_INTRIN_ENDPOINT /* placed here due to relative jump range */
handleIn1: ;[38]
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
; 2006-06-10 as suggested by O.Tamura: support second INTR IN / BULK IN endpoint
cpi x3, USB_CFG_EP3_NUMBER;[38]
breq handleIn3 ;[39]
#endif
lds cnt, usbTxLen1 ;[40]
sbrc cnt, 4 ;[42] all handshake tokens have bit 4 set
rjmp sendCntAndReti ;[43] 47 + 16 = 63 until SOP
sts usbTxLen1, x1 ;[44] x1 == USBPID_NAK from above
ldi YL, lo8(usbTxBuf1) ;[46]
ldi YH, hi8(usbTxBuf1) ;[47]
rjmp usbSendAndReti ;[48] 50 + 12 = 62 until SOP
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
handleIn3:
lds cnt, usbTxLen3 ;[41]
sbrc cnt, 4 ;[43]
rjmp sendCntAndReti ;[44] 49 + 16 = 65 until SOP
sts usbTxLen3, x1 ;[45] x1 == USBPID_NAK from above
ldi YL, lo8(usbTxBuf3) ;[47]
ldi YH, hi8(usbTxBuf3) ;[48]
rjmp usbSendAndReti ;[49] 51 + 12 = 63 until SOP
#endif
#endif

View File

@ -0,0 +1,16 @@
#include <DigiCDC.h>
void setup() {
// initialize the digital pin as an output.
SerialUSB.begin();
SerialUSB.println("CDC Test");
}
// the loop routine runs over and over again forever:
void loop() {
if (SerialUSB.available()) {
SerialUSB.write(SerialUSB.read());
}
SerialUSB.delay(10); // keep usb alive // can alos use SerialUSB.refresh();
}

View File

@ -0,0 +1,22 @@
This is the Readme file for the libs-device directory. This directory contains
code snippets which may be useful for USB device firmware.
WHAT IS INCLUDED IN THIS DIRECTORY?
===================================
osccal.c and osccal.h
This module contains a function which calibrates the AVR's built-in RC
oscillator based on the USB frame clock. See osccal.h for a documentation
of the API.
osctune.h
This header file contains a code snippet for usbconfig.h. With this code,
you can keep the AVR's internal RC oscillator in sync with the USB frame
clock. This is a continuous synchronization, not a single calibration at
USB reset as with osccal.c above. Please note that this code works only
if D- is wired to the interrupt, not D+.
----------------------------------------------------------------------------
(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH.
http://www.obdev.at/

View File

@ -0,0 +1,50 @@
/* Name: oddebug.c
* Project: AVR library
* Author: Christian Starkjohann
* Creation Date: 2005-01-16
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: oddebug.c 692 2008-11-07 15:07:40Z cs $
*/
#include "oddebug.h"
#if DEBUG_LEVEL > 0
#warning "Never compile production devices with debugging enabled"
static void uartPutc(char c)
{
while(!(ODDBG_USR & (1 << ODDBG_UDRE))); /* wait for data register empty */
ODDBG_UDR = c;
}
static uchar hexAscii(uchar h)
{
h &= 0xf;
if(h >= 10)
h += 'a' - (uchar)10 - '0';
h += '0';
return h;
}
static void printHex(uchar c)
{
uartPutc(hexAscii(c >> 4));
uartPutc(hexAscii(c));
}
void odDebug(uchar prefix, uchar *data, uchar len)
{
printHex(prefix);
uartPutc(':');
while(len--){
uartPutc(' ');
printHex(*data++);
}
uartPutc('\r');
uartPutc('\n');
}
#endif

View File

@ -0,0 +1,123 @@
/* Name: oddebug.h
* Project: AVR library
* Author: Christian Starkjohann
* Creation Date: 2005-01-16
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: oddebug.h 692 2008-11-07 15:07:40Z cs $
*/
#ifndef __oddebug_h_included__
#define __oddebug_h_included__
/*
General Description:
This module implements a function for debug logs on the serial line of the
AVR microcontroller. Debugging can be configured with the define
'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging
calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is
2, DBG1 and DBG2 logs will be printed.
A debug log consists of a label ('prefix') to indicate which debug log created
the output and a memory block to dump in hex ('data' and 'len').
*/
#ifndef F_CPU
# define F_CPU 12000000 /* 12 MHz */
#endif
/* make sure we have the UART defines: */
#include "usbportability.h"
#ifndef uchar
# define uchar unsigned char
#endif
#if DEBUG_LEVEL > 0 && !(defined TXEN || defined TXEN0) /* no UART in device */
# warning "Debugging disabled because device has no UART"
# undef DEBUG_LEVEL
#endif
#ifndef DEBUG_LEVEL
# define DEBUG_LEVEL 0
#endif
/* ------------------------------------------------------------------------- */
#if DEBUG_LEVEL > 0
# define DBG1(prefix, data, len) odDebug(prefix, data, len)
#else
# define DBG1(prefix, data, len)
#endif
#if DEBUG_LEVEL > 1
# define DBG2(prefix, data, len) odDebug(prefix, data, len)
#else
# define DBG2(prefix, data, len)
#endif
/* ------------------------------------------------------------------------- */
#if DEBUG_LEVEL > 0
extern void odDebug(uchar prefix, uchar *data, uchar len);
/* Try to find our control registers; ATMEL likes to rename these */
#if defined UBRR
# define ODDBG_UBRR UBRR
#elif defined UBRRL
# define ODDBG_UBRR UBRRL
#elif defined UBRR0
# define ODDBG_UBRR UBRR0
#elif defined UBRR0L
# define ODDBG_UBRR UBRR0L
#endif
#if defined UCR
# define ODDBG_UCR UCR
#elif defined UCSRB
# define ODDBG_UCR UCSRB
#elif defined UCSR0B
# define ODDBG_UCR UCSR0B
#endif
#if defined TXEN
# define ODDBG_TXEN TXEN
#else
# define ODDBG_TXEN TXEN0
#endif
#if defined USR
# define ODDBG_USR USR
#elif defined UCSRA
# define ODDBG_USR UCSRA
#elif defined UCSR0A
# define ODDBG_USR UCSR0A
#endif
#if defined UDRE
# define ODDBG_UDRE UDRE
#else
# define ODDBG_UDRE UDRE0
#endif
#if defined UDR
# define ODDBG_UDR UDR
#elif defined UDR0
# define ODDBG_UDR UDR0
#endif
static inline void odDebugInit(void)
{
ODDBG_UCR |= (1<<ODDBG_TXEN);
ODDBG_UBRR = F_CPU / (19200 * 16L) - 1;
}
#else
# define odDebugInit()
#endif
/* ------------------------------------------------------------------------- */
#endif /* __oddebug_h_included__ */

View File

@ -0,0 +1,63 @@
/* Name: osccal.c
* Author: Christian Starkjohann
* Creation Date: 2008-04-10
* Tabsize: 4
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: osccal.c 762 2009-08-12 17:10:30Z cs $
*/
#include <avr/io.h>
#ifndef uchar
#define uchar unsigned char
#endif
/* ------------------------------------------------------------------------- */
/* ------------------------ Oscillator Calibration ------------------------- */
/* ------------------------------------------------------------------------- */
/* Calibrate the RC oscillator. Our timing reference is the Start Of Frame
* signal (a single SE0 bit) repeating every millisecond immediately after
* a USB RESET. We first do a binary search for the OSCCAL value and then
* optimize this value with a neighboorhod search.
*/
void calibrateOscillator(void)
{
uchar step = 128;
uchar trialValue = 0, optimumValue;
int x, optimumDev, targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);
/* do a binary search: */
do{
OSCCAL = trialValue + step;
x = usbMeasureFrameLength(); /* proportional to current real frequency */
if(x < targetValue) /* frequency still too low */
trialValue += step;
step >>= 1;
}while(step > 0);
/* We have a precision of +/- 1 for optimum OSCCAL here */
/* now do a neighborhood search for optimum value */
optimumValue = trialValue;
optimumDev = x; /* this is certainly far away from optimum */
for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
x = usbMeasureFrameLength() - targetValue;
if(x < 0)
x = -x;
if(x < optimumDev){
optimumDev = x;
optimumValue = OSCCAL;
}
}
OSCCAL = optimumValue;
}
/*
Note: This calibration algorithm may try OSCCAL values of up to 192 even if
the optimum value is far below 192. It may therefore exceed the allowed clock
frequency of the CPU in low voltage designs!
You may replace this search algorithm with any other algorithm you like if
you have additional constraints such as a maximum CPU clock.
For version 5.x RC oscillators (those with a split range of 2x128 steps, e.g.
ATTiny25, ATTiny45, ATTiny85), it may be useful to search for the optimum in
both regions.
*/

View File

@ -0,0 +1,65 @@
/* Name: osccal.h
* Author: Christian Starkjohann
* Creation Date: 2008-04-10
* Tabsize: 4
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: osccal.h 762 2009-08-12 17:10:30Z cs $
*/
/*
General Description:
This module contains a function which calibrates the AVR's internal RC
oscillator so that the CPU runs at F_CPU (F_CPU is a macro which must be
defined when the module is compiled, best passed in the compiler command
line). The time reference is the USB frame clock of 1 kHz available
immediately after a USB RESET condition. Timing is done by counting CPU
cycles, so all interrupts must be disabled while the calibration runs. For
low level timing measurements, usbMeasureFrameLength() is called. This
function must be enabled in usbconfig.h by defining
USB_CFG_HAVE_MEASURE_FRAME_LENGTH to 1. It is recommended to call
calibrateOscillator() from the reset hook in usbconfig.h:
*/
#ifndef __ASSEMBLER__
#include <avr/interrupt.h> // for sei()
extern void calibrateOscillator(void);
#endif
#define USB_RESET_HOOK(resetStarts) if(!resetStarts){cli(); calibrateOscillator(); sei();}
/*
This routine is an alternative to the continuous synchronization described
in osctune.h.
Algorithm used:
calibrateOscillator() first does a binary search in the OSCCAL register for
the best matching oscillator frequency. Then it does a next neighbor search
to find the value with the lowest clock rate deviation. It is guaranteed to
find the best match among neighboring values, but for version 5 oscillators
(which have a discontinuous relationship between OSCCAL and frequency) a
better match might be available in another OSCCAL region.
Limitations:
This calibration algorithm may try OSCCAL values of up to 192 even if the
optimum value is far below 192. It may therefore exceed the allowed clock
frequency of the CPU in low voltage designs!
Precision depends on the OSCCAL vs. frequency dependency of the oscillator.
Typical precision for an ATMega168 (derived from the OSCCAL vs. F_RC diagram
in the data sheet) should be in the range of 0.4%. Only the 12.8 MHz and
16.5 MHz versions of V-USB (with built-in receiver PLL) can tolerate this
deviation! All other frequency modules require at least 0.2% precision.
*/
#ifndef __OSCCAL_H_INCLUDED__
#define __OSCCAL_H_INCLUDED__
//void calibrateOscillator(void);
/* This function calibrates the RC oscillator so that the CPU runs at F_CPU.
* It MUST be called immediately after the end of a USB RESET condition!
* Disable all interrupts during the call!
* It is recommended that you store the resulting value in EEPROM so that a
* good guess value is available after the next reset.
*/
#endif /* __OSCCAL_H_INCLUDED__ */

View File

@ -0,0 +1,88 @@
/* Name: osctune.h
* Author: Christian Starkjohann
* Creation Date: 2008-10-18
* Tabsize: 4
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: osctune.h 692 2008-11-07 15:07:40Z cs $
*/
/*
General Description:
This file is declared as C-header file although it is mostly documentation
how the RC oscillator can be kept in sync to the USB frame rate. The code
shown here must be added to usbconfig.h or this header file is included from
there. This code works only if D- is wired to the interrupt, not D+!!!
This is an alternative to the osccal routine in osccal.c. It has the advantage
that the synchronization is done continuously and that it has more compact
code size. The disadvantages are slow synchronization (it may take a while
until the driver works), that messages immediately after the SOF pulse may be
lost (and need to be retried by the host) and that the interrupt is on D-
contrary to most examples.
You may want to store a good calibration value in EEPROM for the next startup.
You know that the calibration value is good when the first USB message is
received. Do not store the value on every received message because the EEPROM
has a limited endurance.
Notes:
(*) You must declare the global character variable "lastTimer0Value" in your
main code.
(*) Timer 0 must be free running (not written by your code) and the prescaling
must be consistent with the TIMER0_PRESCALING define.
(*) Good values for Timer 0 prescaling depend on how precise the clock must
be tuned and how far away from the default clock rate the target clock is.
For precise tuning, choose a low prescaler factor, for a broad range of tuning
choose a high one. A prescaler factor of 64 is good for the entire OSCCAL
range and allows a precision of better than +/-1%. A prescaler factor of 8
allows tuning to slightly more than +/-6% of the default frequency and is
more precise than one step of OSCCAL. It is therefore not suitable to tune an
8 MHz oscillator to 12.5 MHz.
Thanks to Henrik Haftmann for the idea to this routine!
*/
#define TIMER0_PRESCALING 64 /* must match the configuration for TIMER0 in main */
#define TOLERATED_DEVIATION_PPT 5 /* max clock deviation before we tune in 1/10 % */
/* derived constants: */
#define EXPECTED_TIMER0_INCREMENT ((F_CPU / (1000 * TIMER0_PRESCALING)) & 0xff)
#define TOLERATED_DEVIATION (TOLERATED_DEVIATION_PPT * F_CPU / (1000000 * TIMER0_PRESCALING))
#ifdef __ASSEMBLER__
macro tuneOsccal
push YH ;[0]
in YL, TCNT0 ;[2]
lds YH, lastTimer0Value ;[3]
sts lastTimer0Value, YL ;[5]
sub YL, YH ;[7] time passed since last frame
subi YL, EXPECTED_TIMER0_INCREMENT ;[8]
#if OSCCAL > 0x3f /* outside I/O addressable range */
lds YH, OSCCAL ;[6]
#else
in YH, OSCCAL ;[6] assembler modle uses __SFR_OFFSET == 0
#endif
cpi YL, TOLERATED_DEVIATION + 1 ;[10]
brmi notTooHigh ;[11]
subi YH, 1 ;[12] clock rate was too high
; brcs tuningOverflow ; optionally check for overflow
rjmp osctuneDone ;[13]
notTooHigh:
cpi YL, -TOLERATED_DEVIATION ;[13]
brpl osctuneDone ;[14] not too low
inc YH ;[15] clock rate was too low
; breq tuningOverflow ; optionally check for overflow
osctuneDone:
#if OSCCAL > 0x3f /* outside I/O addressable range */
sts OSCCAL, YH ;[12-13] store tuned value
#else
out OSCCAL, YH ;[12-13] store tuned value
#endif
tuningOverflow:
pop YH ;[17]
endm ;[19] max number of cycles
#endif
#define USB_SOF_HOOK tuneOsccal

View File

@ -0,0 +1,87 @@
/*******************************************************************************************************************
*
* See the http://www.fourwalledcubicle.com/files/LightweightRingBuff.h for the license information.
*
*******************************************************************************************************************/
#include <avr/interrupt.h>
#include <stdint.h>
#include <util/atomic.h>
/*----------------------------------------------------------------------------------------------------------------*/
typedef struct
{
uint8_t* In; /**< Current storage location in the circular buffer. */
uint8_t* Out; /**< Current retrieval location in the circular buffer. */
uint8_t* Start; /**< Pointer to the start of the buffer's underlying storage array. */
uint8_t* End; /**< Pointer to the end of the buffer's underlying storage array. */
uint16_t Size; /**< Size of the buffer's underlying storage array. */
uint16_t Count; /**< Number of bytes currently stored in the buffer. */
} RingBuffer_t;
/*----------------------------------------------------------------------------------------------------------------*/
static inline void RingBuffer_InitBuffer(RingBuffer_t* Buffer,uint8_t* const DataPtr,const uint16_t Size)
{
Buffer->In = DataPtr;
Buffer->Out = DataPtr;
Buffer->Start = &DataPtr[0];
Buffer->End = &DataPtr[Size];
Buffer->Size = Size;
Buffer->Count = 0;
}
/*----------------------------------------------------------------------------------------------------------------*/
static inline uint16_t RingBuffer_GetCount(RingBuffer_t* const Buffer)
{
uint16_t Count;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
Count = Buffer->Count;
}
return Count;
}
/*----------------------------------------------------------------------------------------------------------------*/
static inline uint16_t RingBuffer_GetFreeCount(RingBuffer_t* const Buffer)
{
return (Buffer->Size - RingBuffer_GetCount(Buffer));
}
/*----------------------------------------------------------------------------------------------------------------*/
static inline uint8_t RingBuffer_IsEmpty(RingBuffer_t* const Buffer)
{
return (RingBuffer_GetCount(Buffer) == 0);
}
/*----------------------------------------------------------------------------------------------------------------*/
static inline uint8_t RingBuffer_IsFull(RingBuffer_t* const Buffer)
{
return (RingBuffer_GetCount(Buffer) == Buffer->Size);
}
/*----------------------------------------------------------------------------------------------------------------*/
static inline void RingBuffer_Insert(RingBuffer_t* Buffer, const uint8_t Data)
{
*Buffer->In = Data;
if (++Buffer->In == Buffer->End)
Buffer->In = Buffer->Start;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
Buffer->Count++;
}
}
/*----------------------------------------------------------------------------------------------------------------*/
static inline uint8_t RingBuffer_Remove(RingBuffer_t* Buffer)
{
uint8_t Data = *Buffer->Out;
if (++Buffer->Out == Buffer->End)
Buffer->Out = Buffer->Start;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
Buffer->Count--;
}
return Data;
}
/*----------------------------------------------------------------------------------------------------------------*/
static inline uint8_t RingBuffer_Peek(RingBuffer_t* const Buffer)
{
return *Buffer->Out;
}
/*----------------------------------------------------------------------------------------------------------------*/

View File

@ -0,0 +1,376 @@
/* Name: usbconfig.h
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Christian Starkjohann
* Creation Date: 2005-04-01
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: usbconfig-prototype.h 785 2010-05-30 17:57:07Z cs $
*/
#ifndef __usbconfig_h_included__
#define __usbconfig_h_included__
/*
General Description:
This file is an example configuration (with inline documentation) for the USB
driver. It configures V-USB for USB D+ connected to Port D bit 2 (which is
also hardware interrupt 0 on many devices) and USB D- to Port D bit 4. You may
wire the lines to any other port, as long as D+ is also wired to INT0 (or any
other hardware interrupt, as long as it is the highest level interrupt, see
section at the end of this file).
+ To create your own usbconfig.h file, copy this file to your project's
+ firmware source directory) and rename it to "usbconfig.h".
+ Then edit it accordingly.
*/
/* ---------------------------- Hardware Config ---------------------------- */
#define USB_CFG_IOPORTNAME D
/* This is the port where the USB bus is connected. When you configure it to
* "B", the registers PORTB, PINB and DDRB will be used.
*/
#define USB_CFG_DMINUS_BIT 4
/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
* This may be any bit in the port.
*/
#define USB_CFG_DPLUS_BIT 2
/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
* This may be any bit in the port. Please note that D+ must also be connected
* to interrupt pin INT0! [You can also use other interrupts, see section
* "Optional MCU Description" below, or you can connect D- to the interrupt, as
* it is required if you use the USB_COUNT_SOF feature. If you use D- for the
* interrupt, the USB interrupt will also be triggered at Start-Of-Frame
* markers every millisecond.]
*/
#define USB_CFG_CLOCK_KHZ (F_CPU/1000)
/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000,
* 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code
* require no crystal, they tolerate +/- 1% deviation from the nominal
* frequency. All other rates require a precision of 2000 ppm and thus a
* crystal!
* Since F_CPU should be defined to your actual clock rate anyway, you should
* not need to modify this setting.
*/
#define USB_CFG_CHECK_CRC 0
/* Define this to 1 if you want that the driver checks integrity of incoming
* data packets (CRC checks). CRC checks cost quite a bit of code size and are
* currently only available for 18 MHz crystal clock. You must choose
* USB_CFG_CLOCK_KHZ = 18000 if you enable this option.
*/
/* ----------------------- Optional Hardware Config ------------------------ */
/* #define USB_CFG_PULLUP_IOPORTNAME D */
/* If you connect the 1.5k pullup resistor from D- to a port pin instead of
* V+, you can connect and disconnect the device from firmware by calling
* the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h).
* This constant defines the port on which the pullup resistor is connected.
*/
/* #define USB_CFG_PULLUP_BIT 4 */
/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined
* above) where the 1.5k pullup resistor is connected. See description
* above for details.
*/
/* --------------------------- Functional Range ---------------------------- */
#define USB_CFG_HAVE_INTRIN_ENDPOINT 0
/* Define this to 1 if you want to compile a version with two endpoints: The
* default control endpoint 0 and an interrupt-in endpoint (any other endpoint
* number).
*/
#define USB_CFG_HAVE_INTRIN_ENDPOINT3 0
/* Define this to 1 if you want to compile a version with three endpoints: The
* default control endpoint 0, an interrupt-in endpoint 3 (or the number
* configured below) and a catch-all default interrupt-in endpoint as above.
* You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature.
*/
#define USB_CFG_EP3_NUMBER 3
/* If the so-called endpoint 3 is used, it can now be configured to any other
* endpoint number (except 0) with this macro. Default if undefined is 3.
*/
/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */
/* The above macro defines the startup condition for data toggling on the
* interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1.
* Since the token is toggled BEFORE sending any data, the first packet is
* sent with the oposite value of this configuration!
*/
#define USB_CFG_IMPLEMENT_HALT 0
/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature
* for endpoint 1 (interrupt endpoint). Although you may not need this feature,
* it is required by the standard. We have made it a config option because it
* bloats the code considerably.
*/
#define USB_CFG_SUPPRESS_INTR_CODE 0
/* Define this to 1 if you want to declare interrupt-in endpoints, but don't
* want to send any data over them. If this macro is defined to 1, functions
* usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if
* you need the interrupt-in endpoints in order to comply to an interface
* (e.g. HID), but never want to send any data. This option saves a couple
* of bytes in flash memory and the transmit buffers in RAM.
*/
#define USB_CFG_INTR_POLL_INTERVAL 10
/* If you compile a version with endpoint 1 (interrupt-in), this is the poll
* interval. The value is in milliseconds and must not be less than 10 ms for
* low speed devices.
*/
#define USB_CFG_IS_SELF_POWERED 0
/* Define this to 1 if the device has its own power supply. Set it to 0 if the
* device is powered from the USB bus.
*/
#define USB_CFG_MAX_BUS_POWER 100
/* Set this variable to the maximum USB bus power consumption of your device.
* The value is in milliamperes. [It will be divided by two since USB
* communicates power requirements in units of 2 mA.]
*/
#define USB_CFG_IMPLEMENT_FN_WRITE 0
/* Set this to 1 if you want usbFunctionWrite() to be called for control-out
* transfers. Set it to 0 if you don't need it and want to save a couple of
* bytes.
*/
#define USB_CFG_IMPLEMENT_FN_READ 0
/* Set this to 1 if you need to send control replies which are generated
* "on the fly" when usbFunctionRead() is called. If you only want to send
* data from a static buffer, set it to 0 and return the data from
* usbFunctionSetup(). This saves a couple of bytes.
*/
#define USB_CFG_IMPLEMENT_FN_WRITEOUT 0
/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints.
* You must implement the function usbFunctionWriteOut() which receives all
* interrupt/bulk data sent to any endpoint other than 0. The endpoint number
* can be found in 'usbRxToken'.
*/
#define USB_CFG_HAVE_FLOWCONTROL 0
/* Define this to 1 if you want flowcontrol over USB data. See the definition
* of the macros usbDisableAllRequests() and usbEnableAllRequests() in
* usbdrv.h.
*/
#define USB_CFG_DRIVER_FLASH_PAGE 0
/* If the device has more than 64 kBytes of flash, define this to the 64 k page
* where the driver's constants (descriptors) are located. Or in other words:
* Define this to 1 for boot loaders on the ATMega128.
*/
#define USB_CFG_LONG_TRANSFERS 0
/* Define this to 1 if you want to send/receive blocks of more than 254 bytes
* in a single control-in or control-out transfer. Note that the capability
* for long transfers increases the driver size.
*/
/* #define USB_RX_USER_HOOK(data, len) if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */
/* This macro is a hook if you want to do unconventional things. If it is
* defined, it's inserted at the beginning of received message processing.
* If you eat the received message and don't want default processing to
* proceed, do a return after doing your things. One possible application
* (besides debugging) is to flash a status LED on each packet.
*/
/* #define USB_RESET_HOOK(resetStarts) if(!resetStarts){hadUsbReset();} */
/* This macro is a hook if you need to know when an USB RESET occurs. It has
* one parameter which distinguishes between the start of RESET state and its
* end.
*/
/* #define USB_SET_ADDRESS_HOOK() hadAddressAssigned(); */
/* This macro (if defined) is executed when a USB SET_ADDRESS request was
* received.
*/
#define USB_COUNT_SOF 0
/* define this macro to 1 if you need the global variable "usbSofCount" which
* counts SOF packets. This feature requires that the hardware interrupt is
* connected to D- instead of D+.
*/
/* #ifdef __ASSEMBLER__
* macro myAssemblerMacro
* in YL, TCNT0
* sts timer0Snapshot, YL
* endm
* #endif
* #define USB_SOF_HOOK myAssemblerMacro
* This macro (if defined) is executed in the assembler module when a
* Start Of Frame condition is detected. It is recommended to define it to
* the name of an assembler macro which is defined here as well so that more
* than one assembler instruction can be used. The macro may use the register
* YL and modify SREG. If it lasts longer than a couple of cycles, USB messages
* immediately after an SOF pulse may be lost and must be retried by the host.
* What can you do with this hook? Since the SOF signal occurs exactly every
* 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in
* designs running on the internal RC oscillator.
* Please note that Start Of Frame detection works only if D- is wired to the
* interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES!
*/
#define USB_CFG_CHECK_DATA_TOGGLING 0
/* define this macro to 1 if you want to filter out duplicate data packets
* sent by the host. Duplicates occur only as a consequence of communication
* errors, when the host does not receive an ACK. Please note that you need to
* implement the filtering yourself in usbFunctionWriteOut() and
* usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable
* for each control- and out-endpoint to check for duplicate packets.
*/
#define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 0
/* define this macro to 1 if you want the function usbMeasureFrameLength()
* compiled in. This function can be used to calibrate the AVR's RC oscillator.
*/
#define USB_USE_FAST_CRC 0
/* The assembler module has two implementations for the CRC algorithm. One is
* faster, the other is smaller. This CRC routine is only used for transmitted
* messages where timing is not critical. The faster routine needs 31 cycles
* per byte while the smaller one needs 61 to 69 cycles. The faster routine
* may be worth the 32 bytes bigger code size if you transmit lots of data and
* run the AVR close to its limit.
*/
/* -------------------------- Device Description --------------------------- */
#define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */
/* USB vendor ID for the device, low byte first. If you have registered your
* own Vendor ID, define it here. Otherwise you may use one of obdev's free
* shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules!
* *** IMPORTANT NOTE ***
* This template uses obdev's shared VID/PID pair for Vendor Class devices
* with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand
* the implications!
*/
#define USB_CFG_DEVICE_ID 0xdc, 0x05 /* = 0x05dc = 1500 */
/* This is the ID of the product, low byte first. It is interpreted in the
* scope of the vendor ID. If you have registered your own VID with usb.org
* or if you have licensed a PID from somebody else, define it here. Otherwise
* you may use one of obdev's free shared VID/PID pairs. See the file
* USB-IDs-for-free.txt for details!
* *** IMPORTANT NOTE ***
* This template uses obdev's shared VID/PID pair for Vendor Class devices
* with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand
* the implications!
*/
#define USB_CFG_DEVICE_VERSION 0x00, 0x01
/* Version number of the device: Minor number first, then major number.
*/
#define USB_CFG_VENDOR_NAME 'o', 'b', 'd', 'e', 'v', '.', 'a', 't'
#define USB_CFG_VENDOR_NAME_LEN 8
/* These two values define the vendor name returned by the USB device. The name
* must be given as a list of characters under single quotes. The characters
* are interpreted as Unicode (UTF-16) entities.
* If you don't want a vendor name string, undefine these macros.
* ALWAYS define a vendor name containing your Internet domain name if you use
* obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for
* details.
*/
#define USB_CFG_DEVICE_NAME 'T', 'e', 'm', 'p', 'l', 'a', 't', 'e'
#define USB_CFG_DEVICE_NAME_LEN 8
/* Same as above for the device name. If you don't want a device name, undefine
* the macros. See the file USB-IDs-for-free.txt before you assign a name if
* you use a shared VID/PID.
*/
/*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */
/*#define USB_CFG_SERIAL_NUMBER_LEN 0 */
/* Same as above for the serial number. If you don't want a serial number,
* undefine the macros.
* It may be useful to provide the serial number through other means than at
* compile time. See the section about descriptor properties below for how
* to fine tune control over USB descriptors such as the string descriptor
* for the serial number.
*/
#define USB_CFG_DEVICE_CLASS 0xff /* set to 0 if deferred to interface */
#define USB_CFG_DEVICE_SUBCLASS 0
/* See USB specification if you want to conform to an existing device class.
* Class 0xff is "vendor specific".
*/
#define USB_CFG_INTERFACE_CLASS 0 /* define class here if not at device level */
#define USB_CFG_INTERFACE_SUBCLASS 0
#define USB_CFG_INTERFACE_PROTOCOL 0
/* See USB specification if you want to conform to an existing device class or
* protocol. The following classes must be set at interface level:
* HID class is 3, no subclass and protocol required (but may be useful!)
* CDC class is 2, use subclass 2 and protocol 1 for ACM
*/
/* #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 42 */
/* Define this to the length of the HID report descriptor, if you implement
* an HID device. Otherwise don't define it or define it to 0.
* If you use this define, you must add a const PROGMEM character array named
* "usbHidReportDescriptor" to your code which contains the report descriptor.
* Don't forget to keep the array and this define in sync!
*/
/* #define USB_PUBLIC static */
/* Use the define above if you #include usbdrv.c instead of linking against it.
* This technique saves a couple of bytes in flash memory.
*/
/* ------------------- Fine Control over USB Descriptors ------------------- */
/* If you don't want to use the driver's default USB descriptors, you can
* provide our own. These can be provided as (1) fixed length static data in
* flash memory, (2) fixed length static data in RAM or (3) dynamically at
* runtime in the function usbFunctionDescriptor(). See usbdrv.h for more
* information about this function.
* Descriptor handling is configured through the descriptor's properties. If
* no properties are defined or if they are 0, the default descriptor is used.
* Possible properties are:
* + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched
* at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is
* used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if
* you want RAM pointers.
* + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found
* in static memory is in RAM, not in flash memory.
* + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash),
* the driver must know the descriptor's length. The descriptor itself is
* found at the address of a well known identifier (see below).
* List of static descriptor names (must be declared const PROGMEM if in flash):
* char usbDescriptorDevice[];
* char usbDescriptorConfiguration[];
* char usbDescriptorHidReport[];
* char usbDescriptorString0[];
* int usbDescriptorStringVendor[];
* int usbDescriptorStringDevice[];
* int usbDescriptorStringSerialNumber[];
* Other descriptors can't be provided statically, they must be provided
* dynamically at runtime.
*
* Descriptor properties are or-ed or added together, e.g.:
* #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18))
*
* The following descriptors are defined:
* USB_CFG_DESCR_PROPS_DEVICE
* USB_CFG_DESCR_PROPS_CONFIGURATION
* USB_CFG_DESCR_PROPS_STRINGS
* USB_CFG_DESCR_PROPS_STRING_0
* USB_CFG_DESCR_PROPS_STRING_VENDOR
* USB_CFG_DESCR_PROPS_STRING_PRODUCT
* USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
* USB_CFG_DESCR_PROPS_HID
* USB_CFG_DESCR_PROPS_HID_REPORT
* USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver)
*
* Note about string descriptors: String descriptors are not just strings, they
* are Unicode strings prefixed with a 2 byte header. Example:
* int serialNumberDescriptor[] = {
* USB_STRING_DESCRIPTOR_HEADER(6),
* 'S', 'e', 'r', 'i', 'a', 'l'
* };
*/
#define USB_CFG_DESCR_PROPS_DEVICE 0
#define USB_CFG_DESCR_PROPS_CONFIGURATION 0
#define USB_CFG_DESCR_PROPS_STRINGS 0
#define USB_CFG_DESCR_PROPS_STRING_0 0
#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0
#define USB_CFG_DESCR_PROPS_HID 0
#define USB_CFG_DESCR_PROPS_HID_REPORT 0
#define USB_CFG_DESCR_PROPS_UNKNOWN 0
/* ----------------------- Optional MCU Description ------------------------ */
/* The following configurations have working defaults in usbdrv.h. You
* usually don't need to set them explicitly. Only if you want to run
* the driver on a device which is not yet supported or with a compiler
* which is not fully supported (such as IAR C) or if you use a differnt
* interrupt than INT0, you may have to define some of these.
*/
/* #define USB_INTR_CFG MCUCR */
/* #define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) */
/* #define USB_INTR_CFG_CLR 0 */
/* #define USB_INTR_ENABLE GIMSK */
/* #define USB_INTR_ENABLE_BIT INT0 */
/* #define USB_INTR_PENDING GIFR */
/* #define USB_INTR_PENDING_BIT INTF0 */
/* #define USB_INTR_VECTOR INT0_vect */
#endif /* __usbconfig_h_included__ */

View File

@ -0,0 +1,438 @@
/* Name: usbconfig.h
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Christian Starkjohann
* Creation Date: 2005-04-01
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: usbconfig-prototype.h 785 2010-05-30 17:57:07Z cs $
*/
#ifndef __usbconfig_h_included__
#define __usbconfig_h_included__
/*
General Description:
This file is an example configuration (with inline documentation) for the USB
driver. It configures V-USB for USB D+ connected to Port D bit 2 (which is
also hardware interrupt 0 on many devices) and USB D- to Port D bit 4. You may
wire the lines to any other port, as long as D+ is also wired to INT0 (or any
other hardware interrupt, as long as it is the highest level interrupt, see
section at the end of this file).
+ To create your own usbconfig.h file, copy this file to your project's
+ firmware source directory) and rename it to "usbconfig.h".
+ Then edit it accordingly.
*/
/* ---------------------------- Hardware Config ---------------------------- */
/* #define USB_CFG_IOPORTNAME D */
/* This is the port where the USB bus is connected. When you configure it to
* "B", the registers PORTB, PINB and DDRB will be used.
*/
/* #define USB_CFG_DMINUS_BIT 4 */
/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
* This may be any bit in the port.
*/
/* #define USB_CFG_DPLUS_BIT 2 */
/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
* This may be any bit in the port. Please note that D+ must also be connected
* to interrupt pin INT0! [You can also use other interrupts, see section
* "Optional MCU Description" below, or you can connect D- to the interrupt, as
* it is required if you use the USB_COUNT_SOF feature. If you use D- for the
* interrupt, the USB interrupt will also be triggered at Start-Of-Frame
* markers every millisecond.]
*/
#if defined (__AVR_ATtiny44__) || defined (__AVR_ATtiny84__)
#define USB_CFG_IOPORTNAME B
#define USB_CFG_DMINUS_BIT 1
#define USB_CFG_DPLUS_BIT 2
#elif defined (__AVR_ATtiny45__) || defined (__AVR_ATtiny85__)
#define USB_CFG_IOPORTNAME B
#define USB_CFG_DMINUS_BIT 3
#define USB_CFG_DPLUS_BIT 4
#elif defined (__AVR_ATtiny87__) || defined (__AVR_ATtiny167__)
#define USB_CFG_IOPORTNAME B
#define USB_CFG_DMINUS_BIT 3
#define USB_CFG_DPLUS_BIT 6
#elif defined (__AVR_ATtiny461__) || defined (__AVR_ATtiny861__)
#define USB_CFG_IOPORTNAME B
#define USB_CFG_DMINUS_BIT 5
#define USB_CFG_DPLUS_BIT 6
#else
/* ATtiny2313, ATmega8/48/88/168 */
#define USB_CFG_IOPORTNAME D
#define USB_CFG_DMINUS_BIT 3
#define USB_CFG_DPLUS_BIT 2
#endif
#define USB_CFG_CLOCK_KHZ (F_CPU/1000)
/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000,
* 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code
* require no crystal, they tolerate +/- 1% deviation from the nominal
* frequency. All other rates require a precision of 2000 ppm and thus a
* crystal!
* Since F_CPU should be defined to your actual clock rate anyway, you should
* not need to modify this setting.
*/
#if USB_CFG_CLOCK_KHZ==18000
#define USB_CFG_CHECK_CRC 1
#else
#define USB_CFG_CHECK_CRC 0
#endif
/* Define this to 1 if you want that the driver checks integrity of incoming
* data packets (CRC checks). CRC checks cost quite a bit of code size and are
* currently only available for 18 MHz crystal clock. You must choose
* USB_CFG_CLOCK_KHZ = 18000 if you enable this option.
*/
/* ----------------------- Optional Hardware Config ------------------------ */
/* #define USB_CFG_PULLUP_IOPORTNAME D */
/* If you connect the 1.5k pullup resistor from D- to a port pin instead of
* V+, you can connect and disconnect the device from firmware by calling
* the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h).
* This constant defines the port on which the pullup resistor is connected.
*/
/* #define USB_CFG_PULLUP_BIT 4 */
/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined
* above) where the 1.5k pullup resistor is connected. See description
* above for details.
*/
/* --------------------------- Functional Range ---------------------------- */
#define USB_CFG_HAVE_INTRIN_ENDPOINT 1
/* Define this to 1 if you want to compile a version with two endpoints: The
* default control endpoint 0 and an interrupt-in endpoint (any other endpoint
* number).
*/
#define USB_CFG_HAVE_INTRIN_ENDPOINT3 1
/* Define this to 1 if you want to compile a version with three endpoints: The
* default control endpoint 0, an interrupt-in endpoint 3 (or the number
* configured below) and a catch-all default interrupt-in endpoint as above.
* You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature.
*/
#define USB_CFG_EP3_NUMBER 3
/* If the so-called endpoint 3 is used, it can now be configured to any other
* endpoint number (except 0) with this macro. Default if undefined is 3.
*/
/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */
/* The above macro defines the startup condition for data toggling on the
* interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1.
* Since the token is toggled BEFORE sending any data, the first packet is
* sent with the oposite value of this configuration!
*/
#define USB_CFG_IMPLEMENT_HALT 0
/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature
* for endpoint 1 (interrupt endpoint). Although you may not need this feature,
* it is required by the standard. We have made it a config option because it
* bloats the code considerably.
*/
#define USB_CFG_SUPPRESS_INTR_CODE 0
/* Define this to 1 if you want to declare interrupt-in endpoints, but don't
* want to send any data over them. If this macro is defined to 1, functions
* usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if
* you need the interrupt-in endpoints in order to comply to an interface
* (e.g. HID), but never want to send any data. This option saves a couple
* of bytes in flash memory and the transmit buffers in RAM.
*/
#define USB_CFG_INTR_POLL_INTERVAL 255
/* If you compile a version with endpoint 1 (interrupt-in), this is the poll
* interval. The value is in milliseconds and must not be less than 10 ms for
* low speed devices.
*/
#define USB_CFG_IS_SELF_POWERED 0
/* Define this to 1 if the device has its own power supply. Set it to 0 if the
* device is powered from the USB bus.
*/
#define USB_CFG_MAX_BUS_POWER 100
/* Set this variable to the maximum USB bus power consumption of your device.
* The value is in milliamperes. [It will be divided by two since USB
* communicates power requirements in units of 2 mA.]
*/
#define USB_CFG_IMPLEMENT_FN_WRITE 1
/* Set this to 1 if you want usbFunctionWrite() to be called for control-out
* transfers. Set it to 0 if you don't need it and want to save a couple of
* bytes.
*/
#define USB_CFG_IMPLEMENT_FN_READ 1
/* Set this to 1 if you need to send control replies which are generated
* "on the fly" when usbFunctionRead() is called. If you only want to send
* data from a static buffer, set it to 0 and return the data from
* usbFunctionSetup(). This saves a couple of bytes.
*/
#define USB_CFG_IMPLEMENT_FN_WRITEOUT 1
/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints.
* You must implement the function usbFunctionWriteOut() which receives all
* interrupt/bulk data sent to any endpoint other than 0. The endpoint number
* can be found in 'usbRxToken'.
*/
#define USB_CFG_HAVE_FLOWCONTROL 1
/* Define this to 1 if you want flowcontrol over USB data. See the definition
* of the macros usbDisableAllRequests() and usbEnableAllRequests() in
* usbdrv.h.
*/
#define USB_CFG_DRIVER_FLASH_PAGE 0
/* If the device has more than 64 kBytes of flash, define this to the 64 k page
* where the driver's constants (descriptors) are located. Or in other words:
* Define this to 1 for boot loaders on the ATMega128.
*/
#define USB_CFG_LONG_TRANSFERS 0
/* Define this to 1 if you want to send/receive blocks of more than 254 bytes
* in a single control-in or control-out transfer. Note that the capability
* for long transfers increases the driver size.
*/
/* #define USB_RX_USER_HOOK(data, len) if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */
/* This macro is a hook if you want to do unconventional things. If it is
* defined, it's inserted at the beginning of received message processing.
* If you eat the received message and don't want default processing to
* proceed, do a return after doing your things. One possible application
* (besides debugging) is to flash a status LED on each packet.
*/
/* #define USB_RESET_HOOK(resetStarts) if(!resetStarts){hadUsbReset();} */
/* This macro is a hook if you need to know when an USB RESET occurs. It has
* one parameter which distinguishes between the start of RESET state and its
* end.
*/
/* #define USB_SET_ADDRESS_HOOK() hadAddressAssigned(); */
/* This macro (if defined) is executed when a USB SET_ADDRESS request was
* received.
*/
#define USB_COUNT_SOF 0
/* define this macro to 1 if you need the global variable "usbSofCount" which
* counts SOF packets. This feature requires that the hardware interrupt is
* connected to D- instead of D+.
*/
/* #ifdef __ASSEMBLER__
* macro myAssemblerMacro
* in YL, TCNT0
* sts timer0Snapshot, YL
* endm
* #endif
* #define USB_SOF_HOOK myAssemblerMacro
* This macro (if defined) is executed in the assembler module when a
* Start Of Frame condition is detected. It is recommended to define it to
* the name of an assembler macro which is defined here as well so that more
* than one assembler instruction can be used. The macro may use the register
* YL and modify SREG. If it lasts longer than a couple of cycles, USB messages
* immediately after an SOF pulse may be lost and must be retried by the host.
* What can you do with this hook? Since the SOF signal occurs exactly every
* 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in
* designs running on the internal RC oscillator.
* Please note that Start Of Frame detection works only if D- is wired to the
* interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES!
*/
#define USB_CFG_CHECK_DATA_TOGGLING 0
/* define this macro to 1 if you want to filter out duplicate data packets
* sent by the host. Duplicates occur only as a consequence of communication
* errors, when the host does not receive an ACK. Please note that you need to
* implement the filtering yourself in usbFunctionWriteOut() and
* usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable
* for each control- and out-endpoint to check for duplicate packets.
*/
#define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 1
#include "osccal.h"
/* define this macro to 1 if you want the function usbMeasureFrameLength()
* compiled in. This function can be used to calibrate the AVR's RC oscillator.
*/
#define USB_USE_FAST_CRC 0
/* The assembler module has two implementations for the CRC algorithm. One is
* faster, the other is smaller. This CRC routine is only used for transmitted
* messages where timing is not critical. The faster routine needs 31 cycles
* per byte while the smaller one needs 61 to 69 cycles. The faster routine
* may be worth the 32 bytes bigger code size if you transmit lots of data and
* run the AVR close to its limit.
*/
/* -------------------------- Device Description --------------------------- */
#define USB_CFG_VENDOR_ID 0xd0, 0x16 /* = 0x16c0 = 5824 = voti.nl */
/* USB vendor ID for the device, low byte first. If you have registered your
* own Vendor ID, define it here. Otherwise you may use one of obdev's free
* shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules!
* *** IMPORTANT NOTE ***
* This template uses obdev's shared VID/PID pair for Vendor Class devices
* with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand
* the implications!
*/
#define USB_CFG_DEVICE_ID 0x7e, 0x08 /* = 0x05e1 = 1505 */
/* This is the ID of the product, low byte first. It is interpreted in the
* scope of the vendor ID. If you have registered your own VID with usb.org
* or if you have licensed a PID from somebody else, define it here. Otherwise
* you may use one of obdev's free shared VID/PID pairs. See the file
* USB-IDs-for-free.txt for details!
* *** IMPORTANT NOTE ***
* This template uses obdev's shared VID/PID pair for Vendor Class devices
* with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand
* the implications!
*/
#define USB_CFG_DEVICE_VERSION 0x00, 0x01
/* Version number of the device: Minor number first, then major number.
*/
#define USB_CFG_VENDOR_NAME 'd','i','g','i','s','t','u','m','p','.','c','o','m'
#define USB_CFG_VENDOR_NAME_LEN 13
/* These two values define the vendor name returned by the USB device. The name
* must be given as a list of characters under single quotes. The characters
* are interpreted as Unicode (UTF-16) entities.
* If you don't want a vendor name string, undefine these macros.
* ALWAYS define a vendor name containing your Internet domain name if you use
* obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for
* details.
*/
#define USB_CFG_DEVICE_NAME 'D','i','g','i','s','p','a','r','k',' ','S','e','r','i','a','l'
#define USB_CFG_DEVICE_NAME_LEN 16
/* Same as above for the device name. If you don't want a device name, undefine
* the macros. See the file USB-IDs-for-free.txt before you assign a name if
* you use a shared VID/PID.
*/
/*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */
/*#define USB_CFG_SERIAL_NUMBER_LEN 0 */
/* Same as above for the serial number. If you don't want a serial number,
* undefine the macros.
* It may be useful to provide the serial number through other means than at
* compile time. See the section about descriptor properties below for how
* to fine tune control over USB descriptors such as the string descriptor
* for the serial number.
*/
#define USB_CFG_DEVICE_CLASS 2 /* set to 0 if deferred to interface */
#define USB_CFG_DEVICE_SUBCLASS 0
/* See USB specification if you want to conform to an existing device class.
* Class 0xff is "vendor specific".
*/
#define USB_CFG_INTERFACE_CLASS 2 /* CDC class */
#define USB_CFG_INTERFACE_SUBCLASS 2 /* Abstract (Modem) */
#define USB_CFG_INTERFACE_PROTOCOL 1 /* AT-Commands */
/* See USB specification if you want to conform to an existing device class or
* protocol. The following classes must be set at interface level:
* HID class is 3, no subclass and protocol required (but may be useful!)
* CDC class is 2, use subclass 2 and protocol 1 for ACM
*/
/* #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 42 */
/* Define this to the length of the HID report descriptor, if you implement
* an HID device. Otherwise don't define it or define it to 0.
* If you use this define, you must add a const PROGMEM character array named
* "usbHidReportDescriptor" to your code which contains the report descriptor.
* Don't forget to keep the array and this define in sync!
*/
/* #define USB_PUBLIC static */
/* Use the define above if you #include usbdrv.c instead of linking against it.
* This technique saves a couple of bytes in flash memory.
*/
/* ------------------- Fine Control over USB Descriptors ------------------- */
/* If you don't want to use the driver's default USB descriptors, you can
* provide our own. These can be provided as (1) fixed length static data in
* flash memory, (2) fixed length static data in RAM or (3) dynamically at
* runtime in the function usbFunctionDescriptor(). See usbdrv.h for more
* information about this function.
* Descriptor handling is configured through the descriptor's properties. If
* no properties are defined or if they are 0, the default descriptor is used.
* Possible properties are:
* + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched
* at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is
* used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if
* you want RAM pointers.
* + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found
* in static memory is in RAM, not in flash memory.
* + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash),
* the driver must know the descriptor's length. The descriptor itself is
* found at the address of a well known identifier (see below).
* List of static descriptor names (must be declared const PROGMEM if in flash):
* char usbDescriptorDevice[];
* char usbDescriptorConfiguration[];
* char usbDescriptorHidReport[];
* char usbDescriptorString0[];
* int usbDescriptorStringVendor[];
* int usbDescriptorStringDevice[];
* int usbDescriptorStringSerialNumber[];
* Other descriptors can't be provided statically, they must be provided
* dynamically at runtime.
*
* Descriptor properties are or-ed or added together, e.g.:
* #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18))
*
* The following descriptors are defined:
* USB_CFG_DESCR_PROPS_DEVICE
* USB_CFG_DESCR_PROPS_CONFIGURATION
* USB_CFG_DESCR_PROPS_STRINGS
* USB_CFG_DESCR_PROPS_STRING_0
* USB_CFG_DESCR_PROPS_STRING_VENDOR
* USB_CFG_DESCR_PROPS_STRING_PRODUCT
* USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
* USB_CFG_DESCR_PROPS_HID
* USB_CFG_DESCR_PROPS_HID_REPORT
* USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver)
*
* Note about string descriptors: String descriptors are not just strings, they
* are Unicode strings prefixed with a 2 byte header. Example:
* int serialNumberDescriptor[] = {
* USB_STRING_DESCRIPTOR_HEADER(6),
* 'S', 'e', 'r', 'i', 'a', 'l'
* };
*/
#define USB_CFG_DESCR_PROPS_DEVICE 0
#define USB_CFG_DESCR_PROPS_CONFIGURATION USB_PROP_IS_DYNAMIC
#define USB_CFG_DESCR_PROPS_STRINGS 0
#define USB_CFG_DESCR_PROPS_STRING_0 0
#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0
#define USB_CFG_DESCR_PROPS_HID 0
#define USB_CFG_DESCR_PROPS_HID_REPORT 0
#define USB_CFG_DESCR_PROPS_UNKNOWN 0
/* ----------------------- Optional MCU Description ------------------------ */
/* ATmega***p/pa needs SIG_ definitions */
#ifndef SIG_INTERRUPT0
#define SIG_INTERRUPT0 _VECTOR(1)
#endif
/* The following configurations have working defaults in usbdrv.h. You
* usually don't need to set them explicitly. Only if you want to run
* the driver on a device which is not yet supported or with a compiler
* which is not fully supported (such as IAR C) or if you use a differnt
* interrupt than INT0, you may have to define some of these.
*/
/* #define USB_INTR_CFG MCUCR */
/* #define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) */
/* #define USB_INTR_CFG_CLR 0 */
/* #define USB_INTR_ENABLE GIMSK */
/* #define USB_INTR_ENABLE_BIT INT0 */
/* #define USB_INTR_PENDING GIFR */
/* #define USB_INTR_PENDING_BIT INTF0 */
/* #define USB_INTR_VECTOR INT0_vect */
#if defined (__AVR_ATtiny45__) || defined (__AVR_ATtiny85__)
#define USB_INTR_CFG PCMSK
#define USB_INTR_CFG_SET (1<<USB_CFG_DPLUS_BIT)
#define USB_INTR_ENABLE_BIT PCIE
#define USB_INTR_PENDING_BIT PCIF
#define USB_INTR_VECTOR SIG_PIN_CHANGE
#endif
#if defined (__AVR_ATtiny87__) || defined (__AVR_ATtiny167__)
#define USB_INTR_CFG PCMSK1
#define USB_INTR_CFG_SET (1 << USB_CFG_DPLUS_BIT)
#define USB_INTR_CFG_CLR 0
#define USB_INTR_ENABLE PCICR
#define USB_INTR_ENABLE_BIT PCIE1
#define USB_INTR_PENDING PCIFR
#define USB_INTR_PENDING_BIT PCIF1
#define USB_INTR_VECTOR PCINT1_vect
#endif
#endif /* __usbconfig_h_included__ */

View File

@ -0,0 +1,625 @@
/* Name: usbdrv.c
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Christian Starkjohann
* Creation Date: 2004-12-29
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: usbdrv.c 791 2010-07-15 15:56:13Z cs $
*/
#include "usbportability.h"
#include "usbdrv.h"
#include "oddebug.h"
/*
General Description:
This module implements the C-part of the USB driver. See usbdrv.h for a
documentation of the entire driver.
*/
/* ------------------------------------------------------------------------- */
/* raw USB registers / interface to assembler code: */
uchar usbRxBuf[2*USB_BUFSIZE]; /* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */
uchar usbInputBufOffset; /* offset in usbRxBuf used for low level receiving */
uchar usbDeviceAddr; /* assigned during enumeration, defaults to 0 */
uchar usbNewDeviceAddr; /* device ID which should be set after status phase */
uchar usbConfiguration; /* currently selected configuration. Administered by driver, but not used */
volatile schar usbRxLen; /* = 0; number of bytes in usbRxBuf; 0 means free, -1 for flow control */
uchar usbCurrentTok; /* last token received or endpoint number for last OUT token if != 0 */
uchar usbRxToken; /* token for data we received; or endpont number for last OUT */
volatile uchar usbTxLen = USBPID_NAK; /* number of bytes to transmit with next IN token or handshake token */
uchar usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen contains handshake token */
#if USB_COUNT_SOF
volatile uchar usbSofCount; /* incremented by assembler module every SOF */
#endif
#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE
usbTxStatus_t usbTxStatus1;
# if USB_CFG_HAVE_INTRIN_ENDPOINT3
usbTxStatus_t usbTxStatus3;
# endif
#endif
#if USB_CFG_CHECK_DATA_TOGGLING
uchar usbCurrentDataToken;/* when we check data toggling to ignore duplicate packets */
#endif
/* USB status registers / not shared with asm code */
uchar *usbMsgPtr; /* data to transmit next -- ROM or RAM address */
static usbMsgLen_t usbMsgLen = USB_NO_MSG; /* remaining number of bytes */
static uchar usbMsgFlags; /* flag values see below */
#define USB_FLG_MSGPTR_IS_ROM (1<<6)
#define USB_FLG_USE_USER_RW (1<<7)
/*
optimizing hints:
- do not post/pre inc/dec integer values in operations
- assign value of USB_READ_FLASH() to register variables and don't use side effects in arg
- use narrow scope for variables which should be in X/Y/Z register
- assign char sized expressions to variables to force 8 bit arithmetics
*/
/* -------------------------- String Descriptors --------------------------- */
#if USB_CFG_DESCR_PROPS_STRINGS == 0
#if USB_CFG_DESCR_PROPS_STRING_0 == 0
#undef USB_CFG_DESCR_PROPS_STRING_0
#define USB_CFG_DESCR_PROPS_STRING_0 sizeof(usbDescriptorString0)
const PROGMEM char usbDescriptorString0[] = { /* language descriptor */
4, /* sizeof(usbDescriptorString0): length of descriptor in bytes */
3, /* descriptor type */
0x09, 0x04, /* language index (0x0409 = US-English) */
};
#endif
#if USB_CFG_DESCR_PROPS_STRING_VENDOR == 0 && USB_CFG_VENDOR_NAME_LEN
#undef USB_CFG_DESCR_PROPS_STRING_VENDOR
#define USB_CFG_DESCR_PROPS_STRING_VENDOR sizeof(usbDescriptorStringVendor)
const PROGMEM int usbDescriptorStringVendor[] = {
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_VENDOR_NAME_LEN),
USB_CFG_VENDOR_NAME
};
#endif
#if USB_CFG_DESCR_PROPS_STRING_PRODUCT == 0 && USB_CFG_DEVICE_NAME_LEN
#undef USB_CFG_DESCR_PROPS_STRING_PRODUCT
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT sizeof(usbDescriptorStringDevice)
const PROGMEM int usbDescriptorStringDevice[] = {
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_DEVICE_NAME_LEN),
USB_CFG_DEVICE_NAME
};
#endif
#if USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER == 0 && USB_CFG_SERIAL_NUMBER_LEN
#undef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER sizeof(usbDescriptorStringSerialNumber)
const PROGMEM int usbDescriptorStringSerialNumber[] = {
USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LEN),
USB_CFG_SERIAL_NUMBER
};
#endif
#endif /* USB_CFG_DESCR_PROPS_STRINGS == 0 */
/* --------------------------- Device Descriptor --------------------------- */
#if USB_CFG_DESCR_PROPS_DEVICE == 0
#undef USB_CFG_DESCR_PROPS_DEVICE
#define USB_CFG_DESCR_PROPS_DEVICE sizeof(usbDescriptorDevice)
const PROGMEM char usbDescriptorDevice[] = { /* USB device descriptor */
18, /* sizeof(usbDescriptorDevice): length of descriptor in bytes */
USBDESCR_DEVICE, /* descriptor type */
0x10, 0x01, /* USB version supported */
USB_CFG_DEVICE_CLASS,
USB_CFG_DEVICE_SUBCLASS,
0, /* protocol */
8, /* max packet size */
/* the following two casts affect the first byte of the constant only, but
* that's sufficient to avoid a warning with the default values.
*/
(char)USB_CFG_VENDOR_ID,/* 2 bytes */
(char)USB_CFG_DEVICE_ID,/* 2 bytes */
USB_CFG_DEVICE_VERSION, /* 2 bytes */
USB_CFG_DESCR_PROPS_STRING_VENDOR != 0 ? 1 : 0, /* manufacturer string index */
USB_CFG_DESCR_PROPS_STRING_PRODUCT != 0 ? 2 : 0, /* product string index */
USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER != 0 ? 3 : 0, /* serial number string index */
1, /* number of configurations */
};
#endif
/* ----------------------- Configuration Descriptor ------------------------ */
#if USB_CFG_DESCR_PROPS_HID_REPORT != 0 && USB_CFG_DESCR_PROPS_HID == 0
#undef USB_CFG_DESCR_PROPS_HID
#define USB_CFG_DESCR_PROPS_HID 9 /* length of HID descriptor in config descriptor below */
#endif
#if USB_CFG_DESCR_PROPS_CONFIGURATION == 0
#undef USB_CFG_DESCR_PROPS_CONFIGURATION
#define USB_CFG_DESCR_PROPS_CONFIGURATION sizeof(usbDescriptorConfiguration)
const PROGMEM char usbDescriptorConfiguration[] = { /* USB configuration descriptor */
9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */
USBDESCR_CONFIG, /* descriptor type */
18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT3 +
(USB_CFG_DESCR_PROPS_HID & 0xff), 0,
/* total length of data returned (including inlined descriptors) */
1, /* number of interfaces in this configuration */
1, /* index of this configuration */
0, /* configuration name string index */
#if USB_CFG_IS_SELF_POWERED
(1 << 7) | USBATTR_SELFPOWER, /* attributes */
#else
(1 << 7), /* attributes */
#endif
USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */
/* interface descriptor follows inline: */
9, /* sizeof(usbDescrInterface): length of descriptor in bytes */
USBDESCR_INTERFACE, /* descriptor type */
0, /* index of this interface */
0, /* alternate setting for this interface */
USB_CFG_HAVE_INTRIN_ENDPOINT + USB_CFG_HAVE_INTRIN_ENDPOINT3, /* endpoints excl 0: number of endpoint descriptors to follow */
USB_CFG_INTERFACE_CLASS,
USB_CFG_INTERFACE_SUBCLASS,
USB_CFG_INTERFACE_PROTOCOL,
0, /* string index for interface */
#if (USB_CFG_DESCR_PROPS_HID & 0xff) /* HID descriptor */
9, /* sizeof(usbDescrHID): length of descriptor in bytes */
USBDESCR_HID, /* descriptor type: HID */
0x01, 0x01, /* BCD representation of HID version */
0x00, /* target country code */
0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */
0x22, /* descriptor type: report */
USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0, /* total length of report descriptor */
#endif
#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */
7, /* sizeof(usbDescrEndpoint) */
USBDESCR_ENDPOINT, /* descriptor type = endpoint */
(char)0x81, /* IN endpoint number 1 */
0x03, /* attrib: Interrupt endpoint */
8, 0, /* maximum packet size */
USB_CFG_INTR_POLL_INTERVAL, /* in ms */
#endif
#if USB_CFG_HAVE_INTRIN_ENDPOINT3 /* endpoint descriptor for endpoint 3 */
7, /* sizeof(usbDescrEndpoint) */
USBDESCR_ENDPOINT, /* descriptor type = endpoint */
(char)(0x80 | USB_CFG_EP3_NUMBER), /* IN endpoint number 3 */
0x03, /* attrib: Interrupt endpoint */
8, 0, /* maximum packet size */
USB_CFG_INTR_POLL_INTERVAL, /* in ms */
#endif
};
#endif
/* ------------------------------------------------------------------------- */
static inline void usbResetDataToggling(void)
{
#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE
USB_SET_DATATOKEN1(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
# if USB_CFG_HAVE_INTRIN_ENDPOINT3
USB_SET_DATATOKEN3(USB_INITIAL_DATATOKEN); /* reset data toggling for interrupt endpoint */
# endif
#endif
}
static inline void usbResetStall(void)
{
#if USB_CFG_IMPLEMENT_HALT && USB_CFG_HAVE_INTRIN_ENDPOINT
usbTxLen1 = USBPID_NAK;
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
usbTxLen3 = USBPID_NAK;
#endif
#endif
}
/* ------------------------------------------------------------------------- */
#if !USB_CFG_SUPPRESS_INTR_CODE
#if USB_CFG_HAVE_INTRIN_ENDPOINT
static void usbGenericSetInterrupt(uchar *data, uchar len, usbTxStatus_t *txStatus)
{
uchar *p;
char i;
#if USB_CFG_IMPLEMENT_HALT
if(usbTxLen1 == USBPID_STALL)
return;
#endif
if(txStatus->len & 0x10){ /* packet buffer was empty */
txStatus->buffer[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* toggle token */
}else{
txStatus->len = USBPID_NAK; /* avoid sending outdated (overwritten) interrupt data */
}
p = txStatus->buffer + 1;
i = len;
do{ /* if len == 0, we still copy 1 byte, but that's no problem */
*p++ = *data++;
}while(--i > 0); /* loop control at the end is 2 bytes shorter than at beginning */
usbCrc16Append(&txStatus->buffer[1], len);
txStatus->len = len + 4; /* len must be given including sync byte */
DBG2(0x21 + (((int)txStatus >> 3) & 3), txStatus->buffer, len + 3);
}
USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len)
{
usbGenericSetInterrupt(data, len, &usbTxStatus1);
}
#endif
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len)
{
usbGenericSetInterrupt(data, len, &usbTxStatus3);
}
#endif
#endif /* USB_CFG_SUPPRESS_INTR_CODE */
/* ------------------ utilities for code following below ------------------- */
/* Use defines for the switch statement so that we can choose between an
* if()else if() and a switch/case based implementation. switch() is more
* efficient for a LARGE set of sequential choices, if() is better in all other
* cases.
*/
#if USB_CFG_USE_SWITCH_STATEMENT
# define SWITCH_START(cmd) switch(cmd){{
# define SWITCH_CASE(value) }break; case (value):{
# define SWITCH_CASE2(v1,v2) }break; case (v1): case(v2):{
# define SWITCH_CASE3(v1,v2,v3) }break; case (v1): case(v2): case(v3):{
# define SWITCH_DEFAULT }break; default:{
# define SWITCH_END }}
#else
# define SWITCH_START(cmd) {uchar _cmd = cmd; if(0){
# define SWITCH_CASE(value) }else if(_cmd == (value)){
# define SWITCH_CASE2(v1,v2) }else if(_cmd == (v1) || _cmd == (v2)){
# define SWITCH_CASE3(v1,v2,v3) }else if(_cmd == (v1) || _cmd == (v2) || (_cmd == v3)){
# define SWITCH_DEFAULT }else{
# define SWITCH_END }}
#endif
#ifndef USB_RX_USER_HOOK
#define USB_RX_USER_HOOK(data, len)
#endif
#ifndef USB_SET_ADDRESS_HOOK
#define USB_SET_ADDRESS_HOOK()
#endif
/* ------------------------------------------------------------------------- */
/* We use if() instead of #if in the macro below because #if can't be used
* in macros and the compiler optimizes constant conditions anyway.
* This may cause problems with undefined symbols if compiled without
* optimizing!
*/
#define GET_DESCRIPTOR(cfgProp, staticName) \
if(cfgProp){ \
if((cfgProp) & USB_PROP_IS_RAM) \
flags = 0; \
if((cfgProp) & USB_PROP_IS_DYNAMIC){ \
len = usbFunctionDescriptor(rq); \
}else{ \
len = USB_PROP_LENGTH(cfgProp); \
usbMsgPtr = (uchar *)(staticName); \
} \
}
/* usbDriverDescriptor() is similar to usbFunctionDescriptor(), but used
* internally for all types of descriptors.
*/
static inline usbMsgLen_t usbDriverDescriptor(usbRequest_t *rq)
{
usbMsgLen_t len = 0;
uchar flags = USB_FLG_MSGPTR_IS_ROM;
SWITCH_START(rq->wValue.bytes[1])
SWITCH_CASE(USBDESCR_DEVICE) /* 1 */
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_DEVICE, usbDescriptorDevice)
SWITCH_CASE(USBDESCR_CONFIG) /* 2 */
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_CONFIGURATION, usbDescriptorConfiguration)
SWITCH_CASE(USBDESCR_STRING) /* 3 */
#if USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC
if(USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_RAM)
flags = 0;
len = usbFunctionDescriptor(rq);
#else /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */
SWITCH_START(rq->wValue.bytes[0])
SWITCH_CASE(0)
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_0, usbDescriptorString0)
SWITCH_CASE(1)
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_VENDOR, usbDescriptorStringVendor)
SWITCH_CASE(2)
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_PRODUCT, usbDescriptorStringDevice)
SWITCH_CASE(3)
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER, usbDescriptorStringSerialNumber)
SWITCH_DEFAULT
if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){
len = usbFunctionDescriptor(rq);
}
SWITCH_END
#endif /* USB_CFG_DESCR_PROPS_STRINGS & USB_PROP_IS_DYNAMIC */
#if USB_CFG_DESCR_PROPS_HID_REPORT /* only support HID descriptors if enabled */
SWITCH_CASE(USBDESCR_HID) /* 0x21 */
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID, usbDescriptorConfiguration + 18)
SWITCH_CASE(USBDESCR_HID_REPORT)/* 0x22 */
GET_DESCRIPTOR(USB_CFG_DESCR_PROPS_HID_REPORT, usbDescriptorHidReport)
#endif
SWITCH_DEFAULT
if(USB_CFG_DESCR_PROPS_UNKNOWN & USB_PROP_IS_DYNAMIC){
len = usbFunctionDescriptor(rq);
}
SWITCH_END
usbMsgFlags = flags;
return len;
}
/* ------------------------------------------------------------------------- */
/* usbDriverSetup() is similar to usbFunctionSetup(), but it's used for
* standard requests instead of class and custom requests.
*/
static inline usbMsgLen_t usbDriverSetup(usbRequest_t *rq)
{
uchar len = 0, *dataPtr = usbTxBuf + 9; /* there are 2 bytes free space at the end of the buffer */
uchar value = rq->wValue.bytes[0];
#if USB_CFG_IMPLEMENT_HALT
uchar index = rq->wIndex.bytes[0];
#endif
dataPtr[0] = 0; /* default reply common to USBRQ_GET_STATUS and USBRQ_GET_INTERFACE */
SWITCH_START(rq->bRequest)
SWITCH_CASE(USBRQ_GET_STATUS) /* 0 */
uchar recipient = rq->bmRequestType & USBRQ_RCPT_MASK; /* assign arith ops to variables to enforce byte size */
if(USB_CFG_IS_SELF_POWERED && recipient == USBRQ_RCPT_DEVICE)
dataPtr[0] = USB_CFG_IS_SELF_POWERED;
#if USB_CFG_IMPLEMENT_HALT
if(recipient == USBRQ_RCPT_ENDPOINT && index == 0x81) /* request status for endpoint 1 */
dataPtr[0] = usbTxLen1 == USBPID_STALL;
#endif
dataPtr[1] = 0;
len = 2;
#if USB_CFG_IMPLEMENT_HALT
SWITCH_CASE2(USBRQ_CLEAR_FEATURE, USBRQ_SET_FEATURE) /* 1, 3 */
if(value == 0 && index == 0x81){ /* feature 0 == HALT for endpoint == 1 */
usbTxLen1 = rq->bRequest == USBRQ_CLEAR_FEATURE ? USBPID_NAK : USBPID_STALL;
usbResetDataToggling();
}
#endif
SWITCH_CASE(USBRQ_SET_ADDRESS) /* 5 */
usbNewDeviceAddr = value;
USB_SET_ADDRESS_HOOK();
SWITCH_CASE(USBRQ_GET_DESCRIPTOR) /* 6 */
len = usbDriverDescriptor(rq);
goto skipMsgPtrAssignment;
SWITCH_CASE(USBRQ_GET_CONFIGURATION) /* 8 */
dataPtr = &usbConfiguration; /* send current configuration value */
len = 1;
SWITCH_CASE(USBRQ_SET_CONFIGURATION) /* 9 */
usbConfiguration = value;
usbResetStall();
SWITCH_CASE(USBRQ_GET_INTERFACE) /* 10 */
len = 1;
#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE
SWITCH_CASE(USBRQ_SET_INTERFACE) /* 11 */
usbResetDataToggling();
usbResetStall();
#endif
SWITCH_DEFAULT /* 7=SET_DESCRIPTOR, 12=SYNC_FRAME */
/* Should we add an optional hook here? */
SWITCH_END
usbMsgPtr = dataPtr;
skipMsgPtrAssignment:
return len;
}
/* ------------------------------------------------------------------------- */
/* usbProcessRx() is called for every message received by the interrupt
* routine. It distinguishes between SETUP and DATA packets and processes
* them accordingly.
*/
static inline void usbProcessRx(uchar *data, uchar len)
{
usbRequest_t *rq = (void *)data;
/* usbRxToken can be:
* 0x2d 00101101 (USBPID_SETUP for setup data)
* 0xe1 11100001 (USBPID_OUT: data phase of setup transfer)
* 0...0x0f for OUT on endpoint X
*/
DBG2(0x10 + (usbRxToken & 0xf), data, len + 2); /* SETUP=1d, SETUP-DATA=11, OUTx=1x */
USB_RX_USER_HOOK(data, len)
#if USB_CFG_IMPLEMENT_FN_WRITEOUT
if(usbRxToken < 0x10){ /* OUT to endpoint != 0: endpoint number in usbRxToken */
usbFunctionWriteOut(data, len);
return;
}
#endif
if(usbRxToken == (uchar)USBPID_SETUP){
if(len != 8) /* Setup size must be always 8 bytes. Ignore otherwise. */
return;
usbMsgLen_t replyLen;
usbTxBuf[0] = USBPID_DATA0; /* initialize data toggling */
usbTxLen = USBPID_NAK; /* abort pending transmit */
usbMsgFlags = 0;
uchar type = rq->bmRequestType & USBRQ_TYPE_MASK;
if(type != USBRQ_TYPE_STANDARD){ /* standard requests are handled by driver */
replyLen = usbFunctionSetup(data);
}else{
replyLen = usbDriverSetup(rq);
}
#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE
if(replyLen == USB_NO_MSG){ /* use user-supplied read/write function */
/* do some conditioning on replyLen, but on IN transfers only */
if((rq->bmRequestType & USBRQ_DIR_MASK) != USBRQ_DIR_HOST_TO_DEVICE){
if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */
replyLen = rq->wLength.bytes[0];
}else{
replyLen = rq->wLength.word;
}
}
usbMsgFlags = USB_FLG_USE_USER_RW;
}else /* The 'else' prevents that we limit a replyLen of USB_NO_MSG to the maximum transfer len. */
#endif
if(sizeof(replyLen) < sizeof(rq->wLength.word)){ /* help compiler with optimizing */
if(!rq->wLength.bytes[1] && replyLen > rq->wLength.bytes[0]) /* limit length to max */
replyLen = rq->wLength.bytes[0];
}else{
if(replyLen > rq->wLength.word) /* limit length to max */
replyLen = rq->wLength.word;
}
usbMsgLen = replyLen;
}else{ /* usbRxToken must be USBPID_OUT, which means data phase of setup (control-out) */
#if USB_CFG_IMPLEMENT_FN_WRITE
if(usbMsgFlags & USB_FLG_USE_USER_RW){
uchar rval = usbFunctionWrite(data, len);
if(rval == 0xff){ /* an error occurred */
usbTxLen = USBPID_STALL;
}else if(rval != 0){ /* This was the final package */
usbMsgLen = 0; /* answer with a zero-sized data packet */
}
}
#endif
}
}
/* ------------------------------------------------------------------------- */
/* This function is similar to usbFunctionRead(), but it's also called for
* data handled automatically by the driver (e.g. descriptor reads).
*/
static uchar usbDeviceRead(uchar *data, uchar len)
{
if(len > 0){ /* don't bother app with 0 sized reads */
#if USB_CFG_IMPLEMENT_FN_READ
if(usbMsgFlags & USB_FLG_USE_USER_RW){
len = usbFunctionRead(data, len);
}else
#endif
{
uchar i = len, *r = usbMsgPtr;
if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){ /* ROM data */
do{
uchar c = USB_READ_FLASH(r); /* assign to char size variable to enforce byte ops */
*data++ = c;
r++;
}while(--i);
}else{ /* RAM data */
do{
*data++ = *r++;
}while(--i);
}
usbMsgPtr = r;
}
}
return len;
}
/* ------------------------------------------------------------------------- */
/* usbBuildTxBlock() is called when we have data to transmit and the
* interrupt routine's transmit buffer is empty.
*/
static inline void usbBuildTxBlock(void)
{
usbMsgLen_t wantLen;
uchar len;
wantLen = usbMsgLen;
if(wantLen > 8)
wantLen = 8;
usbMsgLen -= wantLen;
usbTxBuf[0] ^= USBPID_DATA0 ^ USBPID_DATA1; /* DATA toggling */
len = usbDeviceRead(usbTxBuf + 1, wantLen);
if(len <= 8){ /* valid data packet */
usbCrc16Append(&usbTxBuf[1], len);
len += 4; /* length including sync byte */
if(len < 12) /* a partial package identifies end of message */
usbMsgLen = USB_NO_MSG;
}else{
len = USBPID_STALL; /* stall the endpoint */
usbMsgLen = USB_NO_MSG;
}
usbTxLen = len;
DBG2(0x20, usbTxBuf, len-1);
}
/* ------------------------------------------------------------------------- */
static inline void usbHandleResetHook(uchar notResetState)
{
#ifdef USB_RESET_HOOK
static uchar wasReset;
uchar isReset = !notResetState;
if(wasReset != isReset){
USB_RESET_HOOK(isReset);
wasReset = isReset;
}
#endif
}
/* ------------------------------------------------------------------------- */
USB_PUBLIC void usbPoll(void)
{
schar len;
uchar i;
len = usbRxLen - 3;
if(len >= 0){
/* We could check CRC16 here -- but ACK has already been sent anyway. If you
* need data integrity checks with this driver, check the CRC in your app
* code and report errors back to the host. Since the ACK was already sent,
* retries must be handled on application level.
* unsigned crc = usbCrc16(buffer + 1, usbRxLen - 3);
*/
usbProcessRx(usbRxBuf + USB_BUFSIZE + 1 - usbInputBufOffset, len);
#if USB_CFG_HAVE_FLOWCONTROL
if(usbRxLen > 0) /* only mark as available if not inactivated */
usbRxLen = 0;
#else
usbRxLen = 0; /* mark rx buffer as available */
#endif
}
if(usbTxLen & 0x10){ /* transmit system idle */
if(usbMsgLen != USB_NO_MSG){ /* transmit data pending? */
usbBuildTxBlock();
}
}
for(i = 20; i > 0; i--){
uchar usbLineStatus = USBIN & USBMASK;
if(usbLineStatus != 0) /* SE0 has ended */
goto isNotReset;
}
/* RESET condition, called multiple times during reset */
usbNewDeviceAddr = 0;
usbDeviceAddr = 0;
usbResetStall();
DBG1(0xff, 0, 0);
isNotReset:
usbHandleResetHook(i);
}
/* ------------------------------------------------------------------------- */
USB_PUBLIC void usbInit(void)
{
#if USB_INTR_CFG_SET != 0
USB_INTR_CFG |= USB_INTR_CFG_SET;
#endif
#if USB_INTR_CFG_CLR != 0
USB_INTR_CFG &= ~(USB_INTR_CFG_CLR);
#endif
USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT);
usbResetDataToggling();
#if USB_CFG_HAVE_INTRIN_ENDPOINT && !USB_CFG_SUPPRESS_INTR_CODE
usbTxLen1 = USBPID_NAK;
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
usbTxLen3 = USBPID_NAK;
#endif
#endif
}
/* ------------------------------------------------------------------------- */

View File

@ -0,0 +1,790 @@
/* Name: usbdrv.h
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Christian Starkjohann
* Creation Date: 2004-12-29
* Tabsize: 4
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* This Revision: $Id: usbdrv.h 793 2010-07-15 15:58:11Z cs $
*/
#ifndef __usbdrv_h_included__
#define __usbdrv_h_included__
#include "usbconfig.h"
#include "usbportability.h"
/*
Hardware Prerequisites:
=======================
USB lines D+ and D- MUST be wired to the same I/O port. We recommend that D+
triggers the interrupt (best achieved by using INT0 for D+), but it is also
possible to trigger the interrupt from D-. If D- is used, interrupts are also
triggered by SOF packets. D- requires a pull-up of 1.5k to +3.5V (and the
device must be powered at 3.5V) to identify as low-speed USB device. A
pull-down or pull-up of 1M SHOULD be connected from D+ to +3.5V to prevent
interference when no USB master is connected. If you use Zener diodes to limit
the voltage on D+ and D-, you MUST use a pull-down resistor, not a pull-up.
We use D+ as interrupt source and not D- because it does not trigger on
keep-alive and RESET states. If you want to count keep-alive events with
USB_COUNT_SOF, you MUST use D- as an interrupt source.
As a compile time option, the 1.5k pull-up resistor on D- can be made
switchable to allow the device to disconnect at will. See the definition of
usbDeviceConnect() and usbDeviceDisconnect() further down in this file.
Please adapt the values in usbconfig.h according to your hardware!
The device MUST be clocked at exactly 12 MHz, 15 MHz, 16 MHz or 20 MHz
or at 12.8 MHz resp. 16.5 MHz +/- 1%. See usbconfig-prototype.h for details.
Limitations:
============
Robustness with respect to communication errors:
The driver assumes error-free communication. It DOES check for errors in
the PID, but does NOT check bit stuffing errors, SE0 in middle of a byte,
token CRC (5 bit) and data CRC (16 bit). CRC checks can not be performed due
to timing constraints: We must start sending a reply within 7 bit times.
Bit stuffing and misplaced SE0 would have to be checked in real-time, but CPU
performance does not permit that. The driver does not check Data0/Data1
toggling, but application software can implement the check.
Input characteristics:
Since no differential receiver circuit is used, electrical interference
robustness may suffer. The driver samples only one of the data lines with
an ordinary I/O pin's input characteristics. However, since this is only a
low speed USB implementation and the specification allows for 8 times the
bit rate over the same hardware, we should be on the safe side. Even the spec
requires detection of asymmetric states at high bit rate for SE0 detection.
Number of endpoints:
The driver supports the following endpoints:
- Endpoint 0, the default control endpoint.
- Any number of interrupt- or bulk-out endpoints. The data is sent to
usbFunctionWriteOut() and USB_CFG_IMPLEMENT_FN_WRITEOUT must be defined
to 1 to activate this feature. The endpoint number can be found in the
global variable 'usbRxToken'.
- One default interrupt- or bulk-in endpoint. This endpoint is used for
interrupt- or bulk-in transfers which are not handled by any other endpoint.
You must define USB_CFG_HAVE_INTRIN_ENDPOINT in order to activate this
feature and call usbSetInterrupt() to send interrupt/bulk data.
- One additional interrupt- or bulk-in endpoint. This was endpoint 3 in
previous versions of this driver but can now be configured to any endpoint
number. You must define USB_CFG_HAVE_INTRIN_ENDPOINT3 in order to activate
this feature and call usbSetInterrupt3() to send interrupt/bulk data. The
endpoint number can be set with USB_CFG_EP3_NUMBER.
Please note that the USB standard forbids bulk endpoints for low speed devices!
Most operating systems allow them anyway, but the AVR will spend 90% of the CPU
time in the USB interrupt polling for bulk data.
Maximum data payload:
Data payload of control in and out transfers may be up to 254 bytes. In order
to accept payload data of out transfers, you need to implement
'usbFunctionWrite()'.
USB Suspend Mode supply current:
The USB standard limits power consumption to 500uA when the bus is in suspend
mode. This is not a problem for self-powered devices since they don't need
bus power anyway. Bus-powered devices can achieve this only by putting the
CPU in sleep mode. The driver does not implement suspend handling by itself.
However, the application may implement activity monitoring and wakeup from
sleep. The host sends regular SE0 states on the bus to keep it active. These
SE0 states can be detected by using D- as the interrupt source. Define
USB_COUNT_SOF to 1 and use the global variable usbSofCount to check for bus
activity.
Operation without an USB master:
The driver behaves neutral without connection to an USB master if D- reads
as 1. To avoid spurious interrupts, we recommend a high impedance (e.g. 1M)
pull-down or pull-up resistor on D+ (interrupt). If Zener diodes are used,
use a pull-down. If D- becomes statically 0, the driver may block in the
interrupt routine.
Interrupt latency:
The application must ensure that the USB interrupt is not disabled for more
than 25 cycles (this is for 12 MHz, faster clocks allow longer latency).
This implies that all interrupt routines must either have the "ISR_NOBLOCK"
attribute set (see "avr/interrupt.h") or be written in assembler with "sei"
as the first instruction.
Maximum interrupt duration / CPU cycle consumption:
The driver handles all USB communication during the interrupt service
routine. The routine will not return before an entire USB message is received
and the reply is sent. This may be up to ca. 1200 cycles @ 12 MHz (= 100us) if
the host conforms to the standard. The driver will consume CPU cycles for all
USB messages, even if they address another (low-speed) device on the same bus.
*/
/* ------------------------------------------------------------------------- */
/* --------------------------- Module Interface ---------------------------- */
/* ------------------------------------------------------------------------- */
#define USBDRV_VERSION 20100715
/* This define uniquely identifies a driver version. It is a decimal number
* constructed from the driver's release date in the form YYYYMMDD. If the
* driver's behavior or interface changes, you can use this constant to
* distinguish versions. If it is not defined, the driver's release date is
* older than 2006-01-25.
*/
#ifndef USB_PUBLIC
#define USB_PUBLIC
#endif
/* USB_PUBLIC is used as declaration attribute for all functions exported by
* the USB driver. The default is no attribute (see above). You may define it
* to static either in usbconfig.h or from the command line if you include
* usbdrv.c instead of linking against it. Including the C module of the driver
* directly in your code saves a couple of bytes in flash memory.
*/
#ifndef __ASSEMBLER__
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef schar
#define schar signed char
#endif
/* shortcuts for well defined 8 bit integer types */
#if USB_CFG_LONG_TRANSFERS /* if more than 254 bytes transfer size required */
# define usbMsgLen_t unsigned
#else
# define usbMsgLen_t uchar
#endif
/* usbMsgLen_t is the data type used for transfer lengths. By default, it is
* defined to uchar, allowing a maximum of 254 bytes (255 is reserved for
* USB_NO_MSG below). If the usbconfig.h defines USB_CFG_LONG_TRANSFERS to 1,
* a 16 bit data type is used, allowing up to 16384 bytes (the rest is used
* for flags in the descriptor configuration).
*/
#define USB_NO_MSG ((usbMsgLen_t)-1) /* constant meaning "no message" */
struct usbRequest; /* forward declaration */
#ifdef __cplusplus
extern "C"{
#endif
USB_PUBLIC void usbInit(void);
/* This function must be called before interrupts are enabled and the main
* loop is entered. We exepct that the PORT and DDR bits for D+ and D- have
* not been changed from their default status (which is 0). If you have changed
* them, set both back to 0 (configure them as input with no internal pull-up).
*/
USB_PUBLIC void usbPoll(void);
#ifdef __cplusplus
} // extern "C"
#endif
/* This function must be called at regular intervals from the main loop.
* Maximum delay between calls is somewhat less than 50ms (USB timeout for
* accepting a Setup message). Otherwise the device will not be recognized.
* Please note that debug outputs through the UART take ~ 0.5ms per byte
* at 19200 bps.
*/
extern uchar *usbMsgPtr;
/* This variable may be used to pass transmit data to the driver from the
* implementation of usbFunctionWrite(). It is also used internally by the
* driver for standard control requests.
*/
#ifdef __cplusplus
extern "C"{
#endif
USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]);
/* This function is called when the driver receives a SETUP transaction from
* the host which is not answered by the driver itself (in practice: class and
* vendor requests). All control transfers start with a SETUP transaction where
* the host communicates the parameters of the following (optional) data
* transfer. The SETUP data is available in the 'data' parameter which can
* (and should) be casted to 'usbRequest_t *' for a more user-friendly access
* to parameters.
*
* If the SETUP indicates a control-in transfer, you should provide the
* requested data to the driver. There are two ways to transfer this data:
* (1) Set the global pointer 'usbMsgPtr' to the base of the static RAM data
* block and return the length of the data in 'usbFunctionSetup()'. The driver
* will handle the rest. Or (2) return USB_NO_MSG in 'usbFunctionSetup()'. The
* driver will then call 'usbFunctionRead()' when data is needed. See the
* documentation for usbFunctionRead() for details.
*
* If the SETUP indicates a control-out transfer, the only way to receive the
* data from the host is through the 'usbFunctionWrite()' call. If you
* implement this function, you must return USB_NO_MSG in 'usbFunctionSetup()'
* to indicate that 'usbFunctionWrite()' should be used. See the documentation
* of this function for more information. If you just want to ignore the data
* sent by the host, return 0 in 'usbFunctionSetup()'.
*
* Note that calls to the functions usbFunctionRead() and usbFunctionWrite()
* are only done if enabled by the configuration in usbconfig.h.
*/
USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq);
#ifdef __cplusplus
} // extern "C"
#endif
/* You need to implement this function ONLY if you provide USB descriptors at
* runtime (which is an expert feature). It is very similar to
* usbFunctionSetup() above, but it is called only to request USB descriptor
* data. See the documentation of usbFunctionSetup() above for more info.
*/
#if USB_CFG_HAVE_INTRIN_ENDPOINT
#ifdef __cplusplus
extern "C"{
#endif
USB_PUBLIC void usbSetInterrupt(uchar *data, uchar len);
#ifdef __cplusplus
} // extern "C"
#endif
/* This function sets the message which will be sent during the next interrupt
* IN transfer. The message is copied to an internal buffer and must not exceed
* a length of 8 bytes. The message may be 0 bytes long just to indicate the
* interrupt status to the host.
* If you need to transfer more bytes, use a control read after the interrupt.
*/
#define usbInterruptIsReady() (usbTxLen1 & 0x10)
/* This macro indicates whether the last interrupt message has already been
* sent. If you set a new interrupt message before the old was sent, the
* message already buffered will be lost.
*/
#if USB_CFG_HAVE_INTRIN_ENDPOINT3
#ifdef __cplusplus
extern "C"{
#endif
USB_PUBLIC void usbSetInterrupt3(uchar *data, uchar len);
#ifdef __cplusplus
} // extern "C"
#endif
#define usbInterruptIsReady3() (usbTxLen3 & 0x10)
/* Same as above for endpoint 3 */
#endif
#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */
#if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* simplified interface for backward compatibility */
#define usbHidReportDescriptor usbDescriptorHidReport
/* should be declared as: const PROGMEM char usbHidReportDescriptor[]; */
/* If you implement an HID device, you need to provide a report descriptor.
* The HID report descriptor syntax is a bit complex. If you understand how
* report descriptors are constructed, we recommend that you use the HID
* Descriptor Tool from usb.org, see http://www.usb.org/developers/hidpage/.
* Otherwise you should probably start with a working example.
*/
#endif /* USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH */
#if USB_CFG_IMPLEMENT_FN_WRITE
#ifdef __cplusplus
extern "C"{
#endif
USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len);
#ifdef __cplusplus
} // extern "C"
#endif
/* This function is called by the driver to provide a control transfer's
* payload data (control-out). It is called in chunks of up to 8 bytes. The
* total count provided in the current control transfer can be obtained from
* the 'length' property in the setup data. If an error occurred during
* processing, return 0xff (== -1). The driver will answer the entire transfer
* with a STALL token in this case. If you have received the entire payload
* successfully, return 1. If you expect more data, return 0. If you don't
* know whether the host will send more data (you should know, the total is
* provided in the usbFunctionSetup() call!), return 1.
* NOTE: If you return 0xff for STALL, 'usbFunctionWrite()' may still be called
* for the remaining data. You must continue to return 0xff for STALL in these
* calls.
* In order to get usbFunctionWrite() called, define USB_CFG_IMPLEMENT_FN_WRITE
* to 1 in usbconfig.h and return 0xff in usbFunctionSetup()..
*/
#endif /* USB_CFG_IMPLEMENT_FN_WRITE */
#if USB_CFG_IMPLEMENT_FN_READ
#ifdef __cplusplus
extern "C"{
#endif
USB_PUBLIC uchar usbFunctionRead(uchar *data, uchar len);
#ifdef __cplusplus
} // extern "C"
#endif
/* This function is called by the driver to ask the application for a control
* transfer's payload data (control-in). It is called in chunks of up to 8
* bytes each. You should copy the data to the location given by 'data' and
* return the actual number of bytes copied. If you return less than requested,
* the control-in transfer is terminated. If you return 0xff, the driver aborts
* the transfer with a STALL token.
* In order to get usbFunctionRead() called, define USB_CFG_IMPLEMENT_FN_READ
* to 1 in usbconfig.h and return 0xff in usbFunctionSetup()..
*/
#endif /* USB_CFG_IMPLEMENT_FN_READ */
extern uchar usbRxToken; /* may be used in usbFunctionWriteOut() below */
#if USB_CFG_IMPLEMENT_FN_WRITEOUT
#ifdef __cplusplus
extern "C"{
#endif
USB_PUBLIC void usbFunctionWriteOut(uchar *data, uchar len);
#ifdef __cplusplus
} // extern "C"
#endif
/* This function is called by the driver when data is received on an interrupt-
* or bulk-out endpoint. The endpoint number can be found in the global
* variable usbRxToken. You must define USB_CFG_IMPLEMENT_FN_WRITEOUT to 1 in
* usbconfig.h to get this function called.
*/
#endif /* USB_CFG_IMPLEMENT_FN_WRITEOUT */
#ifdef USB_CFG_PULLUP_IOPORTNAME
#define usbDeviceConnect() ((USB_PULLUP_DDR |= (1<<USB_CFG_PULLUP_BIT)), \
(USB_PULLUP_OUT |= (1<<USB_CFG_PULLUP_BIT)))
#define usbDeviceDisconnect() ((USB_PULLUP_DDR &= ~(1<<USB_CFG_PULLUP_BIT)), \
(USB_PULLUP_OUT &= ~(1<<USB_CFG_PULLUP_BIT)))
#else /* USB_CFG_PULLUP_IOPORTNAME */
#define usbDeviceConnect() (USBDDR &= ~(1<<USBMINUS))
#define usbDeviceDisconnect() (USBDDR |= (1<<USBMINUS))
#endif /* USB_CFG_PULLUP_IOPORTNAME */
/* The macros usbDeviceConnect() and usbDeviceDisconnect() (intended to look
* like a function) connect resp. disconnect the device from the host's USB.
* If the constants USB_CFG_PULLUP_IOPORT and USB_CFG_PULLUP_BIT are defined
* in usbconfig.h, a disconnect consists of removing the pull-up resisitor
* from D-, otherwise the disconnect is done by brute-force pulling D- to GND.
* This does not conform to the spec, but it works.
* Please note that the USB interrupt must be disabled while the device is
* in disconnected state, or the interrupt handler will hang! You can either
* turn off the USB interrupt selectively with
* USB_INTR_ENABLE &= ~(1 << USB_INTR_ENABLE_BIT)
* or use cli() to disable interrupts globally.
*/
extern unsigned usbCrc16(unsigned data, uchar len);
#define usbCrc16(data, len) usbCrc16((unsigned)(data), len)
/* This function calculates the binary complement of the data CRC used in
* USB data packets. The value is used to build raw transmit packets.
* You may want to use this function for data checksums or to verify received
* data. We enforce 16 bit calling conventions for compatibility with IAR's
* tiny memory model.
*/
#ifdef __cplusplus
extern "C"{
#endif
extern unsigned usbCrc16Append(unsigned data, uchar len);
#ifdef __cplusplus
} // extern "C"
#endif
#define usbCrc16Append(data, len) usbCrc16Append((unsigned)(data), len)
/* This function is equivalent to usbCrc16() above, except that it appends
* the 2 bytes CRC (lowbyte first) in the 'data' buffer after reading 'len'
* bytes.
*/
#if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
extern unsigned usbMeasureFrameLength(void);
/* This function MUST be called IMMEDIATELY AFTER USB reset and measures 1/7 of
* the number of CPU cycles during one USB frame minus one low speed bit
* length. In other words: return value = 1499 * (F_CPU / 10.5 MHz)
* Since this is a busy wait, you MUST disable all interrupts with cli() before
* calling this function.
* This can be used to calibrate the AVR's RC oscillator.
*/
#endif
extern uchar usbConfiguration;
/* This value contains the current configuration set by the host. The driver
* allows setting and querying of this variable with the USB SET_CONFIGURATION
* and GET_CONFIGURATION requests, but does not use it otherwise.
* You may want to reflect the "configured" status with a LED on the device or
* switch on high power parts of the circuit only if the device is configured.
*/
#if USB_COUNT_SOF
extern volatile uchar usbSofCount;
/* This variable is incremented on every SOF packet. It is only available if
* the macro USB_COUNT_SOF is defined to a value != 0.
*/
#endif
#if USB_CFG_CHECK_DATA_TOGGLING
extern uchar usbCurrentDataToken;
/* This variable can be checked in usbFunctionWrite() and usbFunctionWriteOut()
* to ignore duplicate packets.
*/
#endif
#define USB_STRING_DESCRIPTOR_HEADER(stringLength) ((2*(stringLength)+2) | (3<<8))
/* This macro builds a descriptor header for a string descriptor given the
* string's length. See usbdrv.c for an example how to use it.
*/
#if USB_CFG_HAVE_FLOWCONTROL
extern volatile schar usbRxLen;
#define usbDisableAllRequests() usbRxLen = -1
/* Must be called from usbFunctionWrite(). This macro disables all data input
* from the USB interface. Requests from the host are answered with a NAK
* while they are disabled.
*/
#define usbEnableAllRequests() usbRxLen = 0
/* May only be called if requests are disabled. This macro enables input from
* the USB interface after it has been disabled with usbDisableAllRequests().
*/
#define usbAllRequestsAreDisabled() (usbRxLen < 0)
/* Use this macro to find out whether requests are disabled. It may be needed
* to ensure that usbEnableAllRequests() is never called when requests are
* enabled.
*/
#endif
#define USB_SET_DATATOKEN1(token) usbTxBuf1[0] = token
#define USB_SET_DATATOKEN3(token) usbTxBuf3[0] = token
/* These two macros can be used by application software to reset data toggling
* for interrupt-in endpoints 1 and 3. Since the token is toggled BEFORE
* sending data, you must set the opposite value of the token which should come
* first.
*/
#endif /* __ASSEMBLER__ */
/* ------------------------------------------------------------------------- */
/* ----------------- Definitions for Descriptor Properties ----------------- */
/* ------------------------------------------------------------------------- */
/* This is advanced stuff. See usbconfig-prototype.h for more information
* about the various methods to define USB descriptors. If you do nothing,
* the default descriptors will be used.
*/
#define USB_PROP_IS_DYNAMIC (1 << 14)
/* If this property is set for a descriptor, usbFunctionDescriptor() will be
* used to obtain the particular descriptor. Data directly returned via
* usbMsgPtr are FLASH data by default, combine (OR) with USB_PROP_IS_RAM to
* return RAM data.
*/
#define USB_PROP_IS_RAM (1 << 15)
/* If this property is set for a descriptor, the data is read from RAM
* memory instead of Flash. The property is used for all methods to provide
* external descriptors.
*/
#define USB_PROP_LENGTH(len) ((len) & 0x3fff)
/* If a static external descriptor is used, this is the total length of the
* descriptor in bytes.
*/
/* all descriptors which may have properties: */
#ifndef USB_CFG_DESCR_PROPS_DEVICE
#define USB_CFG_DESCR_PROPS_DEVICE 0
#endif
#ifndef USB_CFG_DESCR_PROPS_CONFIGURATION
#define USB_CFG_DESCR_PROPS_CONFIGURATION 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRINGS
#define USB_CFG_DESCR_PROPS_STRINGS 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_0
#define USB_CFG_DESCR_PROPS_STRING_0 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_VENDOR
#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_PRODUCT
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0
#endif
#ifndef USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0
#endif
#ifndef USB_CFG_DESCR_PROPS_HID
#define USB_CFG_DESCR_PROPS_HID 0
#endif
#if !(USB_CFG_DESCR_PROPS_HID_REPORT)
# undef USB_CFG_DESCR_PROPS_HID_REPORT
# if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH /* do some backward compatibility tricks */
# define USB_CFG_DESCR_PROPS_HID_REPORT USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
# else
# define USB_CFG_DESCR_PROPS_HID_REPORT 0
# endif
#endif
#ifndef USB_CFG_DESCR_PROPS_UNKNOWN
#define USB_CFG_DESCR_PROPS_UNKNOWN 0
#endif
/* ------------------ forward declaration of descriptors ------------------- */
/* If you use external static descriptors, they must be stored in global
* arrays as declared below:
*/
#ifndef __ASSEMBLER__
extern
#if !(USB_CFG_DESCR_PROPS_DEVICE & USB_PROP_IS_RAM)
const PROGMEM
#endif
char usbDescriptorDevice[];
extern
#if !(USB_CFG_DESCR_PROPS_CONFIGURATION & USB_PROP_IS_RAM)
const PROGMEM
#endif
char usbDescriptorConfiguration[];
#ifdef __cplusplus
extern "C"{
#endif
extern
#if !(USB_CFG_DESCR_PROPS_HID_REPORT & USB_PROP_IS_RAM)
const PROGMEM
#endif
char usbDescriptorHidReport[];
#ifdef __cplusplus
} // extern "C"
#endif
extern
#if !(USB_CFG_DESCR_PROPS_STRING_0 & USB_PROP_IS_RAM)
const PROGMEM
#endif
char usbDescriptorString0[];
extern
#if !(USB_CFG_DESCR_PROPS_STRING_VENDOR & USB_PROP_IS_RAM)
const PROGMEM
#endif
int usbDescriptorStringVendor[];
extern
#if !(USB_CFG_DESCR_PROPS_STRING_PRODUCT & USB_PROP_IS_RAM)
const PROGMEM
#endif
int usbDescriptorStringDevice[];
extern
#if !(USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER & USB_PROP_IS_RAM)
const PROGMEM
#endif
int usbDescriptorStringSerialNumber[];
#endif /* __ASSEMBLER__ */
/* ------------------------------------------------------------------------- */
/* ------------------------ General Purpose Macros ------------------------- */
/* ------------------------------------------------------------------------- */
#define USB_CONCAT(a, b) a ## b
#define USB_CONCAT_EXPANDED(a, b) USB_CONCAT(a, b)
#define USB_OUTPORT(name) USB_CONCAT(PORT, name)
#define USB_INPORT(name) USB_CONCAT(PIN, name)
#define USB_DDRPORT(name) USB_CONCAT(DDR, name)
/* The double-define trick above lets us concatenate strings which are
* defined by macros.
*/
/* ------------------------------------------------------------------------- */
/* ------------------------- Constant definitions -------------------------- */
/* ------------------------------------------------------------------------- */
#if !defined __ASSEMBLER__ && (!defined USB_CFG_VENDOR_ID || !defined USB_CFG_DEVICE_ID)
#warning "You should define USB_CFG_VENDOR_ID and USB_CFG_DEVICE_ID in usbconfig.h"
/* If the user has not defined IDs, we default to obdev's free IDs.
* See USB-IDs-for-free.txt for details.
*/
#endif
/* make sure we have a VID and PID defined, byte order is lowbyte, highbyte */
#ifndef USB_CFG_VENDOR_ID
# define USB_CFG_VENDOR_ID 0xc0, 0x16 /* = 0x16c0 = 5824 = voti.nl */
#endif
#ifndef USB_CFG_DEVICE_ID
# if USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH
# define USB_CFG_DEVICE_ID 0xdf, 0x05 /* = 0x5df = 1503, shared PID for HIDs */
# elif USB_CFG_INTERFACE_CLASS == 2
# define USB_CFG_DEVICE_ID 0xe1, 0x05 /* = 0x5e1 = 1505, shared PID for CDC Modems */
# else
# define USB_CFG_DEVICE_ID 0xdc, 0x05 /* = 0x5dc = 1500, obdev's free PID */
# endif
#endif
/* Derive Output, Input and DataDirection ports from port names */
#ifndef USB_CFG_IOPORTNAME
#error "You must define USB_CFG_IOPORTNAME in usbconfig.h, see usbconfig-prototype.h"
#endif
#define USBOUT USB_OUTPORT(USB_CFG_IOPORTNAME)
#define USB_PULLUP_OUT USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
#define USBIN USB_INPORT(USB_CFG_IOPORTNAME)
#define USBDDR USB_DDRPORT(USB_CFG_IOPORTNAME)
#define USB_PULLUP_DDR USB_DDRPORT(USB_CFG_PULLUP_IOPORTNAME)
#define USBMINUS USB_CFG_DMINUS_BIT
#define USBPLUS USB_CFG_DPLUS_BIT
#define USBIDLE (1<<USB_CFG_DMINUS_BIT) /* value representing J state */
#define USBMASK ((1<<USB_CFG_DPLUS_BIT) | (1<<USB_CFG_DMINUS_BIT)) /* mask for USB I/O bits */
/* defines for backward compatibility with older driver versions: */
#define USB_CFG_IOPORT USB_OUTPORT(USB_CFG_IOPORTNAME)
#ifdef USB_CFG_PULLUP_IOPORTNAME
#define USB_CFG_PULLUP_IOPORT USB_OUTPORT(USB_CFG_PULLUP_IOPORTNAME)
#endif
#ifndef USB_CFG_EP3_NUMBER /* if not defined in usbconfig.h */
#define USB_CFG_EP3_NUMBER 3
#endif
#ifndef USB_CFG_HAVE_INTRIN_ENDPOINT3
#define USB_CFG_HAVE_INTRIN_ENDPOINT3 0
#endif
#define USB_BUFSIZE 11 /* PID, 8 bytes data, 2 bytes CRC */
/* ----- Try to find registers and bits responsible for ext interrupt 0 ----- */
#ifndef USB_INTR_CFG /* allow user to override our default */
# if defined EICRA
# define USB_INTR_CFG EICRA
# else
# define USB_INTR_CFG MCUCR
# endif
#endif
#ifndef USB_INTR_CFG_SET /* allow user to override our default */
# if defined(USB_COUNT_SOF) || defined(USB_SOF_HOOK)
# define USB_INTR_CFG_SET (1 << ISC01) /* cfg for falling edge */
/* If any SOF logic is used, the interrupt must be wired to D- where
* we better trigger on falling edge
*/
# else
# define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) /* cfg for rising edge */
# endif
#endif
#ifndef USB_INTR_CFG_CLR /* allow user to override our default */
# define USB_INTR_CFG_CLR 0 /* no bits to clear */
#endif
#ifndef USB_INTR_ENABLE /* allow user to override our default */
# if defined GIMSK
# define USB_INTR_ENABLE GIMSK
# elif defined EIMSK
# define USB_INTR_ENABLE EIMSK
# else
# define USB_INTR_ENABLE GICR
# endif
#endif
#ifndef USB_INTR_ENABLE_BIT /* allow user to override our default */
# define USB_INTR_ENABLE_BIT INT0
#endif
#ifndef USB_INTR_PENDING /* allow user to override our default */
# if defined EIFR
# define USB_INTR_PENDING EIFR
# else
# define USB_INTR_PENDING GIFR
# endif
#endif
#ifndef USB_INTR_PENDING_BIT /* allow user to override our default */
# define USB_INTR_PENDING_BIT INTF0
#endif
/*
The defines above don't work for the following chips
at90c8534: no ISC0?, no PORTB, can't find a data sheet
at86rf401: no PORTB, no MCUCR etc, low clock rate
atmega103: no ISC0? (maybe omission in header, can't find data sheet)
atmega603: not defined in avr-libc
at43usb320, at43usb355, at76c711: have USB anyway
at94k: is different...
at90s1200, attiny11, attiny12, attiny15, attiny28: these have no RAM
*/
/* ------------------------------------------------------------------------- */
/* ----------------- USB Specification Constants and Types ----------------- */
/* ------------------------------------------------------------------------- */
/* USB Token values */
#define USBPID_SETUP 0x2d
#define USBPID_OUT 0xe1
#define USBPID_IN 0x69
#define USBPID_DATA0 0xc3
#define USBPID_DATA1 0x4b
#define USBPID_ACK 0xd2
#define USBPID_NAK 0x5a
#define USBPID_STALL 0x1e
#ifndef USB_INITIAL_DATATOKEN
#define USB_INITIAL_DATATOKEN USBPID_DATA1
#endif
#ifndef __ASSEMBLER__
typedef struct usbTxStatus{
volatile uchar len;
uchar buffer[USB_BUFSIZE];
}usbTxStatus_t;
extern usbTxStatus_t usbTxStatus1, usbTxStatus3;
#define usbTxLen1 usbTxStatus1.len
#define usbTxBuf1 usbTxStatus1.buffer
#define usbTxLen3 usbTxStatus3.len
#define usbTxBuf3 usbTxStatus3.buffer
typedef union usbWord{
unsigned word;
uchar bytes[2];
}usbWord_t;
typedef struct usbRequest{
uchar bmRequestType;
uchar bRequest;
usbWord_t wValue;
usbWord_t wIndex;
usbWord_t wLength;
}usbRequest_t;
/* This structure matches the 8 byte setup request */
#endif
/* bmRequestType field in USB setup:
* d t t r r r r r, where
* d ..... direction: 0=host->device, 1=device->host
* t ..... type: 0=standard, 1=class, 2=vendor, 3=reserved
* r ..... recipient: 0=device, 1=interface, 2=endpoint, 3=other
*/
/* USB setup recipient values */
#define USBRQ_RCPT_MASK 0x1f
#define USBRQ_RCPT_DEVICE 0
#define USBRQ_RCPT_INTERFACE 1
#define USBRQ_RCPT_ENDPOINT 2
/* USB request type values */
#define USBRQ_TYPE_MASK 0x60
#define USBRQ_TYPE_STANDARD (0<<5)
#define USBRQ_TYPE_CLASS (1<<5)
#define USBRQ_TYPE_VENDOR (2<<5)
/* USB direction values: */
#define USBRQ_DIR_MASK 0x80
#define USBRQ_DIR_HOST_TO_DEVICE (0<<7)
#define USBRQ_DIR_DEVICE_TO_HOST (1<<7)
/* USB Standard Requests */
#define USBRQ_GET_STATUS 0
#define USBRQ_CLEAR_FEATURE 1
#define USBRQ_SET_FEATURE 3
#define USBRQ_SET_ADDRESS 5
#define USBRQ_GET_DESCRIPTOR 6
#define USBRQ_SET_DESCRIPTOR 7
#define USBRQ_GET_CONFIGURATION 8
#define USBRQ_SET_CONFIGURATION 9
#define USBRQ_GET_INTERFACE 10
#define USBRQ_SET_INTERFACE 11
#define USBRQ_SYNCH_FRAME 12
/* USB descriptor constants */
#define USBDESCR_DEVICE 1
#define USBDESCR_CONFIG 2
#define USBDESCR_STRING 3
#define USBDESCR_INTERFACE 4
#define USBDESCR_ENDPOINT 5
#define USBDESCR_HID 0x21
#define USBDESCR_HID_REPORT 0x22
#define USBDESCR_HID_PHYS 0x23
//#define USBATTR_BUSPOWER 0x80 // USB 1.1 does not define this value any more
#define USBATTR_SELFPOWER 0x40
#define USBATTR_REMOTEWAKE 0x20
/* USB HID Requests */
#define USBRQ_HID_GET_REPORT 0x01
#define USBRQ_HID_GET_IDLE 0x02
#define USBRQ_HID_GET_PROTOCOL 0x03
#define USBRQ_HID_SET_REPORT 0x09
#define USBRQ_HID_SET_IDLE 0x0a
#define USBRQ_HID_SET_PROTOCOL 0x0b
/* ------------------------------------------------------------------------- */
#endif /* __usbdrv_h_included__ */

View File

@ -0,0 +1,393 @@
/* Name: usbdrvasm.S
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
* Author: Christian Starkjohann
* Creation Date: 2007-06-13
* Tabsize: 4
* Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
* Revision: $Id: usbdrvasm.S 785 2010-05-30 17:57:07Z cs $
*/
/*
General Description:
This module is the assembler part of the USB driver. This file contains
general code (preprocessor acrobatics and CRC computation) and then includes
the file appropriate for the given clock rate.
*/
#define __SFR_OFFSET 0 /* used by avr-libc's register definitions */
#include "usbportability.h"
#include "usbdrv.h" /* for common defs */
/* register names */
#define x1 r16
#define x2 r17
#define shift r18
#define cnt r19
#define x3 r20
#define x4 r21
#define x5 r22
#define bitcnt x5
#define phase x4
#define leap x4
/* Some assembler dependent definitions and declarations: */
#ifdef __IAR_SYSTEMS_ASM__
extern usbRxBuf, usbDeviceAddr, usbNewDeviceAddr, usbInputBufOffset
extern usbCurrentTok, usbRxLen, usbRxToken, usbTxLen
extern usbTxBuf, usbTxStatus1, usbTxStatus3
# if USB_COUNT_SOF
extern usbSofCount
# endif
public usbCrc16
public usbCrc16Append
COMMON INTVEC
# ifndef USB_INTR_VECTOR
ORG INT0_vect
# else /* USB_INTR_VECTOR */
ORG USB_INTR_VECTOR
# undef USB_INTR_VECTOR
# endif /* USB_INTR_VECTOR */
# define USB_INTR_VECTOR usbInterruptHandler
rjmp USB_INTR_VECTOR
RSEG CODE
#else /* __IAR_SYSTEMS_ASM__ */
# ifndef USB_INTR_VECTOR /* default to hardware interrupt INT0 */
# ifdef INT0_vect
# define USB_INTR_VECTOR INT0_vect // this is the "new" define for the vector
# else
# define USB_INTR_VECTOR SIG_INTERRUPT0 // this is the "old" vector
# endif
# endif
.text
.global USB_INTR_VECTOR
.type USB_INTR_VECTOR, @function
.global usbCrc16
.global usbCrc16Append
#endif /* __IAR_SYSTEMS_ASM__ */
#if USB_INTR_PENDING < 0x40 /* This is an I/O address, use in and out */
# define USB_LOAD_PENDING(reg) in reg, USB_INTR_PENDING
# define USB_STORE_PENDING(reg) out USB_INTR_PENDING, reg
#else /* It's a memory address, use lds and sts */
# define USB_LOAD_PENDING(reg) lds reg, USB_INTR_PENDING
# define USB_STORE_PENDING(reg) sts USB_INTR_PENDING, reg
#endif
#define usbTxLen1 usbTxStatus1
#define usbTxBuf1 (usbTxStatus1 + 1)
#define usbTxLen3 usbTxStatus3
#define usbTxBuf3 (usbTxStatus3 + 1)
;----------------------------------------------------------------------------
; Utility functions
;----------------------------------------------------------------------------
#ifdef __IAR_SYSTEMS_ASM__
/* Register assignments for usbCrc16 on IAR cc */
/* Calling conventions on IAR:
* First parameter passed in r16/r17, second in r18/r19 and so on.
* Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
* Result is passed in r16/r17
* In case of the "tiny" memory model, pointers are only 8 bit with no
* padding. We therefore pass argument 1 as "16 bit unsigned".
*/
RTMODEL "__rt_version", "3"
/* The line above will generate an error if cc calling conventions change.
* The value "3" above is valid for IAR 4.10B/W32
*/
# define argLen r18 /* argument 2 */
# define argPtrL r16 /* argument 1 */
# define argPtrH r17 /* argument 1 */
# define resCrcL r16 /* result */
# define resCrcH r17 /* result */
# define ptrL ZL
# define ptrH ZH
# define ptr Z
# define byte r22
# define bitCnt r19
# define polyL r20
# define polyH r21
# define scratch r23
#else /* __IAR_SYSTEMS_ASM__ */
/* Register assignments for usbCrc16 on gcc */
/* Calling conventions on gcc:
* First parameter passed in r24/r25, second in r22/23 and so on.
* Callee must preserve r1-r17, r28/r29
* Result is passed in r24/r25
*/
# define argLen r22 /* argument 2 */
# define argPtrL r24 /* argument 1 */
# define argPtrH r25 /* argument 1 */
# define resCrcL r24 /* result */
# define resCrcH r25 /* result */
# define ptrL XL
# define ptrH XH
# define ptr x
# define byte r18
# define bitCnt r19
# define polyL r20
# define polyH r21
# define scratch r23
#endif
#if USB_USE_FAST_CRC
; This implementation is faster, but has bigger code size
; Thanks to Slawomir Fras (BoskiDialer) for this code!
; It implements the following C pseudo-code:
; unsigned table(unsigned char x)
; {
; unsigned value;
;
; value = (unsigned)x << 6;
; value ^= (unsigned)x << 7;
; if(parity(x))
; value ^= 0xc001;
; return value;
; }
; unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen)
; {
; unsigned crc = 0xffff;
;
; while(argLen--)
; crc = table(lo8(crc) ^ *argPtr++) ^ hi8(crc);
; return ~crc;
; }
; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
; argPtr r24+25 / r16+r17
; argLen r22 / r18
; temp variables:
; byte r18 / r22
; scratch r23
; resCrc r24+r25 / r16+r17
; ptr X / Z
usbCrc16:
mov ptrL, argPtrL
mov ptrH, argPtrH
ldi resCrcL, 0xFF
ldi resCrcH, 0xFF
rjmp usbCrc16LoopTest
usbCrc16ByteLoop:
ld byte, ptr+
eor resCrcL, byte ; resCrcL is now 'x' in table()
mov byte, resCrcL ; compute parity of 'x'
swap byte
eor byte, resCrcL
mov scratch, byte
lsr byte
lsr byte
eor byte, scratch
inc byte
lsr byte
andi byte, 1 ; byte is now parity(x)
mov scratch, resCrcL
mov resCrcL, resCrcH
eor resCrcL, byte ; low byte of if(parity(x)) value ^= 0xc001;
neg byte
andi byte, 0xc0
mov resCrcH, byte ; high byte of if(parity(x)) value ^= 0xc001;
clr byte
lsr scratch
ror byte
eor resCrcH, scratch
eor resCrcL, byte
lsr scratch
ror byte
eor resCrcH, scratch
eor resCrcL, byte
usbCrc16LoopTest:
subi argLen, 1
brsh usbCrc16ByteLoop
com resCrcL
com resCrcH
ret
#else /* USB_USE_FAST_CRC */
; This implementation is slower, but has less code size
;
; extern unsigned usbCrc16(unsigned char *argPtr, unsigned char argLen);
; argPtr r24+25 / r16+r17
; argLen r22 / r18
; temp variables:
; byte r18 / r22
; bitCnt r19
; poly r20+r21
; scratch r23
; resCrc r24+r25 / r16+r17
; ptr X / Z
usbCrc16:
mov ptrL, argPtrL
mov ptrH, argPtrH
ldi resCrcL, 0
ldi resCrcH, 0
ldi polyL, lo8(0xa001)
ldi polyH, hi8(0xa001)
com argLen ; argLen = -argLen - 1: modified loop to ensure that carry is set
ldi bitCnt, 0 ; loop counter with starnd condition = end condition
rjmp usbCrcLoopEntry
usbCrcByteLoop:
ld byte, ptr+
eor resCrcL, byte
usbCrcBitLoop:
ror resCrcH ; carry is always set here (see brcs jumps to here)
ror resCrcL
brcs usbCrcNoXor
eor resCrcL, polyL
eor resCrcH, polyH
usbCrcNoXor:
subi bitCnt, 224 ; (8 * 224) % 256 = 0; this loop iterates 8 times
brcs usbCrcBitLoop
usbCrcLoopEntry:
subi argLen, -1
brcs usbCrcByteLoop
usbCrcReady:
ret
; Thanks to Reimar Doeffinger for optimizing this CRC routine!
#endif /* USB_USE_FAST_CRC */
; extern unsigned usbCrc16Append(unsigned char *data, unsigned char len);
usbCrc16Append:
rcall usbCrc16
st ptr+, resCrcL
st ptr+, resCrcH
ret
#undef argLen
#undef argPtrL
#undef argPtrH
#undef resCrcL
#undef resCrcH
#undef ptrL
#undef ptrH
#undef ptr
#undef byte
#undef bitCnt
#undef polyL
#undef polyH
#undef scratch
#if USB_CFG_HAVE_MEASURE_FRAME_LENGTH
#ifdef __IAR_SYSTEMS_ASM__
/* Register assignments for usbMeasureFrameLength on IAR cc */
/* Calling conventions on IAR:
* First parameter passed in r16/r17, second in r18/r19 and so on.
* Callee must preserve r4-r15, r24-r29 (r28/r29 is frame pointer)
* Result is passed in r16/r17
* In case of the "tiny" memory model, pointers are only 8 bit with no
* padding. We therefore pass argument 1 as "16 bit unsigned".
*/
# define resL r16
# define resH r17
# define cnt16L r30
# define cnt16H r31
# define cntH r18
#else /* __IAR_SYSTEMS_ASM__ */
/* Register assignments for usbMeasureFrameLength on gcc */
/* Calling conventions on gcc:
* First parameter passed in r24/r25, second in r22/23 and so on.
* Callee must preserve r1-r17, r28/r29
* Result is passed in r24/r25
*/
# define resL r24
# define resH r25
# define cnt16L r24
# define cnt16H r25
# define cntH r26
#endif
# define cnt16 cnt16L
; extern unsigned usbMeasurePacketLength(void);
; returns time between two idle strobes in multiples of 7 CPU clocks
.global usbMeasureFrameLength
usbMeasureFrameLength:
ldi cntH, 6 ; wait ~ 10 ms for D- == 0
clr cnt16L
clr cnt16H
usbMFTime16:
dec cntH
breq usbMFTimeout
usbMFWaitStrobe: ; first wait for D- == 0 (idle strobe)
sbiw cnt16, 1 ;[0] [6]
breq usbMFTime16 ;[2]
sbic USBIN, USBMINUS ;[3]
rjmp usbMFWaitStrobe ;[4]
usbMFWaitIdle: ; then wait until idle again
sbis USBIN, USBMINUS ;1 wait for D- == 1
rjmp usbMFWaitIdle ;2
ldi cnt16L, 1 ;1 represents cycles so far
clr cnt16H ;1
usbMFWaitLoop:
in cntH, USBIN ;[0] [7]
adiw cnt16, 1 ;[1]
breq usbMFTimeout ;[3]
andi cntH, USBMASK ;[4]
brne usbMFWaitLoop ;[5]
usbMFTimeout:
#if resL != cnt16L
mov resL, cnt16L
mov resH, cnt16H
#endif
ret
#undef resL
#undef resH
#undef cnt16
#undef cnt16L
#undef cnt16H
#undef cntH
#endif /* USB_CFG_HAVE_MEASURE_FRAME_LENGTH */
;----------------------------------------------------------------------------
; Now include the clock rate specific code
;----------------------------------------------------------------------------
#ifndef USB_CFG_CLOCK_KHZ
# ifdef F_CPU
# define USB_CFG_CLOCK_KHZ (F_CPU/1000)
# else
# error "USB_CFG_CLOCK_KHZ not defined in usbconfig.h and no F_CPU set!"
# endif
#endif
#if USB_CFG_CHECK_CRC /* separate dispatcher for CRC type modules */
# if USB_CFG_CLOCK_KHZ == 18000
# include "usbdrvasm18-crc.inc"
# else
# error "USB_CFG_CLOCK_KHZ is not one of the supported crc-rates!"
# endif
#else /* USB_CFG_CHECK_CRC */
# if USB_CFG_CLOCK_KHZ == 12000
# include "usbdrvasm12.inc"
# elif USB_CFG_CLOCK_KHZ == 12800
# include "usbdrvasm128.inc"
# elif USB_CFG_CLOCK_KHZ == 15000
# include "usbdrvasm15.inc"
# elif USB_CFG_CLOCK_KHZ == 16000
# include "usbdrvasm16.inc"
# elif USB_CFG_CLOCK_KHZ == 16500
# include "usbdrvasm165.inc"
# elif USB_CFG_CLOCK_KHZ == 20000
# include "usbdrvasm20.inc"
# else
# error "USB_CFG_CLOCK_KHZ is not one of the supported non-crc-rates!"
# endif
#endif /* USB_CFG_CHECK_CRC */

Some files were not shown because too many files have changed in this diff Show More