mirror of
https://github.com/sjlongland/cluster-powerctl.git
synced 2025-09-13 12:03:14 +10:00
Initial check-in
This commit is contained in:
commit
882541392f
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.*.swp
|
||||
*.swp
|
||||
*.o
|
||||
*.elf
|
||||
*.hex
|
340
COPYING
Normal file
340
COPYING
Normal file
@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin St, 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 St, 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 Library General
|
||||
Public License instead of this License.
|
50
Makefile
Normal file
50
Makefile
Normal file
@ -0,0 +1,50 @@
|
||||
# Solar Powered Personal Cloud Power Controller
|
||||
# (C) 2016 Stuart Longland
|
||||
#
|
||||
# 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 St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
-include local.mk
|
||||
|
||||
CFLAGS = -Os -g -mmcu=attiny24a -Wall -Werror
|
||||
LDFLAGS = -mmcu=attiny24a -Wall -Werror
|
||||
CPPFLAGS = -DF_CPU=1000000UL
|
||||
CROSS_COMPILE ?= avr-
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
OBJCOPY = $(CROSS_COMPILE)objcopy
|
||||
OBJDUMP = $(CROSS_COMPILE)objdump
|
||||
SIZE = $(CROSS_COMPILE)size
|
||||
PROG_ARGS ?=-c stk500v2 -P /dev/ttyACM0
|
||||
PROG_DEV ?= t24
|
||||
|
||||
.PHONY: clean all
|
||||
|
||||
all: powerctl.ihex
|
||||
|
||||
clean:
|
||||
-rm *.ihex *.elf *.o
|
||||
|
||||
%.ihex: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -O ihex $^ $@
|
||||
|
||||
%.elf:
|
||||
$(CC) $(LDFLAGS) -o $@ $^
|
||||
$(SIZE) -d $@
|
||||
|
||||
powerctl.elf: powerctl.o uart.o
|
||||
powerctl.o: board.h
|
||||
uart.o: uartcfg.h uart.h
|
||||
|
||||
%.pgm: %.ihex
|
||||
avrdude $(PROG_ARGS) -p $(PROG_DEV) -U flash:w:$^:i
|
111
README.md
Normal file
111
README.md
Normal file
@ -0,0 +1,111 @@
|
||||
Power controller for solar powered personal cloud
|
||||
=================================================
|
||||
|
||||
This firmware is intended to control the charging of a battery bank that
|
||||
powers a small computer cluster running a private cloud system. The
|
||||
idea is to try to keep the battery within a small range of voltages,
|
||||
charging from solar or mains based chargers as necessary to top the
|
||||
battery back up.
|
||||
|
||||
Circuit description
|
||||
-------------------
|
||||
|
||||
An ATTiny24A microcontroller runs from a 5V rail derived from the
|
||||
battery. It uses its internal RC oscillator running at 1MHz.
|
||||
|
||||
Connected to PB0 and PB1 are the two MOSFETs that turn on the input
|
||||
sources, one for solar (PB1), the other for a mains charger (PB0).
|
||||
|
||||
The source pins of these connect to the battery positive input, so when
|
||||
the FET is on, power may flow from that source to the battery.
|
||||
|
||||
A third MOSFET connects to PB2, this is PWM-controlled to manage some
|
||||
cooling fans. The internal temperature sensor is used to decide whether
|
||||
the fans should be on or off, and at what speed.
|
||||
|
||||
Connecting to each input, and to the battery, are separate voltage
|
||||
dividers, comprising of a 1.5kOhm and 100Ohm resistors. These divide
|
||||
the input voltage by 16, and the divided voltage is fed into the ADC
|
||||
pins PA0 (mains), PA1 (solar) and PA2 (battery).
|
||||
|
||||
LEDs connect to PA7, PA6, PA5, PA4 and PA3 to 0v. ICSP is shared with the
|
||||
LEDs.
|
||||
|
||||
GPIOs
|
||||
-----
|
||||
|
||||
PB0: Mains MOSFET (active HIGH)
|
||||
PB1: Solar MOSFET (active HIGH)
|
||||
PB2: Fan MOSFET (active HIGH)
|
||||
PB3: nRESET
|
||||
PA7: Temperature Low LED (active HIGH)
|
||||
PA6: Temperature High LED (active HIGH) + ICSP MOSI
|
||||
PA5: Battery Voltage High LED (active HIGH) + ICSP MISO
|
||||
PA4: Warning LED (active high) + ICSP SCK + Debug Tx
|
||||
PA3: Battery Voltage Good LED (active HIGH)
|
||||
PA2: Analogue Input: Battery voltage
|
||||
PA1: Analogue Input: Solar voltage
|
||||
PA0: Analogue Input: Mains voltage
|
||||
|
||||
Firmware description
|
||||
--------------------
|
||||
|
||||
The firmware may be compiled in DEBUG mode by adding -DDEBUG to the
|
||||
CPPFLAGS. In this mode, PA4 is used instead for a UART Tx pin at 1200
|
||||
baud, 8 bits, no parity, one stop bit. This is done in software, using
|
||||
Timer 1 as a baud rate generator.
|
||||
|
||||
Timer 1 also does double-duty managing timings for events.
|
||||
|
||||
Timer 0 is used in PWM mode to control the fans.
|
||||
|
||||
The firmware does some quick initialisation before entering the main
|
||||
loop. If DEBUG is enabled, "INIT xx" will be displayed, where xx is the
|
||||
value of the MCUSR register.
|
||||
|
||||
Two counters are decremented by the Timer 1 overflow interrupt.
|
||||
`led_timeout` causes the main loop to update the state of the LEDs when
|
||||
it hits zero, and `adc_timeout` triggers a new ADC capture run when it
|
||||
reaches zero.
|
||||
|
||||
The three analogue inputs and temperature sensor are scanned when
|
||||
`adc_timeout` reaches zero, then the state analysed. The battery
|
||||
voltage is compared to the previous reading to dissern if the battery is
|
||||
charging, discharging or holding steady.
|
||||
|
||||
If this state has not changed, a battery state counter increments,
|
||||
otherwise it is reset.
|
||||
|
||||
The current state of the FETs is checked. Three states are valid:
|
||||
- Idle state: all FETs off
|
||||
- Mains charge: MAINS FET turned on
|
||||
- Solar charge: SOLAR FET turned on
|
||||
|
||||
IF statements at this point compare the battery voltage to the
|
||||
thresholds, and decide whether to switch voltage or not.
|
||||
|
||||
LED indications
|
||||
---------------
|
||||
|
||||
The LEDs have the following meanings:
|
||||
|
||||
Warning LED (PA4; DEBUG undefined):
|
||||
- Off: No warning condition
|
||||
- Flashing: Battery below critical threshold or temperature above
|
||||
maximum threshold
|
||||
- On: Not used
|
||||
|
||||
When in DEBUG mode, this LED may flicker with serial activity, and will
|
||||
remain ON when idle.
|
||||
|
||||
Temperature LEDs (PA6, PA7):
|
||||
- PA7 On, PA6 Off: Temperature below minimum threshold
|
||||
- PA7 Flashing, PA6 Off: Temperature above minimum threshold
|
||||
- PA7 Off, PA6 Flashing: Temperature above maximum threshold
|
||||
- Other states: not used
|
||||
|
||||
Battery LEDs (PA5, PA3):
|
||||
- PA3 Flashing, PA5 Off: Battery below low threshold
|
||||
- PA3 Off, PA5 Flashing: Battery above high threshold
|
||||
- PA3 On, PA5 Off: Battery is in "good" range (between low and high)
|
||||
- Other states: not used
|
37
board.h
Normal file
37
board.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef _BOARD_H
|
||||
#define _BOARD_H
|
||||
|
||||
/* LEDs */
|
||||
#define LED_TEMP_LOW (1 << 7)
|
||||
#define LED_TEMP_HIGH (1 << 6)
|
||||
#define LED_BATT_HIGH (1 << 5)
|
||||
#define LED_WARNING (1 << 4)
|
||||
#define LED_BATT_GOOD (1 << 3)
|
||||
#define LED_PORT PORTA
|
||||
#define LED_PORT_DDR_REG DDRA
|
||||
#define LED_PORT_DDR_VAL ( LED_TEMP_LOW \
|
||||
| LED_TEMP_HIGH \
|
||||
| LED_BATT_HIGH \
|
||||
| LED_WARNING \
|
||||
| LED_BATT_GOOD )
|
||||
|
||||
/* MOSFETs */
|
||||
#define FET_MAINS (1 << 0)
|
||||
#define FET_SOLAR (1 << 1)
|
||||
#define FET_FAN (1 << 2)
|
||||
#define FET_SRC_MASK (FET_MAINS|FET_SOLAR)
|
||||
#define FET_PORT PORTB
|
||||
#define FET_PORT_DDR_REG DDRB
|
||||
#define FET_PORT_DDR_VAL ( FET_MAINS \
|
||||
| FET_SOLAR \
|
||||
| FET_FAN )
|
||||
|
||||
/* ADC channels */
|
||||
#define ADC_CH_MAINS (1 << 0)
|
||||
#define ADC_CH_SOLAR (1 << 1)
|
||||
#define ADC_CH_BATT (1 << 2)
|
||||
#define ADC_CH_EN ( ADC_CH_MAINS \
|
||||
| ADC_CH_SOLAR \
|
||||
| ADC_CH_BATT )
|
||||
|
||||
#endif
|
506
powerctl.c
Normal file
506
powerctl.c
Normal file
@ -0,0 +1,506 @@
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
#include <stdint.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
/*! If enabled, the warning LED doubles as UART Tx pin */
|
||||
#include "uart.h"
|
||||
#endif
|
||||
|
||||
#include "board.h"
|
||||
|
||||
/*! ADMUX setting for selecting 1.1V reference */
|
||||
#define ADC_REF_1V1 (2 << REFS0)
|
||||
/*! ADMUX setting for mains input voltage reading */
|
||||
#define ADC_MUX_MAINS (ADC_REF_1V1 | 0x00)
|
||||
/*! ADMUX setting for solar input voltage reading */
|
||||
#define ADC_MUX_SOLAR (ADC_REF_1V1 | 0x01)
|
||||
/*! ADMUX setting for battery input voltage reading */
|
||||
#define ADC_MUX_BATT (ADC_REF_1V1 | 0x02)
|
||||
/*! ADMUX setting for temperature reading */
|
||||
#define ADC_MUX_TEMP (ADC_REF_1V1 | 0x22)
|
||||
|
||||
/*!
|
||||
* For state machine, the last state of the ADC MUX so we know whether
|
||||
* to ignore the sample or not. Datasheet recommends discarding samples
|
||||
* to let things stabalise when switching sources/references.
|
||||
*/
|
||||
static volatile uint8_t last_admux = 0;
|
||||
|
||||
/*!
|
||||
* For state machine, determines what the battery was one sample ago so
|
||||
* we know if it's charging, discharging, or remaining static. ADC units.
|
||||
*/
|
||||
static volatile uint16_t last_adc_batt = 0;
|
||||
|
||||
/*!
|
||||
* Current reading of the battery voltage in ADC units.
|
||||
*/
|
||||
static volatile uint16_t adc_batt = 0;
|
||||
|
||||
/*!
|
||||
* Current reading of the solar charger voltage in ADC units.
|
||||
*/
|
||||
static volatile uint16_t adc_solar = 0;
|
||||
|
||||
/*!
|
||||
* Current reading of the mains charger voltage in ADC units.
|
||||
*/
|
||||
static volatile uint16_t adc_mains = 0;
|
||||
|
||||
/*!
|
||||
* Current reading of the internal temperature sensor in ADC units.
|
||||
*/
|
||||
static volatile uint16_t adc_temp = 0;
|
||||
|
||||
/*!
|
||||
* How long before we next take a reading?
|
||||
*/
|
||||
static volatile uint16_t adc_timeout = 0;
|
||||
/*!
|
||||
* How many Timer1 ticks between ADC readings?
|
||||
*/
|
||||
#define ADC_TIMEOUT (1200)
|
||||
|
||||
/*!
|
||||
* State of the battery.
|
||||
* -1: discharging
|
||||
* 0: remaining steady
|
||||
* 1: charging
|
||||
*/
|
||||
static volatile int8_t batt_state = 0;
|
||||
/*!
|
||||
* The state of the battery at last check.
|
||||
*/
|
||||
static volatile int8_t last_batt_state = 0;
|
||||
/*!
|
||||
* The number of readings that the battery has maintained this state.
|
||||
*/
|
||||
static volatile uint8_t batt_state_counter = 0;
|
||||
/*!
|
||||
* How long before we can consider switching sources.
|
||||
*/
|
||||
static volatile uint8_t src_timeout = 0;
|
||||
#define SRC_TIMEOUT (15) /*!< How long to wait before switching */
|
||||
|
||||
/*!
|
||||
* How long before we change LED states?
|
||||
*/
|
||||
static volatile uint8_t led_timeout = 0;
|
||||
#define LED_TIMEOUT (150)
|
||||
|
||||
/*
|
||||
* Temperature ranges and fan PWM settings
|
||||
*/
|
||||
#define TEMP_MIN (275 << 6) /*!< ~20°C, approx ADC reading */
|
||||
#define TEMP_MAX (295 << 6) /*!< ~30°C, approx ADC reading */
|
||||
#define FAN_PWM_MIN (128) /*!< Minimum PWM value */
|
||||
#define FAN_PWM_MAX (255) /*!< Maximum PWM value */
|
||||
|
||||
/*
|
||||
* ADC Voltage divider settings
|
||||
*/
|
||||
#define VDIV_R1 (1500ULL) /*!< R1 = 1.5kOhm */
|
||||
#define VDIV_R2 (100ULL) /*!< R2 = 100 Ohm */
|
||||
/*
|
||||
* ADC settings
|
||||
*/
|
||||
#define ADC_REF (1100ULL) /*!< AREF = 1.1mV */
|
||||
#define ADC_MAX (65535ULL) /*!< ADLAR = 1 */
|
||||
|
||||
/*!
|
||||
* Macro for computing ADC measurements. This assumes the input to the
|
||||
* ADC pin is via a voltage divider made up of resistors R1 and R2, with
|
||||
* the input voltage applied across both resistors and the ADC measuring
|
||||
* across R2.
|
||||
*
|
||||
* @param mv Voltage in millivolts
|
||||
* @returns Approximate ADC reading
|
||||
*/
|
||||
# define ADC_READ(mv) ( \
|
||||
(ADC_MAX * ((uint64_t)(mv)) * VDIV_R2) \
|
||||
/ \
|
||||
(ADC_REF * (VDIV_R1 + VDIV_R2)) \
|
||||
)
|
||||
|
||||
/*!
|
||||
* "Critical" battery voltage. This is considered a serious condition.
|
||||
*/
|
||||
#define VBATT_CRIT ADC_READ(11800)
|
||||
/*!
|
||||
* "Low" battery voltage. Indication that we should turn a charger on.
|
||||
*/
|
||||
#define VBATT_LOW ADC_READ(12000)
|
||||
/*!
|
||||
* "High" battery voltage. Indication we should turn the charger off.
|
||||
*/
|
||||
#define VBATT_HIGH ADC_READ(13500)
|
||||
|
||||
/* Debug messages */
|
||||
#ifdef DEBUG
|
||||
const char STR_INIT[] PROGMEM = {"INIT "};
|
||||
const char STR_ADC[] PROGMEM = {"ADC "};
|
||||
const char STR_START[] PROGMEM = {"START "};
|
||||
const char STR_READ[] PROGMEM = {"READ "};
|
||||
const char STR_NL[] PROGMEM = {"\r\n"};
|
||||
#endif
|
||||
|
||||
#define SRC_NONE (0) /*!< Turn off all chargers */
|
||||
#define SRC_SOLAR (1) /*!< Turn on solar charger */
|
||||
#define SRC_MAINS (2) /*!< Turn on mains charger */
|
||||
/*!
|
||||
* Switch between chargers. This is does a "break-before-make" switchover
|
||||
* of charging sources to switch from mains to solar, solar to mains, or to
|
||||
* switch from charging to discharging mode. It expressly forbids turning
|
||||
* both chargers on simultaneously.
|
||||
*/
|
||||
void select_src(uint8_t src) {
|
||||
switch(src) {
|
||||
case SRC_SOLAR:
|
||||
FET_PORT &= ~FET_MAINS;
|
||||
FET_PORT |= FET_SOLAR;
|
||||
break;
|
||||
case SRC_MAINS:
|
||||
FET_PORT &= ~FET_SOLAR;
|
||||
FET_PORT |= FET_MAINS;
|
||||
break;
|
||||
case SRC_NONE:
|
||||
default:
|
||||
FET_PORT &= ~FET_SRC_MASK;
|
||||
break;
|
||||
}
|
||||
src_timeout = SRC_TIMEOUT;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Main entrypoint */
|
||||
int main(void) {
|
||||
/* Configure LEDs */
|
||||
LED_PORT_DDR_REG = LED_PORT_DDR_VAL;
|
||||
LED_PORT = 0;
|
||||
|
||||
/* Configure MOSFETs */
|
||||
FET_PORT_DDR_REG = FET_PORT_DDR_VAL;
|
||||
FET_PORT = 0;
|
||||
|
||||
/* Turn on ADC and timers */
|
||||
PRR &= ~((1 << PRTIM0) | (1 << PRTIM1) | (1 << PRADC));
|
||||
|
||||
/* Configure Timer0: Fan PWM */
|
||||
TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00);
|
||||
TCCR0B = (1 << CS00);
|
||||
/* Half-speed fan until we know what to do */
|
||||
OCR0A = 128;
|
||||
|
||||
/*
|
||||
* Configure Timer1: 1.2kHz System tick timer
|
||||
* / baud rate generator for debug output
|
||||
*/
|
||||
TCCR1A = 0;
|
||||
TCCR1B = (1 << WGM12) | (1 << CS10);
|
||||
TCCR1C = 0;
|
||||
OCR1A = F_CPU/1200;
|
||||
TIMSK1 = (1 << OCIE1A);
|
||||
|
||||
/* ADC configuration */
|
||||
DIDR0 = ADC_CH_EN;
|
||||
ADMUX = ADC_MUX_TEMP;
|
||||
ADCSRB = (1 << ADLAR);
|
||||
ADCSRA = (1 << ADIE)
|
||||
| (1 << ADPS2)
|
||||
| (1 << ADPS1)
|
||||
| (1 << ADPS0);
|
||||
|
||||
/* Configure UART */
|
||||
sei();
|
||||
#ifdef DEBUG
|
||||
uart_init();
|
||||
uart_tx_str(STR_INIT);
|
||||
uart_tx_hex_byte(MCUSR);
|
||||
uart_tx_str(STR_NL);
|
||||
#endif
|
||||
MCUSR = 0;
|
||||
while(1) {
|
||||
if (!led_timeout) {
|
||||
#ifndef DEBUG
|
||||
if ((adc_batt < VBATT_CRIT)
|
||||
|| (adc_temp > TEMP_MAX)) {
|
||||
/* Warning conditions */
|
||||
LED_PORT ^= LED_WARNING;
|
||||
} else {
|
||||
LED_PORT &= ~LED_WARNING;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (adc_batt < VBATT_LOW) {
|
||||
/* Battery is low */
|
||||
LED_PORT &= ~LED_BATT_HIGH;
|
||||
LED_PORT ^= LED_BATT_GOOD;
|
||||
} else if (adc_batt >= VBATT_HIGH) {
|
||||
/* Battery is above "high" threshold */
|
||||
LED_PORT ^= LED_BATT_HIGH;
|
||||
LED_PORT &= ~LED_BATT_GOOD;
|
||||
} else {
|
||||
/* Battery is above "low" threshold */
|
||||
LED_PORT |= LED_BATT_GOOD;
|
||||
LED_PORT &= ~LED_BATT_HIGH;
|
||||
}
|
||||
|
||||
if (adc_temp < TEMP_MIN) {
|
||||
LED_PORT |= LED_TEMP_LOW;
|
||||
LED_PORT &= ~LED_TEMP_HIGH;
|
||||
} else if (adc_temp < TEMP_MAX) {
|
||||
LED_PORT ^= LED_TEMP_LOW;
|
||||
LED_PORT &= ~LED_TEMP_HIGH;
|
||||
} else {
|
||||
LED_PORT &= ~LED_TEMP_LOW;
|
||||
LED_PORT ^= LED_TEMP_HIGH;
|
||||
}
|
||||
led_timeout = LED_TIMEOUT;
|
||||
}
|
||||
if (!adc_timeout) {
|
||||
adc_timeout = ADC_TIMEOUT;
|
||||
ADCSRA |= (1 << ADEN) | (1 << ADSC);
|
||||
#ifdef DEBUG
|
||||
uart_tx_str(STR_ADC);
|
||||
uart_tx_str(STR_READ);
|
||||
#endif
|
||||
while(ADCSRA & (1 << ADEN));
|
||||
#ifdef DEBUG
|
||||
uart_tx_str(STR_NL);
|
||||
uart_tx_str(STR_ADC);
|
||||
uart_tx('T'); uart_tx_hex_word(adc_temp);
|
||||
uart_tx(' ');
|
||||
uart_tx('B'); uart_tx_hex_word(adc_batt);
|
||||
uart_tx(' ');
|
||||
uart_tx('L'); uart_tx_hex_word(last_adc_batt);
|
||||
uart_tx(' ');
|
||||
uart_tx('d');
|
||||
if (last_adc_batt > adc_batt) {
|
||||
uart_tx('-');
|
||||
uart_tx_hex_word(last_adc_batt - adc_batt);
|
||||
} else {
|
||||
uart_tx('+');
|
||||
uart_tx_hex_word(adc_batt - last_adc_batt);
|
||||
}
|
||||
uart_tx(' ');
|
||||
uart_tx('S'); uart_tx_hex_word(adc_solar);
|
||||
uart_tx(' ');
|
||||
uart_tx('M'); uart_tx_hex_word(adc_mains);
|
||||
uart_tx(' ');
|
||||
uart_tx('F'); uart_tx_hex_byte(FET_PORT);
|
||||
#endif
|
||||
|
||||
/* Battery direction */
|
||||
#ifdef DEBUG
|
||||
uart_tx(' ');
|
||||
uart_tx('b');
|
||||
#endif
|
||||
if ((!last_adc_batt) || (adc_batt == last_adc_batt)) {
|
||||
batt_state = 0; /* Steady? */
|
||||
#ifdef DEBUG
|
||||
uart_tx('=');
|
||||
#endif
|
||||
} else if (adc_batt > last_adc_batt) {
|
||||
batt_state = 1;
|
||||
#ifdef DEBUG
|
||||
uart_tx('+');
|
||||
#endif
|
||||
} else if (adc_batt < last_adc_batt) {
|
||||
batt_state = -1;
|
||||
#ifdef DEBUG
|
||||
uart_tx('-');
|
||||
#endif
|
||||
}
|
||||
|
||||
if (last_batt_state == batt_state) {
|
||||
batt_state_counter++;
|
||||
} else {
|
||||
batt_state_counter = 0;
|
||||
last_batt_state = batt_state;
|
||||
}
|
||||
|
||||
/* Battery control */
|
||||
uint8_t state = FET_PORT & FET_SRC_MASK;
|
||||
switch (state) {
|
||||
case 0:
|
||||
/* Idle state */
|
||||
#ifdef DEBUG
|
||||
uart_tx('I');
|
||||
#endif
|
||||
if ((adc_batt < VBATT_CRIT)
|
||||
&& (adc_mains > adc_batt)) {
|
||||
/* Charger urgently needed. */
|
||||
#ifdef DEBUG
|
||||
uart_tx('C');
|
||||
uart_tx('M');
|
||||
#endif
|
||||
select_src(SRC_MAINS);
|
||||
} else if (adc_batt < VBATT_LOW) {
|
||||
/* Charger needed. */
|
||||
#ifdef DEBUG
|
||||
uart_tx('L');
|
||||
#endif
|
||||
if ((adc_solar >= adc_mains)
|
||||
&& (adc_solar > adc_batt)) {
|
||||
#ifdef DEBUG
|
||||
uart_tx('S');
|
||||
#endif
|
||||
select_src(SRC_SOLAR);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
uart_tx('M');
|
||||
#endif
|
||||
select_src(SRC_MAINS);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FET_SOLAR:
|
||||
#ifdef DEBUG
|
||||
uart_tx('S');
|
||||
#endif
|
||||
/* Are we over voltage? */
|
||||
if (adc_batt >= VBATT_HIGH) {
|
||||
#ifdef DEBUG
|
||||
uart_tx('H');
|
||||
#endif
|
||||
select_src(SRC_NONE);
|
||||
} else if ((adc_batt < VBATT_CRIT)
|
||||
&& (adc_mains > adc_solar)
|
||||
&& (adc_mains > adc_batt)) {
|
||||
#ifdef DEBUG
|
||||
uart_tx('C');
|
||||
#endif
|
||||
select_src(SRC_MAINS);
|
||||
/* Are we still discharging? */
|
||||
} else if ((!src_timeout)
|
||||
&& (adc_mains > adc_batt)
|
||||
&& (batt_state <= 0)
|
||||
&& (batt_state_counter > 10)) {
|
||||
#ifdef DEBUG
|
||||
uart_tx('M');
|
||||
#endif
|
||||
select_src(SRC_MAINS);
|
||||
} else if (src_timeout) {
|
||||
#ifdef DEBUG
|
||||
uart_tx('s');
|
||||
uart_tx_hex_byte(batt_state_counter);
|
||||
uart_tx('t');
|
||||
uart_tx_hex_byte(src_timeout);
|
||||
#endif
|
||||
src_timeout--;
|
||||
}
|
||||
break;
|
||||
case FET_MAINS:
|
||||
#ifdef DEBUG
|
||||
uart_tx('M');
|
||||
#endif
|
||||
/* Are we over voltage? */
|
||||
if (adc_batt >= VBATT_HIGH) {
|
||||
#ifdef DEBUG
|
||||
uart_tx('H');
|
||||
#endif
|
||||
select_src(SRC_NONE);
|
||||
/* Are we still critical? */
|
||||
} else if (adc_batt < VBATT_CRIT) {
|
||||
#ifdef DEBUG
|
||||
uart_tx('C');
|
||||
#endif
|
||||
if (adc_mains < adc_solar) {
|
||||
/* Mains no good, try solar */
|
||||
#ifdef DEBUG
|
||||
uart_tx('S');
|
||||
#endif
|
||||
select_src(SRC_SOLAR);
|
||||
}
|
||||
/* Is solar better now? */
|
||||
} else if ((!src_timeout)
|
||||
&& (adc_solar > adc_mains)) {
|
||||
#ifdef DEBUG
|
||||
uart_tx('S');
|
||||
#endif
|
||||
select_src(SRC_SOLAR);
|
||||
} else if (src_timeout) {
|
||||
#ifdef DEBUG
|
||||
uart_tx('t');
|
||||
uart_tx_hex_byte(src_timeout);
|
||||
#endif
|
||||
src_timeout--;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Should not get here */
|
||||
#ifdef DEBUG
|
||||
uart_tx('!');
|
||||
#endif
|
||||
select_src(SRC_NONE);
|
||||
}
|
||||
|
||||
/* Fan control */
|
||||
if (adc_temp > TEMP_MAX) {
|
||||
/* We're at the maximum temperature, FULL SPEED! */
|
||||
OCR0A = FAN_PWM_MAX;
|
||||
} else if (adc_temp > TEMP_MIN) {
|
||||
/* Scale fan speed linearly with temperature */
|
||||
OCR0A = (((adc_temp - TEMP_MIN)
|
||||
* (FAN_PWM_MIN - FAN_PWM_MAX))
|
||||
/ (TEMP_MAX - TEMP_MIN))
|
||||
+ FAN_PWM_MIN;
|
||||
} else {
|
||||
/* Turn fans off completely. */
|
||||
OCR0A = 0;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
uart_tx(' ');
|
||||
uart_tx('f');
|
||||
uart_tx_hex_byte(OCR0A);
|
||||
|
||||
uart_tx_str(STR_NL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ISR(TIM1_COMPA_vect) {
|
||||
#ifdef DEBUG
|
||||
uart_tick();
|
||||
#endif
|
||||
if (adc_timeout)
|
||||
adc_timeout--;
|
||||
if (led_timeout)
|
||||
led_timeout--;
|
||||
}
|
||||
|
||||
ISR(ADC_vect) {
|
||||
uint16_t adc = ADCW;
|
||||
if (last_admux == ADMUX) {
|
||||
switch(last_admux) {
|
||||
case ADC_MUX_TEMP:
|
||||
adc_temp = adc;
|
||||
ADMUX = ADC_MUX_BATT;
|
||||
ADCSRA |= (1 << ADSC);
|
||||
break;
|
||||
case ADC_MUX_BATT:
|
||||
last_adc_batt = adc_batt;
|
||||
adc_batt = adc;
|
||||
ADMUX = ADC_MUX_SOLAR;
|
||||
ADCSRA |= (1 << ADSC);
|
||||
break;
|
||||
case ADC_MUX_SOLAR:
|
||||
adc_solar = adc;
|
||||
ADMUX = ADC_MUX_MAINS;
|
||||
ADCSRA |= (1 << ADSC);
|
||||
break;
|
||||
case ADC_MUX_MAINS:
|
||||
adc_mains = adc;
|
||||
default:
|
||||
ADMUX = ADC_MUX_TEMP;
|
||||
ADCSRA &= ~(1 << ADEN);
|
||||
}
|
||||
} else {
|
||||
ADCSRA |= (1 << ADSC);
|
||||
last_admux = ADMUX;
|
||||
}
|
||||
}
|
116
uart.c
Normal file
116
uart.c
Normal file
@ -0,0 +1,116 @@
|
||||
/*!
|
||||
* Very simple software UART for AVR microcontrollers
|
||||
* (C) 2016 Stuart Longland
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "uart.h"
|
||||
#include "uartcfg.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
#include <stdint.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define TX_BIT (1 << UART_TX_BIT)
|
||||
|
||||
#define BIT_US (1000000/UART_BAUD) /*!< Bit period in microseconds */
|
||||
|
||||
static volatile uint8_t uart_ticks = 0;
|
||||
|
||||
/*!
|
||||
* Configure the UART pins.
|
||||
*/
|
||||
void uart_init() {
|
||||
UART_TX_DDR |= TX_BIT;
|
||||
UART_TX_PORT |= TX_BIT;
|
||||
}
|
||||
|
||||
static void uart_wait(uint8_t ticks) {
|
||||
uart_ticks = ticks;
|
||||
while(uart_ticks);
|
||||
}
|
||||
|
||||
void uart_tick() {
|
||||
if (uart_ticks)
|
||||
uart_ticks--;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Send a raw byte to the UART.
|
||||
*/
|
||||
void uart_tx(uint8_t byte) {
|
||||
uint8_t mask = 1;
|
||||
/* Start bit */
|
||||
UART_TX_PORT &= ~TX_BIT; uart_wait(1);
|
||||
while(mask) {
|
||||
if (mask & byte)
|
||||
UART_TX_PORT |= TX_BIT;
|
||||
else
|
||||
UART_TX_PORT &= ~TX_BIT;
|
||||
uart_wait(1);
|
||||
mask <<= 1;
|
||||
}
|
||||
/* Stop bit */
|
||||
UART_TX_PORT |= TX_BIT; uart_wait(1);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Send a text string (in pgmspace) to the UART.
|
||||
* String shall be null-terminated!
|
||||
*/
|
||||
void uart_tx_str(const char* str) {
|
||||
char c = pgm_read_byte(str);
|
||||
while (c) {
|
||||
str++;
|
||||
uart_tx(c);
|
||||
c = pgm_read_byte(str);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Send a 4-bit nybble to the UART.
|
||||
*/
|
||||
void uart_tx_hex(uint8_t nybble) {
|
||||
if (nybble >= 10)
|
||||
uart_tx(nybble - 10 + 'a');
|
||||
else
|
||||
uart_tx(nybble + '0');
|
||||
}
|
||||
|
||||
/*!
|
||||
* Send a 8-bit byte to the UART.
|
||||
*/
|
||||
void uart_tx_hex_byte(uint8_t byte) {
|
||||
uart_tx_hex(byte >> 4);
|
||||
uart_tx_hex(byte & 0x0f);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Send a 16-bit word to the UART.
|
||||
*/
|
||||
void uart_tx_hex_word(uint16_t word) {
|
||||
uart_tx_hex_byte(word >> 8);
|
||||
uart_tx_hex_byte(word & 0xff);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Send a 32-bit long word to the UART.
|
||||
*/
|
||||
void uart_tx_hex_lword(uint32_t lword) {
|
||||
uart_tx_hex_word(lword >> 16);
|
||||
uart_tx_hex_word(lword & 0xffff);
|
||||
}
|
60
uart.h
Normal file
60
uart.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef _UART_H
|
||||
#define _UART_H
|
||||
|
||||
/*!
|
||||
* Very simple software UART for AVR microcontrollers
|
||||
* (C) 2016 Stuart Longland
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*!
|
||||
* Configure the UART pins.
|
||||
*/
|
||||
void uart_init();
|
||||
|
||||
/*!
|
||||
* UART tick timer
|
||||
*/
|
||||
void uart_tick();
|
||||
|
||||
/*!
|
||||
* Send a raw byte to the UART.
|
||||
*/
|
||||
void uart_tx(uint8_t byte);
|
||||
|
||||
/*!
|
||||
* Send a text string (in pgmspace) to the UART.
|
||||
* String shall be null-terminated!
|
||||
*/
|
||||
void uart_tx_str(const char* str);
|
||||
|
||||
/*!
|
||||
* Send a 8-bit byte to the UART.
|
||||
*/
|
||||
void uart_tx_hex_byte(uint8_t byte);
|
||||
|
||||
/*!
|
||||
* Send a 16-bit word to the UART.
|
||||
*/
|
||||
void uart_tx_hex_word(uint16_t word);
|
||||
|
||||
/*!
|
||||
* Send a 32-bit long word to the UART.
|
||||
*/
|
||||
void uart_tx_hex_lword(uint32_t lword);
|
||||
#endif
|
37
uartcfg.h
Normal file
37
uartcfg.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef _UARTCFG_H
|
||||
#define _UARTCFG_H
|
||||
/*!
|
||||
* Very simple software UART for AVR microcontrollers
|
||||
* (C) 2016 Stuart Longland
|
||||
*
|
||||
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/* The following defines the configuration for the UART driver. */
|
||||
|
||||
/*!
|
||||
* UART BAUD rate. This is the speed that we transmit at. For the 1MHz
|
||||
* RC clock, 4800 is the maximum speed (out of the "standard" ones) that
|
||||
* will work. If you're running at 8MHz or with an external crystal, you
|
||||
* may go higher.
|
||||
*/
|
||||
#define UART_BAUD (300)
|
||||
|
||||
/* Port settings */
|
||||
#define UART_TX_PORT PORTA /*!< GPIO port register for Tx */
|
||||
#define UART_TX_DDR DDRA /*!< GPIO direction register for Tx */
|
||||
#define UART_TX_BIT 4 /*!< GPIO pin for Tx */
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user