initial release
This commit is contained in:
parent
62a932ecdd
commit
252b61a1ec
5
Changelog.txt
Normal file
5
Changelog.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
$Id: Changelog.txt,v 1.1 2007/07/29 17:19:50 rschaten Exp $
|
||||||
|
|
||||||
|
* Release 070729
|
||||||
|
|
||||||
|
- initial release
|
340
License.txt
Normal file
340
License.txt
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 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.
|
||||||
|
|
||||||
|
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 Lesser General
|
||||||
|
Public License instead of this License.
|
115
Makefile
Normal file
115
Makefile
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
# $Id: Makefile,v 1.1 2007/07/29 17:19:50 rschaten Exp $
|
||||||
|
|
||||||
|
# microcontroller settings
|
||||||
|
F_CPU = 20000000UL
|
||||||
|
MCU = attiny2313
|
||||||
|
|
||||||
|
# usb programmer:
|
||||||
|
AVRDUDE = avrdude -p $(MCU) -P /dev/tts/USB0 -b 115200 -c avr109
|
||||||
|
# parallel programmer, used to set fuse bits:
|
||||||
|
AVRDUDE2 = avrdude -p $(MCU) -P /dev/parport0 -c stk200 -E noreset,vcc
|
||||||
|
|
||||||
|
|
||||||
|
COMPILE = avr-gcc -Wall -Os -I../common -I. -mmcu=$(MCU) -DF_CPU=$(F_CPU) -Wa,-ahlms=$(<:.c=.lst) #-DDEBUG_LEVEL=2
|
||||||
|
|
||||||
|
OBJECTS = main.o usiTwiSlave.o
|
||||||
|
|
||||||
|
TODAY=`date "+%y%m%d"`
|
||||||
|
DIR=`basename \`pwd\``
|
||||||
|
PACKETNAME=$(DIR)_$(TODAY)
|
||||||
|
|
||||||
|
all: usage
|
||||||
|
|
||||||
|
usage:
|
||||||
|
@echo "Usage of this makefile:"
|
||||||
|
@echo "make firmware create firmware"
|
||||||
|
@echo "make program send firmware to the device"
|
||||||
|
@echo "make fuses set fuses of the device"
|
||||||
|
@echo "make docs create documentation"
|
||||||
|
@echo "make tarball packs a tarball for shipping"
|
||||||
|
@echo "make clean tidy the directory"
|
||||||
|
@echo
|
||||||
|
@echo "For further information, consult the documentation in Readme.txt."
|
||||||
|
|
||||||
|
# symbolic targets:
|
||||||
|
firmware: main.hex
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(COMPILE) -c $< -o $@
|
||||||
|
|
||||||
|
.c.s:
|
||||||
|
$(COMPILE) -S $< -o $@
|
||||||
|
|
||||||
|
program: firmware
|
||||||
|
$(AVRDUDE) -U flash:w:main.hex
|
||||||
|
|
||||||
|
# Fuse low byte:
|
||||||
|
# 0xef = 1 1 1 0 1 1 1 1
|
||||||
|
# ^ ^ \+/ \--+--/
|
||||||
|
# | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz)
|
||||||
|
# | | +--------------- SUT 1..0 (BOD enabled, fast rising power)
|
||||||
|
# | +------------------ CKOUT (clock output on CKOUT pin -> disabled)
|
||||||
|
# +-------------------- CKDIV8 (divide clock by 8 -> don't divide)
|
||||||
|
#
|
||||||
|
# Fuse high byte:
|
||||||
|
# 0xdb = 1 1 0 1 1 0 1 1
|
||||||
|
# ^ ^ ^ ^ \-+-/ ^
|
||||||
|
# | | | | | +---- RSTDISBL (disable external reset -> enabled)
|
||||||
|
# | | | | +-------- BODLEVEL 2..0 (brownout trigger level -> 2.7V)
|
||||||
|
# | | | +-------------- WDTON (watchdog timer always on -> disable)
|
||||||
|
# | | +---------------- SPIEN (enable serial programming -> enabled)
|
||||||
|
# | +------------------ EESAVE (preserve EEPROM on Chip Erase -> not preserved)
|
||||||
|
# +-------------------- DWEN (debug wire enable)
|
||||||
|
fuses:
|
||||||
|
$(AVRDUDE2) -u -U hfuse:w:0xdb:m -U lfuse:w:0xef:m
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f main.lst main.obj main.cof main.list main.map main.eep.hex main.bin *.o main.s *.lst
|
||||||
|
rm -rf htmldoc latexdoc Readme.txt refman.pdf
|
||||||
|
rm -f $(PACKETNAME).tar.gz
|
||||||
|
|
||||||
|
# file targets:
|
||||||
|
main.bin: $(OBJECTS)
|
||||||
|
$(COMPILE) -o main.bin $(OBJECTS)
|
||||||
|
|
||||||
|
main.hex: main.bin
|
||||||
|
rm -f main.hex main.eep.hex
|
||||||
|
avr-objcopy -j .text -j .data -O ihex main.bin main.hex
|
||||||
|
avr-size main.hex
|
||||||
|
|
||||||
|
# doc generation
|
||||||
|
docs: readme pdf
|
||||||
|
@echo "documentation created"
|
||||||
|
|
||||||
|
readme: doxygen
|
||||||
|
echo "This file is auto-generated from the content of <main.c>." > Readme.txt
|
||||||
|
echo "You'll have more fun if you read the HTML-content in htmldoc or the PDF." >> Readme.txt
|
||||||
|
echo >> Readme.txt
|
||||||
|
lynx -dump htmldoc/main.html >> Readme.txt
|
||||||
|
|
||||||
|
pdf: doxygen
|
||||||
|
make -C latexdoc
|
||||||
|
mv latexdoc/refman.pdf .
|
||||||
|
rm -rf latexdoc
|
||||||
|
|
||||||
|
doxygen:
|
||||||
|
doxygen i2c-dimmer.doxygen
|
||||||
|
|
||||||
|
tarball: firmware clean docs
|
||||||
|
@echo
|
||||||
|
@echo
|
||||||
|
@echo "I assume you updated the Changelog...? Press Enter to continue..."
|
||||||
|
@read
|
||||||
|
mv -v main.hex main_$(TODAY).hex
|
||||||
|
[ -e "main_$(TODAY).hex" ] || exit
|
||||||
|
rm --force $(PACKETNAME).tar.gz; \
|
||||||
|
tar --directory=.. \
|
||||||
|
--exclude=$(DIR)/Makefile \
|
||||||
|
--exclude=CVS \
|
||||||
|
--exclude=*.ps \
|
||||||
|
--create \
|
||||||
|
--gzip \
|
||||||
|
--verbose \
|
||||||
|
--file ../$(PACKETNAME).tar.gz $(DIR)
|
||||||
|
rm -f main_$(TODAY).hex
|
||||||
|
|
BIN
USI_TWI_Slave.zip
Normal file
BIN
USI_TWI_Slave.zip
Normal file
Binary file not shown.
1257
i2c-dimmer.doxygen
Normal file
1257
i2c-dimmer.doxygen
Normal file
File diff suppressed because it is too large
Load Diff
541
main.c
Normal file
541
main.c
Normal file
@ -0,0 +1,541 @@
|
|||||||
|
/**
|
||||||
|
* \file main.c
|
||||||
|
* \brief Firmware for the i2c-dimmer
|
||||||
|
* \author Ronald Schaten <ronald@schatenseite.de> & Thomas Stegemann
|
||||||
|
* \version $Id: main.c,v 1.1 2007/07/29 17:19:50 rschaten Exp $
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software and its
|
||||||
|
* documentation under the terms of the GNU General Public License is hereby
|
||||||
|
* granted. No representations are made about the suitability of this software
|
||||||
|
* for any purpose. It is provided "as is" without express or implied warranty.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \mainpage I2C-dimmer
|
||||||
|
*
|
||||||
|
* \section sec_intro Introduction
|
||||||
|
*
|
||||||
|
* I haven't done many microcontroller-projects till now, but more than one of
|
||||||
|
* the few projects I did involved controlling LEDs by pulse width modulation
|
||||||
|
* (PWM). Doing this for one or more LEDs is a stressful task for a little
|
||||||
|
* microcontroller, but if you want to do some other more or less complicated
|
||||||
|
* things while keeping LEDs at certain brightnesses is likely to ruin the
|
||||||
|
* timings that are used in the PWM. Not to talk about the program code, which
|
||||||
|
* gets more and more unreadable if you try to do several different things 'at
|
||||||
|
* the same time'.
|
||||||
|
*
|
||||||
|
* For my next project I need to fade some LEDs again, so I was looking for an
|
||||||
|
* easier way to do it. The plans include reading from memory cards, talking to
|
||||||
|
* real time clocks and displaying text on an LCD, so I'm almost sure that I
|
||||||
|
* won't be able to reliably control the five channels I'm going to use.
|
||||||
|
*
|
||||||
|
* The first plan was to use a ready-made chip. I looked around and the best
|
||||||
|
* thing I could find was one made by Philips (PCA something, I forgot the
|
||||||
|
* number) that can be controlled via I2C-bus. That part is able to control
|
||||||
|
* eight LEDs, but apart from 'on' and 'off' you can set the LEDs only to two
|
||||||
|
* different brightnesses. Those are variable, nevertheless, but it would be
|
||||||
|
* impossible to light one LED at 20%, one at 50% and one at 80%. Another
|
||||||
|
* drawback is that it is SMD-only, and my soldering-skills don't including
|
||||||
|
* working with stuff that small.
|
||||||
|
*
|
||||||
|
* So the Idea was to set up a separate controller for LED-fading, that can be
|
||||||
|
* externally controlled, ideally via I2C-bus since I intend to use several
|
||||||
|
* other devices in my next project that can make use of the bus. So I set up
|
||||||
|
* an ATtiny2313 on my breadboard, clocked it with an external 20MHz-crystal
|
||||||
|
* and we tried to control as many LEDs as possible...
|
||||||
|
*
|
||||||
|
* \section sec_pwm Pulse width modulation
|
||||||
|
*
|
||||||
|
* \subsection sec_pwm1 The old way
|
||||||
|
*
|
||||||
|
* Controlling the brightness of LEDs by PWM is a common technique, I used it
|
||||||
|
* myself in several projects. Till now I used to switch on all LEDs that
|
||||||
|
* should light up at a level greater than zero, waited till the first of the
|
||||||
|
* LEDs has to be switched off, switched it off, waited for the next one and so
|
||||||
|
* on. After a certain time all LEDs are switched off, and I start again.
|
||||||
|
*
|
||||||
|
* I try to visualize that with a little picture:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* . . . . .| . .
|
||||||
|
* 1 *************************************************|************************
|
||||||
|
* 2 *************************************** |************************
|
||||||
|
* 3 ********* |**********
|
||||||
|
* 4 |
|
||||||
|
* 5 ***************************** |************************
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* In this example, a full cycle of the PWM would need 50 units of time. The
|
||||||
|
* first LED is switched on the full time (100%), the second for 40 of the 50
|
||||||
|
* units (80%), the third one for ten (20%) and the fifth one for 30 units
|
||||||
|
* (60%). The fourth LED is off (0%). We see that after 50 units of time the
|
||||||
|
* modulation starts again.
|
||||||
|
*
|
||||||
|
* The drawback of this technique is, that it's slow. And for each additional
|
||||||
|
* channel you try to control, it gets even slower. We tried, but we weren't
|
||||||
|
* able to control more than five LEDs in this way without them to start
|
||||||
|
* flickering to a visible amount.
|
||||||
|
*
|
||||||
|
* We tried to create an array with all states of the process, so the PWM only
|
||||||
|
* would have to loop through the array and set the outputs accordingly. But
|
||||||
|
* that didn't work either, because the used microcontroller doesn't have
|
||||||
|
* enough RAM to store the array.
|
||||||
|
*
|
||||||
|
* \subsection sec_pwm2 Thomas' idea
|
||||||
|
*
|
||||||
|
* After some tests that didn't work out too well, Thomas had a great idea how
|
||||||
|
* to implement the PWM. It also works with an array for all states, but the
|
||||||
|
* states of the modulation are not displayed for the same time. The first
|
||||||
|
* state is displayed for one time-unit, the second one for two time-units, the
|
||||||
|
* third one for four and so on. In this way the LEDs are turned on and off
|
||||||
|
* more than once per cycle of the PWM, but that doesn't hurt.
|
||||||
|
*
|
||||||
|
* Let's try to paint a picture again:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* . . . . . . | .
|
||||||
|
* .. . . . . |.. . .
|
||||||
|
* 1 * |*
|
||||||
|
* 2 ** | **
|
||||||
|
* 3 *** |***
|
||||||
|
* 4 **** | ****
|
||||||
|
* 5 * **** |* ****
|
||||||
|
* 6 ****** | ******
|
||||||
|
* 7 ******* |*******
|
||||||
|
* 8 ******** | ****
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* So here we see a PWM with eight channels that are able to display up to 64
|
||||||
|
* different brightnesses. Channel one is switched on for one unit of time,
|
||||||
|
* channel two for two units and so on. The most interesting thing is on
|
||||||
|
* channel five: the LED is switched on for one unit of time, switched off, and
|
||||||
|
* switched on again for four units of time.
|
||||||
|
*
|
||||||
|
* Lets try a more complicated example -- with brighter LEDs, too:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* . . . . . . | .
|
||||||
|
* .. . . . . |.. . .
|
||||||
|
* 1 * *******************************|*
|
||||||
|
* 2 ** **************** | **
|
||||||
|
* 3 ******* **************** |*******
|
||||||
|
* 4 *******************************|
|
||||||
|
* 5 * **** **************** |* ****
|
||||||
|
* 6 *************************************************************| **********
|
||||||
|
* 7 **************************************************************|***********
|
||||||
|
* 8 ************************ | ****
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* The channels 1 to 8 have the brightnesses 33, 18, 23, 32, 21, 63, 64 and 24.
|
||||||
|
*
|
||||||
|
* The advantage of this technique is that on the one hand you have to save a
|
||||||
|
* limited number of states (six states in the example), and the looping
|
||||||
|
* through the states is very simple: state n is sent to the output pins, then
|
||||||
|
* we wait for 2^(n-1) time units, then the next state is sent.
|
||||||
|
*
|
||||||
|
* Each state represents the bit-pattern that has to be sent during one step.
|
||||||
|
* In other words: one column out of the above picture at the start of a new
|
||||||
|
* time period. So in this example, we have six states: 01010101, 01100110,
|
||||||
|
* 01110100, 11100000, 11110110 and 01101001. The first one is displayed for
|
||||||
|
* one unit of time, the second one for two units, the third one for four units
|
||||||
|
* and so on...
|
||||||
|
*
|
||||||
|
* Using this technique has the advantage that adding more channels does almost
|
||||||
|
* nothing in terms of system load. The only time that the algorithm has to do
|
||||||
|
* actual calculations is when a new value has been delivered and has to be
|
||||||
|
* converted into the states. <strong>So using this algorithm, it is possible
|
||||||
|
* to show different brightnesses on all free pins of the controller. With an
|
||||||
|
* ATtiny2313 that means that you can fade 13 different LEDs while still
|
||||||
|
* talking I2C to communicate with other devices!</strong>
|
||||||
|
*
|
||||||
|
* \section sec_i2c I2C communication
|
||||||
|
*
|
||||||
|
* Speaking I2C is no rocket science, but since one has to do a lot of
|
||||||
|
* bit-shifting when implementing it, I took a ready-made library.
|
||||||
|
*
|
||||||
|
* The one I used is <strong>written by Donald R. Blake</strong>, he was so
|
||||||
|
* kind to put it under GPL and post it to avrfreaks.net. You can find the
|
||||||
|
* original post in a thread called '<a
|
||||||
|
* href="http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=48395">8
|
||||||
|
* bit communication between AVR using TWI</a>' and some additions in the
|
||||||
|
* thread '<a
|
||||||
|
* href="http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=51467">I2C
|
||||||
|
* Slave on an ATtiny45</a>'.
|
||||||
|
*
|
||||||
|
* Thanks for the great work, Donald! And for putting it under a free license.
|
||||||
|
*
|
||||||
|
* Since his package seems to be only available as a forum-attachment, and I'm
|
||||||
|
* not sure for how long that will be, I included it into the tarball of this
|
||||||
|
* project.
|
||||||
|
*
|
||||||
|
* \section sec_install Building and installing
|
||||||
|
*
|
||||||
|
* The firmware is built and installed on the controller with the included
|
||||||
|
* makefile. You might need to need to customize it to match your individual
|
||||||
|
* environment.
|
||||||
|
*
|
||||||
|
* Don't forget to set the fuses on the controller to make use of the external
|
||||||
|
* crystal. This project is using a fine algorithm, but it still needs the full
|
||||||
|
* power of 20MHz. The settings I used are included in the makefile, too.
|
||||||
|
*
|
||||||
|
* Oh, and if you want the slave to use an I2C-address different from 0x10: no
|
||||||
|
* problem. Just change it in the code.
|
||||||
|
*
|
||||||
|
* \section sec_usage Usage
|
||||||
|
*
|
||||||
|
* You should be able to use this device in the same way you would use any
|
||||||
|
* other I2C-slave:
|
||||||
|
*
|
||||||
|
* \subsection sec_usage_hardware Connecting it
|
||||||
|
*
|
||||||
|
* The controller needs to have the following pins connected in the circuit:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>Pin 1 - Reset - should be connected to VCC with a 10k-resistor</li>
|
||||||
|
* <li>Pin 4 and 5 - XTAL1 and XTAL2 - connected to a 20MHz-crystal, using
|
||||||
|
* 22p-capacitors against GND</li>
|
||||||
|
* <li>Pin 10 - GND - Ground</li>
|
||||||
|
* <li>Pin 17 - SDA - I2C-data</li>
|
||||||
|
* <li>Pin 19 - SCL - I2C-clock</li>
|
||||||
|
* <li>Pin 20 - VCC - 5V</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* Your I2C-data and -clock lines should be terminated by 4,7k-resistors to
|
||||||
|
* pull up the lines. All the other pins can be used to connect LEDs. They are
|
||||||
|
* arranged in this way:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>Pin 2 - PD0 - Channel 0</li>
|
||||||
|
* <li>Pin 3 - PD1 - Channel 1</li>
|
||||||
|
* <li>Pin 6 - PD2 - Channel 2</li>
|
||||||
|
* <li>Pin 7 - PD3 - Channel 3</li>
|
||||||
|
* <li>Pin 8 - PD4 - Channel 4</li>
|
||||||
|
* <li>Pin 9 - PD5 - Channel 5</li>
|
||||||
|
* <li>Pin 11 - PD6 - Channel 6</li>
|
||||||
|
* <li>Pin 12 - PB0 - Channel 7</li>
|
||||||
|
* <li>Pin 13 - PB1 - Channel 8</li>
|
||||||
|
* <li>Pin 14 - PB2 - Channel 9</li>
|
||||||
|
* <li>Pin 15 - PB3 - Channel 10</li>
|
||||||
|
* <li>Pin 16 - PB4 - Channel 11</li>
|
||||||
|
* <li>Pin 18 - PB6 - Channel 12</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* \subsection sec_usage_software Talking to it
|
||||||
|
*
|
||||||
|
* For my tests I used an ATmega8 as I2C-master with the library
|
||||||
|
* <strong>written by Peter Fleury</strong>. You can find it on <a
|
||||||
|
* href="http://jump.to/fleury">http://jump.to/fleury</a>. Thanks to him for
|
||||||
|
* putting it online!
|
||||||
|
*
|
||||||
|
* The typical send function looks like this:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* #define I2C_DIMMER 0x10
|
||||||
|
*
|
||||||
|
* void sendi2cBytes(uint8_t address, uint8_t brightness) {
|
||||||
|
* // address: number of the LED to set (0..12)
|
||||||
|
* // brightness: value between 0 and 127
|
||||||
|
* // start the communication...
|
||||||
|
* i2c_start_wait((I2C_DIMMER << 1) + I2C_WRITE);
|
||||||
|
* // write a byte with the address. we want the highest bit of the
|
||||||
|
* // address to be 1, so the slave can be sure that this is an address.
|
||||||
|
* i2c_write(address | 0x80);
|
||||||
|
* // calculate the actual duration the LED should light up. we could do
|
||||||
|
* // this on the slave's side, but we assume that the device is more
|
||||||
|
* // flexible when it is done on the master side.
|
||||||
|
* uint16_t duration = (brightness + 1) * (brightness + 1) - 1;
|
||||||
|
* // calculate the low- and the high-byte and send it. note that we split
|
||||||
|
* // the duration into 7-bit-values, not 8 bit! in this way the highest
|
||||||
|
* // bit of the transferred bytes is always low, allowing the slave to
|
||||||
|
* // recognize the transmitted bytes as values, not as addresses.
|
||||||
|
* i2c_write(duration & 0x7f); // low byte
|
||||||
|
* i2c_write((duration >> 7) & 0x7f); // high byte
|
||||||
|
* // stop the communication...
|
||||||
|
* i2c_stop();
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* \section sec_drawbacks Drawbacks
|
||||||
|
*
|
||||||
|
* Till now, the device worked in all situations I tested it in. So far
|
||||||
|
* everything is fine.
|
||||||
|
*
|
||||||
|
* I guess that, compared to the ready-made off-the-hook-parts that controls
|
||||||
|
* LEDs via I2C, this module is a bit slow. I can't see any flickering in the
|
||||||
|
* LEDs since they are still switched very fast (about every 6ms, which would
|
||||||
|
* result in a 166Hz flickering -- too fast for me).
|
||||||
|
*
|
||||||
|
* \section sec_files Files in the distribution
|
||||||
|
*
|
||||||
|
* - \e Readme.txt: Documentation, created from the htmldoc-directory.
|
||||||
|
* - \e htmldoc/: Documentation, created from main.c.
|
||||||
|
* - \e refman.pdf: Documentation, created from main.c.
|
||||||
|
* - \e main.c: Source code of the firmware.
|
||||||
|
* - \e main_*.hex: Compiled version of the firmware.
|
||||||
|
* - \e usiTwiSlave.c: I2C-library.
|
||||||
|
* - \e usiTwiSlave.h: I2C-library.
|
||||||
|
* - \e USI_TWI_Slave.zip: I2C-library (package).
|
||||||
|
* - \e i2c-dimmer.doxygen: Support for creating the documentation.
|
||||||
|
* - \e License.txt: Public license for all contents of this project, except
|
||||||
|
* for the USB driver. Look in firmware/usbdrv/License.txt for further info.
|
||||||
|
* - \e Changelog.txt: Logfile documenting changes in soft-, firm- and
|
||||||
|
* hardware.
|
||||||
|
*
|
||||||
|
* \section sec_thanks Thanks!
|
||||||
|
*
|
||||||
|
* Once again, special credits go to <b>Thomas Stegemann</b>. He had the great
|
||||||
|
* idea for the PWM-algorithm, and I am always astonished by the patience he
|
||||||
|
* has to show me how to do anything complicated in a sick language like C...
|
||||||
|
*
|
||||||
|
* \section sec_license About the license
|
||||||
|
*
|
||||||
|
* My work is licensed under the GNU General Public License (GPL). A copy of
|
||||||
|
* the GPL is included in License.txt.
|
||||||
|
*
|
||||||
|
* <b>(c) 2007 by Ronald Schaten - http://www.schatenseite.de</b>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <avr/wdt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <avr/pgmspace.h> // keeping constants in program memory
|
||||||
|
|
||||||
|
#include "usiTwiSlave.h" // i2c-routines by Donald R. Blake
|
||||||
|
|
||||||
|
#define TWI_SLA 0x10 /**< i2c slave address */
|
||||||
|
|
||||||
|
#define CHANNEL_COUNT 13 /**< number of 'fadeable' channels */
|
||||||
|
#define PORT_COUNT 2 /**< the channels are distributed over two ports */
|
||||||
|
|
||||||
|
#define OUTPORT0 PORTB /**< output port 0 */
|
||||||
|
#define OUTDDR0 DDRB /**< set port 0 to be output */
|
||||||
|
#define OUTMASK0 0x5F /**< see channel_pin, channel_port */
|
||||||
|
|
||||||
|
#define OUTPORT1 PORTD /**< output port 0 */
|
||||||
|
#define OUTDDR1 DDRD /**< set port 0 to be output */
|
||||||
|
#define OUTMASK1 0x7F /**< see channel_pin, channel_port */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We want to drive as many channels as possible. Unfortunately the usable pins
|
||||||
|
* aren't 'in a row', so we have to determine which channel ends up on which
|
||||||
|
* port and pin.
|
||||||
|
*/
|
||||||
|
/** this is used to determine the port that is used for output */
|
||||||
|
const uint8_t channel_port[CHANNEL_COUNT] PROGMEM = {
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
1, 1, 1, 1, 1, 1, 1 };
|
||||||
|
/** this is used to determine the pin that is used for output */
|
||||||
|
const uint8_t channel_pin[CHANNEL_COUNT] PROGMEM = {
|
||||||
|
0x01, 0x02, 0x04, 0x08, 0x10, 0x40,
|
||||||
|
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40 };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a special treatment for the states lasting very long. If you simply
|
||||||
|
* double the times for each state, you eventually end up having long pauses in
|
||||||
|
* the modulation. We try to suppress this effect by not waiting for 8192
|
||||||
|
* cycles but better performing the shorter 4096-cycle twice.
|
||||||
|
*/
|
||||||
|
#define STATE_COUNT 14 /**< number of states for pwm */
|
||||||
|
#define STATE_START_COUNT 2 /**< number of state groups to be treated individually */
|
||||||
|
/** interval length of the states */
|
||||||
|
const uint16_t switch_timer[STATE_COUNT] PROGMEM = {
|
||||||
|
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 4096 };
|
||||||
|
/** start interval of the state groups */
|
||||||
|
const uint8_t switch_timer_index[STATE_START_COUNT]= { 13, 0 };
|
||||||
|
|
||||||
|
/** contains the port assignments for each interval */
|
||||||
|
uint8_t switch_state[STATE_COUNT][PORT_COUNT];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Three bytes have to be received for a full command. This enum is used to
|
||||||
|
* indicate what part of the command we are waiting for.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
WAIT_FOR_ADDRESS, /**< first byte is the address */
|
||||||
|
WAIT_FOR_VALUE_LOW, /**< second byte is the lower part of the value */
|
||||||
|
WAIT_FOR_VALUE_HIGH, /**< third byte is the higher part of the value */
|
||||||
|
} ReadCommandState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds one command that is received via i2c. The command consists of an
|
||||||
|
* address (number of output channel) and a 16-bit value. The state is used to
|
||||||
|
* indicate what part of the next command we are waiting for.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t address; /**< number of output channel (between 0 and
|
||||||
|
CHANNEL_COUNT-1 */
|
||||||
|
uint16_t value; /**< value to be assigned to the channel (between
|
||||||
|
0 and 128*128-1 = 16383 */
|
||||||
|
ReadCommandState state; /**< what are we waiting for? */
|
||||||
|
} Command;
|
||||||
|
|
||||||
|
/** the next command is built in this variable */
|
||||||
|
Command command = {0, 0, WAIT_FOR_ADDRESS};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initialize timer
|
||||||
|
*/
|
||||||
|
void timer_start() {
|
||||||
|
TCCR1A = 0x00; // no hardware-pwm
|
||||||
|
/* CS12, CS11, CS10 (clock select bits)
|
||||||
|
* 0 1 0 cpu-clock / 8
|
||||||
|
*/
|
||||||
|
TCCR1B = (0 << WGM13) | (0 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10); // WGM1=4
|
||||||
|
sei();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set brightness on one channel.
|
||||||
|
* \param channel the channel to address (0 .. CHANNEL_COUNT)
|
||||||
|
* \param brightness the value to set (0 .. 16383)
|
||||||
|
*/
|
||||||
|
void set_brightness(uint8_t channel, uint16_t brightness){
|
||||||
|
uint8_t i;
|
||||||
|
// read port mask and port for this channel from program memory
|
||||||
|
uint8_t mask= pgm_read_word(&channel_pin[channel]);
|
||||||
|
uint8_t port= pgm_read_word(&channel_port[channel]);
|
||||||
|
// set the bits in the output-states according to the brightness
|
||||||
|
for (i= 0; i < STATE_COUNT; i++){
|
||||||
|
// walk through all states...
|
||||||
|
if (brightness & 1) {
|
||||||
|
// set the bit if it needs to be set in this state
|
||||||
|
switch_state[i][port] |= mask;
|
||||||
|
} else {
|
||||||
|
// clear it otherwise
|
||||||
|
switch_state[i][port] &= ~mask;
|
||||||
|
}
|
||||||
|
// shift the value to look at the next bit
|
||||||
|
brightness >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initialize hardware
|
||||||
|
*/
|
||||||
|
void init_ports(void){
|
||||||
|
OUTDDR0 |= OUTMASK0;
|
||||||
|
OUTPORT0 &= ~OUTMASK0; // clear all masked bits
|
||||||
|
|
||||||
|
OUTDDR1 |= OUTMASK1;
|
||||||
|
OUTPORT1 &= ~OUTMASK1; // clear all masked bits
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set output
|
||||||
|
* \param port port to set
|
||||||
|
* \param state value to be sent to the port
|
||||||
|
*/
|
||||||
|
void set_port(int port, uint8_t state){
|
||||||
|
switch(port){
|
||||||
|
case 0:
|
||||||
|
OUTPORT0 |= (state & OUTMASK0); // set bits
|
||||||
|
OUTPORT0 &= (state | ~OUTMASK0); // clear bits
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
OUTPORT1 |= (state & OUTMASK1); // set bits
|
||||||
|
OUTPORT1 &= (state | ~OUTMASK1); // clear bits
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if anything has been received via i2c and evaluate the received data.
|
||||||
|
* The received data is set into the command variable according to the state of
|
||||||
|
* the command we are waiting for.
|
||||||
|
*/
|
||||||
|
void evaluate_i2c_input(void) {
|
||||||
|
uint8_t byte_received = 0;
|
||||||
|
if (usiTwiDataInReceiveBuffer()) {
|
||||||
|
// we have input
|
||||||
|
byte_received = usiTwiReceiveByte();
|
||||||
|
switch(command.state){
|
||||||
|
case WAIT_FOR_ADDRESS:
|
||||||
|
if (byte_received & 0x80) {
|
||||||
|
// bit 7 is set -> address received
|
||||||
|
command.address = (byte_received & 0x7f);
|
||||||
|
command.state = WAIT_FOR_VALUE_LOW;
|
||||||
|
}
|
||||||
|
// do nothing if this byte didn't look like an address
|
||||||
|
break;
|
||||||
|
case WAIT_FOR_VALUE_LOW:
|
||||||
|
if (!(byte_received & 0x80)) {
|
||||||
|
// bit 7 is not set -> could be a value
|
||||||
|
command.value = byte_received;
|
||||||
|
command.state = WAIT_FOR_VALUE_HIGH;
|
||||||
|
} else {
|
||||||
|
// seems to be an address
|
||||||
|
command.address = byte_received;
|
||||||
|
command.state = WAIT_FOR_VALUE_LOW;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WAIT_FOR_VALUE_HIGH:
|
||||||
|
if (!(byte_received & 0x80)) {
|
||||||
|
// bit 7 is not set -> could be a value
|
||||||
|
command.value += (byte_received << 7);
|
||||||
|
command.state = WAIT_FOR_ADDRESS;
|
||||||
|
// we have a complete command
|
||||||
|
set_brightness(command.address, command.value);
|
||||||
|
} else {
|
||||||
|
// seems to be an address
|
||||||
|
command.address = byte_received;
|
||||||
|
command.state = WAIT_FOR_VALUE_LOW;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main-function. Initializes everything and contains the main loop which
|
||||||
|
* controls the actual PWM output.
|
||||||
|
* \return An integer. Whatever... :-)
|
||||||
|
*/
|
||||||
|
int main(void) {
|
||||||
|
uint8_t state_number = 0;
|
||||||
|
uint8_t state_start = 0;
|
||||||
|
uint8_t port = 0;
|
||||||
|
uint16_t timer = 0;
|
||||||
|
|
||||||
|
// initialize output ports
|
||||||
|
init_ports();
|
||||||
|
// set all channels to 0
|
||||||
|
uint8_t i;
|
||||||
|
for(i= 0; i < CHANNEL_COUNT; i++) {
|
||||||
|
set_brightness(i, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// own TWI slave address
|
||||||
|
usiTwiSlaveInit(TWI_SLA);
|
||||||
|
|
||||||
|
// start timer
|
||||||
|
timer_start();
|
||||||
|
|
||||||
|
// init watchdog
|
||||||
|
wdt_enable(WDTO_15MS); // 15ms watchdog
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// loop forever
|
||||||
|
for (state_start = 0; state_start < STATE_START_COUNT; state_start++) {
|
||||||
|
// treat state groups...
|
||||||
|
for (state_number = switch_timer_index[state_start]; state_number < STATE_COUNT; state_number++) {
|
||||||
|
// cycle through all steps...
|
||||||
|
for (port = 0; port < PORT_COUNT; port++) {
|
||||||
|
// set all output ports according to the current step...
|
||||||
|
set_port(port, switch_state[state_number][port]);
|
||||||
|
}
|
||||||
|
// determine how long to wait for the next step
|
||||||
|
timer = pgm_read_word(&switch_timer[state_number]);
|
||||||
|
// restart timer
|
||||||
|
TCNT1 = 0;
|
||||||
|
while (timer > TCNT1) {
|
||||||
|
// wait for the next step... meanwhile...
|
||||||
|
wdt_reset(); // feed the watchdog
|
||||||
|
evaluate_i2c_input(); // read i2c commands
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
581
usiTwiSlave.c
Normal file
581
usiTwiSlave.c
Normal file
@ -0,0 +1,581 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
USI TWI Slave driver.
|
||||||
|
|
||||||
|
Created by Donald R. Blake
|
||||||
|
donblake at worldnet.att.net
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Created from Atmel source files for Application Note AVR312: Using the USI Module
|
||||||
|
as an I2C slave.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Change Activity:
|
||||||
|
|
||||||
|
Date Description
|
||||||
|
------ -------------
|
||||||
|
16 Mar 2007 Created.
|
||||||
|
27 Mar 2007 Added support for ATtiny261, 461 and 861.
|
||||||
|
26 Apr 2007 Fixed ACK of slave address on a read.
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
includes
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include "usiTwiSlave.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
device dependent defines
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#if defined( __AVR_ATtiny2313__ )
|
||||||
|
# define DDR_USI DDRB
|
||||||
|
# define PORT_USI PORTB
|
||||||
|
# define PIN_USI PINB
|
||||||
|
# define PORT_USI_SDA PB5
|
||||||
|
# define PORT_USI_SCL PB7
|
||||||
|
# define PIN_USI_SDA PINB5
|
||||||
|
# define PIN_USI_SCL PINB7
|
||||||
|
# define USI_START_COND_INT USISIF
|
||||||
|
# define USI_START_VECTOR USI_START_vect
|
||||||
|
# define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined( __AVR_ATtiny25__ ) | \
|
||||||
|
defined( __AVR_ATtiny45__ ) | \
|
||||||
|
defined( __AVR_ATtiny85__ )
|
||||||
|
# define DDR_USI DDRB
|
||||||
|
# define PORT_USI PORTB
|
||||||
|
# define PIN_USI PINB
|
||||||
|
# define PORT_USI_SDA PB0
|
||||||
|
# define PORT_USI_SCL PB2
|
||||||
|
# define PIN_USI_SDA PINB0
|
||||||
|
# define PIN_USI_SCL PINB2
|
||||||
|
# define USI_START_COND_INT USICIF
|
||||||
|
# define USI_START_VECTOR USI_START_vect
|
||||||
|
# define USI_OVERFLOW_VECTOR USI_OVF_vect
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined( __AVR_ATtiny26__ )
|
||||||
|
# define DDR_USI DDRB
|
||||||
|
# define PORT_USI PORTB
|
||||||
|
# define PIN_USI PINB
|
||||||
|
# define PORT_USI_SDA PB0
|
||||||
|
# define PORT_USI_SCL PB2
|
||||||
|
# define PIN_USI_SDA PINB0
|
||||||
|
# define PIN_USI_SCL PINB2
|
||||||
|
# define USI_START_COND_INT USISIF
|
||||||
|
# define USI_START_VECTOR USI_STRT_vect
|
||||||
|
# define USI_OVERFLOW_VECTOR USI_OVF_vect
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined( __AVR_ATtiny261__ ) | \
|
||||||
|
defined( __AVR_ATtiny461__ ) | \
|
||||||
|
defined( __AVR_ATtiny861__ )
|
||||||
|
# define DDR_USI DDRB
|
||||||
|
# define PORT_USI PORTB
|
||||||
|
# define PIN_USI PINB
|
||||||
|
# define PORT_USI_SDA PB0
|
||||||
|
# define PORT_USI_SCL PB2
|
||||||
|
# define PIN_USI_SDA PINB0
|
||||||
|
# define PIN_USI_SCL PINB2
|
||||||
|
# define USI_START_COND_INT USISIF
|
||||||
|
# define USI_START_VECTOR USI_START_vect
|
||||||
|
# define USI_OVERFLOW_VECTOR USI_OVF_vect
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined( __AVR_ATmega165__ ) | \
|
||||||
|
defined( __AVR_ATmega325__ ) | \
|
||||||
|
defined( __AVR_ATmega3250__ ) | \
|
||||||
|
defined( __AVR_ATmega645__ ) | \
|
||||||
|
defined( __AVR_ATmega6450__ ) | \
|
||||||
|
defined( __AVR_ATmega329__ ) | \
|
||||||
|
defined( __AVR_ATmega3290__ )
|
||||||
|
# define DDR_USI DDRE
|
||||||
|
# define PORT_USI PORTE
|
||||||
|
# define PIN_USI PINE
|
||||||
|
# define PORT_USI_SDA PE5
|
||||||
|
# define PORT_USI_SCL PE4
|
||||||
|
# define PIN_USI_SDA PINE5
|
||||||
|
# define PIN_USI_SCL PINE4
|
||||||
|
# define USI_START_COND_INT USISIF
|
||||||
|
# define USI_START_VECTOR USI_START_vect
|
||||||
|
# define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined( __AVR_ATmega169__ )
|
||||||
|
# define DDR_USI DDRE
|
||||||
|
# define PORT_USI PORTE
|
||||||
|
# define PIN_USI PINE
|
||||||
|
# define PORT_USI_SDA PE5
|
||||||
|
# define PORT_USI_SCL PE4
|
||||||
|
# define PIN_USI_SDA PINE5
|
||||||
|
# define PIN_USI_SCL PINE4
|
||||||
|
# define USI_START_COND_INT USISIF
|
||||||
|
# define USI_START_VECTOR USI_START_vect
|
||||||
|
# define USI_OVERFLOW_VECTOR USI_OVERFLOW_vect
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
functions implemented as macros
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#define SET_USI_TO_SEND_ACK( ) \
|
||||||
|
{ \
|
||||||
|
/* prepare ACK */ \
|
||||||
|
USIDR = 0; \
|
||||||
|
/* set SDA as output */ \
|
||||||
|
DDR_USI |= ( 1 << PORT_USI_SDA ); \
|
||||||
|
/* clear all interrupt flags, except Start Cond */ \
|
||||||
|
USISR = \
|
||||||
|
( 0 << USI_START_COND_INT ) | \
|
||||||
|
( 1 << USIOIF ) | ( 1 << USIPF ) | \
|
||||||
|
( 1 << USIDC )| \
|
||||||
|
/* set USI counter to shift 1 bit */ \
|
||||||
|
( 0x0E << USICNT0 ); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SET_USI_TO_READ_ACK( ) \
|
||||||
|
{ \
|
||||||
|
/* set SDA as input */ \
|
||||||
|
DDR_USI &= ~( 1 << PORT_USI_SDA ); \
|
||||||
|
/* prepare ACK */ \
|
||||||
|
USIDR = 0; \
|
||||||
|
/* clear all interrupt flags, except Start Cond */ \
|
||||||
|
USISR = \
|
||||||
|
( 0 << USI_START_COND_INT ) | \
|
||||||
|
( 1 << USIOIF ) | \
|
||||||
|
( 1 << USIPF ) | \
|
||||||
|
( 1 << USIDC ) | \
|
||||||
|
/* set USI counter to shift 1 bit */ \
|
||||||
|
( 0x0E << USICNT0 ); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SET_USI_TO_TWI_START_CONDITION_MODE( ) \
|
||||||
|
{ \
|
||||||
|
USICR = \
|
||||||
|
/* enable Start Condition Interrupt, disable Overflow Interrupt */ \
|
||||||
|
( 1 << USISIE ) | ( 0 << USIOIE ) | \
|
||||||
|
/* set USI in Two-wire mode, no USI Counter overflow hold */ \
|
||||||
|
( 1 << USIWM1 ) | ( 0 << USIWM0 ) | \
|
||||||
|
/* Shift Register Clock Source = External, positive edge */ \
|
||||||
|
/* 4-Bit Counter Source = external, both edges */ \
|
||||||
|
( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) | \
|
||||||
|
/* no toggle clock-port pin */ \
|
||||||
|
( 0 << USITC ); \
|
||||||
|
USISR = \
|
||||||
|
/* clear all interrupt flags, except Start Cond */ \
|
||||||
|
( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \
|
||||||
|
( 1 << USIDC ) | ( 0x0 << USICNT0 ); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SET_USI_TO_SEND_DATA( ) \
|
||||||
|
{ \
|
||||||
|
/* set SDA as output */ \
|
||||||
|
DDR_USI |= ( 1 << PORT_USI_SDA ); \
|
||||||
|
/* clear all interrupt flags, except Start Cond */ \
|
||||||
|
USISR = \
|
||||||
|
( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | \
|
||||||
|
( 1 << USIDC) | \
|
||||||
|
/* set USI to shift out 8 bits */ \
|
||||||
|
( 0x0 << USICNT0 ); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SET_USI_TO_READ_DATA( ) \
|
||||||
|
{ \
|
||||||
|
/* set SDA as input */ \
|
||||||
|
DDR_USI &= ~( 1 << PORT_USI_SDA ); \
|
||||||
|
/* clear all interrupt flags, except Start Cond */ \
|
||||||
|
USISR = \
|
||||||
|
( 0 << USI_START_COND_INT ) | ( 1 << USIOIF ) | \
|
||||||
|
( 1 << USIPF ) | ( 1 << USIDC ) | \
|
||||||
|
/* set USI to shift out 8 bits */ \
|
||||||
|
( 0x0 << USICNT0 ); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
typedef's
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
USI_SLAVE_CHECK_ADDRESS = 0x00,
|
||||||
|
USI_SLAVE_SEND_DATA = 0x01,
|
||||||
|
USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA = 0x02,
|
||||||
|
USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA = 0x03,
|
||||||
|
USI_SLAVE_REQUEST_DATA = 0x04,
|
||||||
|
USI_SLAVE_GET_DATA_AND_SEND_ACK = 0x05
|
||||||
|
} overflowState_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
local variables
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
static uint8_t slaveAddress;
|
||||||
|
static volatile overflowState_t overflowState;
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t rxBuf[ TWI_RX_BUFFER_SIZE ];
|
||||||
|
static volatile uint8_t rxHead;
|
||||||
|
static volatile uint8_t rxTail;
|
||||||
|
|
||||||
|
static uint8_t txBuf[ TWI_TX_BUFFER_SIZE ];
|
||||||
|
static volatile uint8_t txHead;
|
||||||
|
static volatile uint8_t txTail;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
local functions
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// flushes the TWI buffers
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
flushTwiBuffers(
|
||||||
|
void
|
||||||
|
)
|
||||||
|
{
|
||||||
|
rxTail = 0;
|
||||||
|
rxHead = 0;
|
||||||
|
txTail = 0;
|
||||||
|
txHead = 0;
|
||||||
|
} // end flushTwiBuffers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
public functions
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// initialise USI for TWI slave mode
|
||||||
|
|
||||||
|
void
|
||||||
|
usiTwiSlaveInit(
|
||||||
|
uint8_t ownAddress
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
flushTwiBuffers( );
|
||||||
|
|
||||||
|
slaveAddress = ownAddress;
|
||||||
|
|
||||||
|
// In Two Wire mode (USIWM1, USIWM0 = 1X), the slave USI will pull SCL
|
||||||
|
// low when a start condition is detected or a counter overflow (only
|
||||||
|
// for USIWM1, USIWM0 = 11). This inserts a wait state. SCL is released
|
||||||
|
// by the ISRs (USI_START_vect and USI_OVERFLOW_vect).
|
||||||
|
|
||||||
|
// Set SCL and SDA as output
|
||||||
|
DDR_USI |= ( 1 << PORT_USI_SCL ) | ( 1 << PORT_USI_SDA );
|
||||||
|
|
||||||
|
// set SCL high
|
||||||
|
PORT_USI |= ( 1 << PORT_USI_SCL );
|
||||||
|
|
||||||
|
// set SDA high
|
||||||
|
PORT_USI |= ( 1 << PORT_USI_SDA );
|
||||||
|
|
||||||
|
// Set SDA as input
|
||||||
|
DDR_USI &= ~( 1 << PORT_USI_SDA );
|
||||||
|
|
||||||
|
USICR =
|
||||||
|
// enable Start Condition Interrupt
|
||||||
|
( 1 << USISIE ) |
|
||||||
|
// disable Overflow Interrupt
|
||||||
|
( 0 << USIOIE ) |
|
||||||
|
// set USI in Two-wire mode, no USI Counter overflow hold
|
||||||
|
( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
|
||||||
|
// Shift Register Clock Source = external, positive edge
|
||||||
|
// 4-Bit Counter Source = external, both edges
|
||||||
|
( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
|
||||||
|
// no toggle clock-port pin
|
||||||
|
( 0 << USITC );
|
||||||
|
|
||||||
|
// clear all interrupt flags and reset overflow counter
|
||||||
|
|
||||||
|
USISR = ( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) | ( 1 << USIPF ) | ( 1 << USIDC );
|
||||||
|
|
||||||
|
} // end usiTwiSlaveInit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// put data in the transmission buffer, wait if buffer is full
|
||||||
|
|
||||||
|
void
|
||||||
|
usiTwiTransmitByte(
|
||||||
|
uint8_t data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint8_t tmphead;
|
||||||
|
|
||||||
|
// calculate buffer index
|
||||||
|
tmphead = ( txHead + 1 ) & TWI_TX_BUFFER_MASK;
|
||||||
|
|
||||||
|
// wait for free space in buffer
|
||||||
|
while ( tmphead == txTail );
|
||||||
|
|
||||||
|
// store data in buffer
|
||||||
|
txBuf[ tmphead ] = data;
|
||||||
|
|
||||||
|
// store new index
|
||||||
|
txHead = tmphead;
|
||||||
|
|
||||||
|
} // end usiTwiTransmitByte
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// return a byte from the receive buffer, wait if buffer is empty
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
usiTwiReceiveByte(
|
||||||
|
void
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
// wait for Rx data
|
||||||
|
while ( rxHead == rxTail );
|
||||||
|
|
||||||
|
// calculate buffer index
|
||||||
|
rxTail = ( rxTail + 1 ) & TWI_RX_BUFFER_MASK;
|
||||||
|
|
||||||
|
// return data from the buffer.
|
||||||
|
return rxBuf[ rxTail ];
|
||||||
|
|
||||||
|
} // end usiTwiReceiveByte
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// check if there is data in the receive buffer
|
||||||
|
|
||||||
|
bool
|
||||||
|
usiTwiDataInReceiveBuffer(
|
||||||
|
void
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
// return 0 (false) if the receive buffer is empty
|
||||||
|
return rxHead != rxTail;
|
||||||
|
|
||||||
|
} // end usiTwiDataInReceiveBuffer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
USI Start Condition ISR
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
ISR( USI_START_VECTOR )
|
||||||
|
{
|
||||||
|
|
||||||
|
// set default starting conditions for new TWI package
|
||||||
|
overflowState = USI_SLAVE_CHECK_ADDRESS;
|
||||||
|
|
||||||
|
// set SDA as input
|
||||||
|
DDR_USI &= ~( 1 << PORT_USI_SDA );
|
||||||
|
|
||||||
|
// wait for SCL to go low to ensure the Start Condition has completed (the
|
||||||
|
// start detector will hold SCL low ) - if a Stop Condition arises then leave
|
||||||
|
// the interrupt to prevent waiting forever - don't use USISR to test for Stop
|
||||||
|
// Condition as in Application Note AVR312 because the Stop Condition Flag is
|
||||||
|
// going to be set from the last TWI sequence
|
||||||
|
while (
|
||||||
|
// SCL his high
|
||||||
|
( PIN_USI & ( 1 << PIN_USI_SCL ) ) &&
|
||||||
|
// and SDA is low
|
||||||
|
!( ( PIN_USI & ( 1 << PIN_USI_SDA ) ) )
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if ( !( PIN_USI & ( 1 << PIN_USI_SDA ) ) )
|
||||||
|
{
|
||||||
|
|
||||||
|
// a Stop Condition did not occur
|
||||||
|
|
||||||
|
USICR =
|
||||||
|
// keep Start Condition Interrupt enabled to detect RESTART
|
||||||
|
( 1 << USISIE ) |
|
||||||
|
// enable Overflow Interrupt
|
||||||
|
( 1 << USIOIE ) |
|
||||||
|
// set USI in Two-wire mode, hold SCL low on USI Counter overflow
|
||||||
|
( 1 << USIWM1 ) | ( 1 << USIWM0 ) |
|
||||||
|
// Shift Register Clock Source = External, positive edge
|
||||||
|
// 4-Bit Counter Source = external, both edges
|
||||||
|
( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
|
||||||
|
// no toggle clock-port pin
|
||||||
|
( 0 << USITC );
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
// a Stop Condition did occur
|
||||||
|
USICR =
|
||||||
|
// enable Start Condition Interrupt
|
||||||
|
( 1 << USISIE ) |
|
||||||
|
// disable Overflow Interrupt
|
||||||
|
( 0 << USIOIE ) |
|
||||||
|
// set USI in Two-wire mode, no USI Counter overflow hold
|
||||||
|
( 1 << USIWM1 ) | ( 0 << USIWM0 ) |
|
||||||
|
// Shift Register Clock Source = external, positive edge
|
||||||
|
// 4-Bit Counter Source = external, both edges
|
||||||
|
( 1 << USICS1 ) | ( 0 << USICS0 ) | ( 0 << USICLK ) |
|
||||||
|
// no toggle clock-port pin
|
||||||
|
( 0 << USITC );
|
||||||
|
|
||||||
|
} // end if
|
||||||
|
|
||||||
|
USISR =
|
||||||
|
// clear interrupt flags - resetting the Start Condition Flag will
|
||||||
|
// release SCL
|
||||||
|
( 1 << USI_START_COND_INT ) | ( 1 << USIOIF ) |
|
||||||
|
( 1 << USIPF ) |( 1 << USIDC ) |
|
||||||
|
// set USI to sample 8 bits (count 16 external SCL pin toggles)
|
||||||
|
( 0x0 << USICNT0);
|
||||||
|
|
||||||
|
} // end ISR( USI_START_VECTOR )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
USI Overflow ISR
|
||||||
|
|
||||||
|
Handles all the communication.
|
||||||
|
|
||||||
|
Only disabled when waiting for a new Start Condition.
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
ISR( USI_OVERFLOW_VECTOR )
|
||||||
|
{
|
||||||
|
|
||||||
|
switch ( overflowState )
|
||||||
|
{
|
||||||
|
|
||||||
|
// Address mode: check address and send ACK (and next USI_SLAVE_SEND_DATA) if OK,
|
||||||
|
// else reset USI
|
||||||
|
case USI_SLAVE_CHECK_ADDRESS:
|
||||||
|
if ( ( USIDR == 0 ) || ( ( USIDR >> 1 ) == slaveAddress) )
|
||||||
|
{
|
||||||
|
if ( USIDR & 0x01 )
|
||||||
|
{
|
||||||
|
overflowState = USI_SLAVE_SEND_DATA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
overflowState = USI_SLAVE_REQUEST_DATA;
|
||||||
|
} // end if
|
||||||
|
SET_USI_TO_SEND_ACK( );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SET_USI_TO_TWI_START_CONDITION_MODE( );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Master write data mode: check reply and goto USI_SLAVE_SEND_DATA if OK,
|
||||||
|
// else reset USI
|
||||||
|
case USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA:
|
||||||
|
if ( USIDR )
|
||||||
|
{
|
||||||
|
// if NACK, the master does not want more data
|
||||||
|
SET_USI_TO_TWI_START_CONDITION_MODE( );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// from here we just drop straight into USI_SLAVE_SEND_DATA if the
|
||||||
|
// master sent an ACK
|
||||||
|
|
||||||
|
// copy data from buffer to USIDR and set USI to shift byte
|
||||||
|
// next USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA
|
||||||
|
case USI_SLAVE_SEND_DATA:
|
||||||
|
// Get data from Buffer
|
||||||
|
if ( txHead != txTail )
|
||||||
|
{
|
||||||
|
txTail = ( txTail + 1 ) & TWI_TX_BUFFER_MASK;
|
||||||
|
USIDR = txBuf[ txTail ];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the buffer is empty
|
||||||
|
SET_USI_TO_TWI_START_CONDITION_MODE( );
|
||||||
|
return;
|
||||||
|
} // end if
|
||||||
|
overflowState = USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA;
|
||||||
|
SET_USI_TO_SEND_DATA( );
|
||||||
|
break;
|
||||||
|
|
||||||
|
// set USI to sample reply from master
|
||||||
|
// next USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA
|
||||||
|
case USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA:
|
||||||
|
overflowState = USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA;
|
||||||
|
SET_USI_TO_READ_ACK( );
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Master read data mode: set USI to sample data from master, next
|
||||||
|
// USI_SLAVE_GET_DATA_AND_SEND_ACK
|
||||||
|
case USI_SLAVE_REQUEST_DATA:
|
||||||
|
overflowState = USI_SLAVE_GET_DATA_AND_SEND_ACK;
|
||||||
|
SET_USI_TO_READ_DATA( );
|
||||||
|
break;
|
||||||
|
|
||||||
|
// copy data from USIDR and send ACK
|
||||||
|
// next USI_SLAVE_REQUEST_DATA
|
||||||
|
case USI_SLAVE_GET_DATA_AND_SEND_ACK:
|
||||||
|
// put data into buffer
|
||||||
|
// Not necessary, but prevents warnings
|
||||||
|
rxHead = ( rxHead + 1 ) & TWI_RX_BUFFER_MASK;
|
||||||
|
rxBuf[ rxHead ] = USIDR;
|
||||||
|
// next USI_SLAVE_REQUEST_DATA
|
||||||
|
overflowState = USI_SLAVE_REQUEST_DATA;
|
||||||
|
SET_USI_TO_SEND_ACK( );
|
||||||
|
break;
|
||||||
|
|
||||||
|
} // end switch
|
||||||
|
|
||||||
|
} // end ISR( USI_OVERFLOW_VECTOR )
|
88
usiTwiSlave.h
Normal file
88
usiTwiSlave.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
Header file for the USI TWI Slave driver.
|
||||||
|
|
||||||
|
Created by Donald R. Blake
|
||||||
|
donblake at worldnet.att.net
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Created from Atmel source files for Application Note AVR312: Using the USI Module
|
||||||
|
as an I2C slave.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Change Activity:
|
||||||
|
|
||||||
|
Date Description
|
||||||
|
------ -------------
|
||||||
|
15 Mar 2007 Created.
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _USI_TWI_SLAVE_H_
|
||||||
|
#define _USI_TWI_SLAVE_H_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
includes
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
prototypes
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
void usiTwiSlaveInit( uint8_t );
|
||||||
|
void usiTwiTransmitByte( uint8_t );
|
||||||
|
uint8_t usiTwiReceiveByte( void );
|
||||||
|
bool usiTwiDataInReceiveBuffer( void );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************
|
||||||
|
|
||||||
|
driver buffer definitions
|
||||||
|
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
// permitted RX buffer sizes: 1, 2, 4, 8, 16, 32, 64, 128 or 256
|
||||||
|
|
||||||
|
#define TWI_RX_BUFFER_SIZE ( 16 )
|
||||||
|
#define TWI_RX_BUFFER_MASK ( TWI_RX_BUFFER_SIZE - 1 )
|
||||||
|
|
||||||
|
#if ( TWI_RX_BUFFER_SIZE & TWI_RX_BUFFER_MASK )
|
||||||
|
# error TWI RX buffer size is not a power of 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// permitted TX buffer sizes: 1, 2, 4, 8, 16, 32, 64, 128 or 256
|
||||||
|
|
||||||
|
#define TWI_TX_BUFFER_SIZE ( 16 )
|
||||||
|
#define TWI_TX_BUFFER_MASK ( TWI_TX_BUFFER_SIZE - 1 )
|
||||||
|
|
||||||
|
#if ( TWI_TX_BUFFER_SIZE & TWI_TX_BUFFER_MASK )
|
||||||
|
# error TWI TX buffer size is not a power of 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ifndef _USI_TWI_SLAVE_H_
|
Loading…
Reference in New Issue
Block a user