Repository: danielnilsson9/bbs-fw
Branch: master
Commit: 10cadba77456
Files: 145
Total size: 1.3 MB
Directory structure:
gitextract_0i0vlkpl/
├── .editorconfig
├── .github/
│ └── FUNDING.yml
├── LICENSE
├── README.md
├── drawings/
│ └── pcb/
│ ├── bbshd.sch
│ └── eagle.epf
└── src/
├── firmware/
│ ├── .gitignore
│ ├── Makefile
│ ├── adc.h
│ ├── app.c
│ ├── app.h
│ ├── battery.c
│ ├── battery.h
│ ├── bbs-fw.sln
│ ├── bbs-fw.vcxproj
│ ├── bbs-fw.vcxproj.filters
│ ├── bbsx/
│ │ ├── adc.c
│ │ ├── cpu.h
│ │ ├── eeprom.c
│ │ ├── interrupt.h
│ │ ├── lights.c
│ │ ├── motor.c
│ │ ├── pins.h
│ │ ├── sensors.c
│ │ ├── stc15.h
│ │ ├── system.c
│ │ ├── timers.c
│ │ ├── timers.h
│ │ ├── uart.c
│ │ ├── uart_motor.h
│ │ └── watchdog.c
│ ├── cfgstore.c
│ ├── cfgstore.h
│ ├── clean.bat
│ ├── eeprom.h
│ ├── eventlog.c
│ ├── eventlog.h
│ ├── extcom.c
│ ├── extcom.h
│ ├── fwconfig.h
│ ├── intellisense.h
│ ├── interrupt.h
│ ├── lights.h
│ ├── main.c
│ ├── motor.h
│ ├── sensors.h
│ ├── system.h
│ ├── throttle.c
│ ├── throttle.h
│ ├── timers.h
│ ├── tohex.bat
│ ├── tsdz2/
│ │ ├── adc.c
│ │ ├── cpu.h
│ │ ├── eeprom.c
│ │ ├── interrupt.h
│ │ ├── lights.c
│ │ ├── motor.c
│ │ ├── pins.h
│ │ ├── sensors.c
│ │ ├── stm8.h
│ │ ├── stm8s/
│ │ │ ├── stm8s.h
│ │ │ ├── stm8s_adc1.h
│ │ │ ├── stm8s_adc2.h
│ │ │ ├── stm8s_awu.h
│ │ │ ├── stm8s_beep.h
│ │ │ ├── stm8s_can.h
│ │ │ ├── stm8s_clk.h
│ │ │ ├── stm8s_exti.h
│ │ │ ├── stm8s_flash.h
│ │ │ ├── stm8s_gpio.h
│ │ │ ├── stm8s_i2c.h
│ │ │ ├── stm8s_itc.h
│ │ │ ├── stm8s_iwdg.h
│ │ │ ├── stm8s_rst.h
│ │ │ ├── stm8s_spi.h
│ │ │ ├── stm8s_tim1.h
│ │ │ ├── stm8s_tim2.h
│ │ │ ├── stm8s_tim3.h
│ │ │ ├── stm8s_tim4.h
│ │ │ ├── stm8s_tim5.h
│ │ │ ├── stm8s_tim6.h
│ │ │ ├── stm8s_uart1.h
│ │ │ ├── stm8s_uart2.h
│ │ │ ├── stm8s_uart3.h
│ │ │ ├── stm8s_uart4.h
│ │ │ └── stm8s_wwdg.h
│ │ ├── system.c
│ │ ├── timers.c
│ │ ├── timers.h
│ │ ├── torquesensor.c
│ │ ├── uart.c
│ │ └── watchdog.c
│ ├── uart.h
│ ├── util.h
│ ├── version.h
│ └── watchdog.h
├── logger/
│ ├── .gitignore
│ ├── .vscode/
│ │ └── extensions.json
│ ├── include/
│ │ └── ComProxy.h
│ ├── platformio.ini
│ └── src/
│ ├── ComProxy.cpp
│ └── Main.cpp
└── tool/
├── .gitignore
├── App.xaml
├── App.xaml.cs
├── AssemblyInfo.cs
├── Model/
│ ├── BbsfwConnection.cs
│ ├── CompletionQueue.cs
│ ├── Configuration.cs
│ └── EventLogEntry.cs
├── Properties/
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── View/
│ ├── AssistLevelCruiseView.xaml
│ ├── AssistLevelCruiseView.xaml.cs
│ ├── AssistLevelPasView.xaml
│ ├── AssistLevelPasView.xaml.cs
│ ├── AssistLevelThrottleView.xaml
│ ├── AssistLevelThrottleView.xaml.cs
│ ├── AssistLevelsView.xaml
│ ├── AssistLevelsView.xaml.cs
│ ├── CalibrationView.xaml
│ ├── CalibrationView.xaml.cs
│ ├── ConnectionView.xaml
│ ├── ConnectionView.xaml.cs
│ ├── Converter/
│ │ └── TimestampConverter.cs
│ ├── EventLogView.xaml
│ ├── EventLogView.xaml.cs
│ ├── Extension/
│ │ └── DataGridExtension.cs
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── SystemView.xaml
│ └── SystemView.xaml.cs
├── ViewModel/
│ ├── AssistLevelViewModel.cs
│ ├── AssistLevelsViewModel.cs
│ ├── Base/
│ │ ├── DelegateCommand.cs
│ │ └── ObservableObject.cs
│ ├── CalibrationViewModel.cs
│ ├── ConfigurationViewModel.cs
│ ├── ConnectionViewModel.cs
│ ├── EventLogViewModel.cs
│ ├── MainViewModel.cs
│ ├── SystemViewModel.cs
│ └── ValueItemViewModel.cs
├── bbs-fw-tool.csproj
└── bbs-fw-tool.sln
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
end_of_line = crlf
insert_final_newline = true
charset = utf-8
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
================================================
FILE: .github/FUNDING.yml
================================================
custom: https://www.paypal.com/donate/?business=LVAYFCMQYN8F4&no_recurring=0&item_name=BBSHD-FW¤cy_code=USD
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
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
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
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 3 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, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program 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, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU 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. But first, please read
.
================================================
FILE: README.md
================================================
# BBSHD/BBS02/TSDZ2 Open Source Firmware



This firmware is intended to replace the original Bafang firmware on the BBSHD/BBS02 motor controller. Almost all functionality of original firmware has been implemented and additional features have been added.
This firmware is compatible with all displays that works with the original Bafang firmware. A custom configuration tool is provided since BafangConfigTool is not compatible due to a different set of supported parameters.
The firmware is also compatible with the TongSheng TSDZ2 controller but requires a custom made cable in order to interface with Bafang compatible displays.
⚠️ Warning: The firmware should NOT be flashed or configured while the eBike battery is charging!
**Download**
https://github.com/danielnilsson9/bbshd-fw/releases
**Install**
https://github.com/danielnilsson9/bbs-fw/wiki/Flash-Firmware-(BBS02-&-BBSHD)
**Configure**
https://github.com/danielnilsson9/bbshd-fw/wiki/Configuration-Tool
If you find this project useful, consider sending a small [donation](https://www.paypal.com/donate/?business=LVAYFCMQYN8F4&no_recurring=0&item_name=BBSHD-FW¤cy_code=USD) to fund further development.
## Known Issues
* ⚠️ Unstable on BBS02 controllers!
## Highlights
* ✅ A bit more power without hardware modifications! (max 33A).
* ✅ No upper voltage limit in software, can by default run up to 63V (maximum rating of components).
* ✅ Support lower voltage cutoff for use with e.g. 36V battery.
* ✅ Smooth Throttle/PAS override.
* ✅ Optional separate set of street legal & offroad assist levels which can be toggled by a key combination.
* ✅ Support setting road speed limit per assist level.
* ✅ Support setting cadence limit per assist level.
* ✅ Support cruise assist levels (i.e. motor power without pedal or throttle input).
* ✅ Thermal limiting gradual ramp down.
* ✅ Low voltage gradual ramp down.
* ✅ Voltage calibration for accurate LVC and low voltage ramp down.
* ✅ Display motor/controller temperature on standard display.
* ✅ Use of speed sensor is optional.

## Supported Hardware
### BBSHD
Revision | MCU | Released | Comment
-------- | ------------ | ----------- | --------------------
V1.4 | STC15W4K56S4 | ~2017 | V1.3 printed on PCB, sticker with 1.4.
V1.5 | IAP15W4K61S4 | ~2019 | V1.4 printed on PCB, sticker with 1.5.
### BBS02B
There are compatibility issues reported, this firmware is suspected to be incompatible with older BBS02 controllers.
If you have a newer BBS02B you are probably fine, if you have an older controller it might not be a good idea to flash this firmware.
Revision | MCU | Released | Comment
-------- | ------------ | ----------- | --------------------
V1.? | STC15F2K60S2 | | Supported from BBS-FW version 1.1
V1.? | IAP15F2K61S2 | | Supported from BBS-FW version 1.1
BBS02A - No idea, not tested, not recommended to try unless you have an already bricked controller.
### TSDZ2
Compatible with TSDZ2A/B using the STM microcontroller (which is nearly all off them).
### Displays and Controller
Only displays with the Bafang display protocol can work.
Also the controllers need to be those, that are officially designed by Bafang, respectively Tongshen.
Some shops sell kits with their own controller.
## Legal
* Installing this firmware will void your warranty.
* I cannot be held responsible for any injuries caused by the use of this firmware, use at your own risk.
================================================
FILE: drawings/pcb/bbshd.sch
================================================
<b>Frames for Sheet and Layout</b>>DRAWING_NAME>LAST_DATE_TIME>SHEETSheet:<b>FRAME</b><p>
DIN A4, landscape with location and doc. field<b>Pin Header Connectors</b><p>
<author>Created by librarian@cadsoft.de</author><b>PIN HEADER</b>>NAME>VALUE<b>PIN HEADER</b>>NAME>VALUE<b>PIN HEADER</b>>NAME>VALUE<b>PIN HEADER</b>>NAME>VALUE<b>PIN HEADER</b>>NAME>VALUE<b>PIN HEADER</b>>NAME>VALUE>NAME>VALUE>NAME>VALUE>NAME>VALUE<b>PIN HEADER</b><b>PIN HEADER</b><b>PIN HEADER</b><b>Supply Symbols</b><p>
GND, VCC, 0V, +5V, -5V, etc.<p>
Please keep in mind, that these devices are necessary for the
automatic wiring of the supply signals.<p>
The pin name defined in the symbol is identical to the net which is to be wired automatically.<p>
In this library the device names are the same as the pin names of the symbols, therefore the correct signal names appear next to the supply symbols in the schematic.<p>
<author>Created by librarian@cadsoft.de</author>>VALUE>VALUE>VALUE>VALUE<b>SUPPLY SYMBOL</b><b>SUPPLY SYMBOL</b><b>SUPPLY SYMBOL</b><b>SUPPLY SYMBOL</b><b>Diodes</b><p>
Based on the following sources:
<ul>
<li>Motorola : www.onsemi.com
<li>Fairchild : www.fairchildsemi.com
<li>Philips : www.semiconductors.com
<li>Vishay : www.vishay.de
</ul>
<author>Created by librarian@cadsoft.de</author><b>SOD-323</b><p>
Source: www.st.com, BAT60J.pdf>NAME>VALUE>NAME>VALUE<b>Schottky barrier diode</b><p>
Source: www.st.com, BAT60J.pdf<b>Resistors, Capacitors, Inductors</b><p>
Based on the previous libraries:
<ul>
<li>r.lbr
<li>cap.lbr
<li>cap-fe.lbr
<li>captant.lbr
<li>polcap.lbr
<li>ipc-smd.lbr
</ul>
All SMD packages are defined according to the IPC specifications and CECC<p>
<author>Created by librarian@cadsoft.de</author><p>
<p>
for Electrolyt Capacitors see also :<p>
www.bccomponents.com <p>
www.panasonic.com<p>
www.kemet.com<p>
http://www.secc.co.jp/pdf/os_e/2004/e_os_all.pdf <b>(SANYO)</b>
<p>
for trimmer refence see : <u>www.electrospec-inc.com/cross_references/trimpotcrossref.asp</u><p>
<table border=0 cellspacing=0 cellpadding=0 width="100%" cellpaddding=0>
<tr valign="top">
<! <td width="10"> </td>
<td width="90%">
<b><font color="#0000FF" size="4">TRIM-POT CROSS REFERENCE</font></b>
<P>
<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=2>
<TR>
<TD COLSPAN=8>
<FONT SIZE=3 FACE=ARIAL><B>RECTANGULAR MULTI-TURN</B></FONT>
</TD>
</TR>
<TR>
<TD ALIGN=CENTER>
<B>
<FONT SIZE=3 FACE=ARIAL color="#FF0000">BOURNS</FONT>
</B>
</TD>
<TD ALIGN=CENTER>
<B>
<FONT SIZE=3 FACE=ARIAL color="#FF0000">BI TECH</FONT>
</B>
</TD>
<TD ALIGN=CENTER>
<B>
<FONT SIZE=3 FACE=ARIAL color="#FF0000">DALE-VISHAY</FONT>
</B>
</TD>
<TD ALIGN=CENTER>
<B>
<FONT SIZE=3 FACE=ARIAL color="#FF0000">PHILIPS/MEPCO</FONT>
</B>
</TD>
<TD ALIGN=CENTER>
<B>
<FONT SIZE=3 FACE=ARIAL color="#FF0000">MURATA</FONT>
</B>
</TD>
<TD ALIGN=CENTER>
<B>
<FONT SIZE=3 FACE=ARIAL color="#FF0000">PANASONIC</FONT>
</B>
</TD>
<TD ALIGN=CENTER>
<B>
<FONT SIZE=3 FACE=ARIAL color="#FF0000">SPECTROL</FONT>
</B>
</TD>
<TD ALIGN=CENTER>
<B>
<FONT SIZE=3 FACE=ARIAL color="#FF0000">MILSPEC</FONT>
</B>
</TD><TD> </TD>
</TR>
<TR>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3 >
3005P<BR>
3006P<BR>
3006W<BR>
3006Y<BR>
3009P<BR>
3009W<BR>
3009Y<BR>
3057J<BR>
3057L<BR>
3057P<BR>
3057Y<BR>
3059J<BR>
3059L<BR>
3059P<BR>
3059Y<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
89P<BR>
89W<BR>
89X<BR>
89PH<BR>
76P<BR>
89XH<BR>
78SLT<BR>
78L ALT<BR>
56P ALT<BR>
78P ALT<BR>
T8S<BR>
78L<BR>
56P<BR>
78P<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
T18/784<BR>
783<BR>
781<BR>
-<BR>
-<BR>
-<BR>
2199<BR>
1697/1897<BR>
1680/1880<BR>
2187<BR>
-<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
8035EKP/CT20/RJ-20P<BR>
-<BR>
RJ-20X<BR>
-<BR>
-<BR>
-<BR>
1211L<BR>
8012EKQ ALT<BR>
8012EKR ALT<BR>
1211P<BR>
8012EKJ<BR>
8012EKL<BR>
8012EKQ<BR>
8012EKR<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
2101P<BR>
2101W<BR>
2101Y<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
2102L<BR>
2102S<BR>
2102Y<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
EVMCOG<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
43P<BR>
43W<BR>
43Y<BR>
-<BR>
-<BR>
-<BR>
-<BR>
40L<BR>
40P<BR>
40Y<BR>
70Y-T602<BR>
70L<BR>
70P<BR>
70Y<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
RT/RTR12<BR>
RT/RTR12<BR>
RT/RTR12<BR>
-<BR>
RJ/RJR12<BR>
RJ/RJR12<BR>
RJ/RJR12<BR></FONT>
</TD>
</TR>
<TR>
<TD COLSPAN=8>
</TD>
</TR>
<TR>
<TD COLSPAN=8>
<FONT SIZE=4 FACE=ARIAL><B>SQUARE MULTI-TURN</B></FONT>
</TD>
</TR>
<TR>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>BOURN</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>BI TECH</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>DALE-VISHAY</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>PHILIPS/MEPCO</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>MURATA</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>PANASONIC</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>SPECTROL</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>MILSPEC</B></FONT>
</TD>
</TR>
<TR>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
3250L<BR>
3250P<BR>
3250W<BR>
3250X<BR>
3252P<BR>
3252W<BR>
3252X<BR>
3260P<BR>
3260W<BR>
3260X<BR>
3262P<BR>
3262W<BR>
3262X<BR>
3266P<BR>
3266W<BR>
3266X<BR>
3290H<BR>
3290P<BR>
3290W<BR>
3292P<BR>
3292W<BR>
3292X<BR>
3296P<BR>
3296W<BR>
3296X<BR>
3296Y<BR>
3296Z<BR>
3299P<BR>
3299W<BR>
3299X<BR>
3299Y<BR>
3299Z<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
66P ALT<BR>
66W ALT<BR>
66X ALT<BR>
66P ALT<BR>
66W ALT<BR>
66X ALT<BR>
-<BR>
64W ALT<BR>
-<BR>
64P ALT<BR>
64W ALT<BR>
64X ALT<BR>
64P<BR>
64W<BR>
64X<BR>
66X ALT<BR>
66P ALT<BR>
66W ALT<BR>
66P<BR>
66W<BR>
66X<BR>
67P<BR>
67W<BR>
67X<BR>
67Y<BR>
67Z<BR>
68P<BR>
68W<BR>
68X<BR>
67Y ALT<BR>
67Z ALT<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
5050<BR>
5091<BR>
5080<BR>
5087<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
T63YB<BR>
T63XB<BR>
-<BR>
-<BR>
-<BR>
5887<BR>
5891<BR>
5880<BR>
-<BR>
-<BR>
-<BR>
T93Z<BR>
T93YA<BR>
T93XA<BR>
T93YB<BR>
T93XB<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
8026EKP<BR>
8026EKW<BR>
8026EKM<BR>
8026EKP<BR>
8026EKB<BR>
8026EKM<BR>
1309X<BR>
1309P<BR>
1309W<BR>
8024EKP<BR>
8024EKW<BR>
8024EKN<BR>
RJ-9P/CT9P<BR>
RJ-9W<BR>
RJ-9X<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
3103P<BR>
3103Y<BR>
3103Z<BR>
3103P<BR>
3103Y<BR>
3103Z<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
3105P/3106P<BR>
3105W/3106W<BR>
3105X/3106X<BR>
3105Y/3106Y<BR>
3105Z/3105Z<BR>
3102P<BR>
3102W<BR>
3102X<BR>
3102Y<BR>
3102Z<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
EVMCBG<BR>
EVMCCG<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
55-1-X<BR>
55-4-X<BR>
55-3-X<BR>
55-2-X<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
50-2-X<BR>
50-4-X<BR>
50-3-X<BR>
-<BR>
-<BR>
-<BR>
64P<BR>
64W<BR>
64X<BR>
64Y<BR>
64Z<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
RT/RTR22<BR>
RT/RTR22<BR>
RT/RTR22<BR>
RT/RTR22<BR>
RJ/RJR22<BR>
RJ/RJR22<BR>
RJ/RJR22<BR>
RT/RTR26<BR>
RT/RTR26<BR>
RT/RTR26<BR>
RJ/RJR26<BR>
RJ/RJR26<BR>
RJ/RJR26<BR>
RJ/RJR26<BR>
RJ/RJR26<BR>
RJ/RJR26<BR>
RT/RTR24<BR>
RT/RTR24<BR>
RT/RTR24<BR>
RJ/RJR24<BR>
RJ/RJR24<BR>
RJ/RJR24<BR>
RJ/RJR24<BR>
RJ/RJR24<BR>
RJ/RJR24<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
</TR>
<TR>
<TD COLSPAN=8>
</TD>
</TR>
<TR>
<TD COLSPAN=8>
<FONT SIZE=4 FACE=ARIAL><B>SINGLE TURN</B></FONT>
</TD>
</TR>
<TR>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>BOURN</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>BI TECH</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>DALE-VISHAY</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>PHILIPS/MEPCO</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>MURATA</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>PANASONIC</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>SPECTROL</B></FONT>
</TD>
<TD ALIGN=CENTER>
<FONT SIZE=3 FACE=ARIAL><B>MILSPEC</B></FONT>
</TD>
</TR>
<TR>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
3323P<BR>
3323S<BR>
3323W<BR>
3329H<BR>
3329P<BR>
3329W<BR>
3339H<BR>
3339P<BR>
3339W<BR>
3352E<BR>
3352H<BR>
3352K<BR>
3352P<BR>
3352T<BR>
3352V<BR>
3352W<BR>
3362H<BR>
3362M<BR>
3362P<BR>
3362R<BR>
3362S<BR>
3362U<BR>
3362W<BR>
3362X<BR>
3386B<BR>
3386C<BR>
3386F<BR>
3386H<BR>
3386K<BR>
3386M<BR>
3386P<BR>
3386S<BR>
3386W<BR>
3386X<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
25P<BR>
25S<BR>
25RX<BR>
82P<BR>
82M<BR>
82PA<BR>
-<BR>
-<BR>
-<BR>
91E<BR>
91X<BR>
91T<BR>
91B<BR>
91A<BR>
91V<BR>
91W<BR>
25W<BR>
25V<BR>
25P<BR>
-<BR>
25S<BR>
25U<BR>
25RX<BR>
25X<BR>
72XW<BR>
72XL<BR>
72PM<BR>
72RX<BR>
-<BR>
72PX<BR>
72P<BR>
72RXW<BR>
72RXL<BR>
72X<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
T7YB<BR>
T7YA<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
TXD<BR>
TYA<BR>
TYP<BR>
-<BR>
TYD<BR>
TX<BR>
-<BR>
150SX<BR>
100SX<BR>
102T<BR>
101S<BR>
190T<BR>
150TX<BR>
101<BR>
-<BR>
-<BR>
101SX<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
ET6P<BR>
ET6S<BR>
ET6X<BR>
RJ-6W/8014EMW<BR>
RJ-6P/8014EMP<BR>
RJ-6X/8014EMX<BR>
TM7W<BR>
TM7P<BR>
TM7X<BR>
-<BR>
8017SMS<BR>
-<BR>
8017SMB<BR>
8017SMA<BR>
-<BR>
-<BR>
CT-6W<BR>
CT-6H<BR>
CT-6P<BR>
CT-6R<BR>
-<BR>
CT-6V<BR>
CT-6X<BR>
-<BR>
-<BR>
8038EKV<BR>
-<BR>
8038EKX<BR>
-<BR>
-<BR>
8038EKP<BR>
8038EKZ<BR>
8038EKW<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
3321H<BR>
3321P<BR>
3321N<BR>
1102H<BR>
1102P<BR>
1102T<BR>
RVA0911V304A<BR>
-<BR>
RVA0911H413A<BR>
RVG0707V100A<BR>
RVA0607V(H)306A<BR>
RVA1214H213A<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
3104B<BR>
3104C<BR>
3104F<BR>
3104H<BR>
-<BR>
3104M<BR>
3104P<BR>
3104S<BR>
3104W<BR>
3104X<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
EVMQ0G<BR>
EVMQIG<BR>
EVMQ3G<BR>
EVMS0G<BR>
EVMQ0G<BR>
EVMG0G<BR>
-<BR>
-<BR>
-<BR>
EVMK4GA00B<BR>
EVM30GA00B<BR>
EVMK0GA00B<BR>
EVM38GA00B<BR>
EVMB6<BR>
EVLQ0<BR>
-<BR>
EVMMSG<BR>
EVMMBG<BR>
EVMMAG<BR>
-<BR>
-<BR>
EVMMCS<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
EVMM1<BR>
-<BR>
-<BR>
EVMM0<BR>
-<BR>
-<BR>
EVMM3<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
62-3-1<BR>
62-1-2<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
67R<BR>
-<BR>
67P<BR>
-<BR>
-<BR>
-<BR>
-<BR>
67X<BR>
63V<BR>
63S<BR>
63M<BR>
-<BR>
-<BR>
63H<BR>
63P<BR>
-<BR>
-<BR>
63X<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
RJ/RJR50<BR>
RJ/RJR50<BR>
RJ/RJR50<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
</TR>
</TABLE>
<P> <P>
<TABLE BORDER=0 CELLSPACING=1 CELLPADDING=3>
<TR>
<TD COLSPAN=7>
<FONT color="#0000FF" SIZE=4 FACE=ARIAL><B>SMD TRIM-POT CROSS REFERENCE</B></FONT>
<P>
<FONT SIZE=4 FACE=ARIAL><B>MULTI-TURN</B></FONT>
</TD>
</TR>
<TR>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>BOURNS</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>BI TECH</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>DALE-VISHAY</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>PHILIPS/MEPCO</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>PANASONIC</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>TOCOS</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>AUX/KYOCERA</B></FONT>
</TD>
</TR>
<TR>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
3224G<BR>
3224J<BR>
3224W<BR>
3269P<BR>
3269W<BR>
3269X<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
44G<BR>
44J<BR>
44W<BR>
84P<BR>
84W<BR>
84X<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
ST63Z<BR>
ST63Y<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
ST5P<BR>
ST5W<BR>
ST5X<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
</TR>
<TR>
<TD COLSPAN=7>
</TD>
</TR>
<TR>
<TD COLSPAN=7>
<FONT SIZE=4 FACE=ARIAL><B>SINGLE TURN</B></FONT>
</TD>
</TR>
<TR>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>BOURNS</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>BI TECH</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>DALE-VISHAY</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>PHILIPS/MEPCO</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>PANASONIC</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>TOCOS</B></FONT>
</TD>
<TD>
<FONT SIZE=3 FACE=ARIAL><B>AUX/KYOCERA</B></FONT>
</TD>
</TR>
<TR>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
3314G<BR>
3314J<BR>
3364A/B<BR>
3364C/D<BR>
3364W/X<BR>
3313G<BR>
3313J<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
23B<BR>
23A<BR>
21X<BR>
21W<BR>
-<BR>
22B<BR>
22A<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
ST5YL/ST53YL<BR>
ST5YJ/5T53YJ<BR>
ST-23A<BR>
ST-22B<BR>
ST-22<BR>
-<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
ST-4B<BR>
ST-4A<BR>
-<BR>
-<BR>
-<BR>
ST-3B<BR>
ST-3A<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
EVM-6YS<BR>
EVM-1E<BR>
EVM-1G<BR>
EVM-1D<BR>
-<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
G4B<BR>
G4A<BR>
TR04-3S1<BR>
TRG04-2S1<BR>
-<BR>
-<BR>
-<BR></FONT>
</TD>
<TD BGCOLOR="#cccccc" ALIGN=CENTER><FONT FACE=ARIAL SIZE=3>
-<BR>
-<BR>
DVR-43A<BR>
CVR-42C<BR>
CVR-42A/C<BR>
-<BR>
-<BR></FONT>
</TD>
</TR>
</TABLE>
<P>
<FONT SIZE=4 FACE=ARIAL><B>ALT = ALTERNATE</B></FONT>
<P>
<P>
</td>
</tr>
</table><b>RESISTOR</b>>NAME>VALUE<b>RESISTOR</b>>NAME>VALUE<b>RESISTOR</b><p>>NAME>VALUE<b>RESISTOR</b> wave soldering<p>>NAME>VALUE<b>RESISTOR</b>>NAME>VALUE<b>RESISTOR</b><p>
wave soldering>NAME>VALUE<b>RESISTOR</b>>NAME>VALUE<b>RESISTOR</b><p>
wave soldering>NAME>VALUE<b>RESISTOR</b>>NAME>VALUE<b>RESISTOR</b><p>
wave soldering>NAME>VALUE<b>RESISTOR</b>>NAME>VALUE<b>RESISTOR</b><p>
wave soldering>NAME>VALUE<b>RESISTOR</b>>NAME>VALUE<b>RESISTOR</b><p>
wave soldering>NAME>VALUE<b>RESISTOR</b>>NAME>VALUE<b>RESISTOR</b><p>
wave soldering>NAME>VALUE<b>RESISTOR</b>>NAME>VALUE<b>RESISTOR</b><p>
wave soldering>NAME>VALUE<b>RESISTOR</b>>NAME>VALUE<b>RESISTOR</b><p>
wave soldering>NAME>VALUE<b>RESISTOR</b><p>
Source: http://download.siliconexpert.com/pdfs/2005/02/24/Semi_Ap/2/VSH/Resistor/dcrcwfre.pdf>NAME>VALUE<b>RESISTOR</b> wave soldering<p>
Source: http://download.siliconexpert.com/pdfs/2005/02/24/Semi_Ap/2/VSH/Resistor/dcrcwfre.pdf>NAME>VALUE<b>RESISTOR</b><p>
MELF 0.10 W>NAME>VALUE<b>RESISTOR</b><p>
MELF 0.25 W>NAME>VALUE<b>RESISTOR</b><p>
MELF 0.12 W>NAME>VALUE<b>RESISTOR</b><p>
MELF 0.10 W>NAME>VALUE<b>RESISTOR</b><p>
MELF 0.25 W>NAME>VALUE<b>RESISTOR</b><p>
MELF 0.25 W>NAME>VALUE<b>RESISTOR</b><p>
MELF 0.12 W>NAME>VALUE<b>RESISTOR</b><p>
MELF 0.25 W>NAME>VALUE<b>RESISTOR</b><p>
type 0204, grid 5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0204, grid 7.5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0204, grid 2.5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0207, grid 10 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0207, grid 12 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0207, grid 15mm>NAME>VALUE<b>RESISTOR</b><p>
type 0207, grid 2.5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0207, grid 5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0207, grid 7.5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0309, grid 10mm>NAME>VALUE<b>RESISTOR</b><p>
type 0309, grid 12.5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0309, grid 2.5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0411, grid 12.5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0411, grid 15 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0411, grid 3.81 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0414, grid 15 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0414, grid 5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0617, grid 17.5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0617, grid 22.5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0617, grid 5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0922, grid 22.5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0613, grid 5 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0613, grid 15 mm>NAME>VALUE<b>RESISTOR</b><p>
type 0817, grid 22.5 mm>NAME>VALUE0817<b>RESISTOR</b><p>
type 0817, grid 6.35 mm>NAME>VALUE0817<b>RESISTOR</b><p>
type V234, grid 12.5 mm>NAME>VALUE<b>RESISTOR</b><p>
type V235, grid 17.78 mm>NAME>VALUE<b>RESISTOR</b><p>
type V526-0, grid 2.5 mm>NAME>VALUE<b>CECC Size RC2211</b> Reflow Soldering<p>
source Beyschlag>NAME>VALUE<b>CECC Size RC2211</b> Wave Soldering<p>
source Beyschlag>NAME>VALUE<b>CECC Size RC3715</b> Reflow Soldering<p>
source Beyschlag>NAME>VALUE<b>CECC Size RC3715</b> Wave Soldering<p>
source Beyschlag>NAME>VALUE<b>CECC Size RC6123</b> Reflow Soldering<p>
source Beyschlag>NAME>VALUE<b>CECC Size RC6123</b> Wave Soldering<p>
source Beyschlag>NAME>VALUE<b>RESISTOR</b><p>
type 0922, grid 7.5 mm>NAME>VALUE0922<b>RESISTOR</b><p>
type RDH, grid 15 mm>NAME>VALUERDH<b>Mini MELF 0102 Axial</b>>NAME>VALUE<b>RESISTOR</b> chip<p>
Source: http://www.vishay.com/docs/20008/dcrcw.pdf>NAME>VALUE<b>Bulk Metal® Foil Technology</b>, Tubular Axial Lead Resistors, Meets or Exceeds MIL-R-39005 Requirements<p>
MIL SIZE RBR52<br>
Source: VISHAY .. vta56.pdf>NAME>VALUE<b>Bulk Metal® Foil Technology</b>, Tubular Axial Lead Resistors, Meets or Exceeds MIL-R-39005 Requirements<p>
MIL SIZE RBR53<br>
Source: VISHAY .. vta56.pdf>NAME>VALUE<b>Bulk Metal® Foil Technology</b>, Tubular Axial Lead Resistors, Meets or Exceeds MIL-R-39005 Requirements<p>
MIL SIZE RBR54<br>
Source: VISHAY .. vta56.pdf>NAME>VALUE<b>Bulk Metal® Foil Technology</b>, Tubular Axial Lead Resistors, Meets or Exceeds MIL-R-39005 Requirements<p>
MIL SIZE RBR55<br>
Source: VISHAY .. vta56.pdf>NAME>VALUE<b>Bulk Metal® Foil Technology</b>, Tubular Axial Lead Resistors, Meets or Exceeds MIL-R-39005 Requirements<p>
MIL SIZE RBR56<br>
Source: VISHAY .. vta56.pdf>NAME>VALUE<b>Bulk Metal® Foil Technology</b>, Tubular Axial Lead Resistors, Meets or Exceeds MIL-R-39005 Requirements<p>
MIL SIZE RNC55<br>
Source: VISHAY .. vta56.pdf>NAME>VALUE<b>Bulk Metal® Foil Technology</b>, Tubular Axial Lead Resistors, Meets or Exceeds MIL-R-39005 Requirements<p>
MIL SIZE RNC60<br>
Source: VISHAY .. vta56.pdf>NAME>VALUE<b>Package 4527</b><p>
Source: http://www.vishay.com/docs/31059/wsrhigh.pdf>NAME>VALUE<b>Wirewound Resistors, Precision Power</b><p>
Source: VISHAY wscwsn.pdf>NAME>VALUE<b>Wirewound Resistors, Precision Power</b><p>
Source: VISHAY wscwsn.pdf>NAME>VALUE<b>Wirewound Resistors, Precision Power</b><p>
Source: VISHAY wscwsn.pdf>NAME>VALUE<b>Wirewound Resistors, Precision Power</b><p>
Source: VISHAY wscwsn.pdf>NAME>VALUE<b>Wirewound Resistors, Precision Power</b><p>
Source: VISHAY wscwsn.pdf>NAME>VALUE<b>Wirewound Resistors, Precision Power</b><p>
Source: VISHAY wscwsn.pdf>NAME>VALUE<b>CRCW1218 Thick Film, Rectangular Chip Resistors</b><p>
Source: http://www.vishay.com .. dcrcw.pdf>NAME>VALUE<b>Chip Monolithic Ceramic Capacitors</b> Medium Voltage High Capacitance for General Use<p>
Source: http://www.murata.com .. GRM43DR72E224KW01.pdf>NAME>VALUE<b>PRL1632 are realized as 1W for 3.2 × 1.6mm(1206)</b><p>
Source: http://www.mouser.com/ds/2/392/products_18-2245.pdf>NAME>VALUE>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b><p>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE<b>CAPACITOR</b><p>
grid 2.5 mm, outline 2.4 x 4.4 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 2.5 mm, outline 2.5 x 5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 2.5 mm, outline 3 x 5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 2.5 mm, outline 4 x 5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 2.5 mm, outline 5 x 5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 2.5 mm, outline 6 x 5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 2.5 mm + 5 mm, outline 2.4 x 7 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 2.5 + 5 mm, outline 2.5 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 2.5 + 5 mm, outline 3.5 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 2.5 + 5 mm, outline 4.5 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 2.5 + 5 mm, outline 5.5 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 5 mm, outline 2.4 x 4.4 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 5 mm, outline 2.5 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 5 mm, outline 4.5 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 5 mm, outline 3 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 5 mm, outline 5 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 5 mm, outline 5.5 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 5 mm, outline 7.5 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
Horizontal, grid 5 mm, outline 7.5 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 7.5 mm, outline 3.2 x 10.3 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 7.5 mm, outline 4.2 x 10.3 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 7.5 mm, outline 5.2 x 10.6 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 10.2 mm, outline 4.3 x 13.3 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 10.2 mm, outline 5.4 x 13.3 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 10.2 mm, outline 6.4 x 13.3 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 10.2 mm + 15.2 mm, outline 6.2 x 18.4 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 15 mm, outline 5.4 x 18.3 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 15 mm, outline 6.4 x 18.3 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 15 mm, outline 7.2 x 18.3 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 15 mm, outline 8.4 x 18.3 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 15 mm, outline 9.1 x 18.2 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 22.5 mm, outline 6.2 x 26.8 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 22.5 mm, outline 7.4 x 26.8 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 22.5 mm, outline 8.7 x 26.8 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 22.5 mm, outline 10.8 x 26.8 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 22.5 mm, outline 11.3 x 26.8 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 27.5 mm, outline 9.3 x 31.6 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 27.5 mm, outline 11.3 x 31.6 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 27.5 mm, outline 13.4 x 31.6 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 27.5 mm, outline 20.5 x 31.6 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 32.5 mm, outline 13.7 x 37.4 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 32.5 mm, outline 16.2 x 37.4 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 32.5 mm, outline 18.2 x 37.4 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 37.5 mm, outline 19.2 x 41.8 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 37.5 mm, outline 20.3 x 41.8 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 5 mm, outline 3.5 x 7.5 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 37.5 mm, outline 15.5 x 41.8 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 7.5 mm, outline 6.3 x 10.6 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 27.5 mm, outline 15.4 x 31.6 mm>NAME>VALUE<b>CAPACITOR</b><p>
grid 27.5 mm, outline 17.3 x 31.6 mm>NAME>VALUE<b>Ceramic Chip Capacitor KEMET 0204 reflow solder</b><p>
Metric Code Size 1005>NAME>VALUE<b>Ceramic Chip Capacitor KEMET 0603 reflow solder</b><p>
Metric Code Size 1608>NAME>VALUE<b>Ceramic Chip Capacitor KEMET 0805 reflow solder</b><p>
Metric Code Size 2012>NAME>VALUE<b>Ceramic Chip Capacitor KEMET 1206 reflow solder</b><p>
Metric Code Size 3216>NAME>VALUE<b>Ceramic Chip Capacitor KEMET 1210 reflow solder</b><p>
Metric Code Size 3225>NAME>VALUE<b>Ceramic Chip Capacitor KEMET 1812 reflow solder</b><p>
Metric Code Size 4532>NAME>VALUE<b>Ceramic Chip Capacitor KEMET 1825 reflow solder</b><p>
Metric Code Size 4564>NAME>VALUE<b>Ceramic Chip Capacitor KEMET 2220 reflow solder</b><p>Metric Code Size 5650>NAME>VALUE<b>Ceramic Chip Capacitor KEMET 2225 reflow solder</b><p>Metric Code Size 5664>NAME>VALUE<b> </b><p>
Source: http://www.vishay.com/docs/10129/hpc0201a.pdf>NAME>VALUESource: http://www.avxcorp.com/docs/catalogs/cx5r.pdf>NAME>VALUE<b>CAPACITOR</b><p>
Source: AVX .. aphvc.pdf>NAME>VALUE<b>CAPACITOR</b><p>
Source: AVX .. aphvc.pdf>NAME>VALUE<b>CAPACITOR</b>>NAME>VALUE>NAME>VALUE>NAME>VALUE<B>RESISTOR</B>, European symbol<B>CAPACITOR</B>, European symbol<b>Linear Devices</b><p>
Operational amplifiers, comparators, voltage regulators, ADCs, DACs, etc.<p>
<author>Created by librarian@cadsoft.de</author><b>Dual In Line Package</b>>NAME>VALUE<b>Small Outline Package 8</b><br>
NS Package M08A>NAME>VALUE>NAME>VALUEV+V-<b>OP AMP</b> also LM158; LM258; LM2904<p>
Source: http://cache.national.com/ds/LM/LM158.pdf<b>LEDs</b><p>
<author>Created by librarian@cadsoft.de</author><br>
Extended by Federico Battaglin <author><federico.rd@fdpinternational.com></author> with DUOLED<b>CHICAGO MINIATURE LAMP, INC.</b><p>
7022X Series SMT LEDs 1206 Package Size>NAME>VALUE<B>LED</B><p>
5 mm, square, Siemens>NAME>VALUE<B>LED</B><p>
2 x 5 mm, rectangle>NAME>VALUE<B>LED</B><p>
3 mm, round>NAME>VALUE<B>LED</B><p>
5 mm, round>NAME>VALUE<B>LED</B><p>
1 mm, round, Siemens>NAME>VALUE<B>LED BLOCK</B><p>
1 LED, Siemens>NAME>VALUE<b>LED HOLDER</b><p>
Siemens>NAME>VALUE<b>LED HOLDER</b><p>
Siemens>NAME>VALUE<b>LED HOLDER</b><p>
SiemensA+K->NAME>VALUE<b>LED HOLDER</b><p>
Siemens>NAME>VALUE+-<B>IR LED</B><p>
infrared emitting diode, Infineon
TO-18, lead spacing 2.54 mm, cathode marking<p>
Inifineon>NAME>VALUE<B>IR LED</B><p>
infrared emitting diode, Infineon
TO-18, lead spacing 2.54 mm, cathode marking<p>
Inifineon>NAME>VALUE<B>LED</B><p>
rectangle, 5.7 x 3.2 mm>NAME>VALUE<B>IR LED</B><p>
IR transmitter Siemens>NAME>VALUE<b>TOPLED® High-optical Power LED (HOP)</b><p>
Source: http://www.osram.convergy.de/ ... ls_t675.pdf>NAME>VALUEAC<b>BLUE LINETM Hyper Mini TOPLED® Hyper-Bright LED</b><p>
Source: http://www.osram.convergy.de/ ... LB M676.pdfAC>NAME>VALUE<b>Super SIDELED® High-Current LED</b><p>
LG A672, LP A672 <br>
Source: http://www.osram.convergy.de/ ... LG_LP_A672.pdf (2004.05.13)CA>NAME>VALUE<b>SmartLEDTM Hyper-Bright LED</b><p>
Source: http://www.osram.convergy.de/ ... LA_LO_LS_LY L896.pdf>NAME>VALUE<b>Hyper TOPLED® RG Hyper-Bright LED</b><p>
Source: http://www.osram.convergy.de/ ... LA_LO_LS_LY T776.pdf>NAME>VALUEAC<b>Hyper Micro SIDELED®</b><p>
Source: http://www.osram.convergy.de/ ... LA_LO_LS_LY Y876.pdf>NAME>VALUE<b>Power TOPLED®</b><p>
Source: http://www.osram.convergy.de/ ... LA_LO_LA_LY E67B.pdf>NAME>VALUECACC<b>Hyper CHIPLED Hyper-Bright LED</b><p>
LB Q993<br>
Source: http://www.osram.convergy.de/ ... Lb_q993.pdf>NAME>VALUE<b>Hyper CHIPLED Hyper-Bright LED</b><p>
LB R99A<br>
Source: http://www.osram.convergy.de/ ... lb_r99a.pdf>NAME>VALUE<b>Mini TOPLED Santana®</b><p>
Source: http://www.osram.convergy.de/ ... LG M470.pdf>NAME>VALUE<b>CHIPLED</b><p>
Source: http://www.osram.convergy.de/ ... LG_R971.pdf>NAME>VALUE<b>CHIPLED</b><p>
Source: http://www.osram.convergy.de/ ... LG_LY N971.pdf>NAME>VALUE<b>CHIPLED</b><p>
Source: http://www.osram.convergy.de/ ... LG_LY Q971.pdf>NAME>VALUE<b>CHIPLED-0603</b><p>
Recommended Solder Pad useable for SmartLEDTM and Chipled - Package 0603<br>
Package able to withstand TTW-soldering heat<br>
Package suitable for TTW-soldering<br>
Source: http://www.osram.convergy.de/ ... LO_LS_LY L89K.pdf>NAME>VALUE<b>SmartLED TTW</b><p>
Recommended Solder Pad useable for SmartLEDTM and Chipled - Package 0603<br>
Package able to withstand TTW-soldering heat<br>
Package suitable for TTW-soldering<br>
Source: http://www.osram.convergy.de/ ... LO_LS_LY L89K.pdf>NAME>VALUE<b>Lumileds Lighting. LUXEON®</b> with cool pad<p>
Source: K2.pdf>NAME>VALUE<b>Lumileds Lighting. LUXEON®</b> without cool pad<p>
Source: K2.pdf>NAME>VALUE<B>LED</B><p>
10 mm, round>NAME>VALUE<b>SURFACE MOUNT LED LAMP</b> 3.5x2.8mm<p>
Source: http://www.kingbright.com/manager/upload/pdf/KA-3528ASYC(Ver1189474662.1)>NAME>VALUE<b>SML0805-2CW-TR (0805 PROFILE)</b> COOL WHITE<p>
Source: http://www.ledtronics.com/ds/smd-0603/Dstr0093.pdf>NAME>VALUE<b>SML10XXKH-TR (HIGH INTENSITY) LED</b><p>
<table>
<tr><td>SML10R3KH-TR</td><td>ULTRA RED</td></tr>
<tr><td>SML10E3KH-TR</td><td>SUPER REDSUPER BLUE</td></tr>
<tr><td>SML10O3KH-TR</td><td>SUPER ORANGE</td></tr>
<tr><td>SML10PY3KH-TR</td><td>PURE YELLOW</td></tr>
<tr><td>SML10OY3KH-TR</td><td>ULTRA YELLOW</td></tr>
<tr><td>SML10AG3KH-TR</td><td>AQUA GREEN</td></tr>
<tr><td>SML10BG3KH-TR</td><td>BLUE GREEN</td></tr>
<tr><td>SML10PB1KH-TR</td><td>SUPER BLUE</td></tr>
<tr><td>SML10CW1KH-TR</td><td>WHITE</td></tr>
</table>
Source: http://www.ledtronics.com/ds/smd-1206/dstr0094.PDF>NAME>VALUE<b>SML0603-XXX (HIGH INTENSITY) LED</b><p>
<table>
<tr><td>AG3K</td><td>AQUA GREEN</td></tr>
<tr><td>B1K</td><td>SUPER BLUE</td></tr>
<tr><td>R1K</td><td>SUPER RED</td></tr>
<tr><td>R3K</td><td>ULTRA RED</td></tr>
<tr><td>O3K</td><td>SUPER ORANGE</td></tr>
<tr><td>O3KH</td><td>SOFT ORANGE</td></tr>
<tr><td>Y3KH</td><td>SUPER YELLOW</td></tr>
<tr><td>Y3K</td><td>SUPER YELLOW</td></tr>
<tr><td>2CW</td><td>WHITE</td></tr>
</table>
Source: http://www.ledtronics.com/ds/smd-0603/Dstr0092.pdf>NAME>VALUE>NAME>VALUE<b>LED</b><p>
<u>OSRAM</u>:<br>
- <u>CHIPLED</u><br>
LG R971, LG N971, LY N971, LG Q971, LY Q971, LO R971, LY R971
LH N974, LH R974<br>
LS Q976, LO Q976, LY Q976<br>
LO Q996<br>
- <u>Hyper CHIPLED</u><br>
LW Q18S<br>
LB Q993, LB Q99A, LB R99A<br>
- <u>SideLED</u><br>
LS A670, LO A670, LY A670, LG A670, LP A670<br>
LB A673, LV A673, LT A673, LW A673<br>
LH A674<br>
LY A675<br>
LS A676, LA A676, LO A676, LY A676, LW A676<br>
LS A679, LY A679, LG A679<br>
- <u>Hyper Micro SIDELED®</u><br>
LS Y876, LA Y876, LO Y876, LY Y876<br>
LT Y87S<br>
- <u>SmartLED</u><br>
LW L88C, LW L88S<br>
LB L89C, LB L89S, LG L890<br>
LS L89K, LO L89K, LY L89K<br>
LS L896, LA L896, LO L896, LY L896<br>
- <u>TOPLED</u><br>
LS T670, LO T670, LY T670, LG T670, LP T670<br>
LSG T670, LSP T670, LSY T670, LOP T670, LYG T670<br>
LG T671, LOG T671, LSG T671<br>
LB T673, LV T673, LT T673, LW T673<br>
LH T674<br>
LS T676, LA T676, LO T676, LY T676, LB T676, LH T676, LSB T676, LW T676<br>
LB T67C, LV T67C, LT T67C, LS T67K, LO T67K, LY T67K, LW E67C<br>
LS E67B, LA E67B, LO E67B, LY E67B, LB E67C, LV E67C, LT E67C<br>
LW T67C<br>
LS T679, LY T679, LG T679<br>
LS T770, LO T770, LY T770, LG T770, LP T770<br>
LB T773, LV T773, LT T773, LW T773<br>
LH T774<br>
LS E675, LA E675, LY E675, LS T675<br>
LS T776, LA T776, LO T776, LY T776, LB T776<br>
LHGB T686<br>
LT T68C, LB T68C<br>
- <u>Hyper Mini TOPLED®</u><br>
LB M676<br>
- <u>Mini TOPLED Santana®</u><br>
LG M470<br>
LS M47K, LO M47K, LY M47K
<p>
Source: http://www.osram.convergy.de<p>
<u>LUXEON:</u><br>
- <u>LUMILED®</u><br>
LXK2-PW12-R00, LXK2-PW12-S00, LXK2-PW14-U00, LXK2-PW14-V00<br>
LXK2-PM12-R00, LXK2-PM12-S00, LXK2-PM14-U00<br>
LXK2-PE12-Q00, LXK2-PE12-R00, LXK2-PE12-S00, LXK2-PE14-T00, LXK2-PE14-U00<br>
LXK2-PB12-K00, LXK2-PB12-L00, LXK2-PB12-M00, LXK2-PB14-N00, LXK2-PB14-P00, LXK2-PB14-Q00<br>
LXK2-PR12-L00, LXK2-PR12-M00, LXK2-PR14-Q00, LXK2-PR14-R00<br>
LXK2-PD12-Q00, LXK2-PD12-R00, LXK2-PD12-S00<br>
LXK2-PH12-R00, LXK2-PH12-S00<br>
LXK2-PL12-P00, LXK2-PL12-Q00, LXK2-PL12-R00
<p>
Source: www.luxeon.com<p>
<u>KINGBRIGHT:</U><p>
KA-3528ASYC<br>
Source: www.kingbright.com<b>PTC and NTC Resistors</b><p>
Siemens, Philips, Valvo<p>
<author>Created by librarian@cadsoft.de</author><b>PHILIPS NTC</b>>NAME>VALUE<b>PHILIPS/VALVO NTC</b>>NAME>VALUE>NAME>VALUE<b>PHILIPS NTC</b><b>PHILIPS NTC</b>Main Harness Signal ConnectorBrakeThrottleRXTXGND5VRXTXComponents missing, located on
the bottom side of pcb right under STC MCU.
Two SOT-23, likely two transistors,
some form of input protection maybe?PAS1PAS2Debug Terminalt?
Constant data output at 9600 baud.Gear sensor??? Has not been traced??? Has not been tracedSPDDaniel NilssonADC6 - Battery voltage measurementTxD4RxD4RxD3TxD3Another UART brought out to pins, no data has been seen.ADC7 - Temperature sensorU (white)V (blue)W (grey)Motor Power EnableNEC TxDSTC RxD2STC TxD2NEC RxDSerial Communication between MCUsDaniel NilssonWARNING:
Not sure this opamp circuit is 100% correct, it looks a bit strange.
OPAMP is there to amplify voltage drop over shunt
resistors in order to get a more detailed reading with ADC.Motor winding temperature sensor.
Labeled as "T" on hall sensor board.Some form of status LED.
Seems to be blinking during normal operation.Motor Control EnableNo effect, but should be high
Since Version 6.2.2 text objects can contain more than one line,
which will not be processed correctly with this version.
================================================
FILE: drawings/pcb/eagle.epf
================================================
[Eagle]
Version="07 05 00"
Platform="Windows"
Serial="62191E841E-LSR-WLM-1EL"
Globals="Globals"
Desktop="Desktop"
[Globals]
AutoSaveProject=1
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/19inch.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/40xx.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/41xx.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/45xx.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/74ac-logic.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/74ttl-din.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/74xx-eu.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/74xx-little-de.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/74xx-little-us.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/74xx-us.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/751xx.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/IQD-Frequency-Products.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/advanced-test-technologies.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/agilent-technologies.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/allegro.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/altera-cyclone-II.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/altera-cyclone-III.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/altera-stratix-iv.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/altera.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/am29-memory.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/amd-mach.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/amd.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/amis.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/analog-devices.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/aplus.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/ase.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/atmel.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/austriamicrosystems.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/avago.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/axis.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/battery.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/belton-engineering.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/burr-brown.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/busbar.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/buzzer.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/c-trimm.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/california-micro-devices.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/capacitor-wima.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/chipcard-siemens.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/cirrus-logic.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-3m.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-4ucon.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-amp-champ.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-amp-micromatch.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-amp-mt.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-amp-mt6.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-amp-quick.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-amp-te.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-amp.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-amphenol.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-avx.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-berg.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-bosch.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-chipcard-iso7816.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-coax.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-commcon.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-conrad.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-cpci.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-cui.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-cypressindustries.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-deutsch.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-dil.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-ebyelectro.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-elco.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-erni.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-faston.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-fci.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-friwo.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-garry.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-harting-h.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-harting-ml.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-harting-v.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-harting.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-hirose.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-hirschmann.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-jack.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-jae.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-jst.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-kycon.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-kyocera-elco.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-lemo.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-leotronics.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-lsta.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-lstb.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-lumberg.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-ml.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-molex.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-neutrik_ag.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-omron.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-panasonic.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-panduit.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-pc.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-pc104.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-phoenix-254.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-phoenix-3.81.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-phoenix-350.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-phoenix-500.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-phoenix-508.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-phoenix-762.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-phoenix-me_max.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-phoenix-mkds_5.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-phoenix-smkdsp.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-ptr500.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-pulse.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-rib.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-samtec.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-shallin.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-shiua-chyuan.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-stewart.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-stocko.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-subd.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-sullinselectronics.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-thomas-betts.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-tyco.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-tycoelectronics.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-vg.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-wago-500.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-wago-508.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-wago.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-wago255.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-weidmueller-sl35.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-wenzhou-yihua.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-xmultiple.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/con-yamaichi.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/crystal.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/csr.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/cypress.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/davicom.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/dc-dc-converter.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/dimensions.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/diode.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/discrete.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/display-hp.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/display-kingbright.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/display-lcd.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/docu-dummy.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/dom-key.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/eagle-ltspice.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/ecl.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/em-microelectronic.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/etx-board.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/exar.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/fairchild-semic.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/farnell.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/fiber-optic-hp.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/fiber-optic-siemens.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/fifo.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/flexipanel.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/fox-electronics.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/frames.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/freescale.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/ftdichip.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/fujitsu.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/fuse.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/gennum.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/halo-electronics.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/heatsink.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/holes.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/holtek.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/ic-package.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/inductor-coilcraft.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/inductor-neosid.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/inductor-nkl.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/inductors.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/infineon-tricore.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/infineon.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/intersil-techwell.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/intersil.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/ir.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/isd.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/johanson-technology.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/jump-0r-smd.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/jumper.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/lantronix.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/lattice.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/lc-filter.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/led-7-segment.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/led-citizen-electronics.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/led-lumiled.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/led.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/lem.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/linear-technology.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/linear.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/linx.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/logo.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/lprs.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/lsi-computer-systems.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/lumiled.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/marks.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/maxim.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/maxstream.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/melexis.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/memory-hitachi.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/memory-idt.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/memory-micron.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/memory-motorola-dram.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/memory-nec.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/memory-samsung.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/memory-sram.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/memory.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/mems.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micrel.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-cyrod.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-fujitsu.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-harris.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-hitachi.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-infineon.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-intel.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-mc68000.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-motorola.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-philips.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-renesas.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-samsung.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micro-siemens.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/microchip.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micron.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/micronas.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/microphon.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/microwave.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/midori-sensor.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/minicircuits.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/mitsubishi-semiconductor.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/motorola-sensor-driver.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/murata-filter.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/murata-sensor.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/nanotec.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/national-instruments.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/national-semiconductor.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/nec-lqfp100-pack.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/nec.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/nrj-semiconductor.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/omnivision.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/on-semiconductor.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/opto-honeywell-3000.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/opto-honeywell-4000.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/opto-honeywell.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/opto-micro-linear.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/opto-trans-siemens.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/opto-transmittter-hp.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/opto-vishay.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/optocoupler.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/pal.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/philips-semiconductors.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/photo-elements.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/piher.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/pinhead.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/plcc-socket.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/pld-intel.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/plxtech.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/pot-vitrohm.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/pot-xicor.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/pot.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/ptc-ntc.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/quantum-research-group.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/rcl.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/recom-international.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/rectifier.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/ref-packages-longpad.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/ref-packages.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/relay.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/renesas.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/resistor-bourns.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/resistor-dil.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/resistor-net.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/resistor-power.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/resistor-ruf.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/resistor-shunt.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/resistor-sil.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/resistor.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/rf-micro-devices.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/rf-solutions.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/rohm.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/roundsolutions.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/semicon-smd-ipc.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/sensor-comus-group.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/sensor-heraeus.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/sensor-infratec.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/sharp.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/silabs.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/sim-technology.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/sipex.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/smd-ipc.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/smd-special.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/solomon-systech.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/solpad.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/speaker.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/special-drill.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/special.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/st-microelectronics.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/stm32xx.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/supertex.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/supply1.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/supply2.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/switch-alps.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/switch-coto.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/switch-dil.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/switch-misc.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/switch-omron.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/switch-raychem.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/switch-reed.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/switch.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/telcom.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/telecontrolli.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/telefunken.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/testpad.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/texas-sn55-sn75.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/texas.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/toshiba.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/traco-electronic.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/trafo-bei.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/trafo-hammondmfg.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/trafo-siemens.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/trafo-xicon.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/trafo.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/transformer-pulse.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/transistor-fet.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/transistor-neu-to92.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/transistor-npn.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/transistor-pnp.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/transistor-power.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/transistor-small-signal.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/transistor.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/triac.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/trimble.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/tripas.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/u-blox.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/uln-udn.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/v-reg-micrel.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/v-reg.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/varistor.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/wafer-scale-psd.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/wirepad.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/xicor.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/xilinx-virtex-v5.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/xilinx-xc18v.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/xilinx-xc9.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/xilinx-xcv.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/zetex.lbr"
UsedLibrary="C:/Program Files/EAGLE-7.5.0/lbr/zilog.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/adafruit.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/bss138_10.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/con-jst2.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/con-usb-2.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/con-usb-3.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/con-usb.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/esp32.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/esp8266-esp12.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/ic.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/microusb.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/motor-driver.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/photo-interrupter.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/potentiometers.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/regulators.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/smps.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/stm32.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/switch-tact.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/power-ic.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Aesthetics.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Batteries.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Boards.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Capacitors.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Clocks.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Coils.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Connectors.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-DigitalIC.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-DiscreteSemi.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Displays.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Electromechanical.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-FreqCtrl.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Fuses.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-GPS.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Hardware.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-IC-Amplifiers.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-IC-Comms.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-IC-Conversion.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-IC-Logic.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-IC-Memory.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-IC-Microcontroller.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-IC-Power.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-IC-Special-Function.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Jumpers.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-LED.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-PowerSymbols.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Resistors.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Retired.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-RF.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Switches.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/SparkFun-Sensors.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/sparkfun/User-Submitted.lbr"
UsedLibrary="D:/Projects/Git/components/eagle-lbr/element14/atmel_element14.lbr"
[Win_1]
Type="Control Panel"
Loc="-8 -8 2551 1368"
State=1
Number=0
[Desktop]
Screen="2560 1440"
Window="Win_1"
================================================
FILE: src/firmware/.gitignore
================================================
**/*.asm
**/*.elf
**/*.ihx
**/*.cdb
**/*.lk
**/*.map
**/*.adb
**/*.lst
**/*.rel
**/*.rst
**/*.sym
*.hex
*.mem
.vs
build
*.vcxproj.user
================================================
FILE: src/firmware/Makefile
================================================
.PHONY: all clean
ifeq '$(findstring ;,$(PATH))' ';'
UNAME := Windows
else
UNAME := $(shell uname 2>/dev/null || echo Unknown)
endif
# Select target controller (normally done from cmd line):
#TARGET_CONTROLLER = BBSHD
#TARGET_CONTROLLER = BBS02
#TARGET_CONTROLLER = TSDZ2
# Compiler
CC = sdcc
# Target name
TARGET = bbs-fw
MAINSRC = main.c
SUBDIRS =
CFLAGS = -Ddouble=float --std-c99 -D$(TARGET_CONTROLLER)
# Target Specific
ifeq ($(TARGET_CONTROLLER), BBSHD)
CFLAGS += -mmcs51 --model-large --xram-size 3840
SUBDIRS += bbsx
endif
ifeq ($(TARGET_CONTROLLER), BBS02)
CFLAGS += -mmcs51 --model-large --xram-size 1792
SUBDIRS += bbsx
endif
ifeq ($(TARGET_CONTROLLER), TSDZ2)
CFLAGS += -mstm8
SUBDIRS += tsdz2
endif
INCS = $(wildcard *.h $(foreach fd, $(SUBDIRS), $(fd)/*.h))
SRCS = $(filter-out main.c, $(wildcard *.c $(foreach fd, $(SUBDIRS), $(fd)/*.c)))
RELS := $(SRCS:.c=.rel)
INC_DIRS = -I./ $(addprefix -I, $(SUBDIRS))
all: precheck $(TARGET) hex
$(TARGET): $(MAINSRC) $(RELS)
$(CC) -o $(TARGET).ihx $(INC_DIRS) $(CFLAGS) $(MAINSRC) $(RELS)
%.rel: %.c $(INCS)
$(CC) -o $@ -c $(INC_DIRS) $(CFLAGS) $<
echo:
$(info SRCS: $(SRCS))
$(info RELS: $(RELS))
$(info INCS: $(INCS))
precheck:
ifndef TARGET_CONTROLLER
$(info TARGET_CONTROLLER is not specified.)
$(info Set to one of [BBSHD, BBS02, TSDZ2])
$(info Example:)
$(info $(null) make all TARGET_CONTROLLER=BBSHD)
$(error )
endif
$(info Building bbs-fw for $(TARGET_CONTROLLER))
hex:
ifeq ($(UNAME), Linux)
@packihx bbs-fw.ihx > bbs-fw.hex
else
@cmd /C tohex.bat
endif
clean:
ifeq ($(UNAME), Linux)
@rm -f bbsx/*.hex tsdz2/*.hex *.hex
@rm -f bbsx/*.ihx tsdz2/*.ihx *.ihx
@rm -f bbsx/*.asm tsdz2/*.asm *.asm
@rm -f bbsx/*.rel tsdz2/*.rel *.rel
@rm -f bbsx/*.lk tsdz2/*.lk *.lk
@rm -f bbsx/*.lst tsdz2/*.lst *.lst
@rm -f bbsx/*.rst tsdz2/*.rst *.rst
@rm -f bbsx/*.sym tsdz2/*.sym *.sym
@rm -f bbsx/*.cdb tsdz2/*.cdb *.cdb
@rm -f bbsx/*.map tsdz2/*.map *.map
@rm -f bbsx/*.elf tsdz2/*.elf *.elf
@rm -f bbsx/*.adb tsdz2/*.adb *.adb
@rm -f bbsx/*.mem tsdz2/*.mem *.mem
else
@cmd /C clean.bat
endif
$(info Clean Finished)
.PHONY = all hex clean precheck echo
.SUFFIXES: .c .rel
================================================
FILE: src/firmware/adc.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _ADC_H_
#define _ADC_H_
#include
void adc_init();
void adc_process();
uint8_t adc_get_throttle();
uint16_t adc_get_torque();
uint16_t adc_get_temperature_contr();
uint16_t adc_get_temperature_motor();
uint16_t adc_get_battery_voltage();
#endif
================================================
FILE: src/firmware/app.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "app.h"
#include "fwconfig.h"
#include "cfgstore.h"
#include "motor.h"
#include "sensors.h"
#include "throttle.h"
#include "lights.h"
#include "uart.h"
#include "eventlog.h"
#include "util.h"
#include "system.h"
typedef struct
{
assist_level_t level;
// cached precomputed values
// ---------------------------------
// speed
int32_t max_wheel_speed_rpm_x10;
// pas
uint8_t keep_current_target_percent;
uint16_t keep_current_ramp_start_rpm_x10;
uint16_t keep_current_ramp_end_rpm_x10;
} assist_level_data_t;
static uint8_t assist_level;
static uint8_t operation_mode;
static uint16_t global_speed_limit_rpm;
static int32_t global_throttle_speed_limit_rpm_x10;
static uint16_t lvc_voltage_x100;
static uint16_t lvc_ramp_down_start_voltage_x100;
static uint16_t lvc_ramp_down_end_voltage_x100;
static assist_level_data_t assist_level_data;
static uint16_t speed_limit_ramp_interval_rpm_x10;
static bool cruise_paused;
static int8_t temperature_contr_c;
static int8_t temperature_motor_c;
static uint16_t ramp_up_current_interval_ms;
static uint32_t power_blocked_until_ms;
static uint16_t pretension_cutoff_speed_rpm_x10;
static bool lights_state = false;
void apply_pas_cadence(uint8_t* target_current, uint8_t throttle_percent);
#if HAS_TORQUE_SENSOR
void apply_pas_torque(uint8_t* target_current);
#endif
void apply_pretension(uint8_t* target_current);
void apply_cruise(uint8_t* target_current, uint8_t throttle_percent);
bool apply_throttle(uint8_t* target_current, uint8_t throttle_percent);
bool apply_speed_limit(uint8_t* target_current, uint8_t throttle_percent, bool pas_engaged, bool throttle_override);
bool apply_thermal_limit(uint8_t* target_current);
bool apply_low_voltage_limit(uint8_t* target_current);
bool apply_shift_sensor_interrupt(uint8_t* target_current);
bool apply_brake(uint8_t* target_current);
void apply_current_ramp_up(uint8_t* target_current, bool enable);
void apply_current_ramp_down(uint8_t* target_current, bool enable);
bool check_power_block();
void block_power_for(uint16_t ms);
void reload_assist_params();
uint16_t convert_wheel_speed_kph_to_rpm(uint8_t speed_kph);
void app_init()
{
motor_disable();
lights_disable();
lights_set(g_config.lights_mode == LIGHTS_MODE_ALWAYS_ON);
lvc_voltage_x100 = g_config.low_cut_off_v * 100u;
uint16_t full_voltage_range_x100 =
EXPAND_U16(g_config.max_battery_x100v_u16h, g_config.max_battery_x100v_u16l) - lvc_voltage_x100;
uint16_t padded_voltage_range_x100 = (uint16_t)(full_voltage_range_x100 *
(100 - BATTERY_FULL_OFFSET_PERCENT - BATTERY_EMPTY_OFFSET_PERCENT) / 100);
lvc_ramp_down_end_voltage_x100 = (uint16_t)(lvc_voltage_x100 +
(full_voltage_range_x100 * BATTERY_EMPTY_OFFSET_PERCENT / 100));
lvc_ramp_down_start_voltage_x100 = (uint16_t)(lvc_ramp_down_end_voltage_x100 +
((padded_voltage_range_x100 * LVC_RAMP_DOWN_OFFSET_PERCENT) / 100));
global_speed_limit_rpm = 0;
global_throttle_speed_limit_rpm_x10 = 0;
temperature_contr_c = 0;
temperature_motor_c = 0;
ramp_up_current_interval_ms = (g_config.max_current_amps * 10u) / g_config.current_ramp_amps_s;
power_blocked_until_ms = 0;
speed_limit_ramp_interval_rpm_x10 = convert_wheel_speed_kph_to_rpm(SPEED_LIMIT_RAMP_DOWN_INTERVAL_KPH) * 10;
pretension_cutoff_speed_rpm_x10 = convert_wheel_speed_kph_to_rpm(g_config.pretension_speed_cutoff_kph) * 10;
cruise_paused = true;
operation_mode = OPERATION_MODE_DEFAULT;
app_set_wheel_max_speed_rpm(convert_wheel_speed_kph_to_rpm(g_config.max_speed_kph));
app_set_assist_level(g_config.assist_startup_level);
reload_assist_params();
if (g_config.assist_mode_select == ASSIST_MODE_SELECT_BRAKE_BOOT && brake_is_activated())
{
app_set_operation_mode(OPERATION_MODE_SPORT);
}
}
void app_process()
{
uint8_t target_current = 0;
uint8_t target_cadence = assist_level_data.level.max_cadence_percent;
uint8_t throttle_percent = throttle_map_response(throttle_read());
bool pas_engaged = false;
bool throttle_override = false;
if (check_power_block())
{
target_current = 0;
}
else if (assist_level == ASSIST_PUSH && g_config.use_push_walk)
{
target_current = 10;
}
else
{
apply_pretension(&target_current);
apply_pas_cadence(&target_current, throttle_percent);
#if HAS_TORQUE_SENSOR
apply_pas_torque(&target_current);
#endif // HAS_TORQUE_SENSOR
pas_engaged = target_current > 0;
apply_cruise(&target_current, throttle_percent);
throttle_override = apply_throttle(&target_current, throttle_percent);
// override target cadence if configured in assist level
if (throttle_override &&
(assist_level_data.level.flags & ASSIST_FLAG_PAS) &&
(assist_level_data.level.flags & ASSIST_FLAG_OVERRIDE_CADENCE))
{
target_cadence = THROTTLE_CADENCE_OVERRIDE_PERCENT;
}
}
bool speed_limiting = apply_speed_limit(&target_current, throttle_percent, pas_engaged, throttle_override);
bool thermal_limiting = apply_thermal_limit(&target_current);
bool lvc_limiting = apply_low_voltage_limit(&target_current);
bool shift_limiting =
#if HAS_SHIFT_SENSOR_SUPPORT
apply_shift_sensor_interrupt(&target_current);
#else
false;
#endif
bool is_limiting = speed_limiting || thermal_limiting || lvc_limiting || shift_limiting;
bool is_braking = apply_brake(&target_current);
apply_current_ramp_up(&target_current, is_limiting || !throttle_override);
apply_current_ramp_down(&target_current, !is_braking && !shift_limiting);
motor_set_target_speed(target_cadence);
motor_set_target_current(target_current);
if (target_current > 0)
{
motor_enable();
}
else
{
motor_disable();
}
if (g_config.lights_mode == LIGHTS_MODE_DISABLED /*|| (motor_status() & MOTOR_ERROR_LVC) */)
{
lights_disable();
}
else
{
lights_enable();
}
}
void app_set_assist_level(uint8_t level)
{
if (assist_level != level)
{
if (assist_level == ASSIST_PUSH && g_config.use_push_walk)
{
// When releasig push walk mode pedals may have been rotating
// with the motor, block motor power for 2 seconds to prevent PAS
// sensor from incorrectly applying power if returning to a PAS level.
block_power_for(1000);
}
assist_level = level;
eventlog_write_data(EVT_DATA_ASSIST_LEVEL, assist_level);
reload_assist_params();
}
}
void app_set_lights(bool on)
{
if ( // it's ok to write ugly code if you say it's ugly...
(g_config.assist_mode_select == ASSIST_MODE_SELECT_LIGHTS) ||
(assist_level == ASSIST_0 && g_config.assist_mode_select == ASSIST_MODE_SELECT_PAS0_LIGHT) ||
(assist_level == ASSIST_1 && g_config.assist_mode_select == ASSIST_MODE_SELECT_PAS1_LIGHT) ||
(assist_level == ASSIST_2 && g_config.assist_mode_select == ASSIST_MODE_SELECT_PAS2_LIGHT) ||
(assist_level == ASSIST_3 && g_config.assist_mode_select == ASSIST_MODE_SELECT_PAS3_LIGHT) ||
(assist_level == ASSIST_4 && g_config.assist_mode_select == ASSIST_MODE_SELECT_PAS4_LIGHT) ||
(assist_level == ASSIST_5 && g_config.assist_mode_select == ASSIST_MODE_SELECT_PAS5_LIGHT) ||
(assist_level == ASSIST_6 && g_config.assist_mode_select == ASSIST_MODE_SELECT_PAS6_LIGHT) ||
(assist_level == ASSIST_7 && g_config.assist_mode_select == ASSIST_MODE_SELECT_PAS7_LIGHT) ||
(assist_level == ASSIST_8 && g_config.assist_mode_select == ASSIST_MODE_SELECT_PAS8_LIGHT) ||
(assist_level == ASSIST_9 && g_config.assist_mode_select == ASSIST_MODE_SELECT_PAS9_LIGHT)
)
{
if (on)
{
app_set_operation_mode(OPERATION_MODE_SPORT);
}
else
{
app_set_operation_mode(OPERATION_MODE_DEFAULT);
}
}
else
{
if (g_config.lights_mode == LIGHTS_MODE_DEFAULT && lights_state != on)
{
lights_state = on;
eventlog_write_data(EVT_DATA_LIGHTS, on);
lights_set(on);
}
}
}
void app_set_operation_mode(uint8_t mode)
{
if (operation_mode != mode)
{
operation_mode = mode;
eventlog_write_data(EVT_DATA_OPERATION_MODE, operation_mode);
reload_assist_params();
}
}
void app_set_wheel_max_speed_rpm(uint16_t value)
{
if (global_speed_limit_rpm != value)
{
global_speed_limit_rpm = value;
global_throttle_speed_limit_rpm_x10 = ((int32_t)global_speed_limit_rpm *
g_config.throttle_global_spd_lim_percent) / 10;
eventlog_write_data(EVT_DATA_WHEEL_SPEED_PPM, value);
reload_assist_params();
}
}
uint8_t app_get_assist_level()
{
return assist_level;
}
uint8_t app_get_lights()
{
return lights_state;
}
uint8_t app_get_status_code()
{
uint16_t motor = motor_status();
if (motor & MOTOR_ERROR_HALL_SENSOR)
{
return STATUS_ERROR_HALL_SENSOR;
}
if (motor & MOTOR_ERROR_CURRENT_SENSE)
{
return STATUS_ERROR_CURRENT_SENSE;
}
if (motor & MOTOR_ERROR_POWER_RESET)
{
// Phase line error code reused, cause and meaning
// of MOTOR_ERROR_POWER_RESET triggered on bbs02 is currently unknown
return STATUS_ERROR_PHASE_LINE;
}
if (!throttle_ok())
{
return STATUS_ERROR_THROTTLE;
}
if (!torque_sensor_ok())
{
return STATUS_ERROR_TORQUE_SENSOR;
}
if (temperature_motor_c > MAX_TEMPERATURE)
{
return STATUS_ERROR_MOTOR_OVER_TEMP;
}
if (temperature_contr_c > MAX_TEMPERATURE)
{
return STATUS_ERROR_CONTROLLER_OVER_TEMP;
}
// Disable LVC error since it is not shown on display in original firmware
// Uncomment if you want to enable
// if (motor & MOTOR_ERROR_LVC)
// {
// return STATUS_ERROR_LVC;
// }
if (brake_is_activated())
{
return STATUS_BRAKING;
}
return STATUS_NORMAL;
}
uint8_t app_get_temperature()
{
int8_t temp_max = MAX(temperature_contr_c, temperature_motor_c);
if (temp_max < 0)
{
return 0;
}
return (uint8_t)temp_max;
}
void apply_pretension(uint8_t* target_current)
{
uint16_t current_speed_rpm_x10 = speed_sensor_get_rpm_x10();
if (g_config.use_speed_sensor && g_config.use_pretension && current_speed_rpm_x10 > pretension_cutoff_speed_rpm_x10)
{
*target_current = 1;
}
return;
}
void apply_pas_cadence(uint8_t* target_current, uint8_t throttle_percent)
{
if ((assist_level_data.level.flags & ASSIST_FLAG_PAS) && !(assist_level_data.level.flags & ASSIST_FLAG_PAS_TORQUE))
{
if (pas_is_pedaling_forwards() && pas_get_pulse_counter() > g_config.pas_start_delay_pulses)
{
if (assist_level_data.level.flags & ASSIST_FLAG_PAS_VARIABLE)
{
uint8_t current = (uint8_t)MAP16(throttle_percent, 0, 100, 0, assist_level_data.level.target_current_percent);
if (current > *target_current)
{
*target_current = current;
}
}
else
{
if (assist_level_data.level.target_current_percent > *target_current)
{
*target_current = assist_level_data.level.target_current_percent;
}
// apply "keep current" ramp
if (g_config.pas_keep_current_percent < 100)
{
if (*target_current > assist_level_data.keep_current_target_percent &&
pas_get_cadence_rpm_x10() > assist_level_data.keep_current_ramp_start_rpm_x10)
{
uint32_t cadence = MIN(pas_get_cadence_rpm_x10(), assist_level_data.keep_current_ramp_end_rpm_x10);
// ramp down current towards keep_current_target_percent with rpm above keep_current_ramp_start_rpm_x10
*target_current = MAP32(
cadence, // in
assist_level_data.keep_current_ramp_start_rpm_x10, // in_min
assist_level_data.keep_current_ramp_end_rpm_x10, // in_max
*target_current, // out_min
assist_level_data.keep_current_target_percent); // out_max
}
}
}
}
}
}
#if HAS_TORQUE_SENSOR
void apply_pas_torque(uint8_t* target_current)
{
if ((assist_level_data.level.flags & ASSIST_FLAG_PAS) && (assist_level_data.level.flags & ASSIST_FLAG_PAS_TORQUE))
{
if (pas_is_pedaling_forwards() && (pas_get_pulse_counter() > g_config.pas_start_delay_pulses || speed_sensor_is_moving()))
{
uint16_t torque_nm_x100 = torque_sensor_get_nm_x100();
uint16_t cadence_rpm_x10 = pas_get_cadence_rpm_x10();
if (cadence_rpm_x10 < TORQUE_POWER_LOWER_RPM_X10)
{
cadence_rpm_x10 = TORQUE_POWER_LOWER_RPM_X10;
}
uint16_t pedal_power_w_x10 = (uint16_t)(((uint32_t)torque_nm_x100 * cadence_rpm_x10) / 955);
// used in division below to calculate target current,
// clamp to 24V if no reading available (unexpected error).
uint16_t battery_voltage_x10 = MAX(motor_get_battery_voltage_x10(), 240);
uint16_t target_current_amp_x100 = (uint16_t)(((uint32_t)10 * pedal_power_w_x10 *
assist_level_data.level.torque_amplification_factor_x10) / battery_voltage_x10);
uint16_t max_current_amp_x100 = g_config.max_current_amps * 100;
// limit target to ensure no overflow in map result
if (target_current_amp_x100 > max_current_amp_x100)
{
target_current_amp_x100 = max_current_amp_x100;
}
uint8_t tmp_percent = (uint8_t)MAP32(target_current_amp_x100, 0, max_current_amp_x100, 0, 100);
// minimum 1 percent current if pedaling
if (tmp_percent < 1)
{
tmp_percent = 1;
}
// limit to maximum assist current for set level
else if (tmp_percent > assist_level_data.level.target_current_percent)
{
tmp_percent = assist_level_data.level.target_current_percent;
}
if (tmp_percent > *target_current)
{
*target_current = tmp_percent;
}
}
}
}
#endif
void apply_cruise(uint8_t* target_current, uint8_t throttle_percent)
{
static bool cruise_block_throttle_return = false;
if ((assist_level_data.level.flags & ASSIST_FLAG_CRUISE) && throttle_ok())
{
// pause cruise if brake activated
if (brake_is_activated())
{
cruise_paused = true;
cruise_block_throttle_return = true;
}
// pause cruise if started pedaling backwards
else if (pas_is_pedaling_backwards() && pas_get_pulse_counter() > CRUISE_DISENGAGE_PAS_PULSES)
{
cruise_paused = true;
cruise_block_throttle_return = true;
}
// pause cruise if throttle touched while cruise active
else if (!cruise_paused && !cruise_block_throttle_return && throttle_percent > 0)
{
cruise_paused = true;
cruise_block_throttle_return = true;
}
// unpause cruise if pedaling forward while engaging throttle > 50%
else if (cruise_paused && !cruise_block_throttle_return && throttle_percent > 50 && pas_is_pedaling_forwards() && pas_get_pulse_counter() > CRUISE_ENGAGE_PAS_PULSES)
{
cruise_paused = false;
cruise_block_throttle_return = true;
}
// reset flag tracking throttle to make sure throttle returns to idle position before engage/disenage cruise with throttle touch
else if (cruise_block_throttle_return && throttle_percent == 0)
{
cruise_block_throttle_return = false;
}
if (cruise_paused)
{
*target_current = 0;
}
else
{
if (assist_level_data.level.target_current_percent > *target_current)
{
*target_current = assist_level_data.level.target_current_percent;
}
}
}
}
bool apply_throttle(uint8_t* target_current, uint8_t throttle_percent)
{
if ((assist_level_data.level.flags & ASSIST_FLAG_THROTTLE) && throttle_percent > 0 && throttle_ok())
{
uint8_t current = (uint8_t)MAP16(throttle_percent, 0, 100, g_config.throttle_start_percent, assist_level_data.level.max_throttle_current_percent);
if (current >= *target_current)
{
*target_current = current;
return true;
}
}
return false;
}
bool apply_speed_limit(uint8_t* target_current, uint8_t throttle_percent, bool pas_engaged, bool throttle_override)
{
static bool speed_limiting = false;
if (!g_config.use_speed_sensor)
{
return false;
}
// global throttle speed limit applies if enabled in configuration, PAS is not engaged and throttle is used
bool global_throttle_limit_active =
!pas_engaged &&
throttle_percent > 0 &&
g_config.throttle_global_spd_lim_percent > 0 &&
(
g_config.throttle_global_spd_lim_opt == THROTTLE_GLOBAL_SPEED_LIMIT_ENABLED ||
(g_config.throttle_global_spd_lim_opt == THROTTLE_GLOBAL_SPEED_LIMIT_STD_LVLS && operation_mode == OPERATION_MODE_DEFAULT)
);
bool throttle_speed_override_active = !global_throttle_limit_active && throttle_override &&
(assist_level_data.level.flags & ASSIST_FLAG_PAS) &&
(assist_level_data.level.flags & ASSIST_FLAG_OVERRIDE_SPEED);
int32_t max_speed_rpm_x10;
if (global_throttle_limit_active)
{
// use configured global throttle override speed limit
max_speed_rpm_x10 = global_throttle_speed_limit_rpm_x10;
}
else if (throttle_speed_override_active)
{
// override assist level speed limit to global speed limit
max_speed_rpm_x10 = global_speed_limit_rpm * 10;
}
else
{
// normal operation, use configured assist level speed limit
max_speed_rpm_x10 = assist_level_data.max_wheel_speed_rpm_x10;
}
int32_t max_speed_ramp_low_rpm_x10 = max_speed_rpm_x10 - speed_limit_ramp_interval_rpm_x10;
int32_t max_speed_ramp_high_rpm_x10 = max_speed_rpm_x10 + speed_limit_ramp_interval_rpm_x10;
if (max_speed_rpm_x10 > 0)
{
int16_t current_speed_rpm_x10 = speed_sensor_get_rpm_x10();
if (current_speed_rpm_x10 < max_speed_ramp_low_rpm_x10)
{
// no limiting
if (speed_limiting)
{
speed_limiting = false;
eventlog_write_data(EVT_DATA_SPEED_LIMITING, 0);
}
}
else
{
if (!speed_limiting)
{
speed_limiting = true;
eventlog_write_data(EVT_DATA_SPEED_LIMITING, 1);
}
if (current_speed_rpm_x10 > max_speed_ramp_high_rpm_x10)
{
if (*target_current > 1)
{
*target_current = 1;
return true;
}
}
else
{
// linear ramp down when approaching max speed.
uint8_t tmp = (uint8_t)MAP32(current_speed_rpm_x10, max_speed_ramp_low_rpm_x10, max_speed_ramp_high_rpm_x10, *target_current, 1);
if (*target_current > tmp)
{
*target_current = tmp;
return true;
}
}
}
}
return false;
}
bool apply_thermal_limit(uint8_t* target_current)
{
static uint32_t next_log_temp_ms = 10000;
static bool temperature_limiting = false;
int16_t temp_contr_x100 = temperature_contr_x100();
temperature_contr_c = temp_contr_x100 / 100;
int16_t temp_motor_x100 = temperature_motor_x100();
temperature_motor_c = temp_motor_x100 / 100;
int16_t max_temp_x100 = MAX(temp_contr_x100, temp_motor_x100);
int8_t max_temp = MAX(temperature_contr_c, temperature_motor_c);
if (eventlog_is_enabled() && g_config.use_temperature_sensor && system_ms() > next_log_temp_ms)
{
next_log_temp_ms = system_ms() + 10000;
eventlog_write_data(EVT_DATA_TEMPERATURE, (uint16_t)temperature_motor_c << 8 | temperature_contr_c);
}
if (max_temp >= (MAX_TEMPERATURE - MAX_TEMPERATURE_RAMP_DOWN_INTERVAL))
{
if (!temperature_limiting)
{
temperature_limiting = true;
eventlog_write_data(EVT_DATA_THERMAL_LIMITING, 1);
}
if (max_temp_x100 > MAX_TEMPERATURE * 100)
{
max_temp_x100 = MAX_TEMPERATURE * 100;
}
uint8_t tmp = (uint8_t)MAP32(
max_temp_x100, // value
(MAX_TEMPERATURE - MAX_TEMPERATURE_RAMP_DOWN_INTERVAL) * 100, // in_min
MAX_TEMPERATURE * 100, // in_max
100, // out_min
MAX_TEMPERATURE_LOW_CURRENT_PERCENT // out_max
);
if (*target_current > tmp)
{
*target_current = tmp;
return true;
}
}
else
{
if (temperature_limiting)
{
temperature_limiting = false;
eventlog_write_data(EVT_DATA_THERMAL_LIMITING, 0);
}
}
return false;
}
bool apply_low_voltage_limit(uint8_t* target_current)
{
static uint32_t next_log_volt_ms = 10000;
static bool lvc_limiting = false;
static uint32_t next_voltage_reading_ms = 125;
static int32_t flt_min_bat_volt_x100 = 100 * 100;
if (system_ms() > next_voltage_reading_ms)
{
next_voltage_reading_ms = system_ms() + 125;
int32_t voltage_reading_x100 = motor_get_battery_voltage_x10() * 10ul;
if (voltage_reading_x100 < flt_min_bat_volt_x100)
{
flt_min_bat_volt_x100 = EXPONENTIAL_FILTER(flt_min_bat_volt_x100, voltage_reading_x100, 8);
}
if (eventlog_is_enabled() && system_ms() > next_log_volt_ms)
{
next_log_volt_ms = system_ms() + 10000;
eventlog_write_data(EVT_DATA_VOLTAGE, (uint16_t)voltage_reading_x100);
}
}
uint16_t voltage_x100 = flt_min_bat_volt_x100;
if (voltage_x100 <= lvc_ramp_down_start_voltage_x100)
{
if (!lvc_limiting)
{
eventlog_write_data(EVT_DATA_LVC_LIMITING, voltage_x100);
lvc_limiting = true;
}
if (voltage_x100 < lvc_voltage_x100)
{
voltage_x100 = lvc_voltage_x100;
}
// Ramp down power until LVC_LOW_CURRENT_PERCENT when approaching LVC
uint8_t tmp = (uint8_t)MAP32(
voltage_x100, // value
lvc_ramp_down_end_voltage_x100, // in_min
lvc_ramp_down_start_voltage_x100, // in_max
LVC_LOW_CURRENT_PERCENT, // out_min
100 // out_max
);
if (*target_current > tmp)
{
*target_current = tmp;
return true;
}
}
return false;
}
#if HAS_SHIFT_SENSOR_SUPPORT
bool apply_shift_sensor_interrupt(uint8_t* target_current)
{
static uint32_t shift_sensor_act_ms = 0;
static bool shift_sensor_last = false;
static bool shift_sensor_interrupting = false;
static bool shift_sensor_logged = false;
// Exit immediately if shift interrupts disabled.
if (!g_config.use_shift_sensor)
{
return false;
}
bool active = shift_sensor_is_activated();
if (active)
{
// Check for new pulse from the gear sensor during shift interrupt
if (!shift_sensor_last && shift_sensor_interrupting)
{
// Consecutive gear change, do restart.
shift_sensor_interrupting = false;
}
if (!shift_sensor_interrupting)
{
uint16_t duration_ms = EXPAND_U16(
g_config.shift_interrupt_duration_ms_u16h,
g_config.shift_interrupt_duration_ms_u16l
);
shift_sensor_act_ms = system_ms() + duration_ms;
shift_sensor_interrupting = true;
}
shift_sensor_last = true;
}
else
{
shift_sensor_last = false;
}
if (!shift_sensor_interrupting)
{
return false;
}
if (system_ms() >= shift_sensor_act_ms)
{
// Shift is finished, reset function state.
shift_sensor_interrupting = false;
// Logging is skipped, unless current has been clamped during shift interrupt.
if (shift_sensor_logged)
{
shift_sensor_logged = false;
eventlog_write_data(EVT_DATA_SHIFT_SENSOR, 0);
}
return false;
}
if ((*target_current) > g_config.shift_interrupt_current_threshold_percent)
{
if (!shift_sensor_logged)
{
// Logging only once per shifting interrupt.
shift_sensor_logged = true;
eventlog_write_data(EVT_DATA_SHIFT_SENSOR, 1);
}
// Set target current based on desired current threshold during shift.
*target_current = g_config.shift_interrupt_current_threshold_percent;
return true;
}
return false;
}
#endif
bool apply_brake(uint8_t* target_current)
{
bool is_braking = brake_is_activated();
if (g_config.lights_mode == LIGHTS_MODE_BRAKE_LIGHT)
{
lights_set(is_braking);
}
if (is_braking)
{
*target_current = 0;
}
return is_braking;
}
void apply_current_ramp_up(uint8_t* target_current, bool enable)
{
static uint8_t ramp_up_target_current = 0;
static uint32_t last_ramp_up_increment_ms = 0;
if (enable && *target_current > ramp_up_target_current)
{
uint32_t now = system_ms();
uint16_t time_diff = now - last_ramp_up_increment_ms;
if (time_diff >= ramp_up_current_interval_ms)
{
++ramp_up_target_current;
if (last_ramp_up_increment_ms == 0)
{
last_ramp_up_increment_ms = now;
}
else
{
// offset for time overshoot to not accumulate large ramp error
last_ramp_up_increment_ms = now - (uint8_t)(time_diff - ramp_up_current_interval_ms);
}
}
*target_current = ramp_up_target_current;
}
else
{
ramp_up_target_current = *target_current;
last_ramp_up_increment_ms = 0;
}
}
void apply_current_ramp_down(uint8_t* target_current, bool enable)
{
static uint8_t ramp_down_target_current = 0;
static uint32_t last_ramp_down_decrement_ms = 0;
// apply fast ramp down if coming from high target current (> 50%)
if (enable && *target_current < ramp_down_target_current)
{
uint32_t now = system_ms();
uint16_t time_diff = now - last_ramp_down_decrement_ms;
if (time_diff >= 10)
{
uint8_t diff = ramp_down_target_current - *target_current;
if (diff >= CURRENT_RAMP_DOWN_PERCENT_10MS)
{
ramp_down_target_current -= CURRENT_RAMP_DOWN_PERCENT_10MS;
}
else
{
ramp_down_target_current -= diff;
}
if (last_ramp_down_decrement_ms == 0)
{
last_ramp_down_decrement_ms = now;
}
else
{
// offset for time overshoot to not accumulate large ramp error
last_ramp_down_decrement_ms = now - (uint8_t)(time_diff - 10);
}
}
*target_current = ramp_down_target_current;
}
else
{
ramp_down_target_current = *target_current;
last_ramp_down_decrement_ms = 0;
}
}
bool check_power_block()
{
if (power_blocked_until_ms != 0)
{
// power block is active, check if time to release
if (system_ms() > power_blocked_until_ms)
{
power_blocked_until_ms = 0;
return false;
}
return true;
}
return false;
}
void block_power_for(uint16_t ms)
{
power_blocked_until_ms = system_ms() + ms;
}
void reload_assist_params()
{
if (assist_level < ASSIST_PUSH)
{
assist_level_data.level = g_config.assist_levels[operation_mode][assist_level];
assist_level_data.max_wheel_speed_rpm_x10 = ((int32_t)global_speed_limit_rpm * assist_level_data.level.max_speed_percent) / 10;
if (assist_level_data.level.flags & ASSIST_FLAG_PAS)
{
assist_level_data.keep_current_target_percent = (uint8_t)((uint16_t)g_config.pas_keep_current_percent * assist_level_data.level.target_current_percent / 100);
assist_level_data.keep_current_ramp_start_rpm_x10 = g_config.pas_keep_current_cadence_rpm * 10;
assist_level_data.keep_current_ramp_end_rpm_x10 = (uint16_t)(((uint32_t)assist_level_data.level.max_cadence_percent * MAX_CADENCE_RPM_X10) / 100);
}
// pause cruise if swiching level
cruise_paused = true;
}
// only apply push walk params if push walk is active in config,
// otherwise data of previous assist level is kept.
else if (assist_level == ASSIST_PUSH && g_config.use_push_walk)
{
assist_level_data.level.flags = 0;
assist_level_data.level.target_current_percent = 0;
assist_level_data.level.max_speed_percent = 0;
assist_level_data.level.max_cadence_percent = 15;
assist_level_data.level.max_throttle_current_percent = 0;
assist_level_data.max_wheel_speed_rpm_x10 = convert_wheel_speed_kph_to_rpm(WALK_MODE_SPEED_KPH) * 10;
}
}
uint16_t convert_wheel_speed_kph_to_rpm(uint8_t speed_kph)
{
float radius_mm = EXPAND_U16(g_config.wheel_size_inch_x10_u16h, g_config.wheel_size_inch_x10_u16l) * 1.27f; // g_config.wheel_size_inch_x10 / 2.f * 2.54f;
return (uint16_t)(25000.f / (3 * 3.14159f * radius_mm) * speed_kph);
}
================================================
FILE: src/firmware/app.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _APP_H_
#define _APP_H_
#include "intellisense.h"
#include
#include
#define ASSIST_0 0x00
#define ASSIST_1 0x01
#define ASSIST_2 0x02
#define ASSIST_3 0x03
#define ASSIST_4 0x04
#define ASSIST_5 0x05
#define ASSIST_6 0x06
#define ASSIST_7 0x07
#define ASSIST_8 0x08
#define ASSIST_9 0x09
#define ASSIST_PUSH 0x0A
#define OPERATION_MODE_DEFAULT 0x00
#define OPERATION_MODE_SPORT 0x01
// Matches status codes used by Bafang
#define STATUS_NORMAL 0x01
#define STATUS_BRAKING 0x03
#define STATUS_ERROR_THROTTLE_HIGH 0x04
#define STATUS_ERROR_THROTTLE 0x05
#define STATUS_ERROR_LVC 0x06
#define STATUS_ERROR_HIGH_VOLTAGE 0x07 // not implemented
#define STATUS_ERROR_HALL_SENSOR 0x08
#define STATUS_ERROR_PHASE_LINE 0x09
#define STATUS_ERROR_CONTROLLER_OVER_TEMP 0x10
#define STATUS_ERROR_MOTOR_OVER_TEMP 0x11
#define STATUS_ERROR_CURRENT_SENSE 0x12
#define STATUS_ERROR_BATTERY_TEMP_SENSOR 0x13 // n/a
#define STATUS_ERROR_MOTOR_TEMP_SENSOR 0x14 // not implemented
#define STATUS_ERROR_CONTROLLER_TEMP_SENSOR 0x15 // not implemented
#define STATUS_ERROR_SPEED_SENSOR 0x21 // not implemented
#define STATUS_ERROR_BMS_COMMUNICATION 0x22 // n/a
#define STATUS_ERROR_HEAD_LIGHT 0x23 // not implemented
#define STATUS_ERROR_HEAD_LIGHT_SENSOR 0x24 // not implemented
#define STATUS_ERROR_TORQUE_SENSOR 0x25
#define STATUS_ERROR_TORQUE_SPEED 0x26 // n/a
#define STATUS_ERROR_COMMUNICATION 0x30 // n/a
void app_init();
void app_process();
void app_set_assist_level(uint8_t level);
void app_set_lights(bool on);
void app_set_operation_mode(uint8_t mode);
void app_set_wheel_max_speed_rpm(uint16_t value);
uint8_t app_get_assist_level();
uint8_t app_get_lights();
uint8_t app_get_status_code();
uint8_t app_get_temperature();
#endif
================================================
FILE: src/firmware/battery.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "battery.h"
#include "motor.h"
#include "system.h"
#include "util.h"
#include "cfgstore.h"
#include "fwconfig.h"
static int16_t battery_empty_x100v;
static int16_t battery_full_x100v;
static uint8_t battery_percent;
static uint32_t motor_disabled_at_ms;
static bool first_reading_done;
/*
No attempt is made to have accurate battery state of charge display.
This is only a voltage based approch using configured max and min battery voltages.
The end values are padded 8% on each side (BATTERY_EMPTY_OFFSET_PERCENT, BATTERY_FULL_OFFSET_PERCENT).
Battery voltage is measured when no motor power has been applied for
at least 2 seconds (BATTERY_NO_LOAD_DELAY_MS). This is to mitigate measuring voltage sag
but is still problematic in cold weather.
Battery SOC percentage is calculated from measured voltage using linear interpolation
between the padded ranges.
The LVC rampdown starts at 10% battery SOC (LVC_RAMP_DOWN_OFFSET_PERCENT) and will linearly
ramp the current down to 20% (LVC_LOW_CURRENT_PERCENT) of the maximum configured current.
For example, if the maximum battery voltage is 58.8V and the low cutoff voltage is 42V, then:
- The full voltage range is 58.8V - 42V = 16.8V
- The padding amount is 0.08 * 16.8V = 1.3V
- The battery is considered at 100% SOC at 58.8V - 1.3V = 57.5V
- The battery is considered at 0% SOC at 42.0V + 1.3V = 43.3V
- LVC rampdown will start at 10% SOC, so: 43.3V + 0.1 * (57.5V - 43.3V) = 44.7V
- Full LVC limiting will occur at 0% SOC, so: 43.3V
*/
static uint8_t compute_battery_percent()
{
int16_t value_x100v = motor_get_battery_voltage_x10() * 10l;
int16_t percent = (int16_t)MAP32(value_x100v, battery_empty_x100v, battery_full_x100v, 0, 100);
return (uint8_t)CLAMP(percent, 0, 100);
}
#if (BATTERY_PERCENT_MAP == BATTERY_PERCENT_MAP_SW102)
static uint8_t map_percent_sw102(uint8_t percent)
{
// Measured on Display
// -----------------------
// 0bar 0-5
// 1bar 5 - 10
// 2bar 10 - 30
// 3bar 31 - 51
// 4bar 52 - 78
// 5bar 78 - 100
if (percent < 5) // 0bar
{
return 0;
}
else if (percent < 21) // 1bar
{
return 7;
}
else if (percent < 41) // 2bar
{
return 20;
}
else if (percent < 61) // 3bar
{
return 40;
}
else if (percent < 81) // 4bar
{
return 60;
}
else // 5bar
{
return 100;
}
}
#endif
void battery_init()
{
// default to 70% until first reading is available
battery_percent = 70;
motor_disabled_at_ms = 0;
first_reading_done = false;
uint16_t battery_min_voltage_x100v = g_config.low_cut_off_v * 100u;
uint16_t battery_max_voltage_x100v =
EXPAND_U16(g_config.max_battery_x100v_u16h, g_config.max_battery_x100v_u16l);
uint16_t battery_range_x100v = battery_max_voltage_x100v - battery_min_voltage_x100v;
battery_full_x100v = battery_max_voltage_x100v -
((BATTERY_FULL_OFFSET_PERCENT * battery_range_x100v) / 100);
battery_empty_x100v = battery_min_voltage_x100v +
((BATTERY_EMPTY_OFFSET_PERCENT * battery_range_x100v) / 100);
}
void battery_process()
{
if (!first_reading_done)
{
if (motor_get_battery_voltage_x10() > 0)
{
battery_percent = compute_battery_percent();
first_reading_done = true;
}
}
else
{
uint8_t target_current = motor_get_target_current();
if (motor_disabled_at_ms == 0 && target_current == 0)
{
motor_disabled_at_ms = system_ms();
}
else if (target_current > 0)
{
motor_disabled_at_ms = 0;
}
if (target_current == 0 && (system_ms() - motor_disabled_at_ms) > BATTERY_NO_LOAD_DELAY_MS)
{
battery_percent = compute_battery_percent();
}
}
}
uint8_t battery_get_percent()
{
return battery_percent;
}
uint8_t battery_get_mapped_percent()
{
#if (BATTERY_PERCENT_MAP == BATTERY_PERCENT_MAP_SW102)
return map_percent_sw102(battery_percent);
#else
return battery_percent;
#endif
}
================================================
FILE: src/firmware/battery.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _BATTERY_H_
#define _BATTERY_H_
#include
void battery_init();
void battery_process();
uint8_t battery_get_percent();
uint8_t battery_get_mapped_percent();
#endif
================================================
FILE: src/firmware/bbs-fw.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33205.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bbs-fw", "bbs-fw.vcxproj", "{1D7732D0-C5BC-4E67-9A24-EFF8000C007D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
BBS02|SDCC = BBS02|SDCC
BBSHD|SDCC = BBSHD|SDCC
TSDZ2|SDCC = TSDZ2|SDCC
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1D7732D0-C5BC-4E67-9A24-EFF8000C007D}.BBS02|SDCC.ActiveCfg = BBS02|x64
{1D7732D0-C5BC-4E67-9A24-EFF8000C007D}.BBS02|SDCC.Build.0 = BBS02|x64
{1D7732D0-C5BC-4E67-9A24-EFF8000C007D}.BBSHD|SDCC.ActiveCfg = BBSHD|x64
{1D7732D0-C5BC-4E67-9A24-EFF8000C007D}.BBSHD|SDCC.Build.0 = BBSHD|x64
{1D7732D0-C5BC-4E67-9A24-EFF8000C007D}.TSDZ2|SDCC.ActiveCfg = TSDZ2|x64
{1D7732D0-C5BC-4E67-9A24-EFF8000C007D}.TSDZ2|SDCC.Build.0 = TSDZ2|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2359A0E3-B5F4-4356-ACB7-0730EF01FF2F}
EndGlobalSection
EndGlobal
================================================
FILE: src/firmware/bbs-fw.vcxproj
================================================
BBS02x64BBSHDx64TSDZ2x6416.0{1D7732D0-C5BC-4E67-9A24-EFF8000C007D}Win32ProjMakefiletruev143Makefiletruev143Makefiletruev143make all TARGET_CONTROLLER=BBSHDbbs-fw.hexmake cleanmake clean
make all TARGET_CONTROLLER=BBSHDBBSHD;$(NMakePreprocessorDefinitions)C:/Program Files/SDCC/include;C:/Program Files/SDCC/include/mcs51;./$(SolutionDir)build\$(Platform)\$(Configuration)\make all TARGET_CONTROLLER=TSDZ2bbs-fw.hexmake cleanmake clean
make all TARGET_CONTROLLER=TSDZ2TSDZ2;$(NMakePreprocessorDefinitions)C:/Program Files/SDCC/include;./$(SolutionDir)build\$(Platform)\$(Configuration)\make all TARGET_CONTROLLER=BBS02bbs-fw.hexmake cleanmake clean
make all TARGET_CONTROLLER=BBS02BBS02;$(NMakePreprocessorDefinitions)C:/Program Files/SDCC/include;C:/Program Files/SDCC/include/mcs51;./$(SolutionDir)build\$(Platform)\$(Configuration)\
================================================
FILE: src/firmware/bbs-fw.vcxproj.filters
================================================
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx{93995380-89BD-4b04-88EB-625FBE52EBFB}h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms{3afcc16a-9b6d-48ec-8c37-3d76d5814243}{0753682d-650f-4c13-a2b2-7a748cc9fdee}Source FilesSource FilesSource FilesSource FilesSource FilesSource FilesSource FilesSource Files\bbsxSource Files\bbsxSource Files\bbsxSource Files\bbsxSource Files\bbsxSource Files\bbsxSource Files\tsdz2Source Files\tsdz2Source Files\tsdz2Source Files\bbsxSource Files\bbsxSource Files\bbsxSource Files\tsdz2Source Files\tsdz2Source Files\tsdz2Source Files\tsdz2Source Files\tsdz2Source Files\tsdz2Source Files\tsdz2Header FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesHeader FilesSource Files\bbsxSource Files\bbsxSource Files\bbsxSource Files\bbsxHeader FilesSource Files\tsdz2Header FilesSource Files\bbsxSource Files\bbsxSource Files\tsdz2Source Files\tsdz2Source Files\tsdz2Source Files\tsdz2Header Files
================================================
FILE: src/firmware/bbsx/adc.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "adc.h"
#include "bbsx/stc15.h"
#include "bbsx/pins.h"
static uint8_t next_channel;
static uint8_t no_adc_reading_counter;
static uint8_t throttle_value;
static uint16_t temperature_contr_value;
static uint16_t temperature_motor_value;
void adc_init()
{
// Setup pin voltage as high impedance input even though it is not used
SET_PIN_INPUT(PIN_VOLTAGE);
// Setup pin throttle as adc input
SET_PIN_INPUT(PIN_THROTTLE);
SET_PIN_LOW(PIN_THROTTLE);
SET_BIT(P1ASF, GET_PIN_NUM(PIN_THROTTLE));
// Setup pin controller temperature pin as adc input
SET_PIN_INPUT(PIN_TEMPERATURE_CONTR);
SET_PIN_LOW(PIN_TEMPERATURE_CONTR);
SET_BIT(P1ASF, GET_PIN_NUM(PIN_TEMPERATURE_CONTR));
#ifdef BBSHD
// Setup pin motor temperature pin as adc input
SET_PIN_INPUT(PIN_TEMPERATURE_MOTOR);
SET_PIN_LOW(PIN_TEMPERATURE_MOTOR);
SET_BIT(P1ASF, GET_PIN_NUM(PIN_TEMPERATURE_MOTOR));
#endif
ADC_RES = 0;
ADC_RESL = 0;
// Arrange adc result for 8bit reading
CLEAR_BIT(PCON2, 5);
ADC_CONTR = (uint8_t)((1 << 7));
no_adc_reading_counter = 0;
throttle_value = 0;
temperature_contr_value = 0;
temperature_motor_value = 0;
next_channel = GET_PIN_NUM(PIN_THROTTLE);
// throttle is read during init since a valid value must be
// needs to be available for fir throttle_process to not mess
// up safeguard logic
// enable adc power and read throttle
ADC_CONTR = (uint8_t)((1 << 7) | (1 << 3) | next_channel);
// wait for throttle reading and process
while (!IS_BIT_SET(ADC_CONTR, 4));
adc_process();
}
void adc_process()
{
// adc reading available
if (IS_BIT_SET(ADC_CONTR, 4))
{
no_adc_reading_counter = 0;
ADC_CONTR = (uint8_t)((1 << 7)); // Clear ADC_FLAG
switch (next_channel)
{
case GET_PIN_NUM(PIN_THROTTLE):
{
throttle_value = ADC_RES;
next_channel = GET_PIN_NUM(PIN_TEMPERATURE_CONTR);
break;
}
case GET_PIN_NUM(PIN_TEMPERATURE_CONTR):
{
temperature_contr_value = (((uint16_t)ADC_RES) << 2) | ADC_RESL;
#ifdef BBSHD
next_channel = GET_PIN_NUM(PIN_TEMPERATURE_MOTOR);
#else
next_channel = GET_PIN_NUM(PIN_THROTTLE);
#endif
break;
}
#ifdef BBSHD
case GET_PIN_NUM(PIN_TEMPERATURE_MOTOR):
{
temperature_motor_value = (((uint16_t)ADC_RES) << 2) | ADC_RESL;
next_channel = GET_PIN_NUM(PIN_THROTTLE);
break;
}
#endif
}
}
else if (++no_adc_reading_counter == 0)
{
// reinitialize adc
ADC_RES = 0;
ADC_CONTR = (uint8_t)(1 << 7);
no_adc_reading_counter = 0;
throttle_value = 0;
temperature_motor_value = 0;
temperature_contr_value = 0;
next_channel = GET_PIN_NUM(PIN_THROTTLE);
}
else
{
return;
}
// start next reading
ADC_RES = 0;
ADC_CONTR = (uint8_t)((1 << 7) | (1 << 3) | next_channel);
}
uint8_t adc_get_throttle()
{
return throttle_value;
}
uint16_t adc_get_torque()
{
return 0;
}
uint16_t adc_get_temperature_contr()
{
return temperature_contr_value;
}
uint16_t adc_get_temperature_motor()
{
return temperature_motor_value;
}
uint16_t adc_get_battery_voltage()
{
// not implemented, motor MCU sends adc battery voltage value
return 0;
}
================================================
FILE: src/firmware/bbsx/cpu.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _BBSX_CPU_H_
#define _BBSX_CPU_H_
#define CPU_FREQ 20000000L
#endif
================================================
FILE: src/firmware/bbsx/eeprom.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "eeprom.h"
#include "bbsx/stc15.h"
#define EEPROM_NUM_SECTORS 4
// STC chips has a special area in flash for eeprom.
#define EEPROM_STC_ADDRESS_OFFSET 0x0000
// IAP chips have no special area, same area as program
// memory and address space is the same. We define the last
// four sectors for eeprom usage ourself.
#define EEPROM_IAP_ADDRESS_OFFSET 0xEC00
#define IAP_CMD_IDLE 0
#define IAP_CMD_READ 1
#define IAP_CMD_PROGRAM 2
#define IAP_CMD_ERASE 3
#define IAP_ENABLE 0x82 // Wait time, CPU_FREQ < 20MHz
static uint16_t address_offset = 0x0000;
static uint16_t selected_sector_offset = 0;
static void eeprom_begin(uint8_t cmd, int offset)
{
IAP_CONTR = IAP_ENABLE;
IAP_CMD = cmd;
uint16_t addr = selected_sector_offset + offset;
IAP_ADDRH = addr >> 8;
IAP_ADDRL = addr;
}
static bool eeprom_trigger()
{
IAP_TRIG = 0x5a;
IAP_TRIG = 0xa5;
NOP();
return !IS_BIT_SET(IAP_CONTR, 4);
}
static void eeprom_end()
{
IAP_CONTR = 0;
IAP_CMD = 0;
IAP_TRIG = 0;
IAP_ADDRH = 0xff;
IAP_ADDRL = 0xff;
}
void eeprom_init()
{
// Detect if we are running on IAP or STC model dependeing on if
// we can read from IAP address offset which is outside eeprom
// address space on STC model.
address_offset = EEPROM_IAP_ADDRESS_OFFSET;
eeprom_select_page(0);
if (eeprom_read_byte(0) == -1)
{
address_offset = EEPROM_STC_ADDRESS_OFFSET;
}
}
bool eeprom_select_page(int page)
{
if (page >= 0 && page < EEPROM_NUM_SECTORS)
{
selected_sector_offset = address_offset + page * 512;
return true;
}
return false;
}
bool eeprom_erase_page()
{
bool res;
eeprom_begin(IAP_CMD_ERASE, 0);
res = eeprom_trigger();
eeprom_end();
return res;
}
int eeprom_read_byte(int offset)
{
int res = -1;
eeprom_begin(IAP_CMD_READ, offset);
if (eeprom_trigger())
{
res = IAP_DATA;
}
eeprom_end();
return res;
}
bool eeprom_write_byte(int offset, uint8_t value)
{
bool res;
eeprom_begin(IAP_CMD_PROGRAM, offset);
IAP_DATA = value;
res = eeprom_trigger();
eeprom_end();
return res;
}
bool eeprom_end_write()
{
return true;
}
================================================
FILE: src/firmware/bbsx/interrupt.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _BBSX_INTERRUPT_H_
#define _BBSX_INTERRUPT_H_
#include
#include "intellisense.h"
#define IRQ_TIMER0 1
#define IRQ_UART1 4
#define IRQ_UART2 8
INTERRUPT_USING(isr_timer0, IRQ_TIMER0, 1); // system.c
INTERRUPT_USING(isr_uart1, IRQ_UART1, 3); // uart.c
INTERRUPT_USING(isr_uart2, IRQ_UART2, 3); // uart.c
#endif
================================================
FILE: src/firmware/bbsx/lights.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "lights.h"
#include "bbsx/pins.h"
#include "bbsx/stc15.h"
void lights_init()
{
SET_PIN_OUTPUT(PIN_LIGHTS_POWER);
SET_PIN_OUTPUT(PIN_LIGHTS);
lights_disable();
lights_set(false);
}
void lights_enable()
{
// enable signal level is swapped on BBSHD vs BBS02...
#if defined(BBSHD)
SET_PIN_HIGH(PIN_LIGHTS_POWER);
#elif defined(BBS02)
SET_PIN_LOW(PIN_LIGHTS_POWER);
#endif
}
void lights_disable()
{
// enable signal level is swapped on BBSHD vs BBS02...
#if defined(BBSHD)
SET_PIN_LOW(PIN_LIGHTS_POWER);
#elif defined(BBS02)
SET_PIN_HIGH(PIN_LIGHTS_POWER);
#endif
}
void lights_set(bool on)
{
if (on)
{
SET_PIN_LOW(PIN_LIGHTS);
}
else
{
SET_PIN_HIGH(PIN_LIGHTS);
}
}
================================================
FILE: src/firmware/bbsx/motor.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "motor.h"
#include "sensors.h"
#include "system.h"
#include "eventlog.h"
#include "bbsx/uart_motor.h"
#include "bbsx/pins.h"
#include
#define OPCODE_LVC 0x60
#define OPCODE_MAX_CURRENT 0x61
#define OPCODE_TARGET_SPEED 0x63
#define OPCODE_TARGET_CURRENT 0x64
#define OPCODE_HELLO 0x67
#define OPCODE_UNKNOWN1 0x68
#define OPCODE_UNKNOWN2 0x69
#define OPCODE_UNKNOWN3 0x6A
#define OPCODE_UNKNOWN4 0x6B
#define OPCODE_UNKNOWN5 0x6C
#define OPCODE_UNKNOWN5 0x6C
#define OPCODE_UNKNOWN6 0x6D
#define OPCODE_UNKNOWN7 0x6E
#define OPCODE_READ_STATUS 0x40
#define OPCODE_READ_CURRENT 0x41
#define OPCODE_READ_VOLTAGE 0x42
#define READ_TIMEOUT 100
#if defined(BBSHD)
#define ADC_STEPS_PER_AMP_X10 69
#define ADC_STEPS_PER_VOLT_X100 1490 // 1460 in orginal firmware
#elif defined(BBS02)
#define ADC_STEPS_PER_AMP_X10 56
#define ADC_STEPS_PER_VOLT_X100 1510
#endif
#define SPEED_STEPS 250
// async om state machine
#define COM_STATE_IDLE 0x01
#define COM_STATE_WAIT_RESPONSE 0x02
#define COM_STATE_SET_CURRENT 0x03
#define COM_STATE_SET_SPEED 0x04
#define COM_STATE_READ_STATUS 0x05
#define COM_STATE_READ_CURRENT 0x06
#define COM_STATE_READ_VOLTAGE 0x07
#define MSGBUF_SIZE 8
static uint8_t is_connected;
static uint8_t msgbuf[MSGBUF_SIZE];
static bool target_speed_changed;
static uint8_t target_speed;
static bool target_current_changed;
static uint8_t target_current;
static uint16_t adc_steps_per_volt_x100;
static uint16_t lvc_volt_x10;
static uint16_t status_flags;
static uint16_t battery_volt_x10;
static uint16_t battery_adc_steps;
static uint16_t battery_amp_x10;
// state machine state
static uint8_t com_state;
static uint8_t last_sent_opcode;
static uint32_t last_request_write_ms;
static uint32_t last_status_read_ms;
static uint8_t next_status_read_opcode;
static uint8_t compute_checksum(uint8_t* msg, uint8_t len);
static void send_request(uint8_t opcode, uint16_t data);
static void send_request_async(uint8_t opcode, uint16_t data);
static int read_response(uint8_t opcode, uint16_t* out_data);
static int try_read_response(uint8_t opcode, uint16_t* out_data);
static int connect();
static int configure(uint16_t max_current_mA, uint8_t lvc_V);
static void process_com_state_machine();
void motor_pre_init()
{
SET_PIN_OUTPUT(PIN_MOTOR_POWER_ENABLE);
SET_PIN_OUTPUT(PIN_MOTOR_CONTROL_ENABLE);
SET_PIN_OUTPUT(PIN_MOTOR_EXTRA);
SET_PIN_LOW(PIN_MOTOR_POWER_ENABLE);
SET_PIN_HIGH(PIN_MOTOR_CONTROL_ENABLE);
SET_PIN_HIGH(PIN_MOTOR_EXTRA);
}
void motor_init(uint16_t max_current_mA, uint8_t lvc_V, int16_t adc_calib_volt_steps_x100)
{
motor_pre_init();
is_connected = 0;
target_speed_changed = false;
target_speed = 0;
target_current_changed = false;
target_current = 0;
status_flags = 0;
adc_steps_per_volt_x100 = ADC_STEPS_PER_VOLT_X100 + adc_calib_volt_steps_x100;
lvc_volt_x10 = (uint16_t)lvc_V * 10;
battery_volt_x10 = 0;
battery_adc_steps = 0;
battery_amp_x10 = 0;
com_state = COM_STATE_IDLE;
last_sent_opcode = 0;
last_request_write_ms = 0;
last_status_read_ms = 0;
next_status_read_opcode = OPCODE_READ_STATUS;
uart_motor_open(4800);
// Give other MCU time to power on
while (system_ms() < 100);
if (connect() && configure(max_current_mA, lvc_V))
{
is_connected = 1;
eventlog_write(EVT_MSG_MOTOR_INIT_OK);
motor_set_target_speed(0);
motor_set_target_current(0);
target_current_changed = true;
target_speed_changed = true;
}
else
{
eventlog_write(EVT_ERROR_INIT_MOTOR);
}
}
void motor_process()
{
if (!is_connected)
{
return;
}
process_com_state_machine();
}
void motor_enable()
{
SET_PIN_HIGH(PIN_MOTOR_POWER_ENABLE);
}
void motor_disable()
{
if (!brake_is_activated())
{
// Brake signal is also connected to motor control MCU.
// If we disable motor power here during braking it causes
// a small issue where change in target current is not accepted
// while in disabled state. This will result in a short power spike
// when brake eventually released.
SET_PIN_LOW(PIN_MOTOR_POWER_ENABLE);
}
}
uint16_t motor_status()
{
return status_flags;
}
uint8_t motor_get_target_speed()
{
return target_speed;
}
uint8_t motor_get_target_current()
{
return target_current;
}
void motor_set_target_speed(uint8_t percent)
{
if (percent > 100)
{
percent = 100;
}
if (target_speed != percent)
{
target_speed = percent;
target_speed_changed = true;
}
}
void motor_set_target_current(uint8_t percent)
{
if (percent > 100)
{
percent = 100;
}
if (target_current != percent)
{
target_current = percent;
target_current_changed = true;
}
}
int16_t motor_calibrate_battery_voltage(uint16_t actual_voltage_x100)
{
int16_t diff = 0;
if (actual_voltage_x100 != 0)
{
uint16_t calibrated_adc_steps_volt_x100 = (uint16_t)(((uint32_t)battery_adc_steps * 10000u) / actual_voltage_x100);
diff = calibrated_adc_steps_volt_x100 - ADC_STEPS_PER_VOLT_X100;
adc_steps_per_volt_x100 = calibrated_adc_steps_volt_x100;
}
else
{
// reset calibration if 0 is received
adc_steps_per_volt_x100 = ADC_STEPS_PER_VOLT_X100;
diff = 0;
}
eventlog_write_data(EVT_DATA_CALIBRATE_VOLTAGE, adc_steps_per_volt_x100);
return diff;
}
uint16_t motor_get_battery_lvc_x10()
{
return lvc_volt_x10;
}
uint16_t motor_get_battery_current_x10()
{
return battery_amp_x10;
}
uint16_t motor_get_battery_voltage_x10()
{
return battery_volt_x10;
}
static uint8_t compute_checksum(uint8_t* msg, uint8_t len)
{
uint8_t checksum = 0;
for (int i = 0; i < len; ++i)
{
checksum += *(msg + i);
}
return checksum;
}
static void send_request(uint8_t opcode, uint16_t data)
{
// empty rx buffer
while (uart_motor_available()) uart_motor_read();
send_request_async(opcode, data);
uart_motor_flush();
}
static void send_request_async(uint8_t opcode, uint16_t data)
{
uint8_t idx = 0;
msgbuf[idx++] = 0xaa; // start of message
msgbuf[idx++] = opcode;
if (opcode == OPCODE_LVC)
{
msgbuf[idx++] = data >> 8;
msgbuf[idx++] = data;
}
else if (opcode != OPCODE_READ_STATUS && opcode != OPCODE_READ_CURRENT && opcode != OPCODE_READ_VOLTAGE)
{
msgbuf[idx++] = data;
}
uint8_t checksum = compute_checksum(msgbuf + 1, idx - 1);
msgbuf[idx++] = checksum;
for (uint8_t i = 0; i < idx; ++i)
{
uart_motor_write(msgbuf[i]);
}
}
static int read_response(uint8_t opcode, uint16_t* out_data)
{
uint32_t end = system_ms() + READ_TIMEOUT;
uint8_t len = (opcode == OPCODE_LVC || opcode == OPCODE_READ_STATUS || opcode == OPCODE_READ_VOLTAGE) ? 5 : 4;
uint8_t i = 0;
while (i < len && system_ms() < end)
{
if (uart_motor_available())
{
msgbuf[i++] = uart_motor_read();
}
}
if (i == len && msgbuf[1] == opcode)
{
uint8_t checksum = compute_checksum(&msgbuf[1], (uint8_t)(i - 2));
if (checksum == msgbuf[i - 1])
{
if (out_data != 0)
{
if (opcode == OPCODE_LVC || opcode == OPCODE_READ_STATUS || opcode == OPCODE_READ_VOLTAGE)
{
*out_data = msgbuf[2] << 8 | msgbuf[3];
}
else
{
*out_data = msgbuf[2];
}
}
return 1;
}
return 0; // failed to verify message
}
// read failure
return 0;
}
static int try_read_response(uint8_t opcode, uint16_t* out_data)
{
uint8_t len = (opcode == OPCODE_LVC || opcode == OPCODE_READ_STATUS || opcode == OPCODE_READ_VOLTAGE) ? 5 : 4;
uint8_t i = 0;
while (uart_motor_available() && i < MSGBUF_SIZE)
{
msgbuf[i++] = uart_motor_read();
}
// clear anything that could be left in rxbuffer in case of error.
while (uart_motor_available()) uart_motor_read();
if (i < len)
{
// failed to read entire response
return 0;
}
if (i == len && msgbuf[1] == opcode)
{
uint8_t checksum = compute_checksum(&msgbuf[1], (uint8_t)(i - 2));
if (checksum == msgbuf[i - 1])
{
if (out_data != 0)
{
if (opcode == OPCODE_LVC || opcode == OPCODE_READ_STATUS || opcode == OPCODE_READ_VOLTAGE)
{
*out_data = ((uint16_t)msgbuf[2] << 8) | msgbuf[3];
}
else
{
*out_data = msgbuf[2];
}
}
return 1;
}
return 0; // failed to verify message
}
// read failure
return 0;
}
static int connect()
{
for (int i = 0; i < 10; ++i)
{
send_request(OPCODE_HELLO, 0x00);
if (read_response(OPCODE_HELLO, 0))
{
system_delay_ms(4);
return 1;
}
else
{
system_delay_ms(1000);
}
}
return 0;
}
static int configure(uint16_t max_current_mA, uint8_t lvc_V)
{
uint16_t tmp = 0;
// This initialization is done exactly as in orginal firmware for BBSHD/BBS02.
// The meaning of most parameters is unknown.
#if defined (BBSHD)
send_request(OPCODE_UNKNOWN1, 0x5a);
#elif defined (BBS02)
send_request(OPCODE_UNKNOWN1, 0x5f);
#else
return 0;
#endif
if (!read_response(OPCODE_UNKNOWN1, 0))
{
return 0;
}
system_delay_ms(4);
send_request(OPCODE_UNKNOWN2, 0x11);
if (!read_response(OPCODE_UNKNOWN2, 0))
{
return 0;
}
system_delay_ms(4);
send_request(OPCODE_UNKNOWN3, 0x78);
if (!read_response(OPCODE_UNKNOWN3, 0))
{
return 0;
}
system_delay_ms(4);
send_request(OPCODE_UNKNOWN4, 0x64);
if (!read_response(OPCODE_UNKNOWN4, 0))
{
return 0;
}
system_delay_ms(4);
send_request(OPCODE_UNKNOWN5, 0x50);
if (!read_response(OPCODE_UNKNOWN5, 0))
{
return 0;
}
system_delay_ms(4);
send_request(OPCODE_UNKNOWN6, 0x46);
if (!read_response(OPCODE_UNKNOWN6, 0))
{
return 0;
}
system_delay_ms(4);
send_request(OPCODE_UNKNOWN7, 0x0c);
if (!read_response(OPCODE_UNKNOWN7, 0))
{
return 0;
}
system_delay_ms(4);
send_request(OPCODE_LVC, (uint32_t)(((uint32_t)lvc_V * adc_steps_per_volt_x100) / 100u));
if (!read_response(OPCODE_LVC, 0))
{
return 0;
}
system_delay_ms(4);
tmp = (uint16_t)((max_current_mA * (uint32_t)ADC_STEPS_PER_AMP_X10) / 10000UL);
if (tmp > 255)
{
tmp = 255;
}
eventlog_write_data(EVT_DATA_MAX_CURRENT_ADC_REQUEST, tmp);
send_request(OPCODE_MAX_CURRENT, tmp);
if (!read_response(OPCODE_MAX_CURRENT, &tmp))
{
return 0;
}
else
{
eventlog_write_data(EVT_DATA_MAX_CURRENT_ADC_RESPONSE, tmp);
}
system_delay_ms(4);
return 1;
}
static void process_com_state_machine_idle()
{
// Async state machine loop for serial communication with motor control MCU.
//
// Handles:
// * Set target current
// * Set target speed
// * Read motor status
// * Read motor current
// * Read battery voltage
//
// Set target speed/current are prioritzed over status reading (shorter check interval).
uint32_t now = system_ms();
// make sure requests have some space between them
if (now - last_request_write_ms < 32)
{
return;
}
if (target_current_changed)
{
send_request_async(OPCODE_TARGET_CURRENT, target_current);
last_sent_opcode = OPCODE_TARGET_CURRENT;
last_request_write_ms = now;
com_state = COM_STATE_WAIT_RESPONSE;
target_current_changed = false;
return;
}
if (target_speed_changed)
{
send_request_async(OPCODE_TARGET_SPEED, (uint8_t)(((uint16_t)SPEED_STEPS * target_speed) / 100));
last_sent_opcode = OPCODE_TARGET_SPEED;
last_request_write_ms = now;
com_state = COM_STATE_WAIT_RESPONSE;
target_speed_changed = false;
return;
}
if ((now - last_status_read_ms) > 200)
{
send_request_async(next_status_read_opcode, 0);
last_sent_opcode = next_status_read_opcode;
last_request_write_ms = now;
com_state = COM_STATE_WAIT_RESPONSE;
if (next_status_read_opcode == OPCODE_READ_STATUS)
{
last_status_read_ms = now;
}
return;
}
}
static void process_com_state_machine_wait_response()
{
uint8_t response_length = 0;
switch (last_sent_opcode)
{
case OPCODE_TARGET_CURRENT:
case OPCODE_TARGET_SPEED:
case OPCODE_READ_CURRENT:
response_length = 4;
break;
case OPCODE_READ_VOLTAGE:
case OPCODE_READ_STATUS:
response_length = 5;
break;
}
if (uart_motor_available() >= response_length || (system_ms() - last_request_write_ms) > 32)
{
switch (last_sent_opcode)
{
case OPCODE_TARGET_CURRENT:
com_state = COM_STATE_SET_CURRENT;
break;
case OPCODE_TARGET_SPEED:
com_state = COM_STATE_SET_SPEED;
break;
case OPCODE_READ_CURRENT:
com_state = COM_STATE_READ_CURRENT;
break;
case OPCODE_READ_VOLTAGE:
com_state = COM_STATE_READ_VOLTAGE;
break;
case OPCODE_READ_STATUS:
com_state = COM_STATE_READ_STATUS;
break;
default:
com_state = COM_STATE_IDLE;
break;
}
}
}
static void process_com_state_machine()
{
uint16_t data;
switch (com_state)
{
case COM_STATE_IDLE:
process_com_state_machine_idle();
break;
case COM_STATE_WAIT_RESPONSE:
process_com_state_machine_wait_response();
break;
case COM_STATE_SET_CURRENT:
if (try_read_response(OPCODE_TARGET_CURRENT, &data))
{
eventlog_write_data(EVT_DATA_TARGET_CURRENT, data);
}
else
{
eventlog_write(EVT_ERROR_CHANGE_TARGET_CURRENT);
}
com_state = COM_STATE_IDLE;
break;
case COM_STATE_SET_SPEED:
if (try_read_response(OPCODE_TARGET_SPEED, &data))
{
eventlog_write_data(EVT_DATA_TARGET_SPEED, (uint8_t)((data * 100) / SPEED_STEPS));
}
else
{
eventlog_write(EVT_ERROR_CHANGE_TARGET_SPEED);
}
com_state = COM_STATE_IDLE;
break;
case COM_STATE_READ_STATUS:
if (try_read_response(OPCODE_READ_STATUS, &data))
{
if (data != status_flags)
{
status_flags = data;
eventlog_write_data(EVT_DATA_MOTOR_STATUS, status_flags);
}
}
else
{
eventlog_write(EVT_ERROR_READ_MOTOR_STATUS);
}
next_status_read_opcode = OPCODE_READ_CURRENT;
com_state = COM_STATE_IDLE;
break;
case COM_STATE_READ_CURRENT:
if (try_read_response(OPCODE_READ_CURRENT, &data))
{
battery_amp_x10 = (data * 100) / ADC_STEPS_PER_AMP_X10;
}
else
{
eventlog_write(EVT_ERROR_READ_MOTOR_CURRENT);
}
next_status_read_opcode = OPCODE_READ_VOLTAGE;
com_state = COM_STATE_IDLE;
break;
case COM_STATE_READ_VOLTAGE:
if (try_read_response(OPCODE_READ_VOLTAGE, &data))
{
battery_adc_steps = data;
battery_volt_x10 = (uint16_t)(((uint32_t)battery_adc_steps * 1000) / adc_steps_per_volt_x100);
}
else
{
eventlog_write(EVT_ERROR_READ_MOTOR_VOLTAGE);
}
next_status_read_opcode = OPCODE_READ_STATUS;
com_state = COM_STATE_IDLE;
break;
}
}
================================================
FILE: src/firmware/bbsx/pins.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _PINS_H_
#define _PINS_H_
// PORT, PIN
#if defined(BBSHD)
#define PIN_MOTOR_POWER_ENABLE 2, 0
#define PIN_MOTOR_CONTROL_ENABLE 2, 1
#define PIN_MOTOR_EXTRA 4, 4
#define PIN_MOTOR_RX 1, 0
#define PIN_MOTOR_TX 1, 1
#define PIN_VOLTAGE 1, 6
#define PIN_TEMPERATURE_CONTR 1, 7
#define PIN_TEMPERATURE_MOTOR 1, 4
#define PIN_PAS1 4, 5
#define PIN_PAS2 4, 6
//#define PIN_HALL_U 5, 0
//#define PIN_HALL_V 3, 4
//#define PIN_HALL_W 0, 6
#define PIN_SPEED_SENSOR 2, 2
#define PIN_BRAKE 2, 4
#define PIN_SHIFT_SENSOR 2, 6
#define PIN_THROTTLE 1, 3
#define PIN_LIGHTS_POWER 2, 3 // P+
#define PIN_LIGHTS 5, 1 // Q
#define PIN_EXTERNAL_RX 3, 0
#define PIN_EXTERNAL_TX 3, 1
#elif defined(BBS02)
#define PIN_MOTOR_POWER_ENABLE 2, 0
#define PIN_MOTOR_CONTROL_ENABLE 5, 4
#define PIN_MOTOR_EXTRA 5, 5
#define PIN_MOTOR_RX 1, 0
#define PIN_MOTOR_TX 1, 1
#define PIN_VOLTAGE 1, 7
#define PIN_TEMPERATURE_CONTR 1, 2
#define PIN_PAS1 2, 3
#define PIN_PAS2 2, 4
#define PIN_SPEED_SENSOR 2, 6
#define PIN_BRAKE 3, 3
#define PIN_SHIFT_SENSOR 3, 6
#define PIN_THROTTLE 1, 5
#define PIN_LIGHTS_POWER 0, 3 // P+
#define PIN_LIGHTS 0, 2 // Q
#define PIN_EXTERNAL_RX 3, 0
#define PIN_EXTERNAL_TX 3, 1
#endif
#endif
================================================
FILE: src/firmware/bbsx/sensors.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "sensors.h"
#include "system.h"
#include "adc.h"
#include "util.h"
#include "cfgstore.h"
#include "eventlog.h"
#include "fwconfig.h"
#include "bbsx/pins.h"
#include "bbsx/stc15.h"
#include "bbsx/timers.h"
#include
#include
#include
// interrupt runs at 100us interval, see timer0 in timers.c
// timer0 is shared between system and sensors modules
#define PAS_SENSOR_NUM_SIGNALS PAS_PULSES_REVOLUTION
#define PAS_SENSOR_MIN_PULSE_MS_X10 50 // 500rpm limit
#define SPEED_SENSOR_MIN_PULSE_MS_X10 500
#define SPEED_SENSOR_TIMEOUT_MS_X10 25000
// Some versions of the BBSHD motor (hall sensor board)
// has a PTC thermistor instead of a NTC thermistor.
// Using standard PT1000 table.
// [R_x100, C_x100]
#ifdef BBSHD
#define BBSHD_PTC_LUT_SIZE 21
typedef struct { int32_t x; int16_t y; } pt_t;
static const pt_t bbshd_ptc_lut[BBSHD_PTC_LUT_SIZE] =
{
{ 92100, -2000 },
{ 96090, -1000 },
{ 100000, 0000 },
{ 103900, 1000 },
{ 107790, 2000 },
{ 109730, 2500 },
{ 111670, 3000 },
{ 113610, 3500 },
{ 115540, 4000 },
{ 117470, 4500 },
{ 119400, 5000 },
{ 121320, 5500 },
{ 123240, 6000 },
{ 125160, 6500 },
{ 127080, 7000 },
{ 128990, 7500 },
{ 130900, 8000 },
{ 132800, 8500 },
{ 134710, 9000 },
{ 136610, 9500 },
{ 138510, 10000 }
};
static bool bbshd_ptc_thermistor;
#endif
static volatile uint16_t pas_pulse_counter;
static volatile bool pas_direction_backward;
static volatile uint16_t pas_period_length; // pulse length counted in interrupt frequency (100us)
static uint16_t pas_period_counter;
static bool pas_prev1;
static bool pas_prev2;
static uint16_t pas_stop_delay_periods;
static volatile uint16_t speed_ticks_period_length; // pulse length counted in interrupt frequency (100us)
static uint16_t speed_period_counter;
static bool speed_prev_state;
static uint8_t speed_ticks_per_rpm;
static float thermistor_ntc_calculate_temperature(float R, float invBeta)
{
const float invT0 = 1.f / 298.15f;
float K = 1.f / (invT0 + invBeta * (logf(R / 10000.f)));
float C = K - 273.15f;
return C;
}
#ifdef BBSHD
static int16_t thermistor_ptc_bbshd_calculate_temperature(int32_t R_x100)
{
// interpolate in lookup table
if (R_x100 < bbshd_ptc_lut[0].x)
{
// use minimum value
return bbshd_ptc_lut[0].y;
}
else if (R_x100 > bbshd_ptc_lut[BBSHD_PTC_LUT_SIZE - 1].x)
{
// use maximum value
return bbshd_ptc_lut[BBSHD_PTC_LUT_SIZE - 1].y;
}
uint8_t i = 0;
for (i = 0; i < BBSHD_PTC_LUT_SIZE - 1; i++)
{
if (bbshd_ptc_lut[i + 1].x > R_x100)
{
break;
}
}
return (uint16_t)MAP32(R_x100,
bbshd_ptc_lut[i].x,
bbshd_ptc_lut[i + 1].x,
bbshd_ptc_lut[i].y,
bbshd_ptc_lut[i + 1].y);
}
#endif
void sensors_init()
{
// will be evaulated when first reading take place
#ifdef BBSHD
bbshd_ptc_thermistor = false;
#endif
pas_period_counter = 0;
pas_pulse_counter = 0;
pas_direction_backward = false;
pas_period_length = 0;
pas_stop_delay_periods = 1500;
speed_period_counter = 0;
speed_ticks_period_length = 0;
speed_prev_state = false;
speed_ticks_per_rpm = 1;
// pins do not have external interrupt, use timer0 to evaluate state frequently
SET_PIN_INPUT(PIN_PAS1);
SET_PIN_INPUT(PIN_PAS2);
SET_PIN_INPUT(PIN_SPEED_SENSOR);
SET_PIN_QUASI(PIN_BRAKE); // input pullup
SET_PIN_QUASI(PIN_SHIFT_SENSOR); // input pullup
pas_prev1 = GET_PIN_STATE(PIN_PAS1);
pas_prev2 = GET_PIN_STATE(PIN_PAS2);
timer0_init_sensors();
}
void sensors_process()
{
}
void pas_set_stop_delay(uint16_t delay_ms)
{
pas_stop_delay_periods = delay_ms * 10;
}
uint16_t pas_get_cadence_rpm_x10()
{
uint16_t tmp;
ET0 = 0; // disable timer0 interrupts
tmp = pas_period_length;
ET0 = 1;
if (tmp > 0)
{
return (uint16_t)((6000000ul / PAS_SENSOR_NUM_SIGNALS) / tmp);
}
else
{
return 0;
}
}
uint16_t pas_get_pulse_counter()
{
uint16_t tmp;
ET0 = 0; // disable timer0 interrupts
tmp = pas_pulse_counter;
ET0 = 1;
return tmp;
}
bool pas_is_pedaling_forwards()
{
uint16_t period_length;
uint8_t direction_backward;
ET0 = 0; // disable timer0 interrupts
period_length = pas_period_length;
direction_backward = pas_direction_backward;
ET0 = 1;
// atomic read operation, no need to disable timer interrupt
return period_length > 0 && !direction_backward;
}
bool pas_is_pedaling_backwards()
{
uint16_t period_length;
uint8_t direction_backward;
ET0 = 0; // disable timer0 interrupts
period_length = pas_period_length;
direction_backward = pas_direction_backward;
ET0 = 1;
return period_length > 0 && direction_backward;
}
void speed_sensor_set_signals_per_rpm(uint8_t num_signals)
{
speed_ticks_per_rpm = num_signals;
}
bool speed_sensor_is_moving()
{
uint16_t tmp;
ET0 = 0; // disable timer0 interrupts
tmp = speed_ticks_period_length;
ET0 = 1;
return tmp > 0;
}
uint16_t speed_sensor_get_rpm_x10()
{
uint16_t tmp;
ET0 = 0; // disable timer0 interrupts
tmp = speed_ticks_period_length;
ET0 = 1;
if (tmp > 0)
{
return 6000000ul / tmp / speed_ticks_per_rpm;
}
return 0;
}
uint16_t torque_sensor_get_nm_x100()
{
return 0;
}
bool torque_sensor_ok()
{
return true;
}
int16_t temperature_contr_x100()
{
const float R1 = 5100.f;
const float invBeta = 1.f / 3600.f;
static int32_t adc_contr_x100 = 0;
if (g_config.use_temperature_sensor & TEMPERATURE_SENSOR_CONTR)
{
if (adc_contr_x100 == 0)
{
adc_contr_x100 = adc_get_temperature_contr() * 100l;
}
else
{
adc_contr_x100 = EXPONENTIAL_FILTER(adc_contr_x100, adc_get_temperature_contr() * 100l, 4);
}
if (adc_contr_x100 != 0)
{
float R = R1 * ((102300.f / (102300.f - adc_contr_x100)) - 1.f);
return (int16_t)(thermistor_ntc_calculate_temperature(R, invBeta) * 100.f + 0.5f);
}
}
return 0;
}
int16_t temperature_motor_x100()
{
// Sensor only present in the BBSHD motor
#if HAS_MOTOR_TEMP_SENSOR
const float R1 = 5100.f;
const float invBeta = 1.f / 3990.f;
static int32_t adc_motor_x100 = 0;
if (g_config.use_temperature_sensor & TEMPERATURE_SENSOR_MOTOR)
{
bool first = false;
if (adc_motor_x100 == 0)
{
first = true;
adc_motor_x100 = adc_get_temperature_motor() * 100l;
}
else
{
adc_motor_x100 = EXPONENTIAL_FILTER(adc_motor_x100, adc_get_temperature_motor() * 100l, 4);
}
if (adc_motor_x100 != 0)
{
float R = R1 * ((102300.f / (102300.f - adc_motor_x100)) - 1.f);
if (first)
{
if (R > 1500.f)
{
// not likely to be a 1k ptc thermistor, assume 10k ntc
bbshd_ptc_thermistor = false;
eventlog_write_data(EVT_DATA_BBSHD_THERMISTOR, 0);
}
else
{
bbshd_ptc_thermistor = true;
eventlog_write_data(EVT_DATA_BBSHD_THERMISTOR, 1);
}
}
if (bbshd_ptc_thermistor)
{
return thermistor_ptc_bbshd_calculate_temperature((int32_t)(R * 100.f + 0.5f));
}
else
{
return(int16_t)(thermistor_ntc_calculate_temperature(R, invBeta) * 100.f + 0.5f);
}
}
}
#endif
return 0;
}
bool brake_is_activated()
{
return !GET_PIN_STATE(PIN_BRAKE);
}
bool shift_sensor_is_activated()
{
return !GET_PIN_STATE(PIN_SHIFT_SENSOR);
}
#pragma save
#pragma nooverlay // See SDCC manual about function calls in ISR
void sensors_timer0_isr() // runs every 100us, see timers.c
{
// WARNING:
// No 16/32 bit or float computations in ISR (multiply/divide/modulo).
// Read SDCC compiler manual for more info.
// Pas
{
bool pas1 = GET_PIN_STATE(PIN_PAS1);
bool pas2 = GET_PIN_STATE(PIN_PAS2);
if (pas1 && !pas_prev1 /* && pas_period_counter > PAS_SENSOR_MIN_PULSE_MS_X10 */)
{
pas_pulse_counter++;
if (pas_direction_backward != pas2)
{
pas_direction_backward = pas2;
// Reset pas pulse counter if pedal direction is changed,
// this variable counts the number of pulses since start of pedaling session.
pas_pulse_counter = 0;
}
if (pas_period_counter > 0)
{
if (pas_period_counter <= pas_stop_delay_periods)
{
pas_period_length = pas_period_counter; // save in order to be able to calculate rpm when needed
}
else
{
pas_period_length = 0;
}
pas_period_counter = 0;
}
}
else
{
// Do not allow wraparound or computed pedaling cadence will wrong after pedals has been still.
if (pas_period_counter < 65535)
{
pas_period_counter++;
}
if (pas_period_length > 0 && pas_period_counter > pas_stop_delay_periods)
{
pas_period_length = 0;
pas_pulse_counter = 0;
pas_direction_backward = false;
}
}
pas_prev1 = pas1;
pas_prev2 = pas2;
}
// Speed sensor
{
bool spd = GET_PIN_STATE(PIN_SPEED_SENSOR);
if (spd && !speed_prev_state && speed_period_counter > SPEED_SENSOR_MIN_PULSE_MS_X10)
{
if (speed_period_counter <= SPEED_SENSOR_TIMEOUT_MS_X10)
{
speed_ticks_period_length = speed_period_counter;
}
else
{
speed_ticks_period_length = 0;
}
speed_period_counter = 0;
}
else
{
// Do not allow wraparound or computed speed will wrong after bike has been still.
if (speed_period_counter < 65535)
{
speed_period_counter++;
}
if (speed_ticks_period_length > 0 && speed_period_counter > SPEED_SENSOR_TIMEOUT_MS_X10)
{
speed_ticks_period_length = 0;
}
}
speed_prev_state = spd;
}
}
#pragma restore
================================================
FILE: src/firmware/bbsx/stc15.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _STC_15_H_
#define _STC_15_H_
#include "intellisense.h"
#if !defined (SDCC) && !defined (__SDCC)
#define __sfr unsigned char
#define __sbit bool
#define __at(X)
#define __xdata
#define __data
#endif
#include <8051.h>
#include
// Peripheral function switch
SFR(P_SW2, 0xBA);
SFR(PCON2, 0x97);
SFR(T2H, 0xD6);
SFR(T2L, 0xD7);
SBIT(P5_4, 0xC8, 4);
SBIT(P5_5, 0xC8, 5);
#define IS_BIT_SET(REG, BIT_NUM) ((REG >> BIT_NUM) & 1)
#define SET_BIT(REG, BIT_NUM) (REG |= (1 << BIT_NUM))
#define CLEAR_BIT(REG, BIT_NUM) (REG &= ~(1 << BIT_NUM))
#define TOGGLE_BIT(REG, BIT_NUM) (REG ^= (1 << BIT_NUM))
#define EXPAND(x) x
#define SET_PIN_INPUT_(PORT, PIN) CLEAR_BIT(P##PORT##M0, PIN); SET_BIT(P##PORT##M1, PIN)
#define SET_PIN_INPUT(...) EXPAND(SET_PIN_INPUT_(__VA_ARGS__))
#define SET_PIN_QUASI_(PORT, PIN) CLEAR_BIT(P##PORT##M0, PIN); CLEAR_BIT(P##PORT##M1, PIN)
#define SET_PIN_QUASI(...) EXPAND(SET_PIN_QUASI_(__VA_ARGS__))
#define SET_PIN_OUTPUT_(PORT, PIN) SET_BIT(P##PORT##M0, PIN); CLEAR_BIT(P##PORT##M1, PIN)
#define SET_PIN_OUTPUT(...) EXPAND(SET_PIN_OUTPUT_(__VA_ARGS__))
#define GET_PIN_STATE_(PORT, PIN) P##PORT##_##PIN
#define GET_PIN_STATE(...) EXPAND(GET_PIN_STATE_(__VA_ARGS__))
#define SET_PIN_HIGH_(PORT, PIN) P##PORT##_##PIN = 1
#define SET_PIN_HIGH(...) EXPAND(SET_PIN_HIGH_(__VA_ARGS__))
#define SET_PIN_LOW_(PORT, PIN) P##PORT##_##PIN = 0
#define SET_PIN_LOW(...) EXPAND(SET_PIN_LOW_(__VA_ARGS__))
#define GET_PIN_NUM_(PORT, PIN) PIN
#define GET_PIN_NUM(...) EXPAND(GET_PIN_NUM_(__VA_ARGS__))
#define GET_PORT_NUM_(PORT, PIN) PORT
#define GET_PORT_NUM(...) EXPAND(GET_PORT_NUM_(__VA_ARGS__))
#endif
================================================
FILE: src/firmware/bbsx/system.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "system.h"
#include "watchdog.h"
#include "timers.h"
#include "bbsx/stc15.h"
static volatile uint32_t _ms;
static volatile uint8_t _x100us;
void system_init()
{
_ms = 0;
_x100us = 0;
// Wait for stable voltage (above lvd)
while (IS_BIT_SET(PCON, 5))
{
CLEAR_BIT(PCON, 5);
}
timer0_init_system();
}
uint32_t system_ms()
{
uint32_t val;
uint8_t et0 = ET0;
ET0 = 0; // disable timer0 interrupts
val = _ms;
ET0 = et0;
return val;
}
void system_delay_ms(uint16_t ms)
{
if (!ms)
{
return;
}
uint32_t end = system_ms() + ms;
while (system_ms() != end)
{
watchdog_yeild();
}
}
#pragma save
#pragma nooverlay // See SDCC manual about function calls in ISR
void system_timer0_isr()
{
_x100us++;
if (_x100us == 10)
{
_x100us = 0;
_ms++;
}
}
#pragma restore
================================================
FILE: src/firmware/bbsx/timers.c
================================================
#include "timers.h"
#include "bbsx/timers.h"
#include "bbsx/interrupt.h"
#include "bbsx/cpu.h"
#include
#define TIMER0_RELOAD ((65535 - CPU_FREQ / 10000) + 1)
extern void system_timer0_isr();
extern void sensors_timer0_isr();
static bool timer0_system_ready;
static bool timer0_sensors_ready;
static void timer0_init()
{
if (timer0_system_ready || timer0_sensors_ready)
{
// already initialized
return;
}
EA = 0; // disable interrupts
TMOD = (TMOD & 0xf0) | 0x00; // Timer 0: 16-bit with autoreload
AUXR |= 0x80; // Run timer 0 at CPU_FREQ
TH0 = TIMER0_RELOAD >> 8;
TL0 = TIMER0_RELOAD;
EA = 1; // enable interrupts
ET0 = 1; // enable timer0 interrupts
TR0 = 1; // start timer 0
}
void timers_init()
{
timer0_system_ready = false;
timer0_sensors_ready = false;
}
void timer0_init_system()
{
timer0_init();
timer0_system_ready = true;
}
void timer0_init_sensors()
{
timer0_init();
timer0_sensors_ready = true;
}
void timer1_init_uart1(uint32_t baudrate)
{
unsigned short reload = 65535 - CPU_FREQ / 4 / baudrate + 1;
// Set up timer 1 for baudrate
TMOD = (TMOD & 0x0f) | 0x00; // Run T1 in mode 0 (16-bit reload)
AUXR |= 0x40; // Run T1 at CPU_FREQ
TL1 = reload; // Set the reload value for given baudrate.
TH1 = reload >> 8;
ET1 = 0; // No interrupts from timer 1.
TR1 = 1; // Start timer 1
}
void timer2_init_uart2(uint32_t baudrate)
{
unsigned short reload = 65535 - CPU_FREQ / 4 / baudrate + 1;
// Set up timer 2 for baudrate
AUXR &= ~(1 << 3); // as timer
AUXR |= (1 << 2); // Run T2 at CPU_FREQ
T2H = reload >> 8;
T2L = reload;
IE2 &= ~(1 << 2); // No interrupts from timer 2
AUXR |= (1 << 4); // Start timer 2
}
// timer0 is shared between system ms counter and sensors check
INTERRUPT_USING(isr_timer0, IRQ_TIMER0, 1)
{
if (timer0_system_ready)
{
system_timer0_isr();
}
if (timer0_sensors_ready)
{
sensors_timer0_isr();
}
}
================================================
FILE: src/firmware/bbsx/timers.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _BBSX_TIMER_H_
#define _BBSX_TIMER_H_
#include "bbsx/stc15.h"
#include
void timer0_init_system();
void timer0_init_sensors();
void timer1_init_uart1(uint32_t baudrate);
void timer2_init_uart2(uint32_t baudrate);
#endif
================================================
FILE: src/firmware/bbsx/uart.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "uart.h"
#include "system.h"
#include "watchdog.h"
#include "bbsx/stc15.h"
#include "bbsx/uart_motor.h"
#include "bbsx/timers.h"
#include "bbsx/pins.h"
#include
// NOTE:
// Variables located in __data are there for atomic access.
// UART1 (main)
#define RX1_BUFFER_SIZE 64
#define RX1_BUFFER_MASK (RX1_BUFFER_SIZE - 1)
#define TX1_BUFFER_SIZE 32
#define TX1_BUFFER_MASK (TX1_BUFFER_SIZE - 1)
static volatile __data uint8_t rx1_head;
static volatile __data uint8_t rx1_tail;
static volatile uint8_t rx1_buf[RX1_BUFFER_SIZE];
static volatile __data uint8_t tx1_head;
static volatile __data uint8_t tx1_tail;
static volatile __data uint8_t tx1_sending;
static volatile uint8_t tx1_buf[TX1_BUFFER_SIZE];
// UART2 (motor)
#define RX2_BUFFER_SIZE 16
#define RX2_BUFFER_MASK (RX2_BUFFER_SIZE - 1)
#define TX2_BUFFER_SIZE 16
#define TX2_BUFFER_MASK (TX2_BUFFER_SIZE - 1)
static volatile __data uint8_t rx2_head;
static volatile __data uint8_t rx2_tail;
static volatile uint8_t rx2_buf[RX2_BUFFER_SIZE];
static volatile __data uint8_t tx2_head;
static volatile __data uint8_t tx2_tail;
static volatile __data uint8_t tx2_sending;
static volatile uint8_t tx2_buf[TX2_BUFFER_SIZE];
void uart_open(uint32_t baudrate)
{
rx1_head = 0;
rx1_tail = 0;
tx1_head = 0;
tx1_tail = 0;
tx1_sending = 0;
#if (GET_PORT_NUM(PIN_EXTERNAL_RX) == 3 && GET_PORT_NUM(PIN_EXTERNAL_TX) == 3)
AUXR1 = (AUXR1 & 0x3f) | 0x00; // Keep UART1 on P3.0/P3.1
#else
#error Unupported UART port configured.
#endif
SET_PIN_QUASI(PIN_EXTERNAL_RX);
SET_PIN_QUASI(PIN_EXTERNAL_TX);
AUXR &= ~0x01; // Clock UART1 from T1
PCON &= ~0x40; // Expose SM0 bit
SM1 = 1; // UART 8-N-1
SM0 = 0;
SM2 = 0; // Point-to-point UART
ES = 1; // Enable serial interrupt
timer1_init_uart1(baudrate);
REN = 1; // Rx enable
}
void uart_motor_open(uint32_t baudrate)
{
rx2_head = 0;
rx2_tail = 0;
tx2_head = 0;
tx2_tail = 0;
tx2_sending = 0;
#if (GET_PORT_NUM(PIN_MOTOR_RX) == 1 && GET_PORT_NUM(PIN_MOTOR_TX) == 1)
{
P_SW2 = (P_SW2 & 0xfe) | 0x00; // Keep UART2 on P1.0/P1.1
}
#else
#error Unupported UART port configured.
#endif
SET_PIN_QUASI(PIN_MOTOR_RX);
SET_PIN_QUASI(PIN_MOTOR_TX);
// UART 2 can only user timer 2
S2CON &= ~(1 << 7); // UART 8-N-1
S2CON &= ~(1 << 5); // Point-to-point UART
IE2 |= (1 << 0); // Enable serial 2 interrupt
timer2_init_uart2(baudrate);
S2CON |= (1 << 4); // Rx enable
}
void uart_close()
{
REN = 0;
uart_flush();
TR1 = 0;
}
void uart_motor_close()
{
S2CON &= ~(1 << 4); // Rx disable
uart_motor_flush();
AUXR &= ~(1 << 4); // Stop timer 2
}
uint8_t uart_available()
{
return (RX1_BUFFER_SIZE + rx1_head - rx1_tail) & RX1_BUFFER_MASK;
}
uint8_t uart_motor_available()
{
return (RX2_BUFFER_SIZE + rx2_head - rx2_tail) & RX2_BUFFER_MASK;
}
uint8_t uart_read()
{
uint8_t byte = rx1_buf[rx1_tail];
rx1_tail = (rx1_tail + 1) & RX1_BUFFER_MASK;
return byte;
}
uint8_t uart_motor_read()
{
uint8_t byte = rx2_buf[rx2_tail];
rx2_tail = (rx2_tail + 1) & RX2_BUFFER_MASK;
return byte;
}
void uart_write(uint8_t byte)
{
if (!tx1_sending)
{
tx1_sending = 1;
SBUF = byte;
return;
}
uint8_t i = (tx1_head + 1) & TX1_BUFFER_MASK;
// wait for free space in buffer
uint8_t prev_tail = tx1_tail;
while (i == tx1_tail)
{
if (tx1_tail != prev_tail)
{
prev_tail = tx1_tail;
watchdog_yeild();
}
}
tx1_buf[tx1_head] = byte;
tx1_head = i;
}
void uart_motor_write(uint8_t byte)
{
if (!tx2_sending)
{
tx2_sending = 1;
S2BUF = byte;
return;
}
uint8_t i = (tx2_head + 1) & TX2_BUFFER_MASK;
// wait for free space in buffer
uint8_t prev_tail = tx2_tail;
while (i == tx2_tail)
{
if (tx2_tail != prev_tail)
{
prev_tail = tx2_tail;
watchdog_yeild();
}
}
tx2_buf[tx2_head] = byte;
tx2_head = i;
}
void uart_flush()
{
while (tx1_sending);
}
void uart_motor_flush()
{
while (tx2_sending);
}
INTERRUPT_USING(isr_uart1, IRQ_UART1, 3)
{
if (RI) // rx interrupt
{
RI = 0;
uint8_t c = SBUF;
uint8_t i = (rx1_head + 1) & RX1_BUFFER_MASK;
if (i != rx1_tail)
{
rx1_buf[rx1_head] = c;
rx1_head = i;
}
}
if (TI) // tx interrupt
{
TI = 0;
if (tx1_head != tx1_tail)
{
tx1_sending = 1;
SBUF = tx1_buf[tx1_tail];
tx1_tail = (tx1_tail + 1) & TX1_BUFFER_MASK;
}
else
{
tx1_sending = 0;
}
}
}
INTERRUPT_USING(isr_uart2, IRQ_UART2, 3)
{
if (S2CON & (1 << 0)) // rx interrupt
{
S2CON &= ~(1 << 0);
uint8_t c = S2BUF;
uint8_t i = (rx2_head + 1) & RX2_BUFFER_MASK;
if (i != rx2_tail)
{
rx2_buf[rx2_head] = c;
rx2_head = i;
}
}
if (S2CON & (1 << 1)) // tx interrupt
{
S2CON &= ~(1 << 1);
if (tx2_head != tx2_tail)
{
tx2_sending = 1;
S2BUF = tx2_buf[tx2_tail];
tx2_tail = (tx2_tail + 1) & TX2_BUFFER_MASK;
}
else
{
tx2_sending = 0;
}
}
}
================================================
FILE: src/firmware/bbsx/uart_motor.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _BBSX_UART_MOTOR_H_
#define _BBSX_UART_MOTOR_H_
#include "bbsx/stc15.h"
#include "bbsx/interrupt.h"
#include
void uart_motor_open(uint32_t baudrate);
void uart_motor_close();
uint8_t uart_motor_available();
uint8_t uart_motor_read();
void uart_motor_write(uint8_t byte);
void uart_motor_flush();
#endif
================================================
FILE: src/firmware/bbsx/watchdog.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "watchdog.h"
#include "bbsx/stc15.h"
static bool triggered;
void watchdog_init()
{
triggered = IS_BIT_SET(WDT_CONTR, 7);
WDT_CONTR = 0x34; // Enable watchdog timer, pre-scaler 32 (625ms, 20MHz)
}
void watchdog_yeild()
{
SET_BIT(WDT_CONTR, 4);
}
bool watchdog_triggered()
{
return triggered;
}
================================================
FILE: src/firmware/cfgstore.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "cfgstore.h"
#include "eeprom.h"
#include "eventlog.h"
#include "uart.h"
#include "fwconfig.h"
#include
#define EEPROM_CONFIG_PAGE 0
#define EEPROM_PSTATE_PAGE 1
#define EEPROM_OK 0
#define EEPROM_ERROR_SELECT_PAGE 1
#define EEPROM_ERROR_READ 2
#define EEPROM_ERROR_VERSION 3
#define EEPROM_ERROR_LENGHT 4
#define EEPROM_ERROR_CHECKSUM 5
#define EEPROM_ERROR_ERASE 6
#define EEPROM_ERROR_WRITE 7
static const uint8_t default_current_limits[] = { 7, 10, 14, 19, 26, 36, 50, 70, 98 };
#if HAS_TORQUE_SENSOR
static const uint8_t default_torque_factors[] = { 10, 15, 23, 44, 57, 74, 88, 105, 126 };
#endif
typedef struct
{
uint8_t version;
uint8_t length;
uint8_t checksum;
} header_t;
static header_t header;
config_t g_config;
pstate_t g_pstate;
static uint8_t read(uint8_t page, uint8_t version, uint8_t* dst, uint8_t size);
static uint8_t write(uint8_t page, uint8_t version, uint8_t* src, uint8_t size);
static bool read_config();
static bool write_config();
static void load_default_config();
static bool read_pstate();
static bool write_pstate();
static void load_default_pstate();
void cfgstore_init()
{
if (!read_config())
{
cfgstore_reset_config();
}
if (!read_pstate())
{
cfgstore_reset_pstate();
}
}
bool cfgstore_reset_config()
{
load_default_config();
if (write_config())
{
eventlog_write(EVT_MSG_CONFIG_RESET);
return true;
}
return false;
}
bool cfgstore_save_config()
{
return write_config();
}
bool cfgstore_reset_pstate()
{
load_default_pstate();
return write_pstate();
}
bool cfgstore_save_pstate()
{
return write_pstate();
}
static bool read_config()
{
eventlog_write(EVT_MSG_CONFIG_READ_BEGIN);
uint8_t res = read(EEPROM_CONFIG_PAGE, CONFIG_VERSION, (uint8_t*)&g_config, sizeof(config_t));
switch (res)
{
default:
eventlog_write(EVT_ERROR_EEPROM_READ);
break;
case EEPROM_ERROR_VERSION:
eventlog_write(EVT_ERROR_EEPROM_VERIFY_VERSION);
break;
case EEPROM_ERROR_LENGHT:
case EEPROM_ERROR_CHECKSUM:
eventlog_write(EVT_ERROR_EEPROM_VERIFY_CHECKSUM);
break;
case EEPROM_OK:
eventlog_write(EVT_MSG_CONFIG_READ_DONE);
break;
}
return res == EEPROM_OK;
}
static bool write_config()
{
eventlog_write(EVT_MSG_CONFIG_WRITE_BEGIN);
uint8_t res = write(EEPROM_CONFIG_PAGE, CONFIG_VERSION, (uint8_t*)&g_config, sizeof(config_t));
switch (res)
{
default:
eventlog_write(EVT_ERROR_EEPROM_WRITE);
break;
case EEPROM_ERROR_ERASE:
eventlog_write(EVT_ERROR_EEPROM_ERASE);
break;
case EEPROM_OK:
eventlog_write(EVT_MSG_CONFIG_WRITE_DONE);
break;
}
return res == EEPROM_OK;
}
static void load_default_config()
{
g_config.use_freedom_units = 0;
#if defined(BBSHD)
g_config.max_current_amps = 30;
#elif defined(BBS02)
g_config.max_current_amps = 25;
#else
g_config.max_current_amps = 20;
#endif
g_config.current_ramp_amps_s = 10;
g_config.max_battery_x100v_u16l = (uint8_t)5460;
g_config.max_battery_x100v_u16h = (uint8_t)(5460 >> 8);
g_config.low_cut_off_v = 42;
g_config.use_speed_sensor = 1;
g_config.use_shift_sensor = HAS_SHIFT_SENSOR_SUPPORT;
g_config.use_push_walk = 1;
g_config.use_pretension = 0;
g_config.pretension_speed_cutoff_kph = 16;
g_config.use_temperature_sensor = TEMPERATURE_SENSOR_CONTR | TEMPERATURE_SENSOR_MOTOR;
g_config.lights_mode = LIGHTS_MODE_DEFAULT;
g_config.wheel_size_inch_x10_u16l = (uint8_t)280;
g_config.wheel_size_inch_x10_u16h = (uint8_t)(280 >> 8);
g_config.speed_sensor_signals = 1;
g_config.max_speed_kph = 100;
g_config.pas_start_delay_pulses = 5;
g_config.pas_stop_delay_x100s = 20;
g_config.pas_keep_current_percent = 60;
g_config.pas_keep_current_cadence_rpm = 40;
g_config.throttle_start_voltage_mv_u16l = (uint8_t)1000;
g_config.throttle_start_voltage_mv_u16h = (uint8_t)(1000 >> 8);
g_config.throttle_end_voltage_mv_u16l = (uint8_t)3600;
g_config.throttle_end_voltage_mv_u16h = (uint8_t)(3600 >> 8);
g_config.throttle_start_percent = 1;
g_config.throttle_global_spd_lim_opt = THROTTLE_GLOBAL_SPEED_LIMIT_DISABLED;
g_config.throttle_global_spd_lim_percent = 100;
g_config.shift_interrupt_duration_ms_u16l = (uint8_t)600;
g_config.shift_interrupt_duration_ms_u16h = (uint8_t)(600 >> 8);
g_config.shift_interrupt_current_threshold_percent = 10;
g_config.walk_mode_data_display = WALK_MODE_DATA_SPEED;
g_config.assist_mode_select = ASSIST_MODE_SELECT_OFF;
g_config.assist_startup_level = 3;
memset(&g_config.assist_levels, 0, 20 * sizeof(assist_level_t));
for (uint8_t i = 0; i < 9; ++i)
{
g_config.assist_levels[0][i+1].flags = ASSIST_FLAG_PAS | ASSIST_FLAG_THROTTLE;
g_config.assist_levels[0][i+1].max_cadence_percent = 100;
g_config.assist_levels[0][i+1].max_speed_percent = 100;
g_config.assist_levels[0][i+1].max_throttle_current_percent = 100;
#if HAS_TORQUE_SENSOR
g_config.assist_levels[0][i+1].flags |= ASSIST_FLAG_PAS_TORQUE;
g_config.assist_levels[0][i+1].target_current_percent = 100;
g_config.assist_levels[0][i+1].torque_amplification_factor_x10 = default_torque_factors[i];
#else
g_config.assist_levels[0][i+1].target_current_percent = default_current_limits[i];
g_config.assist_levels[0][i+1].torque_amplification_factor_x10 = 0;
#endif
}
}
static bool read_pstate()
{
eventlog_write(EVT_MSG_PSTATE_READ_BEGIN);
uint8_t res = read(EEPROM_PSTATE_PAGE, PSTATE_VERSION, (uint8_t*)&g_pstate, sizeof(pstate_t));
switch (res)
{
default:
eventlog_write(EVT_ERROR_EEPROM_READ);
break;
case EEPROM_ERROR_VERSION:
eventlog_write(EVT_ERROR_EEPROM_VERIFY_VERSION);
break;
case EEPROM_ERROR_LENGHT:
case EEPROM_ERROR_CHECKSUM:
eventlog_write(EVT_ERROR_EEPROM_VERIFY_CHECKSUM);
break;
case EEPROM_OK:
eventlog_write(EVT_MSG_PSTATE_READ_DONE);
break;
}
return res == EEPROM_OK;
}
static bool write_pstate()
{
eventlog_write(EVT_MSG_PSTATE_WRITE_BEGIN);
uint8_t res = write(EEPROM_PSTATE_PAGE, PSTATE_VERSION, (uint8_t*)&g_pstate, sizeof(pstate_t));
switch (res)
{
default:
eventlog_write(EVT_ERROR_EEPROM_WRITE);
break;
case EEPROM_ERROR_ERASE:
eventlog_write(EVT_ERROR_EEPROM_ERASE);
break;
case EEPROM_OK:
eventlog_write(EVT_MSG_PSTATE_WRITE_DONE);
break;
}
return res == EEPROM_OK;
}
static void load_default_pstate()
{
g_pstate.adc_voltage_calibration_steps_x100_i16l = 0;
g_pstate.adc_voltage_calibration_steps_x100_i16h = 0;
}
static uint8_t read(uint8_t page, uint8_t version, uint8_t* dst, uint8_t size)
{
uint8_t read_offset = 0;
uint8_t* ptr = 0;
uint8_t i = 0;
int data;
if (!eeprom_select_page(page))
{
return EEPROM_ERROR_SELECT_PAGE;
}
ptr = (uint8_t*)&header;
for (i = 0; i < sizeof(header_t); ++i)
{
data = eeprom_read_byte(read_offset);
if (data < 0)
{
return EEPROM_ERROR_READ;
}
*ptr = (uint8_t)data;
++read_offset;
++ptr;
}
// verify header ok
if (header.version != version)
{
return EEPROM_ERROR_VERSION;
}
if (header.length != size)
{
return EEPROM_ERROR_LENGHT;
}
uint8_t checksum = 0;
ptr = dst;
for (i = 0; i < size; ++i)
{
data = eeprom_read_byte(read_offset);
if (data < 0)
{
return EEPROM_ERROR_READ;
}
checksum += (uint8_t)data;
*ptr = (uint8_t)data;
++read_offset;
++ptr;
}
if (header.checksum != checksum)
{
return EEPROM_ERROR_CHECKSUM;
}
return EEPROM_OK;
}
static uint8_t write(uint8_t page, uint8_t version, uint8_t* src, uint8_t size)
{
uint8_t write_offset = 0;
uint8_t* ptr = 0;
uint8_t i = 0;
header.version = version;
header.length = size;
header.checksum = 0;
if (!eeprom_select_page(page))
{
return EEPROM_ERROR_SELECT_PAGE;
}
if (!eeprom_erase_page())
{
return EEPROM_ERROR_ERASE;
}
write_offset += sizeof(header_t);
ptr = src;
for (i = 0; i < size; ++i)
{
if (!eeprom_write_byte(write_offset, *ptr))
{
eeprom_end_write();
return EEPROM_ERROR_WRITE;
}
header.checksum += *ptr;
++write_offset;
++ptr;
}
write_offset = 0;
ptr = (uint8_t*)&header;
for (i = 0; i < sizeof(header_t); ++i)
{
if (!eeprom_write_byte(write_offset, *ptr))
{
eeprom_end_write();
return EEPROM_ERROR_WRITE;
}
++write_offset;
++ptr;
}
eeprom_end_write();
return EEPROM_OK;
}
================================================
FILE: src/firmware/cfgstore.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _CFGSTORE_H_
#define _CFGSTORE_H_
#include "intellisense.h"
#include
#include
#define ASSIST_FLAG_PAS 0x01
#define ASSIST_FLAG_THROTTLE 0x02
#define ASSIST_FLAG_CRUISE 0x04
#define ASSIST_FLAG_PAS_VARIABLE 0x08 // pas mode using throttle to set power level
#define ASSIST_FLAG_PAS_TORQUE 0x10 // pas mode using torque sensor reading
#define ASSIST_FLAG_OVERRIDE_CADENCE 0x20 // pas option where max cadence is set to 100% when throttle overrides pas
#define ASSIST_FLAG_OVERRIDE_SPEED 0x40 // pas option where max speed is set to 100% when throttle overrides pas
#define ASSIST_MODE_SELECT_OFF 0x00
#define ASSIST_MODE_SELECT_STANDARD 0x01
#define ASSIST_MODE_SELECT_LIGHTS 0x02
#define ASSIST_MODE_SELECT_PAS0_LIGHT 0x03
#define ASSIST_MODE_SELECT_PAS1_LIGHT 0x04
#define ASSIST_MODE_SELECT_PAS2_LIGHT 0x05
#define ASSIST_MODE_SELECT_PAS3_LIGHT 0x06
#define ASSIST_MODE_SELECT_PAS4_LIGHT 0x07
#define ASSIST_MODE_SELECT_PAS5_LIGHT 0x08
#define ASSIST_MODE_SELECT_PAS6_LIGHT 0x09
#define ASSIST_MODE_SELECT_PAS7_LIGHT 0x0A
#define ASSIST_MODE_SELECT_PAS8_LIGHT 0x0B
#define ASSIST_MODE_SELECT_PAS9_LIGHT 0x0C
#define ASSIST_MODE_SELECT_BRAKE_BOOT 0x0D
#define TEMPERATURE_SENSOR_CONTR 0x01
#define TEMPERATURE_SENSOR_MOTOR 0x02
#define WALK_MODE_DATA_SPEED 0
#define WALK_MODE_DATA_TEMPERATURE 1
#define WALK_MODE_DATA_REQUESTED_POWER 2
#define WALK_MODE_DATA_BATTERY_PERCENT 3
#define THROTTLE_GLOBAL_SPEED_LIMIT_DISABLED 0
#define THROTTLE_GLOBAL_SPEED_LIMIT_ENABLED 1
#define THROTTLE_GLOBAL_SPEED_LIMIT_STD_LVLS 2
#define LIGHTS_MODE_DEFAULT 0
#define LIGHTS_MODE_DISABLED 1
#define LIGHTS_MODE_ALWAYS_ON 2
#define LIGHTS_MODE_BRAKE_LIGHT 3
#define CONFIG_VERSION 5
#define PSTATE_VERSION 1
typedef struct
{
uint8_t flags;
uint8_t target_current_percent;
uint8_t max_throttle_current_percent;
uint8_t max_cadence_percent;
uint8_t max_speed_percent;
// 10 => 1.0: 100w human power gives and additional 100w motor power
uint8_t torque_amplification_factor_x10;
} assist_level_t;
// SDCC uses little endian for MCS51 and big endian for STM8...
typedef struct
{
// hmi units
uint8_t use_freedom_units;
// global
uint8_t max_current_amps;
uint8_t current_ramp_amps_s;
uint8_t max_battery_x100v_u16l;
uint8_t max_battery_x100v_u16h;
uint8_t low_cut_off_v;
uint8_t max_speed_kph;
// externals
uint8_t use_speed_sensor;
uint8_t use_shift_sensor;
uint8_t use_push_walk;
uint8_t use_temperature_sensor;
uint8_t lights_mode;
uint8_t use_pretension;
uint8_t pretension_speed_cutoff_kph;
// speed sensor
uint8_t wheel_size_inch_x10_u16l;
uint8_t wheel_size_inch_x10_u16h;
uint8_t speed_sensor_signals;
// pas options
uint8_t pas_start_delay_pulses;
uint8_t pas_stop_delay_x100s;
uint8_t pas_keep_current_percent;
uint8_t pas_keep_current_cadence_rpm;
// throttle options
uint8_t throttle_start_voltage_mv_u16l;
uint8_t throttle_start_voltage_mv_u16h;
uint8_t throttle_end_voltage_mv_u16l;
uint8_t throttle_end_voltage_mv_u16h;
uint8_t throttle_start_percent;
uint8_t throttle_global_spd_lim_opt;
uint8_t throttle_global_spd_lim_percent;
// shift interrupt options
uint8_t shift_interrupt_duration_ms_u16l;
uint8_t shift_interrupt_duration_ms_u16h;
uint8_t shift_interrupt_current_threshold_percent;
// misc
uint8_t walk_mode_data_display;
// assist levels
uint8_t assist_mode_select;
uint8_t assist_startup_level;
assist_level_t assist_levels[2][10];
} config_t;
typedef struct
{
uint8_t adc_voltage_calibration_steps_x100_i16l;
uint8_t adc_voltage_calibration_steps_x100_i16h;
} pstate_t;
extern config_t g_config;
extern pstate_t g_pstate;
void cfgstore_init();
bool cfgstore_reset_config();
bool cfgstore_save_config();
bool cfgstore_reset_pstate();
bool cfgstore_save_pstate();
#endif
================================================
FILE: src/firmware/clean.bat
================================================
@ECHO OFF
del /s /q *.hex >NUL 2>NUL
del /s /q *.ihx >NUL 2>NUL
del /s /q *.asm >NUL 2>NUL
del /s /q *.rel >NUL 2>NUL
del /s /q *.lk >NUL 2>NUL
del /s /q *.lst >NUL 2>NUL
del /s /q *.rst >NUL 2>NUL
del /s /q *.sym >NUL 2>NUL
del /s /q *.cdb >NUL 2>NUL
del /s /q *.map >NUL 2>NUL
del /s /q *.elf >NUL 2>NUL
del /s /q *.adb >NUL 2>NUL
del /s /q *.mem >NUL 2>NUL
@ECHO ON
================================================
FILE: src/firmware/eeprom.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _EEPROM_H_
#define _EEPROM_H_
#include "intellisense.h"
#include
#include
void eeprom_init();
bool eeprom_select_page(int page);
int eeprom_read_byte(int offset);
bool eeprom_erase_page();
bool eeprom_write_byte(int offset, uint8_t value);
bool eeprom_end_write();
#endif
================================================
FILE: src/firmware/eventlog.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "eventlog.h"
#include "uart.h"
static bool is_enabled;
void eventlog_init(bool enabled)
{
is_enabled = enabled;
}
bool eventlog_is_enabled()
{
return is_enabled;
}
void eventlog_set_enabled(bool enabled)
{
is_enabled = enabled;
}
void eventlog_write(uint8_t evt)
{
if (!is_enabled)
{
return;
}
uart_write(0xee);
uart_write(evt);
uart_write((uint8_t)0xee + evt);
}
void eventlog_write_data(uint8_t evt, int16_t data)
{
if (!is_enabled)
{
return;
}
uint8_t checksum = 0;
uart_write(0xed); checksum += (uint8_t)0xed;
uart_write(evt); checksum += evt;
uart_write((uint8_t)(data >> 8)); checksum += (uint8_t)(data >> 8);
uart_write((uint8_t)data); checksum += (uint8_t)data;
uart_write(checksum);
}
================================================
FILE: src/firmware/eventlog.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _EVENTLOG_H_
#define _EVENTLOG_H_
#include "intellisense.h"
#include
#include
#define EVT_MSG_MOTOR_INIT_OK 1
#define EVT_MSG_CONFIG_READ_DONE 2
#define EVT_MSG_CONFIG_RESET 3
#define EVT_MSG_CONFIG_WRITE_DONE 4
#define EVT_MSG_CONFIG_READ_BEGIN 5
#define EVT_MSG_CONFIG_WRITE_BEGIN 6
#define EVT_MSG_PSTATE_READ_BEGIN 7
#define EVT_MSG_PSTATE_READ_DONE 8
#define EVT_MSG_PSTATE_WRITE_BEGIN 9
#define EVT_MSG_PSTATE_WRITE_DONE 10
#define EVT_ERROR_INIT_MOTOR 64
#define EVT_ERROR_CHANGE_TARGET_SPEED 65
#define EVT_ERROR_CHANGE_TARGET_CURRENT 66
#define EVT_ERROR_READ_MOTOR_STATUS 67
#define EVT_ERROR_READ_MOTOR_CURRENT 68
#define EVT_ERROR_READ_MOTOR_VOLTAGE 69
#define EVT_ERROR_EEPROM_READ 70
#define EVT_ERROR_EEPROM_WRITE 71
#define EVT_ERROR_EEPROM_ERASE 72
#define EVT_ERROR_EEPROM_VERIFY_VERSION 73
#define EVT_ERROR_EEPROM_VERIFY_CHECKSUM 74
#define EVT_ERROR_THROTTLE_LOW_LIMIT 75
#define EVT_ERROR_THROTTLE_HIGH_LIMIT 76
#define EVT_ERROR_WATCHDOG_TRIGGERED 77
#define EVT_ERROR_EXTCOM_CHEKSUM 78
#define EVT_ERROR_EXTCOM_DISCARD 79
#define EVT_DATA_TARGET_CURRENT 128
#define EVT_DATA_TARGET_SPEED 129
#define EVT_DATA_MOTOR_STATUS 130
#define EVT_DATA_ASSIST_LEVEL 131
#define EVT_DATA_OPERATION_MODE 132
#define EVT_DATA_WHEEL_SPEED_PPM 133
#define EVT_DATA_LIGHTS 134
#define EVT_DATA_TEMPERATURE 135
#define EVT_DATA_THERMAL_LIMITING 136
#define EVT_DATA_SPEED_LIMITING 137
#define EVT_DATA_MAX_CURRENT_ADC_REQUEST 138
#define EVT_DATA_MAX_CURRENT_ADC_RESPONSE 139
#define EVT_DATA_MAIN_LOOP_TIME 140
#define EVT_DATA_THROTTLE_ADC 141
#define EVT_DATA_LVC_LIMITING 142
#define EVT_DATA_SHIFT_SENSOR 143
#define EVT_DATA_BBSHD_THERMISTOR 144
#define EVT_DATA_VOLTAGE 145
#define EVT_DATA_CALIBRATE_VOLTAGE 146
#define EVT_DATA_TORQUE_ADC 147
#define EVT_DATA_TORQUE_ADC_CALIBRATED 148
void eventlog_init(bool enabled);
bool eventlog_is_enabled();
void eventlog_set_enabled(bool enabled);
void eventlog_write(uint8_t evt);
void eventlog_write_data(uint8_t evt, int16_t data);
#endif
================================================
FILE: src/firmware/extcom.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "extcom.h"
#include "cfgstore.h"
#include "eventlog.h"
#include "uart.h"
#include "system.h"
#include "sensors.h"
#include "motor.h"
#include "battery.h"
#include "app.h"
#include "util.h"
#include "version.h"
#include "intellisense.h"
#include "fwconfig.h"
#include
#include
#include
#define KEEP 0
#define DISCARD -1
#define BUFFER_SIZE 192
#define DISCARD_TIMEOUT_MS 50
#define REQUEST_TYPE_READ 0x01
#define REQUEST_TYPE_WRITE 0x02
#define REQUEST_TYPE_BAFANG_READ 0x11
#define REQUEST_TYPE_BAFANG_WRITE 0x16
// Firmware config tool communication
#define OPCODE_READ_FW_VERSION 0x01
#define OPCODE_READ_EVTLOG_ENABLE 0x02
#define OPCODE_READ_CONFIG 0x03
#define OPCODE_READ_STATUS 0x04
#define OPCODE_WRITE_EVTLOG_ENABLE 0xf0
#define OPCODE_WRITE_CONFIG 0xf1
#define OPCODE_WRITE_RESET_CONFIG 0xf2
#define OPCODE_WRITE_ADC_VOLTAGE_CALIBRATION 0xf3
// Bafang display communication
#define OPCODE_BAFANG_DISPLAY_READ_STATUS 0x08
#define OPCODE_BAFANG_DISPLAY_READ_CURRENT 0x0a
#define OPCODE_BAFANG_DISPLAY_READ_BATTERY 0x11
#define OPCODE_BAFANG_DISPLAY_READ_SPEED 0x20
#define OPCODE_BAFANG_DISPLAY_READ_UNKNOWN1 0x21
#define OPCODE_BAFANG_DISPLAY_READ_RANGE 0x22
#define OPCODE_BAFANG_DISPLAY_READ_CALORIES 0x24
#define OPCODE_BAFANG_DISPLAY_READ_UNKNOWN3 0x25
#define OPCODE_BAFANG_DISPLAY_READ_MOVING 0x31
#define OPCODE_BAFANG_DISPLAY_WRITE_PAS 0x0b
#define OPCODE_BAFANG_DISPLAY_WRITE_MODE 0x0c
#define OPCODE_BAFANG_DISPLAY_WRITE_LIGHTS 0x1a
#define OPCODE_BAFANG_DISPLAY_WRITE_SPEED_LIM 0x1f
// Bafang config tool communication (not supported, just discard messages)
#define OPCODE_BAFANG_TOOL_READ_CONNECT 0x51
#define OPCODE_BAFANG_TOOL_READ_BASIC 0x52
#define OPCODE_BAFANG_TOOL_READ_PAS 0x53
#define OPCODE_BAFANG_TOOL_READ_THROTTLE 0x54
#define OPCODE_BAFANG_TOOL_WRITE_BASIC 0x52
#define OPCODE_BAFANG_TOOL_WRITE_PAS 0x53
#define OPCODE_BAFANG_TOOL_WRITE_THROTTLE 0x54
static uint8_t msg_len;
static uint8_t msgbuf[BUFFER_SIZE];
static uint32_t last_recv_ms;
static uint32_t discard_until_ms;
static uint8_t compute_checksum(uint8_t* buf, uint8_t length);
static void write_uart_and_increment_checksum(uint8_t data, uint8_t* checksum);
static int16_t try_process_request();
static int16_t try_process_read_request();
static int16_t try_process_write_request();
static int16_t try_process_bafang_read_request();
static int16_t try_process_bafang_write_request();
static int16_t process_read_fw_version();
static int16_t process_read_evtlog_enable();
static int16_t process_read_config();
static int16_t process_read_status();
static int16_t process_write_evtlog_enable();
static int16_t process_write_config();
static int16_t process_write_reset_config();
static int16_t process_write_adc_voltage_calibration();
static int16_t process_bafang_display_read_status();
static int16_t process_bafang_display_read_current();
static int16_t process_bafang_display_read_battery();
static int16_t process_bafang_display_read_speed();
static int16_t process_bafang_display_read_unknown1();
static int16_t process_bafang_display_read_range();
static int16_t process_bafang_display_read_calories();
static int16_t process_bafang_display_read_unknown3();
static int16_t process_bafang_display_read_moving();
static int16_t process_bafang_display_write_pas();
static int16_t process_bafang_display_write_mode();
static int16_t process_bafang_display_write_lights();
static int16_t process_bafang_display_write_speed_limit();
void extcom_init()
{
msg_len = 0;
last_recv_ms = 0;
discard_until_ms = 0;
// Bafang standard baud rate
uart_open(1200);
// Wait one second for config tool connection.
// This is here to that the config tool can enable
// the event log before system proceeds with initialization.
uint32_t end = system_ms() + 1000;
while (system_ms() < end)
{
extcom_process();
system_delay_ms(10);
}
}
void extcom_process()
{
uint32_t now = system_ms();
while (uart_available())
{
if (msg_len == BUFFER_SIZE || (discard_until_ms != 0 && now < discard_until_ms))
{
// communication error, reset
msg_len = 0;
while (uart_available()) uart_read();
}
else
{
msgbuf[msg_len++] = uart_read();
last_recv_ms = now;
discard_until_ms = 0;
}
}
if (msg_len > 0 && now - last_recv_ms > 100)
{
// communication error, reset
msg_len = 0;
}
int16_t res = try_process_request();
if (res == DISCARD)
{
msg_len = 0;
last_recv_ms = 0;
// Discard received data for the next DISCARD_TIMEOUT_MS milliseconds
discard_until_ms = now + DISCARD_TIMEOUT_MS;
eventlog_write(EVT_ERROR_EXTCOM_DISCARD);
}
else if (res > 0)
{
if (res < msg_len)
{
// will not occur due to request/response communication
memcpy(msgbuf, msgbuf + res, msg_len - res);
msg_len -= res;
}
else
{
msg_len = 0;
last_recv_ms = 0;
}
}
}
static uint8_t compute_checksum(uint8_t* buf, uint8_t length)
{
uint8_t result = 0;
for (uint8_t i = 0; i < length; ++i)
{
result += buf[i];
}
return result;
}
static void write_uart_and_increment_checksum(uint8_t data, uint8_t* checksum)
{
*checksum += data;
uart_write(data);
}
static int16_t try_process_request()
{
if (msg_len < 1)
{
return KEEP;
}
switch (msgbuf[0])
{
case REQUEST_TYPE_READ:
return try_process_read_request();
case REQUEST_TYPE_WRITE:
return try_process_write_request();
case REQUEST_TYPE_BAFANG_READ:
return try_process_bafang_read_request();
case REQUEST_TYPE_BAFANG_WRITE:
return try_process_bafang_write_request();
}
return DISCARD; // unknown message
}
static int16_t try_process_read_request()
{
if (msg_len < 2)
{
return KEEP;
}
switch (msgbuf[1])
{
case OPCODE_READ_FW_VERSION:
return process_read_fw_version();
case OPCODE_READ_EVTLOG_ENABLE:
return process_read_evtlog_enable();
case OPCODE_READ_CONFIG:
return process_read_config();
case OPCODE_READ_STATUS:
return process_read_status();
}
return DISCARD;
}
static int16_t try_process_write_request()
{
if (msg_len < 2)
{
return KEEP;
}
switch (msgbuf[1])
{
case OPCODE_WRITE_EVTLOG_ENABLE:
return process_write_evtlog_enable();
case OPCODE_WRITE_CONFIG:
return process_write_config();
case OPCODE_WRITE_RESET_CONFIG:
return process_write_reset_config();
case OPCODE_WRITE_ADC_VOLTAGE_CALIBRATION:
return process_write_adc_voltage_calibration();
}
return DISCARD;
}
static int16_t try_process_bafang_read_request()
{
if (msg_len < 2)
{
return KEEP;
}
switch (msgbuf[1])
{
case OPCODE_BAFANG_DISPLAY_READ_STATUS:
return process_bafang_display_read_status();
case OPCODE_BAFANG_DISPLAY_READ_CURRENT:
return process_bafang_display_read_current();
case OPCODE_BAFANG_DISPLAY_READ_BATTERY:
return process_bafang_display_read_battery();
case OPCODE_BAFANG_DISPLAY_READ_SPEED:
return process_bafang_display_read_speed();
case OPCODE_BAFANG_DISPLAY_READ_UNKNOWN1:
return process_bafang_display_read_unknown1();
case OPCODE_BAFANG_DISPLAY_READ_RANGE:
return process_bafang_display_read_range();
case OPCODE_BAFANG_DISPLAY_READ_CALORIES:
return process_bafang_display_read_calories();
case OPCODE_BAFANG_DISPLAY_READ_UNKNOWN3:
return process_bafang_display_read_unknown3();
case OPCODE_BAFANG_DISPLAY_READ_MOVING:
return process_bafang_display_read_moving();
}
return DISCARD;
}
static int16_t try_process_bafang_write_request()
{
if (msg_len < 2)
{
return KEEP;
}
switch (msgbuf[1])
{
case OPCODE_BAFANG_DISPLAY_WRITE_PAS:
return process_bafang_display_write_pas();
case OPCODE_BAFANG_DISPLAY_WRITE_MODE:
return process_bafang_display_write_mode();
case OPCODE_BAFANG_DISPLAY_WRITE_LIGHTS:
return process_bafang_display_write_lights();
case OPCODE_BAFANG_DISPLAY_WRITE_SPEED_LIM:
return process_bafang_display_write_speed_limit();
}
return DISCARD;
}
static int16_t process_read_fw_version()
{
if (msg_len < 3)
{
return KEEP;
}
if (compute_checksum(msgbuf, 2) == msgbuf[2])
{
uint8_t checksum = 0;
write_uart_and_increment_checksum(REQUEST_TYPE_READ, &checksum);
write_uart_and_increment_checksum(OPCODE_READ_FW_VERSION, &checksum);
write_uart_and_increment_checksum(VERSION_MAJOR, &checksum);
write_uart_and_increment_checksum(VERSION_MINOR, &checksum);
write_uart_and_increment_checksum(VERSION_PATCH, &checksum);
write_uart_and_increment_checksum(CONFIG_VERSION, &checksum);
write_uart_and_increment_checksum(CTRL_TYPE, &checksum);
uart_write(checksum);
}
else
{
eventlog_write(EVT_ERROR_EXTCOM_CHEKSUM);
return DISCARD;
}
return 3;
}
static int16_t process_read_evtlog_enable()
{
if (msg_len < 3)
{
return KEEP;
}
if (compute_checksum(msgbuf, 2) == msgbuf[2])
{
uint8_t checksum = 0;
write_uart_and_increment_checksum(REQUEST_TYPE_READ, &checksum);
write_uart_and_increment_checksum(OPCODE_READ_EVTLOG_ENABLE, &checksum);
write_uart_and_increment_checksum((uint8_t)eventlog_is_enabled(), &checksum);
uart_write(checksum);
}
else
{
eventlog_write(EVT_ERROR_EXTCOM_CHEKSUM);
return DISCARD;
}
return 3;
}
static int16_t process_read_config()
{
if (msg_len < 3)
{
return KEEP;
}
if (compute_checksum(msgbuf, 2) == msgbuf[2])
{
uint8_t checksum = 0;
write_uart_and_increment_checksum(REQUEST_TYPE_READ, &checksum);
write_uart_and_increment_checksum(OPCODE_READ_CONFIG, &checksum);
write_uart_and_increment_checksum(CONFIG_VERSION, &checksum);
write_uart_and_increment_checksum(sizeof(config_t), &checksum);
uint8_t* cfg = (uint8_t*)&g_config;
for (uint8_t i = 0; i < sizeof(config_t); ++i)
{
write_uart_and_increment_checksum(*(cfg + i), &checksum);
}
uart_write(checksum);
}
else
{
eventlog_write(EVT_ERROR_EXTCOM_CHEKSUM);
return DISCARD;
}
return 3;
}
static int16_t process_read_status()
{
// :TODO:
return 0;
}
static int16_t process_write_evtlog_enable()
{
if (msg_len < 4)
{
return KEEP;
}
if (compute_checksum(msgbuf, 3) == msgbuf[3])
{
eventlog_set_enabled((bool)msgbuf[2]);
uint8_t checksum = 0;
write_uart_and_increment_checksum(REQUEST_TYPE_WRITE, &checksum);
write_uart_and_increment_checksum(OPCODE_WRITE_EVTLOG_ENABLE, &checksum);
write_uart_and_increment_checksum(msgbuf[2], &checksum);
uart_write(checksum);
}
else
{
eventlog_write(EVT_ERROR_EXTCOM_CHEKSUM);
return DISCARD;
}
return 4;
}
static int16_t process_write_config()
{
if (msg_len < 4)
{
return KEEP;
}
uint8_t version = msgbuf[2];
uint8_t length = msgbuf[3];
if (msg_len < 4 + length + 1)
{
return KEEP;
}
if (compute_checksum(msgbuf, (uint8_t)(4 + sizeof(config_t))) == msgbuf[4 + sizeof(config_t)])
{
bool result = false;
if (version == CONFIG_VERSION && length == sizeof(config_t))
{
memcpy(&g_config, msgbuf + 4, sizeof(config_t));
result = cfgstore_save_config();
}
uint8_t checksum = 0;
write_uart_and_increment_checksum(REQUEST_TYPE_WRITE, &checksum);
write_uart_and_increment_checksum(OPCODE_WRITE_CONFIG, &checksum);
write_uart_and_increment_checksum(result, &checksum);
uart_write(checksum);
}
else
{
eventlog_write(EVT_ERROR_EXTCOM_CHEKSUM);
return DISCARD;
}
return 4 + length + 1;
}
static int16_t process_write_reset_config()
{
if (msg_len < 3)
{
return KEEP;
}
if (compute_checksum(msgbuf, 2) == msgbuf[2])
{
bool res = cfgstore_reset_config();
uint8_t checksum = 0;
write_uart_and_increment_checksum(REQUEST_TYPE_WRITE, &checksum);
write_uart_and_increment_checksum(OPCODE_WRITE_RESET_CONFIG, &checksum);
write_uart_and_increment_checksum((uint8_t)res, &checksum);
uart_write(checksum);
}
else
{
eventlog_write(EVT_ERROR_EXTCOM_CHEKSUM);
return DISCARD;
}
return 3;
}
static int16_t process_write_adc_voltage_calibration()
{
if (msg_len < 5)
{
return KEEP;
}
if (compute_checksum(msgbuf, 4) == msgbuf[4])
{
uint16_t actual_volt_x100 = ((uint16_t)msgbuf[2] << 8) | msgbuf[3];
int16_t calibration_offset = motor_calibrate_battery_voltage(actual_volt_x100);
g_pstate.adc_voltage_calibration_steps_x100_i16l = (uint8_t)(calibration_offset);
g_pstate.adc_voltage_calibration_steps_x100_i16h = (uint8_t)(calibration_offset >> 8);
cfgstore_save_pstate();
uint8_t checksum = 0;
write_uart_and_increment_checksum(REQUEST_TYPE_WRITE, &checksum);
write_uart_and_increment_checksum(OPCODE_WRITE_ADC_VOLTAGE_CALIBRATION, &checksum);
write_uart_and_increment_checksum(msgbuf[2], &checksum);
write_uart_and_increment_checksum(msgbuf[3], &checksum);
uart_write(checksum);
}
else
{
eventlog_write(EVT_ERROR_EXTCOM_CHEKSUM);
return DISCARD;
}
return 5;
}
static int16_t process_bafang_display_read_status()
{
if (msg_len < 2)
{
return KEEP;
}
uart_write(app_get_status_code());
return 2;
}
static int16_t process_bafang_display_read_current()
{
if (msg_len < 2)
{
return KEEP;
}
uint8_t amp_x2 = (uint8_t)((motor_get_battery_current_x10() * 2) / 10);
uart_write(amp_x2);
uart_write(amp_x2); // checksum
return 2;
}
static int16_t process_bafang_display_read_battery()
{
if (msg_len < 2)
{
return KEEP;
}
uint8_t value = battery_get_mapped_percent();
uart_write(value);
uart_write(value); // checksum
return 2;
}
static int16_t process_bafang_display_read_speed()
{
if (msg_len < 2)
{
return KEEP;
}
uint16_t speed = 0;
if (g_config.walk_mode_data_display != WALK_MODE_DATA_SPEED && app_get_assist_level() == ASSIST_PUSH)
{
uint16_t data = 0;
switch (g_config.walk_mode_data_display)
{
case WALK_MODE_DATA_TEMPERATURE:
// Keep temperature in C, farenheit would be out of range
data = app_get_temperature();
break;
case WALK_MODE_DATA_REQUESTED_POWER:
data = motor_get_target_current();
break;
case WALK_MODE_DATA_BATTERY_PERCENT:
data = battery_get_percent();
break;
}
if (g_config.use_freedom_units)
{
// Compensate for kph -> mph conversion display will do.
data = (data * 161) / 100;
}
// T_kph -> rpm
speed = (uint16_t)(25000.f / (3 * 3.14159f * 1.27f * EXPAND_U16(g_config.wheel_size_inch_x10_u16h, g_config.wheel_size_inch_x10_u16l)) * data);
}
else
{
speed = speed_sensor_get_rpm_x10() / 10;
}
uint8_t checksum = 0;
write_uart_and_increment_checksum(speed >> 8, &checksum);
write_uart_and_increment_checksum((uint8_t)speed, &checksum);
uart_write(checksum + (uint8_t)0x20); // weird checksum
return 2;
}
static int16_t process_bafang_display_read_unknown1()
{
if (msg_len < 3)
{
return KEEP;
}
uart_write(0x00);
uart_write(0x00);
uart_write(0x00); // checksum
return 3;
}
static int16_t process_bafang_display_read_range()
{
if (msg_len < 3)
{
return KEEP;
}
uint16_t value = 0;
#if DISPLAY_RANGE_FIELD_DATA == DISPLAY_RANGE_FIELD_TEMPERATURE
value = app_get_temperature();
if (g_config.use_freedom_units)
{
// Convert to farenheit and compensate for the km -> miles conversion the diplay will do
// F_miles = (C * 9/5 + 32) * 161 / 100
// Approximistation:
// F_miles = 2.9C + 50.5
value = ((290u * value) + 5050u) / 100u;
}
#elif DISPLAY_RANGE_FIELD_DATA == DISPLAY_RANGE_FIELD_POWER
if (app_get_lights())
{
value = motor_get_battery_current_x10();
}
else
{
uint16_t max_current_amp_x10 = g_config.max_current_amps * 10;
value = MAP32(motor_get_target_current(), 0, 100, 0, max_current_amp_x10);
}
if (g_config.use_freedom_units)
{
// compensate for km -> miles conversion the display will do
value = (value * 161u) / 100u;
}
#endif
uint8_t checksum = 0;
write_uart_and_increment_checksum((uint8_t)(value >> 8), &checksum);
write_uart_and_increment_checksum((uint8_t)value, &checksum);
uart_write(checksum); // checksum
return 3;
}
static int16_t process_bafang_display_read_calories()
{
if (msg_len < 3)
{
return KEEP;
}
uint8_t checksum = 0;
// send battery voltage x10 to show in calories field
uint16_t volt = motor_get_battery_voltage_x10();
write_uart_and_increment_checksum(volt >> 8, & checksum);
write_uart_and_increment_checksum(volt & 0xff, & checksum);
uart_write(checksum); // checksum
return 3;
}
static int16_t process_bafang_display_read_unknown3()
{
if (msg_len < 3)
{
return KEEP;
}
uart_write(0x00);
uart_write(0x00);
uart_write(0x00);
uart_write(0x00);
uart_write(0x00); // checksum
return 3;
}
static int16_t process_bafang_display_read_moving()
{
if (msg_len < 2)
{
return KEEP;
}
uint8_t data = speed_sensor_is_moving() ? 0x31 : 0x30;
uart_write(data);
uart_write(data); // checksum
return 2;
}
static int16_t process_bafang_display_write_pas()
{
if (msg_len < 4)
{
return KEEP;
}
if (compute_checksum(msgbuf, 3) == msgbuf[3])
{
switch (msgbuf[2])
{
case 0x00:
app_set_assist_level(ASSIST_0);
break;
case 0x01:
app_set_assist_level(ASSIST_1);
break;
case 0x0b:
app_set_assist_level(ASSIST_2);
break;
case 0x0c:
app_set_assist_level(ASSIST_3);
break;
case 0x0d:
app_set_assist_level(ASSIST_4);
break;
case 0x02:
app_set_assist_level(ASSIST_5);
break;
case 0x15:
app_set_assist_level(ASSIST_6);
break;
case 0x16:
app_set_assist_level(ASSIST_7);
break;
case 0x17:
app_set_assist_level(ASSIST_8);
break;
case 0x03:
app_set_assist_level(ASSIST_9);
break;
case 0x06:
app_set_assist_level(ASSIST_PUSH);
break;
default:
// Unsupported level, ignore
break;
}
}
else
{
eventlog_write(EVT_ERROR_EXTCOM_CHEKSUM);
return DISCARD;
}
return 4;
}
static int16_t process_bafang_display_write_mode()
{
if (msg_len < 4)
{
return KEEP;
}
if (compute_checksum(msgbuf, 3) == msgbuf[3])
{
switch (msgbuf[2])
{
case 0x02:
app_set_operation_mode(OPERATION_MODE_DEFAULT);
break;
case 0x04:
app_set_operation_mode(OPERATION_MODE_SPORT);
break;
default:
// Unsupported mode, ignore
break;
}
}
else
{
eventlog_write(EVT_ERROR_EXTCOM_CHEKSUM);
return DISCARD;
}
return 4;
}
static int16_t process_bafang_display_write_lights()
{
if (msg_len < 3)
{
return KEEP;
}
// No checksum
switch (msgbuf[2])
{
case 0xf0:
app_set_lights(false);
break;
case 0xf1:
app_set_lights(true);
break;
default:
return DISCARD; // unsupported state, assume communication error
}
return 3;
}
static int16_t process_bafang_display_write_speed_limit()
{
if (msg_len < 5)
{
return KEEP;
}
/*
if (compute_checksum(msgbuf, 4) == msgbuf[4])
{
// Ignoring speed limit requested by display,
// Global speed limit is configured in firmware config tool.
uint16_t value = ((msgbuf[2] << 8) | msgbuf[3]);
app_set_wheel_max_speed_rpm(value);
}
else
{
eventlog_write(EVT_ERROR_EXTCOM_CHEKSUM);
return DISCARD;
}
*/
return 5;
}
================================================
FILE: src/firmware/extcom.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _EXTCOM_H_
#define _EXTCOM_H_
void extcom_init();
void extcom_process();
#endif
================================================
FILE: src/firmware/fwconfig.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _FWCONFIG_H_
#define _FWCONFIG_H_
#if defined(BBSHD)
#define HAS_MOTOR_TEMP_SENSOR 1
#else
#define HAS_MOTOR_TEMP_SENSOR 0
#endif
#if defined(BBSHD) || defined(BBS02)
#define HAS_CONTROLLER_TEMP_SENSOR 1
#else
#define HAS_CONTROLLER_TEMP_SENSOR 0
#endif
#if defined(TSDZ2)
#define HAS_TORQUE_SENSOR 1
#else
#define HAS_TORQUE_SENSOR 0
#endif
#if defined(BBSHD) || defined(BBS02)
#define HAS_SHIFT_SENSOR_SUPPORT 1
#else
#define HAS_SHIFT_SENSOR_SUPPORT 0
#endif
#if defined(BBS02)
#define MAX_CADENCE_RPM_X10 1500
#elif defined(BBSHD)
// Measured on BBSHD at 48V
#define MAX_CADENCE_RPM_X10 1680
#else
#define MAX_CADENCE_RPM_X10 1200
#endif
#if defined(BBS02) || defined(BBSHD)
#define PAS_PULSES_REVOLUTION 24
#elif defined(TSDZ2)
#define PAS_PULSES_REVOLUTION 20
#endif
// Applied to both motor and controller tmeperature sensor
#define MAX_TEMPERATURE 85
// Current ramp down starts at MAX_TEMPERATURE - 5.
#define MAX_TEMPERATURE_RAMP_DOWN_INTERVAL 5
// Maximum allowed motor current in percent of maximum configured current (A)
// to still apply when maximum temperature has been reached.
// Motor current is ramped down linearly until this value when approaching
// max temperature.
#define MAX_TEMPERATURE_LOW_CURRENT_PERCENT 20
// No battery percent mapping
#define BATTERY_PERCENT_MAP_NONE 0
// Map battery percent to provide a linear relationship on the
// 5-bar battery indicator of the SW102 display.
#define BATTERY_PERCENT_MAP_SW102 1
// Select battery percent mapping
#define BATTERY_PERCENT_MAP BATTERY_PERCENT_MAP_NONE
// Time with no motor load until battery voltage is updated to avoid voltage sag.
#define BATTERY_NO_LOAD_DELAY_MS 2000
// Padding values for voltage range of battery.
#define BATTERY_FULL_OFFSET_PERCENT 8
#define BATTERY_EMPTY_OFFSET_PERCENT 8
// Battery SOC percentage when current ramp down starts.
#define LVC_RAMP_DOWN_OFFSET_PERCENT 10
// Maximum allowed motor current in percent of maximum configured current (A)
// to still apply when 0% battery has been reached.
// Motor current is ramped down linearly until this value when approaching "empty".
#define LVC_LOW_CURRENT_PERCENT 20
// Size of speed limit ramp down interval.
// If max speed is 50 and this is set to 3 then the
// target current will start ramping down when passing 47
// and be at 50% of assist target current when reaching 50.
#define SPEED_LIMIT_RAMP_DOWN_INTERVAL_KPH 3
// Current ramp down (e.g. when releasing throttle, stop pedaling etc.) in percent per 10 millisecond.
// Specifying 1 will make ramp down periond 1 second if releasing from full throttle.
// Set to 100 to disable
#define CURRENT_RAMP_DOWN_PERCENT_10MS 5
// Target speed in km/h when walk mode is engaged
#define WALK_MODE_SPEED_KPH 4
#define THROTTLE_RESPONSE_LINEAR 1
#define THROTTLE_RESPONSE_QUADRATIC 2
#define THROTTLE_RESPONSE_CUSTOM 3
#define THROTTLE_RESPONSE_CURVE THROTTLE_RESPONSE_CUSTOM
// Custom throttle map
// y = pow(x / 100.0, 1.5) * 100.0
#define THROTTLE_CUSTOM_MAP \
0, 1, 1, 1, 2, 2, 2, 3, 3, 3, \
4, 4, 4, 5, 5, 6, 6, 7, 8, 8, \
9, 10, 10, 11, 12, 12, 13, 14, 15, 16, \
16, 17, 18, 19, 20, 21, 22, 23, 23, 24, \
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, \
35, 36, 37, 39, 40, 41, 42, 43, 44, 45, \
46, 48, 49, 50, 51, 52, 54, 55, 56, 57, \
59, 60, 61, 62, 64, 65, 66, 68, 69, 70, \
72, 73, 74, 76, 77, 78, 80, 81, 83, 84, \
85, 87, 88, 90, 91, 93, 94, 96, 97, 99, \
100
// This value is used when assist level is configured with throttle cadence
// override flag in config tool. Default is 100%.
#define THROTTLE_CADENCE_OVERRIDE_PERCENT 100
// Lower limit for cadence rpm in power calculation
// for torque pas assist. When cadence is below this
// limit you will get extra power.
//
// power_w = torque_Nm * cadence_rpm * 0.105
//
// The calculated power is then multipled by a factor
// set by the assist level to get the final power which
// the motor will contribute.
//
// The value configured below is the minimum value for
// cadence_rpm to be used in the formula above. If the
// actual cadence is lower it will be overriden by this
// configured value.
#define TORQUE_POWER_LOWER_RPM_X10 300
// Number of PAS sensor pulses to engage cruise mode,
// there are 24 pulses per revolution.
#define CRUISE_ENGAGE_PAS_PULSES PAS_PULSES_REVOLUTION / 2
// Number of PAS sensor pulses to disengage curise mode
// by pedaling backwards.
#define CRUISE_DISENGAGE_PAS_PULSES PAS_PULSES_REVOLUTION / 2
// Option to control what data is displayed in "Range" field on display
// since range calculation is not implemented.
#define DISPLAY_RANGE_FIELD_ZERO 0
#define DISPLAY_RANGE_FIELD_TEMPERATURE 1 // max temperature of controller / motor
#define DISPLAY_RANGE_FIELD_POWER 2 // requested current x10 (lights off) / actual current x10 (lights on)
// uncomment and select option above
// #define DISPLAY_RANGE_FIELD_DATA DISPLAY_RANGE_FIELD_ZERO
// default to temperature if temperature sensors available (BBS2/BBSHD), else power (TSDZ2)
#ifndef DISPLAY_RANGE_FIELD_DATA
#if HAS_CONTROLLER_TEMP_SENSOR || HAS_MOTOR_TEMP_SENSOR
#define DISPLAY_RANGE_FIELD_DATA DISPLAY_RANGE_FIELD_TEMPERATURE
#else
#define DISPLAY_RANGE_FIELD_DATA DISPLAY_RANGE_FIELD_POWER
#endif
#endif
#endif
================================================
FILE: src/firmware/intellisense.h
================================================
#ifndef _INTELLISENSE_H_
#define _INTELLISENSE_H_
// NOTE:
// The defines below are here to keep IntelliSense
// in Visual Studio happy and not throw incorrect errors.
#if !defined (SDCC) && !defined (__SDCC)
#define INTERRUPT(name, vector) void name()
#define INTERRUPT_USING(name, vector,regnum) void name()
#define __interrupt(vector)
#define enableInterrupts()
#define disableInterrupts()
#define NOP()
#define _Bool uint8_t
#endif
#endif
================================================
FILE: src/firmware/interrupt.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_
// Interrupt rouines declarations required to be included from main.c
#if defined(BBSHD) || defined(BBS02)
#include "bbsx/interrupt.h"
#elif defined(TSDZ2)
#include "tsdz2/interrupt.h"
#endif
#endif
================================================
FILE: src/firmware/lights.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _LIGHTS_H_
#define _LIGHTS_H_
#include "intellisense.h"
#include
#include
void lights_init();
void lights_enable();
void lights_disable();
void lights_set(bool on);
#endif
================================================
FILE: src/firmware/main.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "interrupt.h" // IMPORTANT: interrupt vector declarations must be included from main.c!
#include "timers.h"
#include "system.h"
#include "eeprom.h"
#include "cfgstore.h"
#include "eventlog.h"
#include "app.h"
#include "battery.h"
#include "watchdog.h"
#include "adc.h"
#include "motor.h"
#include "extcom.h"
#include "sensors.h"
#include "throttle.h"
#include "lights.h"
#include "uart.h"
#include "util.h"
#define APP_PROCESS_INTERVAL_MS 5
void main(void)
{
motor_pre_init();
watchdog_init();
timers_init();
system_init();
eventlog_init(false);
extcom_init();
if (watchdog_triggered())
{
// force write watchdog reset to eventlog
bool prev = eventlog_is_enabled();
eventlog_set_enabled(true);
eventlog_write(EVT_ERROR_WATCHDOG_TRIGGERED);
eventlog_set_enabled(prev);
}
eeprom_init();
cfgstore_init();
adc_init();
sensors_init();
speed_sensor_set_signals_per_rpm(g_config.speed_sensor_signals);
pas_set_stop_delay((uint16_t)g_config.pas_stop_delay_x100s * 10);
battery_init();
throttle_init(
EXPAND_U16(g_config.throttle_start_voltage_mv_u16h, g_config.throttle_start_voltage_mv_u16l),
EXPAND_U16(g_config.throttle_end_voltage_mv_u16h, g_config.throttle_end_voltage_mv_u16l)
);
motor_init(g_config.max_current_amps * 1000, g_config.low_cut_off_v,
EXPAND_I16(g_pstate.adc_voltage_calibration_steps_x100_i16h, g_pstate.adc_voltage_calibration_steps_x100_i16l));
lights_init();
app_init();
uint32_t next_app_proccess = system_ms();
while (1)
{
uint32_t now = system_ms();
adc_process();
motor_process();
if (now >= next_app_proccess)
{
next_app_proccess = now + APP_PROCESS_INTERVAL_MS;
battery_process();
sensors_process();
extcom_process();
app_process();
}
watchdog_yeild();
}
}
================================================
FILE: src/firmware/motor.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _MOTOR_H_
#define _MOTOR_H_
#include
#define MOTOR_ERROR_LVC 0x0800
#define MOTOR_ERROR_HALL_SENSOR 0x2000
#define MOTOR_ERROR_CURRENT_SENSE 0x0004
#define MOTOR_ERROR_POWER_RESET 0x0020
void motor_pre_init();
void motor_init(uint16_t max_current_mA, uint8_t lvc_V, int16_t adc_calib_volt_step_offset);
void motor_process();
void motor_enable();
void motor_disable();
uint16_t motor_status();
uint8_t motor_get_target_speed();
uint8_t motor_get_target_current();
void motor_set_target_speed(uint8_t percent);
void motor_set_target_current(uint8_t percent);
int16_t motor_calibrate_battery_voltage(uint16_t actual_voltage_x100);
uint16_t motor_get_battery_lvc_x10();
uint16_t motor_get_battery_current_x10();
uint16_t motor_get_battery_voltage_x10();
#endif
================================================
FILE: src/firmware/sensors.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _SENSORS_H_
#define _SENSORS_H_
#include "intellisense.h"
#include
#include
void sensors_init();
void sensors_process();
void pas_set_stop_delay(uint16_t delay_ms);
uint16_t pas_get_cadence_rpm_x10();
uint16_t pas_get_pulse_counter();
bool pas_is_pedaling_forwards();
bool pas_is_pedaling_backwards();
void speed_sensor_set_signals_per_rpm(uint8_t num_signals);
bool speed_sensor_is_moving();
uint16_t speed_sensor_get_rpm_x10();
uint16_t torque_sensor_get_nm_x100();
bool torque_sensor_ok();
int16_t temperature_contr_x100();
int16_t temperature_motor_x100();
bool brake_is_activated();
bool shift_sensor_is_activated();
#endif
================================================
FILE: src/firmware/system.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _SYSTEM_H_
#define _SYSTEM_H_
#include "version.h"
#include
#if defined(BBSHD) || defined(BBS02)
#include "bbsx/cpu.h"
#elif defined(TSDZ2)
#include "tsdz2/cpu.h"
#endif
void system_init();
uint32_t system_ms();
void system_delay_ms(uint16_t ms);
#endif
================================================
FILE: src/firmware/throttle.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "throttle.h"
#include "intellisense.h"
#include "system.h"
#include "eventlog.h"
#include "util.h"
#include "adc.h"
#include "fwconfig.h"
#include
static uint8_t min_voltage_adc;
static uint8_t max_voltage_adc;
static bool throttle_detected;
static bool throttle_low_ok;
static bool throttle_hard_ok;
static uint32_t throttle_hard_limit_hit_at;
//#define LOG_THROTTLE_ADC
#define ADC_VOLTAGE_MV 5000ul
#define THROTTLE_HARD_LOW_LIMIT_MV 500ul
#define THROTTLE_HARD_HIGH_LIMIT_MV 4500ul
#define THROTTLE_HARD_LOW_LIMIT_ADC ((THROTTLE_HARD_LOW_LIMIT_MV * 256) / ADC_VOLTAGE_MV)
#define THROTTLE_HARD_HIGH_LIMIT_ADC ((THROTTLE_HARD_HIGH_LIMIT_MV * 256) / ADC_VOLTAGE_MV)
#define THROTTLE_HARD_LIMIT_TOLERANCE_MS 100
#if (THROTTLE_RESPONSE_CURVE == THROTTLE_RESPONSE_CUSTOM)
static const uint8_t throttle_custom_map_lut[101] =
{
THROTTLE_CUSTOM_MAP
};
#endif
void throttle_init(uint16_t min_mv, uint16_t max_mv)
{
min_voltage_adc = (uint8_t)(((uint32_t)min_mv * 256) / ADC_VOLTAGE_MV);
max_voltage_adc = (uint8_t)(((uint32_t)max_mv * 256) / ADC_VOLTAGE_MV);
throttle_detected = false;
throttle_low_ok = false;
throttle_hard_ok = true;
throttle_hard_limit_hit_at = 0;
}
bool throttle_ok()
{
return !throttle_detected || (throttle_low_ok && throttle_hard_ok);
}
uint8_t throttle_read()
{
static uint8_t throttle_percent = 0;
int16_t value = adc_get_throttle();
#ifdef LOG_THROTTLE_ADC
static uint8_t last_logged_throttle_adc = 0;
if (ABS(value - last_logged_throttle_adc) > 1)
{
last_logged_throttle_adc = value;
eventlog_write_data(EVT_DATA_THROTTLE_ADC, value);
}
#endif
if (value < THROTTLE_HARD_LOW_LIMIT_ADC || value > THROTTLE_HARD_HIGH_LIMIT_ADC)
{
// allow invalid throttle input value for a number of milliseconds before reporting throttle error.
if (throttle_hard_limit_hit_at != 0)
{
if (throttle_hard_ok && (system_ms() - throttle_hard_limit_hit_at) > THROTTLE_HARD_LIMIT_TOLERANCE_MS)
{
if (throttle_detected && value < THROTTLE_HARD_LOW_LIMIT_ADC)
{
eventlog_write(EVT_ERROR_THROTTLE_LOW_LIMIT);
}
else if (value > THROTTLE_HARD_HIGH_LIMIT_ADC)
{
eventlog_write(EVT_ERROR_THROTTLE_HIGH_LIMIT);
}
throttle_hard_ok = false;
}
}
else
{
throttle_hard_limit_hit_at = system_ms();
}
}
else
{
if (value >= THROTTLE_HARD_LOW_LIMIT_ADC)
{
throttle_detected = true;
}
throttle_hard_limit_hit_at = 0;
throttle_hard_ok = true;
}
if (value < min_voltage_adc)
{
// throttle is considered not working until it has given a signal below minimum
// configured value but more than 0.
throttle_low_ok = true;
// hysteresis
if (throttle_percent > 0)
{
value += 1;
}
if (value < min_voltage_adc)
{
throttle_percent = 0;
return throttle_percent;
}
}
if (value > max_voltage_adc)
{
value = max_voltage_adc;
}
throttle_percent = (uint8_t)MAP16(value, min_voltage_adc, max_voltage_adc, 1, 100);
return throttle_percent;
}
uint8_t throttle_map_response(uint8_t throttle_percent)
{
#if (THROTTLE_RESPONSE_CURVE == THROTTLE_RESPONSE_QUADRATIC)
return (uint8_t)(((uint16_t)throttle_percent * throttle_percent) / 100);
#elif (THROTTLE_RESPONSE_CURVE == THROTTLE_RESPONSE_CUSTOM)
return throttle_custom_map_lut[throttle_percent];
#else
return throttle_percent;
#endif
}
================================================
FILE: src/firmware/throttle.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _THROTTLE_H_
#define _THROTTLE_H_
#include "intellisense.h"
#include
#include
void throttle_init(uint16_t min_mv, uint16_t max_mv);
bool throttle_ok();
uint8_t throttle_read();
uint8_t throttle_map_response(uint8_t throttle_percent);
#endif
================================================
FILE: src/firmware/timers.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _TIMER_H_
#define _TIMER_H_
void timers_init();
#endif
================================================
FILE: src/firmware/tohex.bat
================================================
@echo off
packihx bbs-fw.ihx > bbs-fw.hex
================================================
FILE: src/firmware/tsdz2/adc.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include
#include "adc.h"
#include "tsdz2/interrupt.h"
#include "tsdz2/stm8.h"
#include "tsdz2/pins.h"
#include "tsdz2/stm8s/stm8s_adc1.h"
#include "tsdz2/stm8s/stm8s.h"
static volatile uint8_t adc_throttle;
static volatile uint16_t adc_battery_voltage;
static volatile uint16_t adc_torque;
// cached variables read from voltatile uint16_t vars while ADC1 interrupt disabled
static uint16_t adc_battery_voltage_cache;
static uint16_t adc_torque_cache;
void adc_init()
{
SET_PIN_INPUT(PIN_BATTERY_CURRENT);
SET_PIN_INPUT(PIN_BATTERY_VOLTAGE);
SET_PIN_INPUT(PIN_THROTTLE);
SET_PIN_INPUT(PIN_TORQUE_SENSOR);
// NOTE:
// adc configuration (except ADC1->CR1) is overwritten in motor.c/isr_timer1_cmp
// which triggeres the conversion.
//
// The motor control interrupt routines performs single mode
// adc conversion of battery current, reads the result and
// then starts buffered scan mode conversion of all adc channels
// with end of conversion interrupt enabled which is handled here.
ADC1->CR1 = ADC1_PRESSEL_FCPU_D2;
ADC1->CR2 = ADC1_ALIGN_LEFT;
// channel (none)
ADC1->CSR = 0x00;
// schmittrig disable all
ADC1->TDRL |= (uint8_t)0xFF;
ADC1->TDRH |= (uint8_t)0xFF;
// Enable the ADC1 peripheral
ADC1->CR1 |= ADC1_CR1_ADON;
}
void adc_process()
{
// Have to disable interrupts globally since ADC1->CSR register
// is manipulated from motor control isr. Very short time, should have no effect.
disableInterrupts();
adc_battery_voltage_cache = adc_battery_voltage; // adc_battery_voltage;
adc_torque_cache = adc_torque;
enableInterrupts();
}
uint8_t adc_get_throttle()
{
// atomic read
return adc_throttle;
}
uint16_t adc_get_torque()
{
// 10 bit resolution
return adc_torque_cache;
}
uint16_t adc_get_temperature_contr()
{
return 0;
}
uint16_t adc_get_temperature_motor()
{
return 0;
}
uint16_t adc_get_battery_voltage()
{
return adc_battery_voltage_cache;
}
void isr_adc1(void) __interrupt(ITC_IRQ_ADC1)
{
if (ADC1->CSR & ADC1_CSR_EOC)
{
// all adc channels converted, data available in buffers
// clear EOC and disable EOC interrupt
ADC1->CSR = 0x00;
// scan mode reads are setup to be left aligned in motor isr
// update cached values
adc_throttle = ADC1->DB7RH; // only 8bit resolution used
// must read in high -> low order according to data sheet
uint8_t high, low;
// read torque
high = ADC1->DB4RH;
low = ADC1->DB4RL;
adc_torque = (uint16_t)high << 2 | low;
// read battery voltage
high = ADC1->DB6RH;
low = ADC1->DB6RL;
adc_battery_voltage = (uint16_t)high << 2 | low;
}
}
================================================
FILE: src/firmware/tsdz2/cpu.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _TSDZ2_CPU_H_
#define _TSDZ2_CPU_H_
#define STM8S105
#define CPU_FREQ 16000000L
#endif
================================================
FILE: src/firmware/tsdz2/eeprom.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "eeprom.h"
#include "watchdog.h"
#include "tsdz2/cpu.h"
#include "stm8s/stm8s.h"
#include "stm8s/stm8s_flash.h"
#define EEPROM_START_ADDRESS 0x4000
static uint16_t selected_address;
void eeprom_init()
{
selected_address = EEPROM_START_ADDRESS;
}
bool eeprom_select_page(int page)
{
if (page >= 0 && page < 2)
{
selected_address = EEPROM_START_ADDRESS + (page * 256);
return true;
}
return false;
}
int eeprom_read_byte(int offset)
{
uint8_t* address = (uint8_t*)(selected_address + offset);
return *address;
}
bool eeprom_erase_page()
{
return true; // not needed
}
bool eeprom_write_byte(int offset, uint8_t value)
{
uint8_t* address = (uint8_t*)(selected_address + offset);
// disable flash write protection if enabled
if (!(FLASH->IAPSR & FLASH_IAPSR_DUL))
{
FLASH->DUKR = FLASH_RASS_KEY2;
FLASH->DUKR = FLASH_RASS_KEY1;
while (!(FLASH->IAPSR & FLASH_IAPSR_DUL));
}
watchdog_yeild(); // :TODO: use faster api to write entire page
*address = value;
while (!(FLASH->IAPSR & FLASH_IAPSR_EOP));
return true;
}
bool eeprom_end_write()
{
// enable write protection
FLASH->IAPSR &= ~FLASH_IAPSR_DUL;
return true;
}
================================================
FILE: src/firmware/tsdz2/interrupt.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _TSDZ2_INTERRUPT_H_
#define _TSDZ2_INTERRUPT_H_
#include "intellisense.h"
#include "tsdz2/cpu.h"
#include "tsdz2/stm8s/stm8s_itc.h"
void isr_timer1_cmp(void) __interrupt(ITC_IRQ_TIM1_CAPCOM); // motor.c
void isr_timer3_ovf(void) __interrupt(ITC_IRQ_TIM3_OVF); // system.c
void isr_timer4_ovf(void) __interrupt(ITC_IRQ_TIM4_OVF); // sensors.c
void isr_adc1(void) __interrupt(ITC_IRQ_ADC1); // adc.c
void isr_uart2_rx(void) __interrupt(ITC_IRQ_UART2_RX); // uart.c
void isr_uart2_tx(void) __interrupt(ITC_IRQ_UART2_TX); // uart.c
#endif
================================================
FILE: src/firmware/tsdz2/lights.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "lights.h"
#include "stm8.h"
#include "pins.h"
static bool lights_enabled;
static bool lights_on;
void lights_init()
{
SET_PIN_OUTPUT(PIN_LIGHTS);
lights_enabled = false;
lights_set(false);
}
void lights_enable()
{
lights_enabled = true;
lights_set(lights_on);
}
void lights_disable()
{
lights_enabled = false;
lights_set(lights_on);
}
void lights_set(bool on)
{
lights_on = on;
if (lights_on && lights_enabled)
{
SET_PIN_HIGH(PIN_LIGHTS);
}
else
{
SET_PIN_LOW(PIN_LIGHTS);
}
}
================================================
FILE: src/firmware/tsdz2/motor.c
================================================
/*
* TongSheng TSDZ2 motor controller firmware/
*
* Copyright (C) Casainho, 2018.
*
* Released under the GPL License, Version 3
*
* - Original motor control code from TongSheng TSDZ2 motor controller firmware.
* - 9bit motor pwm from fork by Frans-Willem.
* - Cleaned up and integrated into bbs-fw by Daniel Nilsson.
*/
#include
#include "motor.h"
#include "system.h"
#include "uart.h"
#include "eventlog.h"
#include "util.h"
#include "adc.h"
#include "tsdz2/cpu.h"
#include "tsdz2/timers.h"
#include "tsdz2/pins.h"
#include "tsdz2/stm8.h"
#include "tsdz2/stm8s/stm8s.h"
#include "tsdz2/stm8s/stm8s_tim1.h"
#include "tsdz2/stm8s/stm8s_itc.h"
#include "tsdz2/stm8s/stm8s_adc1.h"
#include "tsdz2/stm8s/stm8s_flash.h"
// Motor
// ---------------------------------------------------------------------------------
// hard current limits
#define MAX_BATTERY_CURRENT_AMPS_X10 200
#define MAX_MOTOR_PHASE_CURRENT_AMPS_X10 300
// Maximum current ramp
// ----------------------------------------------
// Every second has 15625 pwm cycles interrupts,
// one ADC battery current step -> 0.156 amps:
//
// A / 0.156 = X (we need to do X steps ramp up per second)
// Therefore :
// 15625 / (A / 0.156) => (15625 * 0.156) / A
//
// 20A/s: (15625 * 0.156) / 20 = 135
#define CURRENT_RAMP_UP_INVERSE_STEP 135
// Choose PWM ramp up/down step (higher value will make the motor acceleration slower)
//
// For a 24V battery, 25 for ramp up seems ok. For an higher voltage battery, this values should be higher
#define PWM_DUTY_CYCLE_RAMP_UP_INVERSE_STEP 24
#define PWM_DUTY_CYCLE_RAMP_DOWN_INVERSE_STEP 28
// This value should be near 0.
// You can try to tune with the whell on the air, full throttle and look at batttery current: adjust for lower battery current
#define MOTOR_ROTOR_OFFSET_ANGLE 11
// This value is ERPS speed after which a transition happens from sinewave no interpolation to have
// interpolation 60 degrees and must be found experimentally
#define MOTOR_ROTOR_ERPS_START_INTERPOLATION_60_DEGREES 10
#define PWM_CYCLES_COUNTER_MAX 3125U // 5 erps minimum speed; 1/5 = 200ms; 200ms/64us = 3125
#define PWM_CYCLES_SECOND 15625U // 1 / 64us (PWM period)
#define PWM_DUTY_CYCLE_MAX 254
#define PWM_DUTY_CYCLE_MIN 20
#define MOTOR_ROTOR_ANGLE_90 (63 + MOTOR_ROTOR_OFFSET_ANGLE)
#define MOTOR_ROTOR_ANGLE_150 (106 + MOTOR_ROTOR_OFFSET_ANGLE)
#define MOTOR_ROTOR_ANGLE_210 (148 + MOTOR_ROTOR_OFFSET_ANGLE)
#define MOTOR_ROTOR_ANGLE_270 (191 + MOTOR_ROTOR_OFFSET_ANGLE)
#define MOTOR_ROTOR_ANGLE_330 (233 + MOTOR_ROTOR_OFFSET_ANGLE)
#define MOTOR_ROTOR_ANGLE_30 (20 + MOTOR_ROTOR_OFFSET_ANGLE)
// motor maximum rotation
// 700 is equal to 124 cadence, as TSDZ2 has a reduction ratio of 41.8
#define MAX_MOTOR_SPEED_ERPS 700
// Set how often the motor speed limit controller runs in the isr
#define SPEED_CONTROLLER_CHECK_PERIODS 2000
// Set how oftern the current controller runs in the isr
#define CURRENT_CONTROLLER_CHECK_PERIODS 14
// adc measurements
// ------------------------------------------
// 10bit: 0.086V per step
// 0.156A per step
#define ADC_10BIT_VOLTAGE_PER_ADC_STEP_X512 44
#define ADC_10BIT_CURRENT_PER_ADC_STEP_X512 80
#define ADC_10BIT_STEPS_PER_VOLT_X512 5953
// filter coefficients
#define BATTERY_CURRENT_FILTER_COEFFICIENT 2
#define PHASE_CURRENT_FILTER_COEFFICIENT 2
#define BATTERY_VOLTAGE_FILTER_COEFFICIENT 2
#define SVM_TABLE_LEN 256
#define SVM_TABLE_MIDDLE 127
#define SIN_TABLE_LEN 60
// motor states
#define BLOCK_COMMUTATION 1
#define SINEWAVE_INTERPOLATION_60_DEGREES 2
// index 0-256 to degrees 0-360
// table is -90 degree preadjusted
static const uint8_t svm_table[SVM_TABLE_LEN] = {
0, 11, 22, 32, 43, 54, 65, 75, 86, 96, 107, 117, 128, 138, 148, 158,
168, 178, 188, 198, 207, 217, 222, 225, 228, 230, 233, 235, 238, 240, 242, 244,
245, 247, 248, 250, 251, 252, 252, 253, 253, 254, 254, 254, 254, 254, 253, 253,
252, 251, 250, 249, 247, 246, 244, 242, 241, 238, 236, 234, 231, 229, 226, 223,
220, 223, 226, 229, 231, 234, 236, 238, 241, 242, 244, 246, 247, 249, 250, 251,
252, 253, 253, 254, 254, 254, 254, 254, 253, 253, 252, 252, 251, 250, 248, 247,
245, 244, 242, 240, 238, 235, 233, 230, 228, 225, 222, 217, 207, 198, 188, 178,
168, 158, 148, 138, 128, 117, 107, 96, 86, 75, 65, 54, 43, 32, 22, 11,
0, 11, 22, 32, 43, 54, 65, 75, 86, 96, 107, 117, 128, 138, 148, 158,
168, 178, 188, 198, 207, 217, 222, 225, 228, 230, 233, 235, 238, 240, 242, 244,
245, 247, 248, 250, 251, 252, 252, 253, 253, 254, 254, 254, 254, 254, 253, 253,
252, 251, 250, 249, 247, 246, 244, 242, 241, 238, 236, 234, 231, 229, 226, 223,
220, 223, 226, 229, 231, 234, 236, 238, 241, 242, 244, 246, 247, 249, 250, 251,
252, 253, 253, 254, 254, 254, 254, 254, 253, 253, 252, 252, 251, 250, 248, 247,
245, 244, 242, 240, 238, 235, 233, 230, 228, 225, 222, 217, 207, 198, 188, 178,
168, 158, 148, 138, 128, 117, 107, 96, 86, 75, 65, 54, 43, 32, 22, 11
};
static const uint8_t sin_table[SIN_TABLE_LEN] =
{
0, 3, 6, 9, 12, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43,
46, 49, 52, 54, 57, 60, 63, 66, 68, 71, 73, 76, 78, 81, 83,
86, 88, 90, 92, 95, 97, 99, 101, 102, 104, 106, 108, 109, 111, 113,
114, 115, 117, 118, 119, 120, 121, 122, 123, 124, 125, 125, 126, 126, 127
};
// motor control state (shared with isr)
// ------------------------------------------------------
#define CONTROL_STATE_DISABLE 0
#define CONTROL_STATE_PREPARE 1
#define CONTROL_STATE_START 2
#define CONTROL_STATE_RUNNING 3
static volatile uint8_t control_state = CONTROL_STATE_DISABLE;
static volatile bool is_lvc_triggered = false;
static volatile bool hall_sensor_error = false;
// not atomic, protected by disabling interrupt while read in compute_foc_angle
static volatile uint16_t speed_erps = 0;
// current reading saved in 8 bits for atomic access, not expected to exceed 255 (40A)
static volatile uint8_t adc_battery_current = 0;
static volatile uint8_t adc_phase_current = 0;
static volatile uint8_t adc_battery_target_current = 0;
static volatile uint8_t foc_angle = 0;
static volatile uint8_t pwm_duty_cycle = 0;
static volatile uint8_t pwm_duty_cycle_target = 0;
// calculated constant limits (from config)
static uint16_t adc_low_voltage_limit = 0;
static uint8_t adc_battery_max_current = 0;
static uint8_t adc_phase_max_current = 0;
// ------------------------------------------------------
// foc angle filter
static uint16_t foc_angle_accumulated = 0;
// battery voltage filter
static uint16_t adc_battery_voltage_accumulated = 0;
static uint16_t adc_battery_voltage_filtered = 0;
// battery current filter
static uint16_t adc_battery_current_accumulated = 0;
static uint16_t adc_battery_current_filtered = 0;
// motor phase current filter
static uint16_t adc_phase_current_accumulated = 0;
static uint16_t adc_phase_current_filtered = 0;
static uint16_t lvc_x10V = 0;
static uint8_t target_speed_percent = 0;
static uint8_t target_current_percent = 0;
static uint16_t adc_steps_per_volt_x512 = ADC_10BIT_STEPS_PER_VOLT_X512;
static void flash_opt2_afr5()
{
// verify if PWM N channels are active on option bytes, if not, enable
static const uint8_t Value = 0x20;
if (OPT->OPT2 != Value)
{
// unlock data memory
if (!(FLASH->IAPSR & FLASH_IAPSR_DUL))
{
FLASH->DUKR = FLASH_RASS_KEY2;
FLASH->DUKR = FLASH_RASS_KEY1;
while (!(FLASH->IAPSR & FLASH_IAPSR_DUL));
}
// Enable write access to option bytes
FLASH->CR2 |= FLASH_CR2_OPT;
FLASH->NCR2 &= (uint8_t)(~FLASH_NCR2_NOPT);
// program option byte and complement
OPT->OPT2 = Value;
OPT->NOPT2 = (uint8_t)(~Value);
while (!(FLASH->IAPSR & FLASH_IAPSR_EOP));
// Disable write access to option bytes
FLASH->CR2 &= (uint8_t)(~FLASH_CR2_OPT);
FLASH->NCR2 |= FLASH_NCR2_NOPT;
// lock data memory
FLASH->IAPSR &= ~FLASH_IAPSR_DUL;
}
}
static void read_battery_voltage()
{
// low pass filter the voltage readed value, to avoid possible fast spikes/noise
adc_battery_voltage_accumulated -= adc_battery_voltage_accumulated >> BATTERY_VOLTAGE_FILTER_COEFFICIENT;
adc_battery_voltage_accumulated += adc_get_battery_voltage();
adc_battery_voltage_filtered = adc_battery_voltage_accumulated >> BATTERY_VOLTAGE_FILTER_COEFFICIENT;
is_lvc_triggered = (adc_battery_voltage_filtered < adc_low_voltage_limit);
}
static void read_battery_current()
{
// low pass filter the positive battery readed value (no regen current), to avoid possible fast spikes/noise
adc_battery_current_accumulated -= adc_battery_current_accumulated >> BATTERY_CURRENT_FILTER_COEFFICIENT;
adc_battery_current_accumulated += adc_battery_current;
adc_battery_current_filtered = adc_battery_current_accumulated >> BATTERY_CURRENT_FILTER_COEFFICIENT;
}
static void read_phase_current()
{
// low pass filter the positive motor pahse value (no regen current), to avoid possible fast spikes/noise
adc_phase_current_accumulated -= adc_phase_current_accumulated >> PHASE_CURRENT_FILTER_COEFFICIENT;
adc_phase_current_accumulated += adc_phase_current;
adc_phase_current_filtered = adc_phase_current_accumulated >> PHASE_CURRENT_FILTER_COEFFICIENT;
}
static uint8_t asin_table(uint8_t inverted_angle_x128)
{
// calc asin also converts the final result to degrees
uint8_t index = 0;
while (index < SIN_TABLE_LEN)
{
if (inverted_angle_x128 < sin_table[index])
{
break;
}
index++;
}
// first value of table is 0 so index will always increment to at least 1 and return 0
return index--;
}
static void compute_foc_angle()
{
uint16_t ui16_temp;
uint32_t ui32_temp;
uint16_t e_phase_voltage;
uint32_t i_phase_current_x2;
uint32_t l_x1048576;
uint32_t w_angular_velocity_x16;
uint16_t iwl_128;
// FOC implementation by calculating the angle between phase current and rotor magnetic flux (BEMF)
// 1. phase voltage is calculate
// 2. I*w*L is calculated, where I is the phase current. L was a measured value for 48V motor.
// 3. inverse sin is calculated of (I*w*L) / phase voltage, were we obtain the angle
// 4. previous calculated angle is applied to phase voltage vector angle and so the
// angle between phase current and rotor magnetic flux (BEMF) is kept at 0 (max torque per amp)
// calc E phase voltage
ui16_temp = adc_battery_voltage_filtered * ADC_10BIT_VOLTAGE_PER_ADC_STEP_X512;
ui16_temp = (ui16_temp >> 8) * pwm_duty_cycle;
e_phase_voltage = ui16_temp >> 9;
// calc I phase current
if (pwm_duty_cycle > 10)
{
ui16_temp = ((uint16_t)adc_battery_current_filtered) * ADC_10BIT_CURRENT_PER_ADC_STEP_X512;
i_phase_current_x2 = ui16_temp / pwm_duty_cycle;
}
else
{
i_phase_current_x2 = 0;
}
// calc W angular velocity: erps * 6.3
// 101 = 6.3 * 16
TIM1->IER &= ~(uint8_t)TIM1_IT_CC4;
ui16_temp = speed_erps;
TIM1->IER |= TIM1_IT_CC4;
w_angular_velocity_x16 = ui16_temp * 101;
// ---------------------------------------------------------------------------------------------------------------------
// 36 V motor: L = 76uH
// 48 V motor: L = 135uH
// ui32_l_x1048576 = 142; // 1048576 = 2^20 | 48V
// ui32_l_x1048576 = 84; // 1048576 = 2^20 | 36V
//
// ui32_l_x1048576 = 142 <--- THIS VALUE WAS verified experimentaly on 2018.07 to be near the best value for a 48V motor
// Test done with a fixed mechanical load, duty_cycle = 200 and 100 and measured battery current was 16 and 6 (10 and 4 amps)
// ---------------------------------------------------------------------------------------------------------------------
#if 0
l_x1048576 = 84; // 36 V motor
#else
l_x1048576 = 142; // 48 V motor
#endif
// calc IwL
ui32_temp = i_phase_current_x2 * l_x1048576;
ui32_temp *= w_angular_velocity_x16;
iwl_128 = ui32_temp >> 18;
// calc FOC angle
uint8_t foc_angle_unfiltered = asin_table(iwl_128 / e_phase_voltage);
// low pass filter FOC angle
foc_angle_accumulated -= foc_angle_accumulated >> 4;
foc_angle_accumulated += foc_angle_unfiltered;
foc_angle = foc_angle_accumulated >> 4;
}
void motor_pre_init()
{
SET_PIN_INPUT(PIN_HALL_SENSOR_A);
SET_PIN_INPUT(PIN_HALL_SENSOR_B);
SET_PIN_INPUT(PIN_HALL_SENSOR_C);
SET_PIN_LOW(PIN_PWM_PHASE_A_LOW);
SET_PIN_LOW(PIN_PWM_PHASE_A_HIGH);
SET_PIN_LOW(PIN_PWM_PHASE_B_LOW);
SET_PIN_LOW(PIN_PWM_PHASE_B_HIGH);
SET_PIN_LOW(PIN_PWM_PHASE_C_LOW);
SET_PIN_LOW(PIN_PWM_PHASE_C_HIGH);
SET_PIN_OUTPUT(PIN_PWM_PHASE_A_LOW);
SET_PIN_OUTPUT(PIN_PWM_PHASE_A_HIGH);
SET_PIN_OUTPUT(PIN_PWM_PHASE_B_LOW);
SET_PIN_OUTPUT(PIN_PWM_PHASE_B_HIGH);
SET_PIN_OUTPUT(PIN_PWM_PHASE_C_LOW);
SET_PIN_OUTPUT(PIN_PWM_PHASE_C_HIGH);
}
void motor_init(uint16_t max_current_mA, uint8_t lvc_V, int16_t adc_calib_volt_step_offset)
{
lvc_x10V = lvc_V * 10;
uint32_t max_current_x10A = max_current_mA / 100;
adc_steps_per_volt_x512 = ADC_10BIT_STEPS_PER_VOLT_X512 + adc_calib_volt_step_offset;
// compute hard current limits (not changed after here)
adc_battery_max_current = (uint8_t)(
((((uint32_t)MIN(max_current_x10A, MAX_BATTERY_CURRENT_AMPS_X10)) * 512) / 10) / ADC_10BIT_CURRENT_PER_ADC_STEP_X512
);
adc_phase_max_current = (uint8_t)(
((((uint32_t)MAX_MOTOR_PHASE_CURRENT_AMPS_X10) * 512) / 10) / ADC_10BIT_CURRENT_PER_ADC_STEP_X512
);
adc_low_voltage_limit = (uint16_t)((((uint32_t)lvc_V) * adc_steps_per_volt_x512) / 512);
flash_opt2_afr5();
timer1_init_motor_pwm();
motor_disable();
}
void motor_process()
{
read_battery_voltage();
read_battery_current();
read_phase_current();
compute_foc_angle();
}
void motor_enable()
{
if (control_state == CONTROL_STATE_DISABLE)
{
control_state = CONTROL_STATE_PREPARE;
}
}
void motor_disable()
{
control_state = CONTROL_STATE_DISABLE;
}
uint16_t motor_status()
{
static uint16_t last_status = 0;
uint16_t status = 0;
if (hall_sensor_error)
status |= MOTOR_ERROR_HALL_SENSOR;
if (is_lvc_triggered)
status |= MOTOR_ERROR_LVC;
if (status != last_status)
{
last_status = status;
eventlog_write_data(EVT_DATA_MOTOR_STATUS, status);
}
return status;
}
uint8_t motor_get_target_speed()
{
return target_speed_percent;
}
uint8_t motor_get_target_current()
{
return target_current_percent;
}
void motor_set_target_speed(uint8_t percent)
{
if (percent > 100)
{
percent = 100;
}
if (percent != target_speed_percent)
{
target_speed_percent = percent;
eventlog_write_data(EVT_DATA_TARGET_SPEED, percent);
if (percent == 0)
{
pwm_duty_cycle_target = 0;
}
else
{
pwm_duty_cycle_target = (uint8_t)MAP16(percent, 1, 100, PWM_DUTY_CYCLE_MIN, PWM_DUTY_CYCLE_MAX);
}
}
}
void motor_set_target_current(uint8_t percent)
{
if (percent > 100)
{
percent = 100;
}
if (percent != target_current_percent)
{
target_current_percent = percent;
eventlog_write_data(EVT_DATA_TARGET_CURRENT, percent);
adc_battery_target_current = ((uint16_t)percent * adc_battery_max_current) / 100;
}
}
int16_t motor_calibrate_battery_voltage(uint16_t actual_voltage_x100)
{
int16_t diff = 0;
if (actual_voltage_x100 != 0)
{
uint16_t calibrated_adc_steps_volt_x512 = (uint16_t)(((uint32_t)adc_battery_voltage_filtered * 51200u) / actual_voltage_x100);
diff = calibrated_adc_steps_volt_x512 - ADC_10BIT_STEPS_PER_VOLT_X512;
adc_steps_per_volt_x512 = calibrated_adc_steps_volt_x512;
}
else
{
// reset calibration if 0 is received
adc_steps_per_volt_x512 = ADC_10BIT_STEPS_PER_VOLT_X512;
diff = 0;
}
eventlog_write_data(EVT_DATA_CALIBRATE_VOLTAGE, adc_steps_per_volt_x512);
return diff;
}
uint16_t motor_get_battery_lvc_x10()
{
return lvc_x10V;
}
uint16_t motor_get_battery_current_x10()
{
return (uint16_t)((((uint32_t)adc_battery_current_filtered * 10) * ADC_10BIT_CURRENT_PER_ADC_STEP_X512) >> 9);
}
uint16_t motor_get_battery_voltage_x10()
{
return (uint16_t)(((uint32_t)adc_battery_voltage_filtered * 5120) / adc_steps_per_volt_x512);
}
// state variables only used by isr
// ---------------------------------------------
static uint8_t hall_sensors_state_last = 0;
static uint8_t rotor_absolute_angle = 0;
static uint8_t half_erps_flag = 0;
static uint8_t commutation_type = BLOCK_COMMUTATION;
static uint16_t pwm_duty_cycle_ramp_up_counter = 0;
static uint16_t pwm_duty_cycle_ramp_down_counter = 0;
static uint16_t pwm_cycles_counter = 1;
static uint16_t pwm_cycles_counter_6 = 1;
static uint16_t pwm_cycles_counter_total = 0xffff;
static uint16_t adc_current_ramp_up_counter = 0;
static uint8_t current_controller_counter = 0;
static uint16_t speed_controller_counter = 0;
static uint8_t adc_battery_ramp_max_current = 0;
// Measures did with a 24V Q85 328 RPM motor, rotating motor backwards by hand:
// Hall sensor A positive to negative transition | BEMF phase B at max value / top of sinewave
// Hall sensor B positive to negative transition | BEMF phase A at max value / top of sinewave
// Hall sensor C positive to negative transition | BEMF phase C at max value / top of sinewave
// runs every 64us (PWM frequency)
// Measured on 2022-12-04, the interrupt code takes about 45% of the total 64us
void isr_timer1_cmp(void) __interrupt(ITC_IRQ_TIM1_CAPCOM)
{
// read battery current adc value, should happen at middle of the pwm duty cycle
// no scan, align data right since we are only interested in the 8 lsb.
ADC1->CR2 = (ADC1_ALIGN_RIGHT);
// disable eoc interrupt, clear EOC flag and select channel 5 (current sense)
ADC1->CSR = 0x05;
// perform single mode ADC1 conversion
ADC1->CR1 |= ADC1_CR1_ADON;
while (!(ADC1->CSR & ADC1_CSR_EOC));
// adc current reading is truncated to 8bit since that allows a
// range of up to 40A which it is not expected to be surpassed.
// check of 8bit overflow and save result, flag is used to limit
// current in isr if overflow for some reason would occur.
uint8_t adc_battery_current_ovf = ADC1->DRH;
// atomic write (uint8), current is not expected to exceed adc 255 (40A)
adc_battery_current = ADC1->DRL;
switch (control_state)
{
case CONTROL_STATE_DISABLE:
// disable outputs
TIM1->CCER1 &= ~(uint8_t)(TIM1_CCER1_CC1E | TIM1_CCER1_CC1NE); // OC1
TIM1->CCER1 &= ~(uint8_t)(TIM1_CCER1_CC2E | TIM1_CCER1_CC2NE); // OC2
TIM1->CCER2 &= ~(uint8_t)(TIM1_CCER2_CC3E | TIM1_CCER2_CC3NE); // OC3
break;
case CONTROL_STATE_PREPARE:
if (speed_erps > 0)
{
// Restart from duty cycle mapped from erps.
// This is probably not the correct way to do this, but
// it seems to work reasonably well. VESC tracks back-emf
// to calculate duty cyle to restart from...
pwm_duty_cycle = (uint8_t)MAP32(speed_erps, 0, MAX_MOTOR_SPEED_ERPS, PWM_DUTY_CYCLE_MIN, PWM_DUTY_CYCLE_MAX);
}
control_state = CONTROL_STATE_START;
break;
case CONTROL_STATE_START:
// enable outputs
TIM1->CCER1 |= (uint8_t)(TIM1_CCER1_CC1E | TIM1_CCER1_CC1NE); // OC1
TIM1->CCER1 |= (uint8_t)(TIM1_CCER1_CC2E | TIM1_CCER1_CC2NE); // OC2
TIM1->CCER2 |= (uint8_t)(TIM1_CCER2_CC3E | TIM1_CCER2_CC3NE); // OC3
control_state = CONTROL_STATE_RUNNING;
break;
default:
break;
}
// calculate motor current adc value
if (pwm_duty_cycle > 0)
{
// atomic write (uint8), current is not expected to exceed adc 255 (40A)
adc_phase_current = (uint8_t)((adc_battery_current * 256u) / pwm_duty_cycle);
}
else
{
adc_phase_current = 0;
}
// trigger adc conversion of all channels (scan conversion, buffered)
// adc scan mode conversion will finish before
// this motor control interrupt will be run next time
//
// enable scan, align left
ADC1->CR2 = (ADC1_ALIGN_LEFT | ADC1_CR2_SCAN);
// clear EOC flag, enable eoc interrupt, scan read all channel 0-7
ADC1->CSR = (ADC1_CSR_EOCIE | 0x07);
// start adc scan mode conversion
ADC1->CR1 |= ADC1_CR1_ADON;
// read hall sensor signals
// find the motor rotor absolute angle
// calc motor speed in erps (speed_erps)
// read hall sensors signal pins and mask other pins
// hall sensors sequence with motor forward rotation: 4, 6, 2, 3, 1, 5
uint8_t hall_sensors_state =
((GET_PORT(PIN_HALL_SENSOR_A)->IDR & GET_PIN(PIN_HALL_SENSOR_A)) >> 5) |
((GET_PORT(PIN_HALL_SENSOR_B)->IDR & GET_PIN(PIN_HALL_SENSOR_B)) >> 1) |
((GET_PORT(PIN_HALL_SENSOR_C)->IDR & GET_PIN(PIN_HALL_SENSOR_C)) >> 3);
// make sure we run next code only when there is a change on the hall sensors signal
if (hall_sensors_state != hall_sensors_state_last)
{
hall_sensors_state_last = hall_sensors_state;
switch (hall_sensors_state)
{
case 3:
rotor_absolute_angle = (uint8_t)MOTOR_ROTOR_ANGLE_150;
break;
case 1:
if (half_erps_flag == 1)
{
half_erps_flag = 0;
pwm_cycles_counter_total = pwm_cycles_counter;
pwm_cycles_counter = 1;
if (pwm_cycles_counter_total > 0)
{
// This division takes 4.4us
speed_erps = PWM_CYCLES_SECOND / pwm_cycles_counter_total;
}
else
{
speed_erps = PWM_CYCLES_SECOND;
}
// update motor commutation state based on motor speed
if (speed_erps > MOTOR_ROTOR_ERPS_START_INTERPOLATION_60_DEGREES)
{
if (commutation_type == BLOCK_COMMUTATION)
{
commutation_type = SINEWAVE_INTERPOLATION_60_DEGREES;
}
}
else
{
if (commutation_type == SINEWAVE_INTERPOLATION_60_DEGREES)
{
commutation_type = BLOCK_COMMUTATION;
foc_angle = 0;
}
}
}
rotor_absolute_angle = (uint8_t)MOTOR_ROTOR_ANGLE_210;
break;
case 5:
rotor_absolute_angle = (uint8_t)MOTOR_ROTOR_ANGLE_270;
break;
case 4:
rotor_absolute_angle = (uint8_t)MOTOR_ROTOR_ANGLE_330;
break;
case 6:
half_erps_flag = 1;
rotor_absolute_angle = (uint8_t)MOTOR_ROTOR_ANGLE_30;
break;
// BEMF is always 90 degrees advanced over motor rotor position degree zero
// and here (hall sensor C blue wire, signal transition from positive to negative),
// phase B BEMF is at max value (measured on osciloscope by rotating the motor)
case 2:
rotor_absolute_angle = (uint8_t)MOTOR_ROTOR_ANGLE_90;
break;
default:
// invalid hall sensor signal
hall_sensor_error = true;
return;
}
hall_sensor_error = false;
pwm_cycles_counter_6 = 1;
}
// count number of fast loops / pwm cycles and reset some states when motor is near zero speed
if (pwm_cycles_counter < PWM_CYCLES_COUNTER_MAX)
{
pwm_cycles_counter++;
pwm_cycles_counter_6++;
}
else // happens when motor is stopped or near zero speed
{
pwm_cycles_counter = 1; // don't put to 0 to avoid 0 divisions
pwm_cycles_counter_6 = 1;
half_erps_flag = 0;
speed_erps = 0;
pwm_cycles_counter_total = 0xffff;
foc_angle = 0;
commutation_type = BLOCK_COMMUTATION;
hall_sensors_state_last = 0; // this way we force execution of hall sensors code next time
}
// calc interpolation angle and sinewave table index
uint8_t svm_table_index = rotor_absolute_angle + foc_angle;
#if 1 // may be useful to disable interpolation when debugging
// calculate the interpolation angle (and it doesn't work when motor starts and at very low speeds)
if (commutation_type == SINEWAVE_INTERPOLATION_60_DEGREES)
{
// division by 0: motor_pwm_cycles_counter_total should never be 0
// TODO: verifiy if (motor_pwm_cycles_counter_6 << 8) do not overflow
uint8_t interpolation_angle = (pwm_cycles_counter_6 << 8) / pwm_cycles_counter_total; // this operations take 4.4us
svm_table_index += interpolation_angle;
}
#endif
// pwm duty cycle controller
// ----------------------------------------------------------------------
// brakes are active
// limit battery undervoltage
// limit battery max current
// limit motor max erps
// ramp up/down pwm duty cycle towards target
++current_controller_counter;
++speed_controller_counter;
if (
control_state == CONTROL_STATE_DISABLE ||
is_lvc_triggered ||
(pwm_duty_cycle_target == 0) ||
(GET_PIN_INPUT_STATE(PIN_BRAKE) == 0) //active low
)
{
if (pwm_duty_cycle)
{
--pwm_duty_cycle;
}
}
// do not control current at every PWM cycle, that will measure and control too fast. Use counter to limit
else if
(
current_controller_counter > CURRENT_CONTROLLER_CHECK_PERIODS &&
(
// check if truncated 8bit current reading did overflow
adc_battery_current_ovf ||
// compare against ramp controller current limit
adc_battery_current > adc_battery_ramp_max_current ||
// or hard motor phase current limit
adc_phase_current > adc_phase_max_current
)
)
{
if (pwm_duty_cycle)
{
--pwm_duty_cycle;
}
}
else if (
speed_controller_counter > SPEED_CONTROLLER_CHECK_PERIODS && // test about every 100ms
speed_erps > MAX_MOTOR_SPEED_ERPS
)
{
if (pwm_duty_cycle)
{
--pwm_duty_cycle;
}
}
else // nothing to limit, so adjust duty_cycle to duty_cycle_target
{
if (pwm_duty_cycle_target > pwm_duty_cycle)
{
if (pwm_duty_cycle_ramp_up_counter++ >= PWM_DUTY_CYCLE_RAMP_UP_INVERSE_STEP)
{
pwm_duty_cycle_ramp_up_counter = 0;
++pwm_duty_cycle;
}
}
else if (pwm_duty_cycle_target < pwm_duty_cycle)
{
if (pwm_duty_cycle_ramp_down_counter++ >= PWM_DUTY_CYCLE_RAMP_DOWN_INVERSE_STEP)
{
pwm_duty_cycle_ramp_down_counter = 0;
--pwm_duty_cycle;
}
}
}
// reset periodic check counters
if (speed_controller_counter > SPEED_CONTROLLER_CHECK_PERIODS)
{
speed_controller_counter = 0;
}
if (current_controller_counter > CURRENT_CONTROLLER_CHECK_PERIODS)
{
current_controller_counter = 0;
}
// calculate final pwm duty cycle values to be applied to TIMER1
// The first half of the table is the positive offset from the middle (0x100),
// in that case just set MSB to 0x1, and the value from the table*duty cycle to LSB.
// The second half of the table is a negative offset from that same middle,
// and should be substracted from 0x100.
// To cheat, we leave it as 0x100 when this value * duty cycle is 0,
// otherwise we assume MSB is 0, and just invert the value from the table from LSB.
// Checking to see if svm_table_index >= 128 (180 degrees) by & 0x80,
// as SDCC is not yet smart enough to do that automatically.
#define CALC_PHASE(PHASE_OUTPUT) do { \
uint8_t tmp = ((uint16_t)(pwm_duty_cycle * svm_table[svm_table_index]) / 256); \
if (tmp > 0 && (svm_table_index & 0x80)) \
{ \
PHASE_OUTPUT##_lsb = 0 - tmp; \
PHASE_OUTPUT##_msb = 0; \
} \
else \
{ \
PHASE_OUTPUT##_lsb = tmp; \
PHASE_OUTPUT##_msb = 1; \
} \
} while (0)
// phase B as reference phase
uint8_t phase_b_voltage_msb;
uint8_t phase_b_voltage_lsb;
CALC_PHASE(phase_b_voltage);
// phase C is advanced 120 degrees over phase B
svm_table_index += 85; // 120º / 360 * 256 = 85
uint8_t phase_c_voltage_msb;
uint8_t phase_c_voltage_lsb;
CALC_PHASE(phase_c_voltage);
// phase A is advanced 240 degrees over phase B
svm_table_index += 86; // 240º / 360 * 256 = 171 - 85 already added = 86
uint8_t phase_a_voltage_msb;
uint8_t phase_a_voltage_lsb;
CALC_PHASE(phase_a_voltage);
// set final duty cycle value to pwm timers
// phase B
TIM1->CCR3H = phase_b_voltage_msb;
TIM1->CCR3L = phase_b_voltage_lsb;
// phase C
TIM1->CCR2H = phase_c_voltage_msb;
TIM1->CCR2L = phase_c_voltage_lsb;
// phase A
TIM1->CCR1H = phase_a_voltage_msb;
TIM1->CCR1L = phase_a_voltage_lsb;
// ramp up motor current
if (adc_battery_target_current > adc_battery_ramp_max_current)
{
if (adc_current_ramp_up_counter++ >= CURRENT_RAMP_UP_INVERSE_STEP)
{
adc_current_ramp_up_counter = 0;
adc_battery_ramp_max_current++;
}
}
else if (adc_battery_target_current < adc_battery_ramp_max_current)
{
// we are not doing a ramp down here, just directly setting to the target value
adc_battery_ramp_max_current = adc_battery_target_current;
}
// clears the timer1 interrupt CC4 pending bit
TIM1->SR1 = (uint8_t)(~(uint8_t)TIM1_IT_CC4);
}
================================================
FILE: src/firmware/tsdz2/pins.h
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#ifndef _TSDZ2_PINS_H_
#define _TSDZ2_PINS_H_
#include "tsdz2/cpu.h"
#include "tsdz2/stm8s/stm8s.h"
#include "tsdz2/stm8s/stm8s_gpio.h"
#define PIN_HALL_SENSOR_A GPIOE, GPIO_PIN_5
#define PIN_HALL_SENSOR_B GPIOD, GPIO_PIN_2
#define PIN_HALL_SENSOR_C GPIOC, GPIO_PIN_5
#define PIN_PWM_PHASE_A_LOW GPIOB, GPIO_PIN_2
#define PIN_PWM_PHASE_A_HIGH GPIOC, GPIO_PIN_3
#define PIN_PWM_PHASE_B_LOW GPIOB, GPIO_PIN_1
#define PIN_PWM_PHASE_B_HIGH GPIOC, GPIO_PIN_2
#define PIN_PWM_PHASE_C_LOW GPIOB, GPIO_PIN_0
#define PIN_PWM_PHASE_C_HIGH GPIOC, GPIO_PIN_1
#define PIN_BATTERY_CURRENT GPIOB, GPIO_PIN_5
#define PIN_BATTERY_VOLTAGE GPIOB, GPIO_PIN_6
#define PIN_PAS1 GPIOD, GPIO_PIN_7
#define PIN_PAS2 GPIOE, GPIO_PIN_0
#define PIN_SPEED_SENSOR GPIOA, GPIO_PIN_1
#define PIN_BRAKE GPIOC, GPIO_PIN_6
#define PIN_THROTTLE GPIOB, GPIO_PIN_7
#define PIN_LIGHTS GPIOD, GPIO_PIN_4
#define PIN_TORQUE_SENSOR GPIOB, GPIO_PIN_3
#define PIN_TORQUE_SENSOR_EXC GPIOD, GPIO_PIN_3
#define PIN_EXTERNAL_RX GPIOD, GPIO_PIN_6
#define PIN_EXTERNAL_TX GPIOD, GPIO_PIN_5
#endif
================================================
FILE: src/firmware/tsdz2/sensors.c
================================================
/*
* bbs-fw
*
* Copyright (C) Daniel Nilsson, 2022.
*
* Released under the GPL License, Version 3
*/
#include "sensors.h"
#include "intellisense.h"
#include "fwconfig.h"
#include "tsdz2/interrupt.h"
#include "tsdz2/timers.h"
#include "tsdz2/stm8.h"
#include "tsdz2/pins.h"
#include "tsdz2/stm8s/stm8s_tim4.h"
// interrupt runs at 100us interval, see timer4 setup in timers.c
// :TODO: this file contains a lot of duplicated code from bbsx version, try to share code
#define PAS_SENSOR_NUM_SIGNALS PAS_PULSES_REVOLUTION
#define PAS_SENSOR_MIN_PULSE_MS_X10 50 // 500rpm limit
#define SPEED_SENSOR_MIN_PULSE_MS_X10 500
#define SPEED_SENSOR_TIMEOUT_MS_X10 25000
static volatile uint16_t pas_pulse_counter;
static volatile bool pas_direction_backward;
static volatile uint16_t pas_period_length; // pulse length counted in interrupt frequency (100us)
static uint16_t pas_period_counter;
static bool pas_prev1;
static bool pas_prev2;
static uint16_t pas_stop_delay_periods;
static volatile uint16_t speed_ticks_period_length; // pulse length counted in interrupt frequency (100us)
static uint16_t speed_period_counter;
static bool speed_prev_state;
static uint8_t speed_ticks_per_rpm;
extern void torque_sensor_init();
extern void torque_sensor_process();
void sensors_init()
{
pas_period_counter = 0;
pas_pulse_counter = 0;
pas_direction_backward = false;
pas_period_length = 0;
pas_stop_delay_periods = 1500;
speed_period_counter = 0;
speed_ticks_period_length = 0;
speed_prev_state = false;
speed_ticks_per_rpm = 1;
// pins do not have external interrupt, use timer0 to evaluate state frequently
SET_PIN_INPUT(PIN_PAS1);
SET_PIN_INPUT(PIN_PAS2);
SET_PIN_INPUT(PIN_SPEED_SENSOR);
SET_PIN_INPUT_PULLUP(PIN_BRAKE);
pas_prev1 = GET_PIN_INPUT_STATE(PIN_PAS1);
pas_prev2 = GET_PIN_INPUT_STATE(PIN_PAS2);
torque_sensor_init();
torque_sensor_process();
timer4_init_sensors();
}
void sensors_process()
{
torque_sensor_process();
}
void pas_set_stop_delay(uint16_t delay_ms)
{
pas_stop_delay_periods = delay_ms * 10;
}
uint16_t pas_get_cadence_rpm_x10()
{
uint16_t tmp;
TIM4->IER &= ~TIM4_IT_UPDATE; // disable timer4 interrupt
tmp = pas_period_length;
TIM4->IER |= TIM4_IT_UPDATE;
if (tmp > 0)
{
return (uint16_t)((6000000ul / PAS_SENSOR_NUM_SIGNALS) / tmp);
}
else
{
return 0;
}
}
uint16_t pas_get_pulse_counter()
{
uint16_t tmp;
TIM4->IER &= ~TIM4_IT_UPDATE; // disable timer4 interrupts
tmp = pas_pulse_counter;
TIM4->IER |= TIM4_IT_UPDATE;
return tmp;
}
bool pas_is_pedaling_forwards()
{
uint16_t period_length;
uint8_t direction_backward;
TIM4->IER &= ~TIM4_IT_UPDATE; // disable timer4 interrupts
period_length = pas_period_length;
direction_backward = pas_direction_backward;
TIM4->IER |= TIM4_IT_UPDATE;
// atomic read operation, no need to disable timer interrupt
return period_length > 0 && !direction_backward;
}
bool pas_is_pedaling_backwards()
{
uint16_t period_length;
uint8_t direction_backward;
TIM4->IER &= ~TIM4_IT_UPDATE; // disable timer4 interrupts
period_length = pas_period_length;
direction_backward = pas_direction_backward;
TIM4->IER |= TIM4_IT_UPDATE;
return (period_length > 0) && direction_backward;
}
void speed_sensor_set_signals_per_rpm(uint8_t num_signals)
{
speed_ticks_per_rpm = num_signals;
}
bool speed_sensor_is_moving()
{
uint16_t tmp;
TIM4->IER &= ~TIM4_IT_UPDATE; // disable timer4 interrupts
tmp = speed_ticks_period_length;
TIM4->IER |= TIM4_IT_UPDATE;
return tmp > 0;
}
uint16_t speed_sensor_get_rpm_x10()
{
uint16_t tmp;
TIM4->IER &= ~TIM4_IT_UPDATE; // disable timer4 interrupts
tmp = speed_ticks_period_length;
TIM4->IER |= TIM4_IT_UPDATE;
if (tmp > 0)
{
return 6000000ul / tmp / speed_ticks_per_rpm;
}
return 0;
}
int16_t temperature_contr_x100()
{
return 0; // n/a
}
int16_t temperature_motor_x100()
{
return 0; // n/a
}
bool brake_is_activated()
{
return !GET_PIN_INPUT_STATE(PIN_BRAKE);
}
bool shift_sensor_is_activated()
{
return false; // n/a
}
void isr_timer4_ovf(void) __interrupt(ITC_IRQ_TIM4_OVF)
{
// clear interrupt bit
TIM4->SR1 &= (uint8_t)(~TIM4_IT_UPDATE);
// Pas
{
bool pas1 = GET_PIN_INPUT_STATE(PIN_PAS1);
bool pas2 = GET_PIN_INPUT_STATE(PIN_PAS2);
if (pas1 && !pas_prev1 /* && pas_period_counter > PAS_SENSOR_MIN_PULSE_MS_X10 */)
{
pas_pulse_counter++;
if (pas_direction_backward != pas2)
{
pas_direction_backward = pas2;
// Reset pas pulse counter if pedal direction is changed,
// this variable counts the number of pulses since start of pedaling session.
pas_pulse_counter = 0;
}
if (pas_period_counter > 0)
{
if (pas_period_counter <= pas_stop_delay_periods)
{
pas_period_length = pas_period_counter; // save in order to be able to calculate rpm when needed
}
else
{
pas_period_length = 0;
}
pas_period_counter = 0;
}
}
else
{
// Do not allow wraparound or computed pedaling cadence will wrong after pedals has been still.
if (pas_period_counter < 65535)
{
pas_period_counter++;
}
if (pas_period_length > 0 && pas_period_counter > pas_stop_delay_periods)
{
pas_period_length = 0;
pas_pulse_counter = 0;
pas_direction_backward = false;
}
}
pas_prev1 = pas1;
pas_prev2 = pas2;
}
// Speed sensor
{
bool spd = GET_PIN_INPUT_STATE(PIN_SPEED_SENSOR);
if (spd && !speed_prev_state && speed_period_counter > SPEED_SENSOR_MIN_PULSE_MS_X10)
{
if (speed_period_counter <= SPEED_SENSOR_TIMEOUT_MS_X10)
{
speed_ticks_period_length = speed_period_counter;
}
else
{
speed_ticks_period_length = 0;
}
speed_period_counter = 0;
}
else
{
// Do not allow wraparound or computed speed will wrong after bike has been still.
if (speed_period_counter < 65535)
{
speed_period_counter++;
}
if (speed_ticks_period_length > 0 && speed_period_counter > SPEED_SENSOR_TIMEOUT_MS_X10)
{
speed_ticks_period_length = 0;
}
}
speed_prev_state = spd;
}
}
================================================
FILE: src/firmware/tsdz2/stm8.h
================================================
#pragma once
#ifndef _TSDZ2_STM_8_H_
#define _TSDZ2_STM_8_H_
#include
#define EXPAND(x) x
#define SET_PIN_INPUT_(PORT, PIN) PORT->DDR &= (uint8_t)(~(PIN)); PORT->CR1 &= (uint8_t)(~(PIN))
#define SET_PIN_INPUT(...) EXPAND(SET_PIN_INPUT_(__VA_ARGS__))
#define SET_PIN_INPUT_PULLUP_(PORT, PIN) PORT->DDR &= (uint8_t)(~(PIN)); PORT->CR1 |= (uint8_t)PIN
#define SET_PIN_INPUT_PULLUP(...) EXPAND(SET_PIN_INPUT_PULLUP_(__VA_ARGS__))
#define SET_PIN_OUTPUT_(PORT, PIN) PORT->DDR |= (uint8_t)PIN; PORT->CR1 |= (uint8_t)PIN; PORT->CR2 |= (uint8_t)(PIN)
#define SET_PIN_OUTPUT(...) EXPAND(SET_PIN_OUTPUT_(__VA_ARGS__))
#define SET_PIN_OUTPUT_OPEN_DRAIN_(PORT, PIN) PORT->DDR |= (uint8_t)PIN; PORT->CR1 &= (uint8_t)(~(PIN)); PORT->CR2 |= (uint8_t)(PIN)
#define SET_PIN_OUTPUT_OPEN_DRAIN(...) EXPAND(SET_PIN_OUTPUT_OPEN_DRAIN_(__VA_ARGS__))
#define GET_PIN_INPUT_STATE_(PORT, PIN) ((PORT->IDR & (uint8_t)PIN) != 0)
#define GET_PIN_INPUT_STATE(...) EXPAND(GET_PIN_INPUT_STATE_(__VA_ARGS__))
#define SET_PIN_HIGH_(PORT, PIN) PORT->ODR |= (uint8_t)PIN
#define SET_PIN_HIGH(...) EXPAND(SET_PIN_HIGH_(__VA_ARGS__))
#define SET_PIN_LOW_(PORT, PIN) PORT->ODR &= (uint8_t)(~PIN)
#define SET_PIN_LOW(...) EXPAND(SET_PIN_LOW_(__VA_ARGS__))
#define TOGGLE_PIN_(PORT, PIN) PORT->ODR ^= (PIN)
#define TOGGLE_PIN(...) EXPAND(TOGGLE_PIN_(__VA_ARGS__))
#define GET_PIN_(PORT, PIN) PIN
#define GET_PIN(...) EXPAND(GET_PIN_(__VA_ARGS__))
#define GET_PORT_(PORT, PIN) PORT
#define GET_PORT(...) EXPAND(GET_PORT_(__VA_ARGS__))
#endif
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s.h
================================================
/**
******************************************************************************
* @file stm8s.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all HW registers definitions and memory mapping.
******************************************************************************
* @attention
*
*
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_BEEP_H
#define __STM8S_BEEP_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/* Exported types ------------------------------------------------------------*/
/** @addtogroup BEEP_Exported_Types
* @{
*/
/**
* @brief BEEP Frequency selection
*/
typedef enum {
BEEP_FREQUENCY_1KHZ = (uint8_t)0x00, /*!< Beep signal output frequency equals to 1 KHz */
BEEP_FREQUENCY_2KHZ = (uint8_t)0x40, /*!< Beep signal output frequency equals to 2 KHz */
BEEP_FREQUENCY_4KHZ = (uint8_t)0x80 /*!< Beep signal output frequency equals to 4 KHz */
} BEEP_Frequency_TypeDef;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @addtogroup BEEP_Exported_Constants
* @{
*/
#define BEEP_CALIBRATION_DEFAULT ((uint8_t)0x0B) /*!< Default value when calibration is not done */
#define LSI_FREQUENCY_MIN ((uint32_t)110000) /*!< LSI minimum value in Hertz */
#define LSI_FREQUENCY_MAX ((uint32_t)150000) /*!< LSI maximum value in Hertz */
/**
* @}
*/
/* Exported macros -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup BEEP_Private_Macros
* @{
*/
/**
* @brief Macro used by the assert function to check the different functions parameters.
*/
/**
* @brief Macro used by the assert function to check the BEEP frequencies.
*/
#define IS_BEEP_FREQUENCY_OK(FREQ) \
(((FREQ) == BEEP_FREQUENCY_1KHZ) || \
((FREQ) == BEEP_FREQUENCY_2KHZ) || \
((FREQ) == BEEP_FREQUENCY_4KHZ))
/**
* @brief Macro used by the assert function to check the LSI frequency (in Hz).
*/
#define IS_LSI_FREQUENCY_OK(FREQ) \
(((FREQ) >= LSI_FREQUENCY_MIN) && \
((FREQ) <= LSI_FREQUENCY_MAX))
/**
* @}
*/
/* Exported functions ------------------------------------------------------- */
/** @addtogroup BEEP_Exported_Functions
* @{
*/
void BEEP_DeInit(void);
void BEEP_Init(BEEP_Frequency_TypeDef BEEP_Frequency);
void BEEP_Cmd(FunctionalState NewState);
void BEEP_LSICalibrationConfig(uint32_t LSIFreqHz);
/**
* @}
*/
#endif /* __STM8S_BEEP_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s_can.h
================================================
/**
******************************************************************************
* @file stm8s_can.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all the functions for the CAN peripheral.
******************************************************************************
* @attention
*
*
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_EXTI_H
#define __STM8S_EXTI_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/* Exported types ------------------------------------------------------------*/
/** @addtogroup EXTI_Exported_Types
* @{
*/
/**
* @brief EXTI Sensitivity values for PORTA to PORTE
*/
typedef enum {
EXTI_SENSITIVITY_FALL_LOW = (uint8_t)0x00, /*!< Interrupt on Falling edge and Low level */
EXTI_SENSITIVITY_RISE_ONLY = (uint8_t)0x01, /*!< Interrupt on Rising edge only */
EXTI_SENSITIVITY_FALL_ONLY = (uint8_t)0x02, /*!< Interrupt on Falling edge only */
EXTI_SENSITIVITY_RISE_FALL = (uint8_t)0x03 /*!< Interrupt on Rising and Falling edges */
} EXTI_Sensitivity_TypeDef;
/**
* @brief EXTI Sensitivity values for TLI
*/
typedef enum {
EXTI_TLISENSITIVITY_FALL_ONLY = (uint8_t)0x00, /*!< Top Level Interrupt on Falling edge only */
EXTI_TLISENSITIVITY_RISE_ONLY = (uint8_t)0x04 /*!< Top Level Interrupt on Rising edge only */
} EXTI_TLISensitivity_TypeDef;
/**
* @brief EXTI PortNum possible values
*/
typedef enum {
EXTI_PORT_GPIOA = (uint8_t)0x00, /*!< GPIO Port A */
EXTI_PORT_GPIOB = (uint8_t)0x01, /*!< GPIO Port B */
EXTI_PORT_GPIOC = (uint8_t)0x02, /*!< GPIO Port C */
EXTI_PORT_GPIOD = (uint8_t)0x03, /*!< GPIO Port D */
EXTI_PORT_GPIOE = (uint8_t)0x04 /*!< GPIO Port E */
} EXTI_Port_TypeDef;
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup EXTI_Private_Macros
* @{
*/
/**
* @brief Macro used by the assert function in order to check the different sensitivity values for PORTA to PORTE.
*/
#define IS_EXTI_SENSITIVITY_OK(SensitivityValue) \
(((SensitivityValue) == EXTI_SENSITIVITY_FALL_LOW) || \
((SensitivityValue) == EXTI_SENSITIVITY_RISE_ONLY) || \
((SensitivityValue) == EXTI_SENSITIVITY_FALL_ONLY) || \
((SensitivityValue) == EXTI_SENSITIVITY_RISE_FALL))
/**
* @brief Macro used by the assert function in order to check the different sensitivity values for TLI.
*/
#define IS_EXTI_TLISENSITIVITY_OK(SensitivityValue) \
(((SensitivityValue) == EXTI_TLISENSITIVITY_FALL_ONLY) || \
((SensitivityValue) == EXTI_TLISENSITIVITY_RISE_ONLY))
/**
* @brief Macro used by the assert function in order to check the different Port values
*/
#define IS_EXTI_PORT_OK(PORT) \
(((PORT) == EXTI_PORT_GPIOA) ||\
((PORT) == EXTI_PORT_GPIOB) ||\
((PORT) == EXTI_PORT_GPIOC) ||\
((PORT) == EXTI_PORT_GPIOD) ||\
((PORT) == EXTI_PORT_GPIOE))
/**
* @brief Macro used by the assert function in order to check the different values of the EXTI PinMask
*/
#define IS_EXTI_PINMASK_OK(PinMask) ((((PinMask) & (uint8_t)0x00) == (uint8_t)0x00) && ((PinMask) != (uint8_t)0x00))
/**
* @}
*/
/* Exported functions ------------------------------------------------------- */
/** @addtogroup EXTI_Exported_Functions
* @{
*/
void EXTI_DeInit(void);
void EXTI_SetExtIntSensitivity(EXTI_Port_TypeDef Port, EXTI_Sensitivity_TypeDef SensitivityValue);
void EXTI_SetTLISensitivity(EXTI_TLISensitivity_TypeDef SensitivityValue);
EXTI_Sensitivity_TypeDef EXTI_GetExtIntSensitivity(EXTI_Port_TypeDef Port);
EXTI_TLISensitivity_TypeDef EXTI_GetTLISensitivity(void);
/**
* @}
*/
#endif /* __STM8S_EXTI_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s_flash.h
================================================
/**
******************************************************************************
* @file stm8s_flash.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all functions prototype and macros for the FLASH peripheral.
******************************************************************************
* @attention
*
*
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_FLASH_H
#define __STM8S_FLASH_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/* Exported constants --------------------------------------------------------*/
/** @addtogroup FLASH_Exported_Constants
* @{
*/
#define FLASH_PROG_START_PHYSICAL_ADDRESS ((uint32_t)0x008000) /*!< Program memory: start address */
#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined (STM8AF52Ax) || defined (STM8AF62Ax)
#define FLASH_PROG_END_PHYSICAL_ADDRESS ((uint32_t)0x027FFF) /*!< Program memory: end address */
#define FLASH_PROG_BLOCKS_NUMBER ((uint16_t)1024) /*!< Program memory: total number of blocks */
#define FLASH_DATA_START_PHYSICAL_ADDRESS ((uint32_t)0x004000) /*!< Data EEPROM memory: start address */
#define FLASH_DATA_END_PHYSICAL_ADDRESS ((uint32_t)0x0047FF) /*!< Data EEPROM memory: end address */
#define FLASH_DATA_BLOCKS_NUMBER ((uint16_t)16) /*!< Data EEPROM memory: total number of blocks */
#define FLASH_BLOCK_SIZE ((uint8_t)128) /*!< Number of bytes in a block (common for Program and Data memories) */
#endif /* STM8S208, STM8S207, STM8S007, STM8AF52Ax, STM8AF62Ax */
#if defined(STM8S105) || defined(STM8S005) || defined(STM8AF626x)
#define FLASH_PROG_END_PHYSICAL_ADDRESS ((uint32_t)0xFFFF) /*!< Program memory: end address */
#define FLASH_PROG_BLOCKS_NUMBER ((uint16_t)256) /*!< Program memory: total number of blocks */
#define FLASH_DATA_START_PHYSICAL_ADDRESS ((uint32_t)0x004000) /*!< Data EEPROM memory: start address */
#define FLASH_DATA_END_PHYSICAL_ADDRESS ((uint32_t)0x0043FF) /*!< Data EEPROM memory: end address */
#define FLASH_DATA_BLOCKS_NUMBER ((uint16_t)8) /*!< Data EEPROM memory: total number of blocks */
#define FLASH_BLOCK_SIZE ((uint8_t)128) /*!< Number of bytes in a block (common for Program and Data memories) */
#endif /* STM8S105 or STM8AF626x */
#if defined(STM8S103) || defined(STM8S003) || defined(STM8S001) || defined(STM8S903) || defined(STM8AF622x)
#define FLASH_PROG_END_PHYSICAL_ADDRESS ((uint32_t)0x9FFF) /*!< Program memory: end address */
#define FLASH_PROG_BLOCKS_NUMBER ((uint16_t)128) /*!< Program memory: total number of blocks */
#define FLASH_DATA_START_PHYSICAL_ADDRESS ((uint32_t)0x004000) /*!< Data EEPROM memory: start address */
#define FLASH_DATA_END_PHYSICAL_ADDRESS ((uint32_t)0x00427F) /*!< Data EEPROM memory: end address */
#define FLASH_DATA_BLOCKS_NUMBER ((uint16_t)10) /*!< Data EEPROM memory: total number of blocks */
#define FLASH_BLOCK_SIZE ((uint8_t)64) /*!< Number of bytes in a block (common for Program and Data memories) */
#endif /* STM8S103 or STM8S003 or STM8S001 or STM8S903 or STM8AF622x*/
#define FLASH_RASS_KEY1 ((uint8_t)0x56) /*!< First RASS key */
#define FLASH_RASS_KEY2 ((uint8_t)0xAE) /*!< Second RASS key */
#define OPTION_BYTE_START_PHYSICAL_ADDRESS ((uint16_t)0x4800)
#define OPTION_BYTE_END_PHYSICAL_ADDRESS ((uint16_t)0x487F)
#define FLASH_OPTIONBYTE_ERROR ((uint16_t)0x5555) /*!< Error code option byte
(if value read is not equal to complement value read) */
/**
* @}
*/
/* Exported types ------------------------------------------------------------*/
/** @addtogroup FLASH_Exported_Types
* @{
*/
/**
* @brief FLASH Memory types
*/
typedef enum {
FLASH_MEMTYPE_PROG = (uint8_t)0xFD, /*!< Program memory */
FLASH_MEMTYPE_DATA = (uint8_t)0xF7 /*!< Data EEPROM memory */
} FLASH_MemType_TypeDef;
/**
* @brief FLASH programming modes
*/
typedef enum {
FLASH_PROGRAMMODE_STANDARD = (uint8_t)0x00, /*!< Standard programming mode */
FLASH_PROGRAMMODE_FAST = (uint8_t)0x10 /*!< Fast programming mode */
} FLASH_ProgramMode_TypeDef;
/**
* @brief FLASH fixed programming time
*/
typedef enum {
FLASH_PROGRAMTIME_STANDARD = (uint8_t)0x00, /*!< Standard programming time fixed at 1/2 tprog */
FLASH_PROGRAMTIME_TPROG = (uint8_t)0x01 /*!< Programming time fixed at tprog */
} FLASH_ProgramTime_TypeDef;
/**
* @brief FLASH Low Power mode select
*/
typedef enum {
FLASH_LPMODE_POWERDOWN = (uint8_t)0x04, /*!< HALT: Power-Down / ACTIVE-HALT: Power-Down */
FLASH_LPMODE_STANDBY = (uint8_t)0x08, /*!< HALT: Standby / ACTIVE-HALT: Standby */
FLASH_LPMODE_POWERDOWN_STANDBY = (uint8_t)0x00, /*!< HALT: Power-Down / ACTIVE-HALT: Standby */
FLASH_LPMODE_STANDBY_POWERDOWN = (uint8_t)0x0C /*!< HALT: Standby / ACTIVE-HALT: Power-Down */
}
FLASH_LPMode_TypeDef;
/**
* @brief FLASH status of the last operation
*/
typedef enum {
#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S105) || \
defined(STM8S005) || defined (STM8AF52Ax) || defined (STM8AF62Ax) || defined(STM8AF626x)
FLASH_STATUS_END_HIGH_VOLTAGE = (uint8_t)0x40, /*!< End of high voltage */
#endif /* STM8S208, STM8S207, STM8S105, STM8AF62Ax, STM8AF52Ax, STM8AF626x */
FLASH_STATUS_SUCCESSFUL_OPERATION = (uint8_t)0x04, /*!< End of operation flag */
FLASH_STATUS_TIMEOUT = (uint8_t)0x02, /*!< Time out error */
FLASH_STATUS_WRITE_PROTECTION_ERROR = (uint8_t)0x01 /*!< Write attempted to protected page */
} FLASH_Status_TypeDef;
/**
* @brief FLASH flags definition
* - Warning : FLAG value = mapping position register
*/
typedef enum {
#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S105) || \
defined(STM8S005) || defined (STM8AF52Ax) || defined (STM8AF62Ax) || defined(STM8AF626x)
FLASH_FLAG_HVOFF = (uint8_t)0x40, /*!< End of high voltage flag */
#endif /* STM8S208, STM8S207, STM8S105, STM8AF62Ax, STM8AF52Ax, STM8AF626x */
FLASH_FLAG_DUL = (uint8_t)0x08, /*!< Data EEPROM unlocked flag */
FLASH_FLAG_EOP = (uint8_t)0x04, /*!< End of programming (write or erase operation) flag */
FLASH_FLAG_PUL = (uint8_t)0x02, /*!< Flash Program memory unlocked flag */
FLASH_FLAG_WR_PG_DIS = (uint8_t)0x01 /*!< Write attempted to protected page flag */
} FLASH_Flag_TypeDef;
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/**
* @brief Macros used by the assert function in order to check the different functions parameters.
* @addtogroup FLASH_Private_Macros
* @{
*/
/**
* @brief Macro used by the assert function in order to check the different sensitivity values for the flash program Address
*/
#define IS_FLASH_PROG_ADDRESS_OK(ADDRESS) (((ADDRESS) >= FLASH_PROG_START_PHYSICAL_ADDRESS) && \
((ADDRESS) <= FLASH_PROG_END_PHYSICAL_ADDRESS))
/**
* @brief Macro used by the assert function in order to check the different sensitivity values for the data eeprom Address
*/
#define IS_FLASH_DATA_ADDRESS_OK(ADDRESS) (((ADDRESS) >= FLASH_DATA_START_PHYSICAL_ADDRESS) && \
((ADDRESS) <= FLASH_DATA_END_PHYSICAL_ADDRESS))
/**
* @brief Macro used by the assert function in order to check the different sensitivity values for the data eeprom and flash program Address
*/
#define IS_FLASH_ADDRESS_OK(ADDRESS)((((ADDRESS) >= FLASH_PROG_START_PHYSICAL_ADDRESS) && ((ADDRESS) <= FLASH_PROG_END_PHYSICAL_ADDRESS)) || \
(((ADDRESS) >= FLASH_DATA_START_PHYSICAL_ADDRESS) && ((ADDRESS) <= FLASH_DATA_END_PHYSICAL_ADDRESS)))
/**
* @brief Macro used by the assert function in order to check the different sensitivity values for the flash program Block number
*/
#define IS_FLASH_PROG_BLOCK_NUMBER_OK(BLOCKNUM) ((BLOCKNUM) < FLASH_PROG_BLOCKS_NUMBER)
/**
* @brief Macro used by the assert function in order to check the different sensitivity values for the data eeprom Block number
*/
#define IS_FLASH_DATA_BLOCK_NUMBER_OK(BLOCKNUM) ((BLOCKNUM) < FLASH_DATA_BLOCKS_NUMBER)
/**
* @brief Macro used by the assert function in order to check the different sensitivity values for the flash memory type
*/
#define IS_MEMORY_TYPE_OK(MEMTYPE) (((MEMTYPE) == FLASH_MEMTYPE_PROG) || \
((MEMTYPE) == FLASH_MEMTYPE_DATA))
/**
* @brief Macro used by the assert function in order to check the different sensitivity values for the flash program mode
*/
#define IS_FLASH_PROGRAM_MODE_OK(MODE) (((MODE) == FLASH_PROGRAMMODE_STANDARD) || \
((MODE) == FLASH_PROGRAMMODE_FAST))
/**
* @brief Macro used by the assert function in order to check the program time mode
*/
#define IS_FLASH_PROGRAM_TIME_OK(TIME) (((TIME) == FLASH_PROGRAMTIME_STANDARD) || \
((TIME) == FLASH_PROGRAMTIME_TPROG))
/**
* @brief Macro used by the assert function in order to check the different
* sensitivity values for the low power mode
*/
#define IS_FLASH_LOW_POWER_MODE_OK(LPMODE) (((LPMODE) == FLASH_LPMODE_POWERDOWN) || \
((LPMODE) == FLASH_LPMODE_STANDBY) || \
((LPMODE) == FLASH_LPMODE_POWERDOWN_STANDBY) || \
((LPMODE) == FLASH_LPMODE_STANDBY_POWERDOWN))
/**
* @brief Macro used by the assert function in order to check the different
* sensitivity values for the option bytes Address
*/
#define IS_OPTION_BYTE_ADDRESS_OK(ADDRESS) (((ADDRESS) >= OPTION_BYTE_START_PHYSICAL_ADDRESS) && \
((ADDRESS) <= OPTION_BYTE_END_PHYSICAL_ADDRESS))
/**
* @brief Macro used by the assert function in order to check the different flags values
*/
#if defined (STM8S208) || defined(STM8S207) || defined(STM8S007) || defined(STM8S105) || \
defined(STM8S005) || defined (STM8AF52Ax) || defined (STM8AF62Ax) || defined(STM8AF626x)
#define IS_FLASH_FLAGS_OK(FLAG) (((FLAG) == FLASH_FLAG_HVOFF) || \
((FLAG) == FLASH_FLAG_DUL) || \
((FLAG) == FLASH_FLAG_EOP) || \
((FLAG) == FLASH_FLAG_PUL) || \
((FLAG) == FLASH_FLAG_WR_PG_DIS))
#else /* STM8S103, STM8S001, STM8S903, STM8AF622x */
#define IS_FLASH_FLAGS_OK(FLAG) (((FLAG) == FLASH_FLAG_DUL) || \
((FLAG) == FLASH_FLAG_EOP) || \
((FLAG) == FLASH_FLAG_PUL) || \
((FLAG) == FLASH_FLAG_WR_PG_DIS))
#endif /* STM8S208, STM8S207, STM8S105, STM8AF62Ax, STM8AF52Ax, STM8AF626x */
/**
* @}
*/
/* Exported functions ------------------------------------------------------- */
/** @addtogroup FLASH_Exported_Functions
* @{
*/
void FLASH_Unlock(FLASH_MemType_TypeDef FLASH_MemType);
void FLASH_Lock(FLASH_MemType_TypeDef FLASH_MemType);
void FLASH_DeInit(void);
void FLASH_ITConfig(FunctionalState NewState);
void FLASH_EraseByte(uint32_t Address);
void FLASH_ProgramByte(uint32_t Address, uint8_t Data);
uint8_t FLASH_ReadByte(uint32_t Address);
void FLASH_ProgramWord(uint32_t Address, uint32_t Data);
uint16_t FLASH_ReadOptionByte(uint16_t Address);
void FLASH_ProgramOptionByte(uint16_t Address, uint8_t Data);
void FLASH_EraseOptionByte(uint16_t Address);
void FLASH_SetLowPowerMode(FLASH_LPMode_TypeDef FLASH_LPMode);
void FLASH_SetProgrammingTime(FLASH_ProgramTime_TypeDef FLASH_ProgTime);
FLASH_LPMode_TypeDef FLASH_GetLowPowerMode(void);
FLASH_ProgramTime_TypeDef FLASH_GetProgrammingTime(void);
uint32_t FLASH_GetBootSize(void);
FlagStatus FLASH_GetFlagStatus(FLASH_Flag_TypeDef FLASH_FLAG);
/**
@code
All the functions declared below must be executed from RAM exclusively, except
for the FLASH_WaitForLastOperation function which can be executed from Flash.
Steps of the execution from RAM differs from one toolchain to another.
for more details refer to stm8s_flash.c file.
To enable execution from RAM you can either uncomment the following define
in the stm8s.h file or define it in your toolchain compiler preprocessor
- #define RAM_EXECUTION (1)
@endcode
*/
IN_RAM(void FLASH_EraseBlock(uint16_t BlockNum, FLASH_MemType_TypeDef FLASH_MemType));
IN_RAM(void FLASH_ProgramBlock(uint16_t BlockNum, FLASH_MemType_TypeDef FLASH_MemType,
FLASH_ProgramMode_TypeDef FLASH_ProgMode, uint8_t *Buffer));
IN_RAM(FLASH_Status_TypeDef FLASH_WaitForLastOperation(FLASH_MemType_TypeDef FLASH_MemType));
/**
* @}
*/
#endif /*__STM8S_FLASH_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s_gpio.h
================================================
/**
******************************************************************************
* @file stm8s_gpio.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all functions prototype and macros for the GPIO peripheral.
******************************************************************************
* @attention
*
*
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_I2C_H
#define __STM8S_I2C_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/* Exported types ------------------------------------------------------------*/
/** @addtogroup I2C_Exported_Types
* @{
*/
/**
* @brief I2C duty cycle (fast mode only)
*/
typedef enum
{
I2C_DUTYCYCLE_2 = (uint8_t)0x00, /*!< Fast mode Tlow/THigh = 2 */
I2C_DUTYCYCLE_16_9 = (uint8_t)0x40 /*!< Fast mode Tlow/Thigh = 16/9 */
} I2C_DutyCycle_TypeDef;
/**
* @brief I2C Acknowledgement configuration
*/
typedef enum
{
I2C_ACK_NONE = (uint8_t)0x00, /*!< No acknowledge */
I2C_ACK_CURR = (uint8_t)0x01, /*!< Acknowledge on the current byte */
I2C_ACK_NEXT = (uint8_t)0x02 /*!< Acknowledge on the next byte */
} I2C_Ack_TypeDef;
/**
* @brief I2C Addressing Mode (slave mode only)
*/
typedef enum
{
I2C_ADDMODE_7BIT = (uint8_t)0x00, /*!< 7-bit slave address (10-bit address not acknowledged) */
I2C_ADDMODE_10BIT = (uint8_t)0x80 /*!< 10-bit slave address (7-bit address not acknowledged) */
} I2C_AddMode_TypeDef;
/**
* @brief I2C Interrupt sources
* Warning: the values correspond to the bit position in the ITR register
*/
typedef enum
{
I2C_IT_ERR = (uint8_t)0x01, /*!< Error Interruption */
I2C_IT_EVT = (uint8_t)0x02, /*!< Event Interruption */
I2C_IT_BUF = (uint8_t)0x04 /*!< Buffer Interruption */
} I2C_IT_TypeDef;
/**
* @brief I2C transfer direction
* Warning: the values correspond to the ADD0 bit position in the OARL register
*/
typedef enum
{
I2C_DIRECTION_TX = (uint8_t)0x00, /*!< Transmission direction */
I2C_DIRECTION_RX = (uint8_t)0x01 /*!< Reception direction */
} I2C_Direction_TypeDef;
/**
* @brief I2C Flags
* @brief Elements values convention: 0xXXYY
* X = SRx registers index
* X = 1 : SR1
* X = 2 : SR2
* X = 3 : SR3
* Y = Flag mask in the register
*/
typedef enum
{
/* SR1 register flags */
I2C_FLAG_TXEMPTY = (uint16_t)0x0180, /*!< Transmit Data Register Empty flag */
I2C_FLAG_RXNOTEMPTY = (uint16_t)0x0140, /*!< Read Data Register Not Empty flag */
I2C_FLAG_STOPDETECTION = (uint16_t)0x0110, /*!< Stop detected flag */
I2C_FLAG_HEADERSENT = (uint16_t)0x0108, /*!< 10-bit Header sent flag */
I2C_FLAG_TRANSFERFINISHED = (uint16_t)0x0104, /*!< Data Byte Transfer Finished flag */
I2C_FLAG_ADDRESSSENTMATCHED = (uint16_t)0x0102, /*!< Address Sent/Matched (master/slave) flag */
I2C_FLAG_STARTDETECTION = (uint16_t)0x0101, /*!< Start bit sent flag */
/* SR2 register flags */
I2C_FLAG_WAKEUPFROMHALT = (uint16_t)0x0220, /*!< Wake Up From Halt Flag */
I2C_FLAG_OVERRUNUNDERRUN = (uint16_t)0x0208, /*!< Overrun/Underrun flag */
I2C_FLAG_ACKNOWLEDGEFAILURE = (uint16_t)0x0204, /*!< Acknowledge Failure Flag */
I2C_FLAG_ARBITRATIONLOSS = (uint16_t)0x0202, /*!< Arbitration Loss Flag */
I2C_FLAG_BUSERROR = (uint16_t)0x0201, /*!< Misplaced Start or Stop condition */
/* SR3 register flags */
I2C_FLAG_GENERALCALL = (uint16_t)0x0310, /*!< General Call header received Flag */
I2C_FLAG_TRANSMITTERRECEIVER = (uint16_t)0x0304, /*!< Transmitter Receiver Flag */
I2C_FLAG_BUSBUSY = (uint16_t)0x0302, /*!< Bus Busy Flag */
I2C_FLAG_MASTERSLAVE = (uint16_t)0x0301 /*!< Master Slave Flag */
} I2C_Flag_TypeDef;
/**
* @brief I2C Pending bits
* Elements values convention: 0xXYZZ
* X = SRx registers index
* X = 1 : SR1
* X = 2 : SR2
* Y = Position of the corresponding Interrupt
* ZZ = flag mask in the dedicated register(X register)
*/
typedef enum
{
/* SR1 register flags */
I2C_ITPENDINGBIT_TXEMPTY = (uint16_t)0x1680, /*!< Transmit Data Register Empty */
I2C_ITPENDINGBIT_RXNOTEMPTY = (uint16_t)0x1640, /*!< Read Data Register Not Empty */
I2C_ITPENDINGBIT_STOPDETECTION = (uint16_t)0x1210, /*!< Stop detected */
I2C_ITPENDINGBIT_HEADERSENT = (uint16_t)0x1208, /*!< 10-bit Header sent */
I2C_ITPENDINGBIT_TRANSFERFINISHED = (uint16_t)0x1204, /*!< Data Byte Transfer Finished */
I2C_ITPENDINGBIT_ADDRESSSENTMATCHED = (uint16_t)0x1202, /*!< Address Sent/Matched (master/slave) */
I2C_ITPENDINGBIT_STARTDETECTION = (uint16_t)0x1201, /*!< Start bit sent */
/* SR2 register flags */
I2C_ITPENDINGBIT_WAKEUPFROMHALT = (uint16_t)0x2220, /*!< Wake Up From Halt */
I2C_ITPENDINGBIT_OVERRUNUNDERRUN = (uint16_t)0x2108, /*!< Overrun/Underrun */
I2C_ITPENDINGBIT_ACKNOWLEDGEFAILURE = (uint16_t)0x2104, /*!< Acknowledge Failure */
I2C_ITPENDINGBIT_ARBITRATIONLOSS = (uint16_t)0x2102, /*!< Arbitration Loss */
I2C_ITPENDINGBIT_BUSERROR = (uint16_t)0x2101 /*!< Misplaced Start or Stop condition */
} I2C_ITPendingBit_TypeDef;
/**
* @brief I2C possible events
* Values convention: 0xXXYY
* XX = Event SR3 corresponding value
* YY = Event SR1 corresponding value
* @note if Event = EV3_2 the rule above does not apply
* YY = Event SR2 corresponding value
*/
typedef enum
{
/*========================================
I2C Master Events (Events grouped in order of communication)
==========================================*/
/**
* @brief Communication start
*
* After sending the START condition (I2C_GenerateSTART() function) the master
* has to wait for this event. It means that the Start condition has been correctly
* released on the I2C bus (the bus is free, no other devices is communicating).
*
*/
/* --EV5 */
I2C_EVENT_MASTER_MODE_SELECT = (uint16_t)0x0301, /*!< BUSY, MSL and SB flag */
/**
* @brief Address Acknowledge
*
* After checking on EV5 (start condition correctly released on the bus), the
* master sends the address of the slave(s) with which it will communicate
* (I2C_Send7bitAddress() function, it also determines the direction of the communication:
* Master transmitter or Receiver).
* Then the master has to wait that a slave acknowledges his address.
* If an acknowledge is sent on the bus, one of the following events will
* be set:
*
* 1) In case of Master Receiver (7-bit addressing):
* the I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED event is set.
*
* 2) In case of Master Transmitter (7-bit addressing):
* the I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED is set
*
* 3) In case of 10-Bit addressing mode, the master (just after generating the START
* and checking on EV5) has to send the header of 10-bit addressing mode (I2C_SendData()
* function).
* Then master should wait on EV9. It means that the 10-bit addressing
* header has been correctly sent on the bus.
* Then master should send the second part of the 10-bit address (LSB) using
* the function I2C_Send7bitAddress(). Then master should wait for event EV6.
*
*/
/* --EV6 */
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED = (uint16_t)0x0782, /*!< BUSY, MSL, ADDR, TXE and TRA flags */
I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED = (uint16_t)0x0302, /*!< BUSY, MSL and ADDR flags */
/* --EV9 */
I2C_EVENT_MASTER_MODE_ADDRESS10 = (uint16_t)0x0308, /*!< BUSY, MSL and ADD10 flags */
/**
* @brief Communication events
*
* If a communication is established (START condition generated and slave address
* acknowledged) then the master has to check on one of the following events for
* communication procedures:
*
* 1) Master Receiver mode: The master has to wait on the event EV7 then to read
* the data received from the slave (I2C_ReceiveData() function).
*
* 2) Master Transmitter mode: The master has to send data (I2C_SendData()
* function) then to wait on event EV8 or EV8_2.
* These two events are similar:
* - EV8 means that the data has been written in the data register and is
* being shifted out.
* - EV8_2 means that the data has been physically shifted out and output
* on the bus.
* In most cases, using EV8 is sufficient for the application.
* Using EV8_2 leads to a slower communication but ensures more reliable test.
* EV8_2 is also more suitable than EV8 for testing on the last data transmission
* (before Stop condition generation).
*
* @note In case the user software does not guarantee that this event EV7 is
* managed before the current byte end of transfer, then user may check on EV7
* and BTF flag at the same time (ie. (I2C_EVENT_MASTER_BYTE_RECEIVED | I2C_FLAG_BTF)).
* In this case the communication may be slower.
*
*/
/* Master RECEIVER mode -----------------------------*/
/* --EV7 */
I2C_EVENT_MASTER_BYTE_RECEIVED = (uint16_t)0x0340, /*!< BUSY, MSL and RXNE flags */
/* Master TRANSMITTER mode --------------------------*/
/* --EV8 */
I2C_EVENT_MASTER_BYTE_TRANSMITTING = (uint16_t)0x0780, /*!< TRA, BUSY, MSL, TXE flags */
/* --EV8_2 */
I2C_EVENT_MASTER_BYTE_TRANSMITTED = (uint16_t)0x0784, /*!< EV8_2: TRA, BUSY, MSL, TXE and BTF flags */
/*========================================
I2C Slave Events (Events grouped in order of communication)
==========================================*/
/**
* @brief Communication start events
*
* Wait on one of these events at the start of the communication. It means that
* the I2C peripheral detected a Start condition on the bus (generated by master
* device) followed by the peripheral address.
* The peripheral generates an ACK condition on the bus (if the acknowledge
* feature is enabled through function I2C_AcknowledgeConfig()) and the events
* listed above are set :
*
* 1) In normal case (only one address managed by the slave), when the address
* sent by the master matches the own address of the peripheral (configured by
* I2C_OwnAddress1 field) the I2C_EVENT_SLAVE_XXX_ADDRESS_MATCHED event is set
* (where XXX could be TRANSMITTER or RECEIVER).
*
* 2) In case the address sent by the master is General Call (address 0x00) and
* if the General Call is enabled for the peripheral (using function I2C_GeneralCallCmd())
* the following event is set I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED.
*
*/
/* --EV1 (all the events below are variants of EV1) */
/* 1) Case of One Single Address managed by the slave */
I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED = (uint16_t)0x0202, /*!< BUSY and ADDR flags */
I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED = (uint16_t)0x0682, /*!< TRA, BUSY, TXE and ADDR flags */
/* 2) Case of General Call enabled for the slave */
I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED = (uint16_t)0x1200, /*!< EV2: GENCALL and BUSY flags */
/**
* @brief Communication events
*
* Wait on one of these events when EV1 has already been checked :
*
* - Slave RECEIVER mode:
* - EV2: When the application is expecting a data byte to be received.
* - EV4: When the application is expecting the end of the communication:
* master sends a stop condition and data transmission is stopped.
*
* - Slave Transmitter mode:
* - EV3: When a byte has been transmitted by the slave and the application
* is expecting the end of the byte transmission.
* The two events I2C_EVENT_SLAVE_BYTE_TRANSMITTED and I2C_EVENT_SLAVE_BYTE_TRANSMITTING
* are similar. The second one can optionally be used when the user software
* doesn't guarantee the EV3 is managed before the current byte end of transfer.
* - EV3_2: When the master sends a NACK in order to tell slave that data transmission
* shall end (before sending the STOP condition).
* In this case slave has to stop sending data bytes and expect a Stop
* condition on the bus.
*
* @note In case the user software does not guarantee that the event EV2 is
* managed before the current byte end of transfer, then user may check on EV2
* and BTF flag at the same time (ie. (I2C_EVENT_SLAVE_BYTE_RECEIVED | I2C_FLAG_BTF)).
* In this case the communication may be slower.
*
*/
/* Slave RECEIVER mode --------------------------*/
/* --EV2 */
I2C_EVENT_SLAVE_BYTE_RECEIVED = (uint16_t)0x0240, /*!< BUSY and RXNE flags */
/* --EV4 */
I2C_EVENT_SLAVE_STOP_DETECTED = (uint16_t)0x0010, /*!< STOPF flag */
/* Slave TRANSMITTER mode -----------------------*/
/* --EV3 */
I2C_EVENT_SLAVE_BYTE_TRANSMITTED = (uint16_t)0x0684, /*!< TRA, BUSY, TXE and BTF flags */
I2C_EVENT_SLAVE_BYTE_TRANSMITTING = (uint16_t)0x0680, /*!< TRA, BUSY and TXE flags */
/* --EV3_2 */
I2C_EVENT_SLAVE_ACK_FAILURE = (uint16_t)0x0004 /*!< AF flag */
} I2C_Event_TypeDef;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @addtogroup I2C_Exported_Constants
* @{
*/
#define I2C_MAX_STANDARD_FREQ ((uint32_t)100000)
#define I2C_MAX_FAST_FREQ ((uint32_t)400000)
#if defined(STM8S208) || defined(STM8S207) || defined(STM8S007)
#define I2C_MAX_INPUT_FREQ ((uint8_t)24)
#else
#define I2C_MAX_INPUT_FREQ ((uint8_t)16)
#endif
/**
* @}
*/
/* Exported macros -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup I2C_Private_Macros
* @{
*/
/**
* @brief Macro used by the assert function to check the different functions parameters.
*/
/**
* @brief Macro used by the assert function to check the different I2C duty cycles.
*/
#define IS_I2C_DUTYCYCLE_OK(DUTY) \
(((DUTY) == I2C_DUTYCYCLE_2) || \
((DUTY) == I2C_DUTYCYCLE_16_9))
/**
* @brief Macro used by the assert function to check the different acknowledgement configuration
*/
#define IS_I2C_ACK_OK(ACK) \
(((ACK) == I2C_ACK_NONE) || \
((ACK) == I2C_ACK_CURR) || \
((ACK) == I2C_ACK_NEXT))
/**
* @brief Macro used by the assert function to check the different I2C addressing modes.
*/
#define IS_I2C_ADDMODE_OK(ADDMODE) \
(((ADDMODE) == I2C_ADDMODE_7BIT) || \
((ADDMODE) == I2C_ADDMODE_10BIT))
/**
* @brief Macro used by the assert function to check the different I2C interrupt types.
*/
#define IS_I2C_INTERRUPT_OK(IT) \
(((IT) == I2C_IT_ERR) || \
((IT) == I2C_IT_EVT) || \
((IT) == I2C_IT_BUF) || \
((IT) == (I2C_IT_ERR | I2C_IT_EVT)) || \
((IT) == (I2C_IT_ERR | I2C_IT_BUF)) || \
((IT) == (I2C_IT_EVT | I2C_IT_BUF)) || \
((IT) == (I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR)))
/**
* @brief Macro used by the assert function to check the different I2C communcation direction.
*/
#define IS_I2C_DIRECTION_OK(DIR) \
(((DIR) == I2C_DIRECTION_TX) || \
((DIR) == I2C_DIRECTION_RX))
/**
* @brief Macro used by the assert function to check the different I2C flags.
*/
#define IS_I2C_FLAG_OK(FLAG) \
(((FLAG) == I2C_FLAG_TXEMPTY) || \
((FLAG) == I2C_FLAG_RXNOTEMPTY) || \
((FLAG) == I2C_FLAG_STOPDETECTION) || \
((FLAG) == I2C_FLAG_HEADERSENT) || \
((FLAG) == I2C_FLAG_TRANSFERFINISHED) || \
((FLAG) == I2C_FLAG_ADDRESSSENTMATCHED) || \
((FLAG) == I2C_FLAG_STARTDETECTION) || \
((FLAG) == I2C_FLAG_WAKEUPFROMHALT) || \
((FLAG) == I2C_FLAG_OVERRUNUNDERRUN) || \
((FLAG) == I2C_FLAG_ACKNOWLEDGEFAILURE) || \
((FLAG) == I2C_FLAG_ARBITRATIONLOSS) || \
((FLAG) == I2C_FLAG_BUSERROR) || \
((FLAG) == I2C_FLAG_GENERALCALL) || \
((FLAG) == I2C_FLAG_TRANSMITTERRECEIVER) || \
((FLAG) == I2C_FLAG_BUSBUSY) || \
((FLAG) == I2C_FLAG_MASTERSLAVE))
/**
* @brief Macro used by the assert function to check the I2C flags to clear.
*/
#define IS_I2C_CLEAR_FLAG_OK(FLAG) ((((uint16_t)(FLAG) & (uint16_t)0xFD00) == 0x00) \
&& ((uint16_t)(FLAG) != 0x00))
/**
* @brief Macro used by the assert function to check the different I2C possible pending bits.
*/
#define IS_I2C_ITPENDINGBIT_OK(ITPENDINGBIT) \
(((ITPENDINGBIT) == I2C_ITPENDINGBIT_TXEMPTY) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_RXNOTEMPTY) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_STOPDETECTION) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_HEADERSENT) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_TRANSFERFINISHED) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_ADDRESSSENTMATCHED) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_STARTDETECTION) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_WAKEUPFROMHALT) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_OVERRUNUNDERRUN) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_ACKNOWLEDGEFAILURE) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_ARBITRATIONLOSS) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_BUSERROR))
/**
* @brief Macro used by the assert function to check the different I2C possible
* pending bits to clear by writing 0.
*/
#define IS_I2C_CLEAR_ITPENDINGBIT_OK(ITPENDINGBIT) \
(((ITPENDINGBIT) == I2C_ITPENDINGBIT_WAKEUPFROMHALT) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_OVERRUNUNDERRUN) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_ACKNOWLEDGEFAILURE) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_ARBITRATIONLOSS) || \
((ITPENDINGBIT) == I2C_ITPENDINGBIT_BUSERROR))
/**
* @brief Macro used by the assert function to check the different I2C possible events.
*/
#define IS_I2C_EVENT_OK(EVENT) (((EVENT) == I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED) || \
((EVENT) == I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED) || \
((EVENT) == I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED) || \
((EVENT) == I2C_EVENT_SLAVE_BYTE_RECEIVED) || \
((EVENT) == (I2C_EVENT_SLAVE_BYTE_RECEIVED | (uint16_t)I2C_FLAG_GENERALCALL)) || \
((EVENT) == I2C_EVENT_SLAVE_BYTE_TRANSMITTED) || \
((EVENT) == (I2C_EVENT_SLAVE_BYTE_TRANSMITTED | (uint16_t)I2C_FLAG_GENERALCALL)) || \
((EVENT) == I2C_EVENT_SLAVE_ACK_FAILURE) || \
((EVENT) == I2C_EVENT_SLAVE_STOP_DETECTED) || \
((EVENT) == I2C_EVENT_MASTER_MODE_SELECT) || \
((EVENT) == I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) || \
((EVENT) == I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) || \
((EVENT) == I2C_EVENT_MASTER_BYTE_RECEIVED) || \
((EVENT) == I2C_EVENT_MASTER_BYTE_TRANSMITTED) || \
((EVENT) == I2C_EVENT_MASTER_BYTE_TRANSMITTING) || \
((EVENT) == I2C_EVENT_MASTER_MODE_ADDRESS10))
/**
* @brief Macro used by the assert function to check the different I2C possible own address.
*/
#define IS_I2C_OWN_ADDRESS_OK(ADDRESS) \
((ADDRESS) <= (uint16_t)0x03FF)
/* The address must be even */
#define IS_I2C_ADDRESS_OK(ADD) \
(((ADD) & (uint8_t)0x01) == (uint8_t)0x00)
/**
* @brief Macro used by the assert function to check that I2C Input clock frequency must be between 1MHz and 50MHz.
*/
#define IS_I2C_INPUT_CLOCK_FREQ_OK(FREQ) \
(((FREQ) >= (uint8_t)1) && ((FREQ) <= I2C_MAX_INPUT_FREQ))
/**
* @brief Macro used by the assert function to check that I2C Output clock frequency must be between 1Hz and 400kHz.
*/
#define IS_I2C_OUTPUT_CLOCK_FREQ_OK(FREQ) \
(((FREQ) >= (uint8_t)1) && ((FREQ) <= I2C_MAX_FAST_FREQ))
/**
* @}
*/
/* Exported functions ------------------------------------------------------- */
/** @addtogroup I2C_Exported_Functions
* @{
*/
void I2C_DeInit(void);
void I2C_Init(uint32_t OutputClockFrequencyHz, uint16_t OwnAddress,
I2C_DutyCycle_TypeDef I2C_DutyCycle, I2C_Ack_TypeDef Ack,
I2C_AddMode_TypeDef AddMode, uint8_t InputClockFrequencyMHz );
void I2C_Cmd(FunctionalState NewState);
void I2C_GeneralCallCmd(FunctionalState NewState);
void I2C_GenerateSTART(FunctionalState NewState);
void I2C_GenerateSTOP(FunctionalState NewState);
void I2C_SoftwareResetCmd(FunctionalState NewState);
void I2C_StretchClockCmd(FunctionalState NewState);
void I2C_AcknowledgeConfig(I2C_Ack_TypeDef Ack);
void I2C_FastModeDutyCycleConfig(I2C_DutyCycle_TypeDef I2C_DutyCycle);
void I2C_ITConfig(I2C_IT_TypeDef I2C_IT, FunctionalState NewState);
uint8_t I2C_ReceiveData(void);
void I2C_Send7bitAddress(uint8_t Address, I2C_Direction_TypeDef Direction);
void I2C_SendData(uint8_t Data);
/**
* @brief
****************************************************************************************
*
* I2C State Monitoring Functions
*
****************************************************************************************
* This I2C driver provides three different ways for I2C state monitoring
* depending on the application requirements and constraints:
*
*
* 1) Basic state monitoring:
* Using I2C_CheckEvent() function:
* It compares the status registers (SR1, SR2 and SR3) content to a given event
* (can be the combination of one or more flags).
* It returns SUCCESS if the current status includes the given flags
* and returns ERROR if one or more flags are missing in the current status.
* - When to use:
* - This function is suitable for most applications as well as for startup
* activity since the events are fully described in the product reference manual
* (RM0016).
* - It is also suitable for users who need to define their own events.
* - Limitations:
* - If an error occurs (ie. error flags are set besides to the monitored flags),
* the I2C_CheckEvent() function may return SUCCESS despite the communication
* hold or corrupted real state.
* In this case, it is advised to use error interrupts to monitor the error
* events and handle them in the interrupt IRQ handler.
*
* @note
* For error management, it is advised to use the following functions:
* - I2C_ITConfig() to configure and enable the error interrupts (I2C_IT_ERR).
* - I2C_IRQHandler() which is called when the I2C interrupts occur.
* - I2C_GetFlagStatus() or I2C_GetITStatus() to be called into the
* I2Cx_IRQHandler() function in order to determine which error occurred.
* - I2C_ClearFlag() or I2C_ClearITPendingBit() and/or I2C_SoftwareResetCmd()
* and/or I2C_GenerateStop() in order to clear the error flag and
* source and return to correct communication status.
*
*
* 2) Advanced state monitoring:
* Using the function I2C_GetLastEvent() which returns the image of both SR1
* & SR3 status registers in a single word (uint16_t) (Status Register 3 value
* is shifted left by 8 bits and concatenated to Status Register 1).
* - When to use:
* - This function is suitable for the same applications above but it allows to
* overcome the limitations of I2C_GetFlagStatus() function (see below).
* The returned value could be compared to events already defined in the
* library (stm8s_i2c.h) or to custom values defined by user.
* - This function is suitable when multiple flags are monitored at the same time.
* - At the opposite of I2C_CheckEvent() function, this function allows user to
* choose when an event is accepted (when all events flags are set and no
* other flags are set or just when the needed flags are set like
* I2C_CheckEvent() function).
* - Limitations:
* - User may need to define his own events.
* - Same remark concerning the error management is applicable for this
* function if user decides to check only regular communication flags (and
* ignores error flags).
*
*
* 3) Flag-based state monitoring:
* Using the function I2C_GetFlagStatus() which simply returns the status of
* one single flag (ie. I2C_FLAG_RXNE ...).
* - When to use:
* - This function could be used for specific applications or in debug phase.
* - It is suitable when only one flag checking is needed (most I2C events
* are monitored through multiple flags).
* - Limitations:
* - When calling this function, the Status register is accessed. Some flags are
* cleared when the status register is accessed. So checking the status
* of one Flag, may clear other ones.
* - Function may need to be called twice or more in order to monitor one
* single event.
*
*/
/**
*
* 1) Basic state monitoring
*******************************************************************************
*/
ErrorStatus I2C_CheckEvent(I2C_Event_TypeDef I2C_Event);
/**
*
* 2) Advanced state monitoring
*******************************************************************************
*/
I2C_Event_TypeDef I2C_GetLastEvent(void);
/**
*
* 3) Flag-based state monitoring
*******************************************************************************
*/
FlagStatus I2C_GetFlagStatus(I2C_Flag_TypeDef I2C_Flag);
/**
*
*******************************************************************************
*/
void I2C_ClearFlag(I2C_Flag_TypeDef I2C_FLAG);
ITStatus I2C_GetITStatus(I2C_ITPendingBit_TypeDef I2C_ITPendingBit);
void I2C_ClearITPendingBit(I2C_ITPendingBit_TypeDef I2C_ITPendingBit);
/**
* @}
*/
#endif /* __STM8S_I2C_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s_itc.h
================================================
/**
******************************************************************************
* @file stm8s_itc.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all functions prototype and macros for the ITC peripheral.
******************************************************************************
* @attention
*
*
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_IWDG_H
#define __STM8S_IWDG_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/** @addtogroup STM8S_StdPeriph_Driver
* @{
*/
/** @addtogroup IWDG_Private_Define
* @{
*/
/**
* @brief Define used to prevent watchdog reset
*/
#define IWDG_KEY_REFRESH ((uint8_t)0xAA) /*!< This value written in the Key register prevent the watchdog reset */
/**
* @brief Define used to start the watchdog counter down
*/
#define IWDG_KEY_ENABLE ((uint8_t)0xCC) /*!< This value written in the Key register start the watchdog counting down*/
/**
* @}
*/
/** @addtogroup IWDG_Private_Macros
* @{
*/
/**
* @brief Macro used by the assert function in order to check the different
* values of the prescaler.
*/
#define IS_IWDG_PRESCALER_OK(VALUE) (((VALUE) == IWDG_Prescaler_4 ) || \
((VALUE) == IWDG_Prescaler_8 ) || \
((VALUE) == IWDG_Prescaler_16 ) || \
((VALUE) == IWDG_Prescaler_32 ) || \
((VALUE) == IWDG_Prescaler_64 ) || \
((VALUE) == IWDG_Prescaler_128 ) || \
((VALUE) == IWDG_Prescaler_256))
/**
* @brief Macro used by the assert function in order to check the different
* values of the counter register.
*/
#define IS_IWDG_WRITEACCESS_MODE_OK(MODE) (((MODE) == IWDG_WriteAccess_Enable) || ((MODE) == IWDG_WriteAccess_Disable))
/**
* @}
*/
/** @addtogroup IWDG_Exported_Types
* @{
*/
/** IWDG write access enumeration */
typedef enum
{
IWDG_WriteAccess_Enable = (uint8_t)0x55, /*!< Code 0x55 in Key register, allow write access to Prescaler and Reload registers */
IWDG_WriteAccess_Disable = (uint8_t)0x00 /*!< Code 0x00 in Key register, not allow write access to Prescaler and Reload registers */
} IWDG_WriteAccess_TypeDef;
/** IWDG prescaler enumaration */
typedef enum
{
IWDG_Prescaler_4 = (uint8_t)0x00, /*!< Used to set prescaler register to 4 */
IWDG_Prescaler_8 = (uint8_t)0x01, /*!< Used to set prescaler register to 8 */
IWDG_Prescaler_16 = (uint8_t)0x02, /*!< Used to set prescaler register to 16 */
IWDG_Prescaler_32 = (uint8_t)0x03, /*!< Used to set prescaler register to 32 */
IWDG_Prescaler_64 = (uint8_t)0x04, /*!< Used to set prescaler register to 64 */
IWDG_Prescaler_128 = (uint8_t)0x05, /*!< Used to set prescaler register to 128 */
IWDG_Prescaler_256 = (uint8_t)0x06 /*!< Used to set prescaler register to 256 */
} IWDG_Prescaler_TypeDef;
/**
* @}
*/
/** @addtogroup IWDG_Exported_Functions
* @{
*/
void IWDG_WriteAccessCmd(IWDG_WriteAccess_TypeDef IWDG_WriteAccess);
void IWDG_SetPrescaler(IWDG_Prescaler_TypeDef IWDG_Prescaler);
void IWDG_SetReload(uint8_t IWDG_Reload);
void IWDG_ReloadCounter(void);
void IWDG_Enable(void);
/**
* @}
*/
#endif /* __STM8S_IWDG_H */
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s_rst.h
================================================
/**
******************************************************************************
* @file stm8s_rst.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all functions prototype and macros for the RST peripheral.
******************************************************************************
* @attention
*
*
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_RST_H
#define __STM8S_RST_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/** @addtogroup STM8S_StdPeriph_Driver
* @{
*/
/** @addtogroup RST_Exported_Types
* @{
*/
typedef enum {
RST_FLAG_EMCF = (uint8_t)0x10, /*!< EMC reset flag */
RST_FLAG_SWIMF = (uint8_t)0x08, /*!< SWIM reset flag */
RST_FLAG_ILLOPF = (uint8_t)0x04, /*!< Illigal opcode reset flag */
RST_FLAG_IWDGF = (uint8_t)0x02, /*!< Independent watchdog reset flag */
RST_FLAG_WWDGF = (uint8_t)0x01 /*!< Window watchdog reset flag */
}RST_Flag_TypeDef;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/** @addtogroup RST_Private_Macros
* @{
*/
/**
* @brief Macro used by the assert function to check the different functions parameters.
*/
/**
* @brief Macro used by the assert function to check the different RST flags.
*/
#define IS_RST_FLAG_OK(FLAG) (((FLAG) == RST_FLAG_EMCF) || \
((FLAG) == RST_FLAG_SWIMF) ||\
((FLAG) == RST_FLAG_ILLOPF) ||\
((FLAG) == RST_FLAG_IWDGF) ||\
((FLAG) == RST_FLAG_WWDGF))
/**
* @}
*/
/** @addtogroup RST_Exported_functions
* @{
*/
FlagStatus RST_GetFlagStatus(RST_Flag_TypeDef RST_Flag);
void RST_ClearFlag(RST_Flag_TypeDef RST_Flag);
/**
* @}
*/
#endif /* __STM8S_RST_H */
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s_spi.h
================================================
/**
******************************************************************************
* @file stm8s_spi.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all functions prototype and macros for the SPI peripheral.
******************************************************************************
* @attention
*
*
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_SPI_H
#define __STM8S_SPI_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/** @addtogroup STM8S_StdPeriph_Driver
* @{
*/
/** @addtogroup SPI_Exported_Types
* @{
*/
/**
* @brief SPI data direction mode
* Warning: element values correspond to BDM, BDOE, RXONLY bits position
*/
typedef enum {
SPI_DATADIRECTION_2LINES_FULLDUPLEX = (uint8_t)0x00, /*!< 2-line uni-directional data mode enable */
SPI_DATADIRECTION_2LINES_RXONLY = (uint8_t)0x04, /*!< Receiver only in 2 line uni-directional data mode */
SPI_DATADIRECTION_1LINE_RX = (uint8_t)0x80, /*!< Receiver only in 1 line bi-directional data mode */
SPI_DATADIRECTION_1LINE_TX = (uint8_t)0xC0 /*!< Transmit only in 1 line bi-directional data mode */
} SPI_DataDirection_TypeDef;
/**
* @brief SPI Slave Select management
* Warning: element values correspond to LSBFIRST bit position
*/
typedef enum
{
SPI_NSS_SOFT = (uint8_t)0x02, /*!< Software slave management disabled */
SPI_NSS_HARD = (uint8_t)0x00 /*!< Software slave management enabled */
} SPI_NSS_TypeDef;
/**
* @brief SPI direction transmit/receive
*/
typedef enum {
SPI_DIRECTION_RX = (uint8_t)0x00, /*!< Selects Rx receive direction in bi-directional mode */
SPI_DIRECTION_TX = (uint8_t)0x01 /*!< Selects Tx transmission direction in bi-directional mode */
} SPI_Direction_TypeDef;
/**
* @brief SPI master/slave mode
* Warning: element values correspond to MSTR bit position
*/
typedef enum {
SPI_MODE_MASTER = (uint8_t)0x04, /*!< SPI Master configuration */
SPI_MODE_SLAVE = (uint8_t)0x00 /*!< SPI Slave configuration */
} SPI_Mode_TypeDef;
/**
* @brief SPI BaudRate Prescaler
* Warning: element values correspond to BR bits position
*/
typedef enum {
SPI_BAUDRATEPRESCALER_2 = (uint8_t)0x00, /*!< SPI frequency = frequency(CPU)/2 */
SPI_BAUDRATEPRESCALER_4 = (uint8_t)0x08, /*!< SPI frequency = frequency(CPU)/4 */
SPI_BAUDRATEPRESCALER_8 = (uint8_t)0x10, /*!< SPI frequency = frequency(CPU)/8 */
SPI_BAUDRATEPRESCALER_16 = (uint8_t)0x18, /*!< SPI frequency = frequency(CPU)/16 */
SPI_BAUDRATEPRESCALER_32 = (uint8_t)0x20, /*!< SPI frequency = frequency(CPU)/32 */
SPI_BAUDRATEPRESCALER_64 = (uint8_t)0x28, /*!< SPI frequency = frequency(CPU)/64 */
SPI_BAUDRATEPRESCALER_128 = (uint8_t)0x30, /*!< SPI frequency = frequency(CPU)/128 */
SPI_BAUDRATEPRESCALER_256 = (uint8_t)0x38 /*!< SPI frequency = frequency(CPU)/256 */
} SPI_BaudRatePrescaler_TypeDef;
/**
* @brief SPI Clock Polarity
* Warning: element values correspond to CPOL bit position
*/
typedef enum {
SPI_CLOCKPOLARITY_LOW = (uint8_t)0x00, /*!< Clock to 0 when idle */
SPI_CLOCKPOLARITY_HIGH = (uint8_t)0x02 /*!< Clock to 1 when idle */
} SPI_ClockPolarity_TypeDef;
/**
* @brief SPI Clock Phase
* Warning: element values correspond to CPHA bit position
*/
typedef enum {
SPI_CLOCKPHASE_1EDGE = (uint8_t)0x00, /*!< The first clock transition is the first data capture edge */
SPI_CLOCKPHASE_2EDGE = (uint8_t)0x01 /*!< The second clock transition is the first data capture edge */
} SPI_ClockPhase_TypeDef;
/**
* @brief SPI Frame Format: MSB or LSB transmitted first
* Warning: element values correspond to LSBFIRST bit position
*/
typedef enum {
SPI_FIRSTBIT_MSB = (uint8_t)0x00, /*!< MSB bit will be transmitted first */
SPI_FIRSTBIT_LSB = (uint8_t)0x80 /*!< LSB bit will be transmitted first */
} SPI_FirstBit_TypeDef;
/**
* @brief SPI CRC Transmit/Receive
*/
typedef enum {
SPI_CRC_RX = (uint8_t)0x00, /*!< Select Tx CRC register */
SPI_CRC_TX = (uint8_t)0x01 /*!< Select Rx CRC register */
} SPI_CRC_TypeDef;
/**
* @brief SPI flags definition - Warning : FLAG value = mapping position register
*/
typedef enum {
SPI_FLAG_BSY = (uint8_t)0x80, /*!< Busy flag */
SPI_FLAG_OVR = (uint8_t)0x40, /*!< Overrun flag */
SPI_FLAG_MODF = (uint8_t)0x20, /*!< Mode fault */
SPI_FLAG_CRCERR = (uint8_t)0x10, /*!< CRC error flag */
SPI_FLAG_WKUP = (uint8_t)0x08, /*!< Wake-up flag */
SPI_FLAG_TXE = (uint8_t)0x02, /*!< Transmit buffer empty */
SPI_FLAG_RXNE = (uint8_t)0x01 /*!< Receive buffer empty */
} SPI_Flag_TypeDef;
/**
* @brief SPI_IT possible values
* Elements values convention: 0xYX
* X: Position of the corresponding Interrupt
* Y: ITPENDINGBIT position
*/
typedef enum
{
SPI_IT_WKUP = (uint8_t)0x34, /*!< Wake-up interrupt*/
SPI_IT_OVR = (uint8_t)0x65, /*!< Overrun interrupt*/
SPI_IT_MODF = (uint8_t)0x55, /*!< Mode fault interrupt*/
SPI_IT_CRCERR = (uint8_t)0x45, /*!< CRC error interrupt*/
SPI_IT_TXE = (uint8_t)0x17, /*!< Transmit buffer empty interrupt*/
SPI_IT_RXNE = (uint8_t)0x06, /*!< Receive buffer not empty interrupt*/
SPI_IT_ERR = (uint8_t)0x05 /*!< Error interrupt*/
} SPI_IT_TypeDef;
/**
* @}
*/
/* Private define ------------------------------------------------------------*/
/** @addtogroup SPI_Private_Macros
* @brief Macros used by the assert_param function to check the different functions parameters.
* @{
*/
/**
* @brief Macro used by the assert_param function in order to check the data direction mode values
*/
#define IS_SPI_DATA_DIRECTION_OK(MODE) (((MODE) == SPI_DATADIRECTION_2LINES_FULLDUPLEX) || \
((MODE) == SPI_DATADIRECTION_2LINES_RXONLY) || \
((MODE) == SPI_DATADIRECTION_1LINE_RX) || \
((MODE) == SPI_DATADIRECTION_1LINE_TX))
/**
* @brief Macro used by the assert_param function in order to check the mode
* half duplex data direction values
*/
#define IS_SPI_DIRECTION_OK(DIRECTION) (((DIRECTION) == SPI_DIRECTION_RX) || \
((DIRECTION) == SPI_DIRECTION_TX))
/**
* @brief Macro used by the assert_param function in order to check the NSS
* management values
*/
#define IS_SPI_SLAVEMANAGEMENT_OK(NSS) (((NSS) == SPI_NSS_SOFT) || \
((NSS) == SPI_NSS_HARD))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the CRC polynomial
*/
#define IS_SPI_CRC_POLYNOMIAL_OK(POLYNOMIAL) ((POLYNOMIAL) > (uint8_t)0x00)
/**
* @brief Macro used by the assert_param function in order to check the SPI Mode values
*/
#define IS_SPI_MODE_OK(MODE) (((MODE) == SPI_MODE_MASTER) || \
((MODE) == SPI_MODE_SLAVE))
/**
* @brief Macro used by the assert_param function in order to check the baudrate values
*/
#define IS_SPI_BAUDRATE_PRESCALER_OK(PRESCALER) (((PRESCALER) == SPI_BAUDRATEPRESCALER_2) || \
((PRESCALER) == SPI_BAUDRATEPRESCALER_4) || \
((PRESCALER) == SPI_BAUDRATEPRESCALER_8) || \
((PRESCALER) == SPI_BAUDRATEPRESCALER_16) || \
((PRESCALER) == SPI_BAUDRATEPRESCALER_32) || \
((PRESCALER) == SPI_BAUDRATEPRESCALER_64) || \
((PRESCALER) == SPI_BAUDRATEPRESCALER_128) || \
((PRESCALER) == SPI_BAUDRATEPRESCALER_256))
/**
* @brief Macro used by the assert_param function in order to check the polarity values
*/
#define IS_SPI_POLARITY_OK(CLKPOL) (((CLKPOL) == SPI_CLOCKPOLARITY_LOW) || \
((CLKPOL) == SPI_CLOCKPOLARITY_HIGH))
/**
* @brief Macro used by the assert_param function in order to check the phase values
*/
#define IS_SPI_PHASE_OK(CLKPHA) (((CLKPHA) == SPI_CLOCKPHASE_1EDGE) || \
((CLKPHA) == SPI_CLOCKPHASE_2EDGE))
/**
* @brief Macro used by the assert_param function in order to check the first
* bit to be transmited values
*/
#define IS_SPI_FIRSTBIT_OK(BIT) (((BIT) == SPI_FIRSTBIT_MSB) || \
((BIT) == SPI_FIRSTBIT_LSB))
/**
* @brief Macro used by the assert_param function in order to check the CRC
* Transmit/Receive
*/
#define IS_SPI_CRC_OK(CRC) (((CRC) == SPI_CRC_TX) || \
((CRC) == SPI_CRC_RX))
/**
* @brief Macro used by the assert_param function in order to check the
* different flags values
*/
#define IS_SPI_FLAGS_OK(FLAG) (((FLAG) == SPI_FLAG_OVR) || \
((FLAG) == SPI_FLAG_MODF) || \
((FLAG) == SPI_FLAG_CRCERR) || \
((FLAG) == SPI_FLAG_WKUP) || \
((FLAG) == SPI_FLAG_TXE) || \
((FLAG) == SPI_FLAG_RXNE) || \
((FLAG) == SPI_FLAG_BSY))
/**
* @brief Macro used by the assert_param function in order to check the
* different sensitivity values for the flag that can be cleared
* by writing 0
*/
#define IS_SPI_CLEAR_FLAGS_OK(FLAG) (((FLAG) == SPI_FLAG_CRCERR) || \
((FLAG) == SPI_FLAG_WKUP))
/**
* @brief Macro used by the assert_param function in order to check the
* different sensitivity values for the Interrupts
*/
#define IS_SPI_CONFIG_IT_OK(Interrupt) (((Interrupt) == SPI_IT_TXE) || \
((Interrupt) == SPI_IT_RXNE) || \
((Interrupt) == SPI_IT_ERR) || \
((Interrupt) == SPI_IT_WKUP))
/**
* @brief Macro used by the assert_param function in order to check the
* different sensitivity values for the pending bit
*/
#define IS_SPI_GET_IT_OK(ITPendingBit) (((ITPendingBit) == SPI_IT_OVR) || \
((ITPendingBit) == SPI_IT_MODF) || \
((ITPendingBit) == SPI_IT_CRCERR) || \
((ITPendingBit) == SPI_IT_WKUP) || \
((ITPendingBit) == SPI_IT_TXE) || \
((ITPendingBit) == SPI_IT_RXNE))
/**
* @brief Macro used by the assert_param function in order to check the
* different sensitivity values for the pending bit that can be cleared
* by writing 0
*/
#define IS_SPI_CLEAR_IT_OK(ITPendingBit) (((ITPendingBit) == SPI_IT_CRCERR) || \
((ITPendingBit) == SPI_IT_WKUP))
/**
* @}
*/
/** @addtogroup SPI_Exported_Functions
* @{
*/
void SPI_DeInit(void);
void SPI_Init(SPI_FirstBit_TypeDef FirstBit,
SPI_BaudRatePrescaler_TypeDef BaudRatePrescaler,
SPI_Mode_TypeDef Mode, SPI_ClockPolarity_TypeDef ClockPolarity,
SPI_ClockPhase_TypeDef ClockPhase,
SPI_DataDirection_TypeDef Data_Direction,
SPI_NSS_TypeDef Slave_Management, uint8_t CRCPolynomial);
void SPI_Cmd(FunctionalState NewState);
void SPI_ITConfig(SPI_IT_TypeDef SPI_IT, FunctionalState NewState);
void SPI_SendData(uint8_t Data);
uint8_t SPI_ReceiveData(void);
void SPI_NSSInternalSoftwareCmd(FunctionalState NewState);
void SPI_TransmitCRC(void);
void SPI_CalculateCRCCmd(FunctionalState NewState);
uint8_t SPI_GetCRC(SPI_CRC_TypeDef SPI_CRC);
void SPI_ResetCRC(void);
uint8_t SPI_GetCRCPolynomial(void);
void SPI_BiDirectionalLineConfig(SPI_Direction_TypeDef SPI_Direction);
FlagStatus SPI_GetFlagStatus(SPI_Flag_TypeDef SPI_FLAG);
void SPI_ClearFlag(SPI_Flag_TypeDef SPI_FLAG);
ITStatus SPI_GetITStatus(SPI_IT_TypeDef SPI_IT);
void SPI_ClearITPendingBit(SPI_IT_TypeDef SPI_IT);
/**
* @}
*/
#endif /* __STM8S_SPI_H */
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s_tim1.h
================================================
/**
******************************************************************************
* @file stm8s_tim1.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all functions prototype and macros for the TIM1 peripheral.
******************************************************************************
* @attention
*
*
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_UART1_H
#define __STM8S_UART1_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/** @addtogroup STM8S_StdPeriph_Driver
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @addtogroup UART1_Exported_Types
* @{
*/
/**
* @brief UART1 Irda Modes
*/
typedef enum { UART1_IRDAMODE_NORMAL = (uint8_t)0x00, /**< 0x00 Irda Normal Mode */
UART1_IRDAMODE_LOWPOWER = (uint8_t)0x01 /**< 0x01 Irda Low Power Mode */
} UART1_IrDAMode_TypeDef;
/**
* @brief UART1 WakeUP Modes
*/
typedef enum { UART1_WAKEUP_IDLELINE = (uint8_t)0x00, /**< 0x01 Idle Line wake up */
UART1_WAKEUP_ADDRESSMARK = (uint8_t)0x08 /**< 0x02 Address Mark wake up */
} UART1_WakeUp_TypeDef;
/**
* @brief UART1 LIN Break detection length possible values
*/
typedef enum { UART1_LINBREAKDETECTIONLENGTH_10BITS = (uint8_t)0x00, /**< 0x01 10 bits Lin Break detection */
UART1_LINBREAKDETECTIONLENGTH_11BITS = (uint8_t)0x01 /**< 0x02 11 bits Lin Break detection */
} UART1_LINBreakDetectionLength_TypeDef;
/**
* @brief UART1 stop bits possible values
*/
typedef enum { UART1_STOPBITS_1 = (uint8_t)0x00, /**< One stop bit is transmitted at the end of frame*/
UART1_STOPBITS_0_5 = (uint8_t)0x10, /**< Half stop bits is transmitted at the end of frame*/
UART1_STOPBITS_2 = (uint8_t)0x20, /**< Two stop bits are transmitted at the end of frame*/
UART1_STOPBITS_1_5 = (uint8_t)0x30 /**< One and half stop bits*/
} UART1_StopBits_TypeDef;
/**
* @brief UART1 parity possible values
*/
typedef enum { UART1_PARITY_NO = (uint8_t)0x00, /**< No Parity*/
UART1_PARITY_EVEN = (uint8_t)0x04, /**< Even Parity*/
UART1_PARITY_ODD = (uint8_t)0x06 /**< Odd Parity*/
} UART1_Parity_TypeDef;
/**
* @brief UART1 Synchrone modes
*/
typedef enum { UART1_SYNCMODE_CLOCK_DISABLE = (uint8_t)0x80, /**< 0x80 Sync mode Disable, SLK pin Disable */
UART1_SYNCMODE_CLOCK_ENABLE = (uint8_t)0x08, /**< 0x08 Sync mode Enable, SLK pin Enable */
UART1_SYNCMODE_CPOL_LOW = (uint8_t)0x40, /**< 0x40 Steady low value on SCLK pin outside transmission window */
UART1_SYNCMODE_CPOL_HIGH = (uint8_t)0x04, /**< 0x04 Steady high value on SCLK pin outside transmission window */
UART1_SYNCMODE_CPHA_MIDDLE = (uint8_t)0x20, /**< 0x20 SCLK clock line activated in middle of data bit */
UART1_SYNCMODE_CPHA_BEGINING = (uint8_t)0x02, /**< 0x02 SCLK clock line activated at beginning of data bit */
UART1_SYNCMODE_LASTBIT_DISABLE = (uint8_t)0x10, /**< 0x10 The clock pulse of the last data bit is not output to the SCLK pin */
UART1_SYNCMODE_LASTBIT_ENABLE = (uint8_t)0x01 /**< 0x01 The clock pulse of the last data bit is output to the SCLK pin */
} UART1_SyncMode_TypeDef;
/**
* @brief UART1 Word length possible values
*/
typedef enum { UART1_WORDLENGTH_8D = (uint8_t)0x00,/**< 0x00 8 bits Data */
UART1_WORDLENGTH_9D = (uint8_t)0x10 /**< 0x10 9 bits Data */
} UART1_WordLength_TypeDef;
/**
* @brief UART1 Mode possible values
*/
typedef enum { UART1_MODE_RX_ENABLE = (uint8_t)0x08, /**< 0x08 Receive Enable */
UART1_MODE_TX_ENABLE = (uint8_t)0x04, /**< 0x04 Transmit Enable */
UART1_MODE_TX_DISABLE = (uint8_t)0x80, /**< 0x80 Transmit Disable */
UART1_MODE_RX_DISABLE = (uint8_t)0x40, /**< 0x40 Single-wire Half-duplex mode */
UART1_MODE_TXRX_ENABLE = (uint8_t)0x0C /**< 0x0C Transmit Enable and Receive Enable */
} UART1_Mode_TypeDef;
/**
* @brief UART1 Flag possible values
*/
typedef enum { UART1_FLAG_TXE = (uint16_t)0x0080, /*!< Transmit Data Register Empty flag */
UART1_FLAG_TC = (uint16_t)0x0040, /*!< Transmission Complete flag */
UART1_FLAG_RXNE = (uint16_t)0x0020, /*!< Read Data Register Not Empty flag */
UART1_FLAG_IDLE = (uint16_t)0x0010, /*!< Idle line detected flag */
UART1_FLAG_OR = (uint16_t)0x0008, /*!< OverRun error flag */
UART1_FLAG_NF = (uint16_t)0x0004, /*!< Noise error flag */
UART1_FLAG_FE = (uint16_t)0x0002, /*!< Framing Error flag */
UART1_FLAG_PE = (uint16_t)0x0001, /*!< Parity Error flag */
UART1_FLAG_LBDF = (uint16_t)0x0210, /*!< Line Break Detection Flag */
UART1_FLAG_SBK = (uint16_t)0x0101 /*!< Send Break characters Flag */
} UART1_Flag_TypeDef;
/**
* @brief UART1 Interrupt definition
* UART1_IT possible values
* Elements values convention: 0xZYX
* X: Position of the corresponding Interrupt
* - For the following values, X means the interrupt position in the CR2 register.
* UART1_IT_TXE
* UART1_IT_TC
* UART1_IT_RXNE
* UART1_IT_IDLE
* UART1_IT_OR
* - For the UART1_IT_PE value, X means the flag position in the CR1 register.
* - For the UART1_IT_LBDF value, X means the flag position in the CR4 register.
* Y: Flag position
* - For the following values, Y means the flag (pending bit) position in the SR register.
* UART1_IT_TXE
* UART1_IT_TC
* UART1_IT_RXNE
* UART1_IT_IDLE
* UART1_IT_OR
* UART1_IT_PE
* - For the UART1_IT_LBDF value, Y means the flag position in the CR4 register.
* Z: Register index: indicate in which register the dedicated interrupt source is:
* - 1==> CR1 register
* - 2==> CR2 register
* - 3==> CR4 register
*/
typedef enum { UART1_IT_TXE = (uint16_t)0x0277, /*!< Transmit interrupt */
UART1_IT_TC = (uint16_t)0x0266, /*!< Transmission Complete interrupt */
UART1_IT_RXNE = (uint16_t)0x0255, /*!< Receive interrupt */
UART1_IT_IDLE = (uint16_t)0x0244, /*!< IDLE line interrupt */
UART1_IT_OR = (uint16_t)0x0235, /*!< Overrun Error interrupt */
UART1_IT_PE = (uint16_t)0x0100, /*!< Parity Error interrupt */
UART1_IT_LBDF = (uint16_t)0x0346, /**< LIN break detection interrupt */
UART1_IT_RXNE_OR = (uint16_t)0x0205 /*!< Receive/Overrun interrupt */
} UART1_IT_TypeDef;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/* Exported macros ------------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup UART1_Private_Macros
* @{
*/
/**
* @brief Macro used by the assert function to check the different functions parameters.
*/
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the MODEs possible combination should be one of
* the following
*/
#define IS_UART1_MODE_OK(Mode) \
(((Mode) == (uint8_t)UART1_MODE_RX_ENABLE) || \
((Mode) == (uint8_t)UART1_MODE_RX_DISABLE) || \
((Mode) == (uint8_t)UART1_MODE_TX_ENABLE) || \
((Mode) == (uint8_t)UART1_MODE_TX_DISABLE) || \
((Mode) == (uint8_t)UART1_MODE_TXRX_ENABLE) || \
((Mode) == (uint8_t)((uint8_t)UART1_MODE_TX_ENABLE|(uint8_t)UART1_MODE_RX_ENABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART1_MODE_TX_ENABLE|(uint8_t)UART1_MODE_RX_DISABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART1_MODE_TX_DISABLE|(uint8_t)UART1_MODE_RX_DISABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART1_MODE_TX_DISABLE|(uint8_t)UART1_MODE_RX_ENABLE)))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the WordLengths
*/
#define IS_UART1_WORDLENGTH_OK(WordLength) \
(((WordLength) == UART1_WORDLENGTH_8D) || \
((WordLength) == UART1_WORDLENGTH_9D))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the SyncModes; it should exclude values such
* as UART1_CLOCK_ENABLE|UART1_CLOCK_DISABLE
*/
#define IS_UART1_SYNCMODE_OK(SyncMode) \
(!((((SyncMode)&(((uint8_t)UART1_SYNCMODE_CLOCK_ENABLE)|((uint8_t)UART1_SYNCMODE_CLOCK_DISABLE))) == (((uint8_t)UART1_SYNCMODE_CLOCK_ENABLE)|((uint8_t)UART1_SYNCMODE_CLOCK_DISABLE))) \
|| (((SyncMode)&(((uint8_t)UART1_SYNCMODE_CPOL_LOW )|((uint8_t)UART1_SYNCMODE_CPOL_HIGH))) == (((uint8_t)UART1_SYNCMODE_CPOL_LOW )|((uint8_t)UART1_SYNCMODE_CPOL_HIGH))) \
||(((SyncMode)&(((uint8_t)UART1_SYNCMODE_CPHA_MIDDLE)|((uint8_t)UART1_SYNCMODE_CPHA_BEGINING))) == (((uint8_t)UART1_SYNCMODE_CPHA_MIDDLE)|((uint8_t)UART1_SYNCMODE_CPHA_BEGINING))) \
|| (((SyncMode)&(((uint8_t)UART1_SYNCMODE_LASTBIT_DISABLE)|((uint8_t)UART1_SYNCMODE_LASTBIT_ENABLE))) == (((uint8_t)UART1_SYNCMODE_LASTBIT_DISABLE)|((uint8_t)UART1_SYNCMODE_LASTBIT_ENABLE)))))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the FLAGs
*/
#define IS_UART1_FLAG_OK(Flag) \
(((Flag) == UART1_FLAG_TXE) || \
((Flag) == UART1_FLAG_TC) || \
((Flag) == UART1_FLAG_RXNE) || \
((Flag) == UART1_FLAG_IDLE) || \
((Flag) == UART1_FLAG_OR) || \
((Flag) == UART1_FLAG_NF) || \
((Flag) == UART1_FLAG_FE) || \
((Flag) == UART1_FLAG_PE) || \
((Flag) == UART1_FLAG_SBK) || \
((Flag) == UART1_FLAG_LBDF))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the FLAGs that can be cleared by writing 0
*/
#define IS_UART1_CLEAR_FLAG_OK(Flag) \
(((Flag) == UART1_FLAG_RXNE) || \
((Flag) == UART1_FLAG_LBDF))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the Interrupts
*/
#define IS_UART1_CONFIG_IT_OK(Interrupt) \
(((Interrupt) == UART1_IT_PE) || \
((Interrupt) == UART1_IT_TXE) || \
((Interrupt) == UART1_IT_TC) || \
((Interrupt) == UART1_IT_RXNE_OR ) || \
((Interrupt) == UART1_IT_IDLE) || \
((Interrupt) == UART1_IT_LBDF))
/**
* @brief Macro used by the assert function in order to check the different
* sensitivity values for the pending bit
*/
#define IS_UART1_GET_IT_OK(ITPendingBit) \
(((ITPendingBit) == UART1_IT_TXE) || \
((ITPendingBit) == UART1_IT_TC) || \
((ITPendingBit) == UART1_IT_RXNE) || \
((ITPendingBit) == UART1_IT_IDLE) || \
((ITPendingBit) == UART1_IT_OR) || \
((ITPendingBit) == UART1_IT_LBDF) || \
((ITPendingBit) == UART1_IT_PE))
/**
* @brief Macro used by the assert function in order to check the different
* sensitivity values for the pending bit that can be cleared by writing 0
*/
#define IS_UART1_CLEAR_IT_OK(ITPendingBit) \
(((ITPendingBit) == UART1_IT_RXNE) || \
((ITPendingBit) == UART1_IT_LBDF))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the IrDAModes
*/
#define IS_UART1_IRDAMODE_OK(IrDAMode) \
(((IrDAMode) == UART1_IRDAMODE_LOWPOWER) || \
((IrDAMode) == UART1_IRDAMODE_NORMAL))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the WakeUps
*/
#define IS_UART1_WAKEUP_OK(WakeUp) \
(((WakeUp) == UART1_WAKEUP_IDLELINE) || \
((WakeUp) == UART1_WAKEUP_ADDRESSMARK))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the LINBreakDetectionLengths
*/
#define IS_UART1_LINBREAKDETECTIONLENGTH_OK(LINBreakDetectionLength) \
(((LINBreakDetectionLength) == UART1_LINBREAKDETECTIONLENGTH_10BITS) || \
((LINBreakDetectionLength) == UART1_LINBREAKDETECTIONLENGTH_11BITS))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the UART1_StopBits
*/
#define IS_UART1_STOPBITS_OK(StopBit) (((StopBit) == UART1_STOPBITS_1) || \
((StopBit) == UART1_STOPBITS_0_5) || \
((StopBit) == UART1_STOPBITS_2) || \
((StopBit) == UART1_STOPBITS_1_5 ))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the Parity
*/
#define IS_UART1_PARITY_OK(Parity) (((Parity) == UART1_PARITY_NO) || \
((Parity) == UART1_PARITY_EVEN) || \
((Parity) == UART1_PARITY_ODD ))
/**
* @brief Macro used by the assert_param function in order to check the maximum
* baudrate value
*/
#define IS_UART1_BAUDRATE_OK(NUM) ((NUM) <= (uint32_t)625000)
/**
* @brief Macro used by the assert_param function in order to check the address
* of the UART1 or UART node
*/
#define UART1_ADDRESS_MAX ((uint8_t)16)
#define IS_UART1_ADDRESS_OK(node) ((node) < UART1_ADDRESS_MAX )
/**
* @}
*/
/* Exported functions ------------------------------------------------------- */
/** @addtogroup UART1_Exported_Functions
* @{
*/
void UART1_DeInit(void);
void UART1_Init(uint32_t BaudRate, UART1_WordLength_TypeDef WordLength,
UART1_StopBits_TypeDef StopBits, UART1_Parity_TypeDef Parity,
UART1_SyncMode_TypeDef SyncMode, UART1_Mode_TypeDef Mode);
void UART1_Cmd(FunctionalState NewState);
void UART1_ITConfig(UART1_IT_TypeDef UART1_IT, FunctionalState NewState);
void UART1_HalfDuplexCmd(FunctionalState NewState);
void UART1_IrDAConfig(UART1_IrDAMode_TypeDef UART1_IrDAMode);
void UART1_IrDACmd(FunctionalState NewState);
void UART1_LINBreakDetectionConfig(UART1_LINBreakDetectionLength_TypeDef UART1_LINBreakDetectionLength);
void UART1_LINCmd(FunctionalState NewState);
void UART1_SmartCardCmd(FunctionalState NewState);
void UART1_SmartCardNACKCmd(FunctionalState NewState);
void UART1_WakeUpConfig(UART1_WakeUp_TypeDef UART1_WakeUp);
void UART1_ReceiverWakeUpCmd(FunctionalState NewState);
uint8_t UART1_ReceiveData8(void);
uint16_t UART1_ReceiveData9(void);
void UART1_SendData8(uint8_t Data);
void UART1_SendData9(uint16_t Data);
void UART1_SendBreak(void);
void UART1_SetAddress(uint8_t UART1_Address);
void UART1_SetGuardTime(uint8_t UART1_GuardTime);
void UART1_SetPrescaler(uint8_t UART1_Prescaler);
FlagStatus UART1_GetFlagStatus(UART1_Flag_TypeDef UART1_FLAG);
void UART1_ClearFlag(UART1_Flag_TypeDef UART1_FLAG);
ITStatus UART1_GetITStatus(UART1_IT_TypeDef UART1_IT);
void UART1_ClearITPendingBit(UART1_IT_TypeDef UART1_IT);
/**
* @}
*/
#endif /* __STM8S_UART1_H */
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s_uart2.h
================================================
/**
********************************************************************************
* @file stm8s_uart2.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all functions prototypes and macros for the UART2 peripheral.
******************************************************************************
* @attention
*
*
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_UART2_H
#define __STM8S_UART2_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/** @addtogroup STM8S_StdPeriph_Driver
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @addtogroup UART2_Exported_Types
* @{
*/
/**
* @brief UART2 Irda Modes
*/
typedef enum { UART2_IRDAMODE_NORMAL = (uint8_t)0x00, /**< 0x00 Irda Normal Mode */
UART2_IRDAMODE_LOWPOWER = (uint8_t)0x01 /**< 0x01 Irda Low Power Mode */
} UART2_IrDAMode_TypeDef;
/**
* @brief UART2 WakeUP Modes
*/
typedef enum { UART2_WAKEUP_IDLELINE = (uint8_t)0x00, /**< 0x01 Idle Line wake up */
UART2_WAKEUP_ADDRESSMARK = (uint8_t)0x08 /**< 0x02 Address Mark wake up */
} UART2_WakeUp_TypeDef;
/**
* @brief UART2 LIN Break detection length possible values
*/
typedef enum { UART2_LINBREAKDETECTIONLENGTH_10BITS = (uint8_t)0x00, /**< 0x01 10 bits Lin Break detection */
UART2_LINBREAKDETECTIONLENGTH_11BITS = (uint8_t)0x01 /**< 0x02 11 bits Lin Break detection */
} UART2_LINBreakDetectionLength_TypeDef;
/**
* @brief UART2 stop bits possible values
*/
typedef enum { UART2_STOPBITS_1 = (uint8_t)0x00, /**< One stop bit is transmitted at the end of frame*/
UART2_STOPBITS_0_5 = (uint8_t)0x10, /**< Half stop bits is transmitted at the end of frame*/
UART2_STOPBITS_2 = (uint8_t)0x20, /**< Two stop bits are transmitted at the end of frame*/
UART2_STOPBITS_1_5 = (uint8_t)0x30 /**< One and half stop bits*/
} UART2_StopBits_TypeDef;
/**
* @brief UART2 parity possible values
*/
typedef enum { UART2_PARITY_NO = (uint8_t)0x00, /**< No Parity*/
UART2_PARITY_EVEN = (uint8_t)0x04, /**< Even Parity*/
UART2_PARITY_ODD = (uint8_t)0x06 /**< Odd Parity*/
} UART2_Parity_TypeDef;
/**
* @brief UART2 Mode possible values
*/
typedef enum { UART2_LIN_MODE_MASTER = (uint8_t)0x00, /**< LIN Master Mode*/
UART2_LIN_MODE_SLAVE = (uint8_t)0x01 /**< LIN Slave Mode*/
} UART2_LinMode_TypeDef;
/**
* @brief UART2 automatic resynchronisation possible values
*/
typedef enum { UART2_LIN_AUTOSYNC_DISABLE = (uint8_t)0x00, /**< LIN Autosynchronization Disable*/
UART2_LIN_AUTOSYNC_ENABLE = (uint8_t)0x01 /**< LIN Autosynchronization Enable*/
} UART2_LinAutosync_TypeDef;
/**
* @brief UART2 Divider Update Method possible values
*/
typedef enum { UART2_LIN_DIVUP_LBRR1 = (uint8_t)0x00, /**< LIN LDIV is updated as soon as LBRR1 is written*/
UART2_LIN_DIVUP_NEXTRXNE = (uint8_t)0x01 /**< LIN LDIV is updated at the next received character*/
} UART2_LinDivUp_TypeDef;
/**
* @brief UART2 Synchrone modes
*/
typedef enum { UART2_SYNCMODE_CLOCK_DISABLE = (uint8_t)0x80, /**< 0x80 Sync mode Disable, SLK pin Disable */
UART2_SYNCMODE_CLOCK_ENABLE = (uint8_t)0x08, /**< 0x08 Sync mode Enable, SLK pin Enable */
UART2_SYNCMODE_CPOL_LOW = (uint8_t)0x40, /**< 0x40 Steady low value on SCLK pin outside transmission window */
UART2_SYNCMODE_CPOL_HIGH = (uint8_t)0x04, /**< 0x04 Steady high value on SCLK pin outside transmission window */
UART2_SYNCMODE_CPHA_MIDDLE = (uint8_t)0x20, /**< 0x20 SCLK clock line activated in middle of data bit */
UART2_SYNCMODE_CPHA_BEGINING = (uint8_t)0x02, /**< 0x02 SCLK clock line activated at beginning of data bit */
UART2_SYNCMODE_LASTBIT_DISABLE = (uint8_t)0x10, /**< 0x10 The clock pulse of the last data bit is not output to the SCLK pin */
UART2_SYNCMODE_LASTBIT_ENABLE = (uint8_t)0x01 /**< 0x01 The clock pulse of the last data bit is output to the SCLK pin */
} UART2_SyncMode_TypeDef;
/**
* @brief UART2 Word length possible values
*/
typedef enum { UART2_WORDLENGTH_8D = (uint8_t)0x00,/**< 0x00 8 bits Data */
UART2_WORDLENGTH_9D = (uint8_t)0x10 /**< 0x10 9 bits Data */
} UART2_WordLength_TypeDef;
/**
* @brief UART2 Mode possible values
*/
typedef enum { UART2_MODE_RX_ENABLE = (uint8_t)0x08, /**< 0x08 Receive Enable */
UART2_MODE_TX_ENABLE = (uint8_t)0x04, /**< 0x04 Transmit Enable */
UART2_MODE_TX_DISABLE = (uint8_t)0x80, /**< 0x80 Transmit Disable */
UART2_MODE_RX_DISABLE = (uint8_t)0x40, /**< 0x40 Single-wire Half-duplex mode */
UART2_MODE_TXRX_ENABLE = (uint8_t)0x0C /**< 0x0C Transmit Enable and Receive Enable */
} UART2_Mode_TypeDef;
/**
* @brief UART2 Flag possible values
*/
typedef enum
{
UART2_FLAG_TXE = (uint16_t)0x0080, /*!< Transmit Data Register Empty flag */
UART2_FLAG_TC = (uint16_t)0x0040, /*!< Transmission Complete flag */
UART2_FLAG_RXNE = (uint16_t)0x0020, /*!< Read Data Register Not Empty flag */
UART2_FLAG_IDLE = (uint16_t)0x0010, /*!< Idle line detected flag */
UART2_FLAG_OR_LHE = (uint16_t)0x0008, /*!< OverRun error flag */
UART2_FLAG_NF = (uint16_t)0x0004, /*!< Noise error flag */
UART2_FLAG_FE = (uint16_t)0x0002, /*!< Framing Error flag */
UART2_FLAG_PE = (uint16_t)0x0001, /*!< Parity Error flag */
UART2_FLAG_SBK = (uint16_t)0x0101, /**< Send Break Complete interrupt flag */
UART2_FLAG_LBDF = (uint16_t)0x0210, /**< LIN Break Detection Flag */
UART2_FLAG_LHDF = (uint16_t)0x0302, /**< LIN Header Detection Flag*/
UART2_FLAG_LSF = (uint16_t)0x0301 /**< LIN Sync Field Flag*/
} UART2_Flag_TypeDef;
/**
* @brief UART2 Interrupt definition
* UART2_IT possible values
* Elements values convention: 0xZYX
* X: Position of the corresponding Interrupt
* - For the following values, X means the interrupt position in the CR2 register.
* UART2_IT_TXE
* UART2_IT_TC
* UART2_IT_RXNE
* UART2_IT_IDLE
* UART2_IT_OR
* - For the UART2_IT_PE value, X means the flag position in the CR1 register.
* - For the UART2_IT_LBDF value, X means the flag position in the CR4 register.
* - For the UART2_IT_LHDF value, X means the flag position in the CR6 register.
* Y: Flag position
* - For the following values, Y means the flag (pending bit) position in the SR register.
* UART2_IT_TXE
* UART2_IT_TC
* UART2_IT_RXNE
* UART2_IT_IDLE
* UART2_IT_OR
* UART2_IT_PE
* - For the UART2_IT_LBDF value, Y means the flag position in the CR4 register.
* - For the UART2_IT_LHDF value, Y means the flag position in the CR6 register.
* Z: Register index: indicate in which register the dedicated interrupt source is:
* - 1==> CR1 register
* - 2==> CR2 register
* - 3==> CR4 register
* - 4==> CR6 register
*/
typedef enum { UART2_IT_TXE = (uint16_t)0x0277, /**< Transmit interrupt */
UART2_IT_TC = (uint16_t)0x0266, /**< Transmission Complete interrupt */
UART2_IT_RXNE = (uint16_t)0x0255, /**< Data Register Not Empty interrupt */
UART2_IT_IDLE = (uint16_t)0x0244, /**< Idle line detected interrupt */
UART2_IT_OR = (uint16_t)0x0235, /**< OverRun error interrupt */
UART2_IT_PE = (uint16_t)0x0100, /**< Parity Error interrupt */
UART2_IT_LBDF = (uint16_t)0x0346, /**< LIN Break Detection interrupt */
UART2_IT_LHDF = (uint16_t)0x0412, /**< LIN Header Detection interrupt*/
UART2_IT_RXNE_OR = (uint16_t)0x0205 /*!< Receive/Overrun interrupt */
} UART2_IT_TypeDef;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/* Exported macros ------------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup UART2_Private_Macros
* @{
*/
/**
* @brief Macro used by the assert function to check the different functions parameters.
*/
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the MODEs possible combination should be one of
* the following.
*/
#define IS_UART2_MODE_OK(Mode) \
(((Mode) == (uint8_t)UART2_MODE_RX_ENABLE) || \
((Mode) == (uint8_t)UART2_MODE_RX_DISABLE) || \
((Mode) == (uint8_t)UART2_MODE_TX_ENABLE) || \
((Mode) == (uint8_t)UART2_MODE_TX_DISABLE) || \
((Mode) == (uint8_t)UART2_MODE_TXRX_ENABLE) || \
((Mode) == (uint8_t)((uint8_t)UART2_MODE_TX_ENABLE|(uint8_t)UART2_MODE_RX_ENABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART2_MODE_TX_ENABLE|(uint8_t)UART2_MODE_RX_DISABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART2_MODE_TX_DISABLE|(uint8_t)UART2_MODE_RX_DISABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART2_MODE_TX_DISABLE|(uint8_t)UART2_MODE_RX_ENABLE)))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the WordLengths
*/
#define IS_UART2_WORDLENGTH_OK(WordLength) \
(((WordLength) == UART2_WORDLENGTH_8D) || \
((WordLength) == UART2_WORDLENGTH_9D))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the SyncModes; it should exclude values such
* as UART2_CLOCK_ENABLE|UART2_CLOCK_DISABLE
*/
#define IS_UART2_SYNCMODE_OK(SyncMode) \
(!((((SyncMode)&(((uint8_t)UART2_SYNCMODE_CLOCK_ENABLE)|((uint8_t)UART2_SYNCMODE_CLOCK_DISABLE))) == (((uint8_t)UART2_SYNCMODE_CLOCK_ENABLE)|((uint8_t)UART2_SYNCMODE_CLOCK_DISABLE))) || \
(((SyncMode)&(((uint8_t)UART2_SYNCMODE_CPOL_LOW )|((uint8_t)UART2_SYNCMODE_CPOL_HIGH))) == (((uint8_t)UART2_SYNCMODE_CPOL_LOW )|((uint8_t)UART2_SYNCMODE_CPOL_HIGH))) || \
(((SyncMode)&(((uint8_t)UART2_SYNCMODE_CPHA_MIDDLE)|((uint8_t)UART2_SYNCMODE_CPHA_BEGINING))) == (((uint8_t)UART2_SYNCMODE_CPHA_MIDDLE)|((uint8_t)UART2_SYNCMODE_CPHA_BEGINING))) || \
(((SyncMode)&(((uint8_t)UART2_SYNCMODE_LASTBIT_DISABLE)|((uint8_t)UART2_SYNCMODE_LASTBIT_ENABLE))) == (((uint8_t)UART2_SYNCMODE_LASTBIT_DISABLE)|((uint8_t)UART2_SYNCMODE_LASTBIT_ENABLE)))))
/**
* @brief Macro used by the assert_param function in order to check the
* different sensitivity values for the FLAGs
*/
#define IS_UART2_FLAG_OK(Flag) \
(((Flag) == UART2_FLAG_TXE) || \
((Flag) == UART2_FLAG_TC) || \
((Flag) == UART2_FLAG_RXNE) || \
((Flag) == UART2_FLAG_IDLE) || \
((Flag) == UART2_FLAG_OR_LHE) || \
((Flag) == UART2_FLAG_NF) || \
((Flag) == UART2_FLAG_FE) || \
((Flag) == UART2_FLAG_PE) || \
((Flag) == UART2_FLAG_SBK) || \
((Flag) == UART2_FLAG_LSF) || \
((Flag) == UART2_FLAG_LHDF) || \
((Flag) == UART2_FLAG_LBDF))
/**
* @brief Macro used by the assert_param function in order to check the
* different sensitivity values for the FLAGs that can be cleared by writing 0
*/
#define IS_UART2_CLEAR_FLAG_OK(Flag) \
(((Flag) == UART2_FLAG_RXNE) || \
((Flag) == UART2_FLAG_LHDF) || \
((Flag) == UART2_FLAG_LSF) || \
((Flag) == UART2_FLAG_LBDF))
/**
* @brief Macro used by the assert_param function in order to check
* the different sensitivity values for the Interrupts
*/
#define IS_UART2_CONFIG_IT_OK(Interrupt) \
(((Interrupt) == UART2_IT_PE) || \
((Interrupt) == UART2_IT_TXE) || \
((Interrupt) == UART2_IT_TC) || \
((Interrupt) == UART2_IT_RXNE_OR ) || \
((Interrupt) == UART2_IT_IDLE) || \
((Interrupt) == UART2_IT_LHDF) || \
((Interrupt) == UART2_IT_LBDF))
/**
* @brief Macro used by the assert function in order to check the different
* sensitivity values for the pending bit
*/
#define IS_UART2_GET_IT_OK(ITPendingBit) \
(((ITPendingBit) == UART2_IT_TXE) || \
((ITPendingBit) == UART2_IT_TC) || \
((ITPendingBit) == UART2_IT_RXNE) || \
((ITPendingBit) == UART2_IT_IDLE) || \
((ITPendingBit) == UART2_IT_OR) || \
((ITPendingBit) == UART2_IT_LBDF) || \
((ITPendingBit) == UART2_IT_LHDF) || \
((ITPendingBit) == UART2_IT_PE))
/**
* @brief Macro used by the assert function in order to check the different
* sensitivity values for the pending bit that can be cleared by writing 0
*/
#define IS_UART2_CLEAR_IT_OK(ITPendingBit) \
(((ITPendingBit) == UART2_IT_RXNE) || \
((ITPendingBit) == UART2_IT_LHDF) || \
((ITPendingBit) == UART2_IT_LBDF))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the IrDAModes
*/
#define IS_UART2_IRDAMODE_OK(IrDAMode) \
(((IrDAMode) == UART2_IRDAMODE_LOWPOWER) || \
((IrDAMode) == UART2_IRDAMODE_NORMAL))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the WakeUps
*/
#define IS_UART2_WAKEUP_OK(WakeUp) \
(((WakeUp) == UART2_WAKEUP_IDLELINE) || \
((WakeUp) == UART2_WAKEUP_ADDRESSMARK))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the LINBreakDetectionLengths
*/
#define IS_UART2_LINBREAKDETECTIONLENGTH_OK(LINBreakDetectionLength) \
(((LINBreakDetectionLength) == UART2_LINBREAKDETECTIONLENGTH_10BITS) || \
((LINBreakDetectionLength) == UART2_LINBREAKDETECTIONLENGTH_11BITS))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the UART2_StopBits
*/
#define IS_UART2_STOPBITS_OK(StopBit) (((StopBit) == UART2_STOPBITS_1) || \
((StopBit) == UART2_STOPBITS_0_5) || \
((StopBit) == UART2_STOPBITS_2) || \
((StopBit) == UART2_STOPBITS_1_5 ))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the Paritys
*/
#define IS_UART2_PARITY_OK(Parity) (((Parity) == UART2_PARITY_NO) || \
((Parity) == UART2_PARITY_EVEN) || \
((Parity) == UART2_PARITY_ODD ))
/**
* @brief Macro used by the assert_param function in order to check the maximum
* baudrate value
*/
#define IS_UART2_BAUDRATE_OK(NUM) ((NUM) <= (uint32_t)625000)
/**
* @brief Macro used by the assert_param function in order to check the address
* of the UART2 or UART node
*/
#define UART2_ADDRESS_MAX ((uint8_t)16)
#define IS_UART2_ADDRESS_OK(node) ((node) < UART2_ADDRESS_MAX )
/**
* @brief Macro used by the assert_param function in order to check the LIN mode
*/
#define IS_UART2_SLAVE_OK(Mode) \
(((Mode) == UART2_LIN_MODE_MASTER) || \
((Mode) == UART2_LIN_MODE_SLAVE))
/**
* @brief Macro used by the assert_param function in order to check the LIN
* automatic resynchronization mode
*/
#define IS_UART2_AUTOSYNC_OK(AutosyncMode) \
(((AutosyncMode) == UART2_LIN_AUTOSYNC_ENABLE) || \
((AutosyncMode) == UART2_LIN_AUTOSYNC_DISABLE))
/**
* @brief Macro used by the assert_param function in order to check the LIN divider update method
*/
#define IS_UART2_DIVUP_OK(DivupMethod) \
(((DivupMethod) == UART2_LIN_DIVUP_LBRR1) || \
((DivupMethod) == UART2_LIN_DIVUP_NEXTRXNE))
/**
* @}
*/
/* Exported functions ------------------------------------------------------- */
/** @addtogroup UART2_Exported_Functions
* @{
*/
void UART2_DeInit(void);
void UART2_Init(uint32_t BaudRate, UART2_WordLength_TypeDef WordLength,
UART2_StopBits_TypeDef StopBits, UART2_Parity_TypeDef Parity,
UART2_SyncMode_TypeDef SyncMode, UART2_Mode_TypeDef Mode);
void UART2_Cmd(FunctionalState NewState);
void UART2_ITConfig(UART2_IT_TypeDef UART2_IT, FunctionalState NewState);
void UART2_HalfDuplexCmd(FunctionalState NewState);
void UART2_IrDAConfig(UART2_IrDAMode_TypeDef UART2_IrDAMode);
void UART2_IrDACmd(FunctionalState NewState);
void UART2_LINBreakDetectionConfig(UART2_LINBreakDetectionLength_TypeDef UART2_LINBreakDetectionLength);
void UART2_LINConfig(UART2_LinMode_TypeDef UART2_Mode,
UART2_LinAutosync_TypeDef UART2_Autosync,
UART2_LinDivUp_TypeDef UART2_DivUp);
void UART2_LINCmd(FunctionalState NewState);
void UART2_SmartCardCmd(FunctionalState NewState);
void UART2_SmartCardNACKCmd(FunctionalState NewState);
void UART2_WakeUpConfig(UART2_WakeUp_TypeDef UART2_WakeUp);
void UART2_ReceiverWakeUpCmd(FunctionalState NewState);
uint8_t UART2_ReceiveData8(void);
uint16_t UART2_ReceiveData9(void);
void UART2_SendData8(uint8_t Data);
void UART2_SendData9(uint16_t Data);
void UART2_SendBreak(void);
void UART2_SetAddress(uint8_t UART2_Address);
void UART2_SetGuardTime(uint8_t UART2_GuardTime);
void UART2_SetPrescaler(uint8_t UART2_Prescaler);
FlagStatus UART2_GetFlagStatus(UART2_Flag_TypeDef UART2_FLAG);
void UART2_ClearFlag(UART2_Flag_TypeDef UART2_FLAG);
ITStatus UART2_GetITStatus(UART2_IT_TypeDef UART2_IT);
void UART2_ClearITPendingBit(UART2_IT_TypeDef UART2_IT);
/**
* @}
*/
#endif /* __STM8S_UART2_H */
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s_uart3.h
================================================
/**
********************************************************************************
* @file stm8s_uart3.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all functions prototypes and macros for the UART3 peripheral.
******************************************************************************
* @attention
*
*
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_UART3_H
#define __STM8S_UART3_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/** @addtogroup STM8S_StdPeriph_Driver
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @addtogroup UART3_Exported_Types
* @{
*/
/**
* @brief UART3 WakeUP Modes
*/
typedef enum { UART3_WAKEUP_IDLELINE = (uint8_t)0x00, /**< 0x01 Idle Line wake up*/
UART3_WAKEUP_ADDRESSMARK = (uint8_t)0x08 /**< 0x02 Address Mark wake up*/
} UART3_WakeUp_TypeDef;
/**
* @brief UART3 LIN Break detection length possible values
*/
typedef enum { UART3_LINBREAKDETECTIONLENGTH_10BITS = (uint8_t)0x00, /**< 10 bits Lin Break detection */
UART3_LINBREAKDETECTIONLENGTH_11BITS = (uint8_t)0x01 /**< 11 bits Lin Break detection */
} UART3_LINBreakDetectionLength_TypeDef;
/**
* @brief UART3 stop bits possible values
*/
typedef enum { UART3_STOPBITS_1 = (uint8_t)0x00, /**< One stop bit is transmitted at the end of frame*/
UART3_STOPBITS_2 = (uint8_t)0x20 /**< Two stop bits are transmitted at the end of frame*/
} UART3_StopBits_TypeDef;
/**
* @brief UART3 parity possible values
*/
typedef enum { UART3_PARITY_NO = (uint8_t)0x00, /**< No Parity*/
UART3_PARITY_EVEN = (uint8_t)0x04, /**< Even Parity*/
UART3_PARITY_ODD = (uint8_t)0x06 /**< Odd Parity*/
} UART3_Parity_TypeDef;
/**
* @brief UART3 Word length possible values
*/
typedef enum { UART3_WORDLENGTH_8D = (uint8_t)0x00, /**< 0x00 8 bits Data*/
UART3_WORDLENGTH_9D = (uint8_t)0x10 /**< 0x10 9 bits Data*/
} UART3_WordLength_TypeDef;
/**
* @brief UART3 Mode Transmit/Receive possible values
*/
typedef enum { UART3_MODE_RX_ENABLE = (uint8_t)0x08, /**< 0x08 Receive Enable*/
UART3_MODE_TX_ENABLE = (uint8_t)0x04, /**< 0x04 Transmit Enable*/
UART3_MODE_TX_DISABLE = (uint8_t)0x80, /**< 0x80 Receive Enable*/
UART3_MODE_RX_DISABLE = (uint8_t)0x40, /**< 0x40 Single-wire Half-duplex mode*/
UART3_MODE_TXRX_ENABLE = (uint8_t)0x0C /**< 0x0C Receive Enable and Transmit enable*/
} UART3_Mode_TypeDef;
/**
* @brief UART3 Mode possible values
*/
typedef enum { UART3_LIN_MODE_MASTER = (uint8_t)0x00, /**< LIN Master Mode*/
UART3_LIN_MODE_SLAVE = (uint8_t)0x01 /**< LIN Slave Mode*/
} UART3_LinMode_TypeDef;
/**
* @brief UART3 automatic resynchronisation possible values
*/
typedef enum { UART3_LIN_AUTOSYNC_DISABLE = (uint8_t)0x00, /**< LIN Autosynchronization Disable*/
UART3_LIN_AUTOSYNC_ENABLE = (uint8_t)0x01 /**< LIN Autosynchronization Enable*/
} UART3_LinAutosync_TypeDef;
/**
* @brief UART3 Divider Update Method possible values
*/
typedef enum { UART3_LIN_DIVUP_LBRR1 = (uint8_t)0x00, /**< LIN LDIV is updated as soon as LBRR1 is written*/
UART3_LIN_DIVUP_NEXTRXNE = (uint8_t)0x01 /**< LIN LDIV is updated at the next received character*/
} UART3_LinDivUp_TypeDef;
/**
* @brief UART3 Flag possible values
*/
typedef enum
{
UART3_FLAG_TXE = (uint16_t)0x0080, /*!< Transmit Data Register Empty flag */
UART3_FLAG_TC = (uint16_t)0x0040, /*!< Transmission Complete flag */
UART3_FLAG_RXNE = (uint16_t)0x0020, /*!< Read Data Register Not Empty flag */
UART3_FLAG_IDLE = (uint16_t)0x0010, /*!< Idle line detected flag */
UART3_FLAG_OR_LHE = (uint16_t)0x0008, /*!< OverRun error flag */
UART3_FLAG_NF = (uint16_t)0x0004, /*!< Noise error flag */
UART3_FLAG_FE = (uint16_t)0x0002, /*!< Framing Error flag */
UART3_FLAG_PE = (uint16_t)0x0001, /*!< Parity Error flag */
UART3_FLAG_SBK = (uint16_t)0x0101, /**< Send Break Complete interrupt flag */
UART3_FLAG_LBDF = (uint16_t)0x0210, /**< LIN Break Detection Flag */
UART3_FLAG_LHDF = (uint16_t)0x0302, /**< LIN Header Detection Flag*/
UART3_FLAG_LSF = (uint16_t)0x0301 /**< LIN Sync Field Flag*/
} UART3_Flag_TypeDef;
/**
* @brief UART3 Interrupt definition
* UART3_IT possible values
* Elements values convention: 0xZYX
* X: Position of the corresponding Interrupt
* - For the following values, X means the interrupt position in the CR2 register.
* UART3_IT_TXE
* UART3_IT_TC
* UART3_IT_RXNE
* UART3_IT_IDLE
* UART3_IT_OR
* - For the UART3_IT_PE value, X means the flag position in the CR1 register.
* - For the UART3_IT_LBDF value, X means the flag position in the CR4 register.
* - For the UART3_IT_LHDF value, X means the flag position in the CR6 register.
* Y: Flag position
* - For the following values, Y means the flag (pending bit) position in the SR register.
* UART3_IT_TXE
* UART3_IT_TC
* UART3_IT_RXNE
* UART3_IT_IDLE
* UART3_IT_OR
* UART3_IT_PE
* - For the UART3_IT_LBDF value, Y means the flag position in the CR4 register.
* - For the UART3_IT_LHDF value, Y means the flag position in the CR6 register.
* Z: Register index: indicate in which register the dedicated interrupt source is:
* - 1==> CR1 register
* - 2==> CR2 register
* - 3==> CR4 register
* - 4==> CR6 register
*/
typedef enum { UART3_IT_TXE = (uint16_t)0x0277, /**< Transmit interrupt */
UART3_IT_TC = (uint16_t)0x0266, /**< Transmission Complete interrupt */
UART3_IT_RXNE = (uint16_t)0x0255, /**< Data Register Not Empty interrupt */
UART3_IT_IDLE = (uint16_t)0x0244, /**< Idle line detected interrupt */
UART3_IT_OR = (uint16_t)0x0235, /**< OverRun error interrupt */
UART3_IT_PE = (uint16_t)0x0100, /**< Parity Error interrupt */
UART3_IT_LBDF = (uint16_t)0x0346, /**< LIN Break Detection interrupt */
UART3_IT_LHDF = (uint16_t)0x0412, /**< LIN Header Detection interrupt*/
UART3_IT_RXNE_OR = (uint16_t)0x0205 /*!< Receive/Overrun interrupt */
} UART3_IT_TypeDef;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/* Exported macros ------------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup UART3_Private_Macros
* @{
*/
/**
* @brief Macro used by the assert_param function in order to check the
* different sensitivity values for the FLAGs
*/
#define IS_UART3_FLAG_OK(Flag) \
(((Flag) == UART3_FLAG_TXE) || \
((Flag) == UART3_FLAG_TC) || \
((Flag) == UART3_FLAG_RXNE) || \
((Flag) == UART3_FLAG_IDLE) || \
((Flag) == UART3_FLAG_OR_LHE) || \
((Flag) == UART3_FLAG_NF) || \
((Flag) == UART3_FLAG_FE) || \
((Flag) == UART3_FLAG_PE) || \
((Flag) == UART3_FLAG_SBK) || \
((Flag) == UART3_FLAG_LSF) || \
((Flag) == UART3_FLAG_LHDF) || \
((Flag) == UART3_FLAG_LBDF))
/**
* @brief Macro used by the assert_param function in order to check the
* different sensitivity values for the FLAGs that can be cleared by writing 0
*/
#define IS_UART3_CLEAR_FLAG_OK(Flag) \
(((Flag) == UART3_FLAG_RXNE) || \
((Flag) == UART3_FLAG_LHDF) || \
((Flag) == UART3_FLAG_LSF) || \
((Flag) == UART3_FLAG_LBDF))
/**
* @brief Macro used by the assert_param function in order to check the
* different sensitivity values for the Interrupts
*/
#define IS_UART3_CONFIG_IT_OK(Interrupt) \
(((Interrupt) == UART3_IT_PE) || \
((Interrupt) == UART3_IT_TXE) || \
((Interrupt) == UART3_IT_TC) || \
((Interrupt) == UART3_IT_RXNE_OR ) || \
((Interrupt) == UART3_IT_IDLE) || \
((Interrupt) == UART3_IT_LHDF) || \
((Interrupt) == UART3_IT_LBDF))
/**
* @brief Macro used by the assert function in order to check the different
* sensitivity values for the pending bit
*/
#define IS_UART3_GET_IT_OK(ITPendingBit) \
(((ITPendingBit) == UART3_IT_TXE) || \
((ITPendingBit) == UART3_IT_TC) || \
((ITPendingBit) == UART3_IT_RXNE) || \
((ITPendingBit) == UART3_IT_IDLE) || \
((ITPendingBit) == UART3_IT_OR) || \
((ITPendingBit) == UART3_IT_LBDF) || \
((ITPendingBit) == UART3_IT_LHDF) || \
((ITPendingBit) == UART3_IT_PE))
/**
* @brief Macro used by the assert function in order to check the different
* sensitivity values for the pending bit that can be cleared by writing 0
*/
#define IS_UART3_CLEAR_IT_OK(ITPendingBit) \
(((ITPendingBit) == UART3_IT_RXNE) || \
((ITPendingBit) == UART3_IT_LHDF) || \
((ITPendingBit) == UART3_IT_LBDF))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the MODEs
*/
#define IS_UART3_MODE_OK(Mode) \
(((Mode) == (uint8_t)UART3_MODE_RX_ENABLE) || \
((Mode) == (uint8_t)UART3_MODE_RX_DISABLE) || \
((Mode) == (uint8_t)UART3_MODE_TX_ENABLE) || \
((Mode) == (uint8_t)UART3_MODE_TX_DISABLE) || \
((Mode) == (uint8_t)UART3_MODE_TXRX_ENABLE) || \
((Mode) == (uint8_t)((uint8_t)UART3_MODE_TX_ENABLE|(uint8_t)UART3_MODE_RX_ENABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART3_MODE_TX_ENABLE|(uint8_t)UART3_MODE_RX_DISABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART3_MODE_TX_DISABLE|(uint8_t)UART3_MODE_RX_DISABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART3_MODE_TX_DISABLE|(uint8_t)UART3_MODE_RX_ENABLE)))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the WordLengths
*/
#define IS_UART3_WORDLENGTH_OK(WordLength) \
(((WordLength) == UART3_WORDLENGTH_8D) || \
((WordLength) == UART3_WORDLENGTH_9D))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the WakeUps
*/
#define IS_UART3_WAKEUP_OK(WakeUpMode) \
(((WakeUpMode) == UART3_WAKEUP_IDLELINE) || \
((WakeUpMode) == UART3_WAKEUP_ADDRESSMARK))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the LINBreakDetectionLengths
*/
#define IS_UART3_LINBREAKDETECTIONLENGTH_OK(LINBreakDetectionLengths) \
(((LINBreakDetectionLengths) == UART3_LINBREAKDETECTIONLENGTH_10BITS) || \
((LINBreakDetectionLengths) == UART3_LINBREAKDETECTIONLENGTH_11BITS))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the UART3_StopBits
*/
#define IS_UART3_STOPBITS_OK(StopBit) \
(((StopBit) == UART3_STOPBITS_1) || \
((StopBit) == UART3_STOPBITS_2))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the Parity
*/
#define IS_UART3_PARITY_OK(Parity) \
(((Parity) == UART3_PARITY_NO) || \
((Parity) == UART3_PARITY_EVEN) || \
((Parity) == UART3_PARITY_ODD ))
/**
* @brief Macro used by the assert_param function in order to check the maximum
* baudrate value
*/
#define IS_UART3_BAUDRATE_OK(NUM) ((NUM) <= (uint32_t)625000)
/**
* @brief Macro used by the assert_param function in order to check the address
* of the UART3 or UART node
*/
#define UART3_ADDRESS_MAX ((uint8_t)16)
#define IS_UART3_ADDRESS_OK(Node) ((Node) < UART3_ADDRESS_MAX)
/**
* @brief Macro used by the assert_param function in order to check the LIN mode
*/
#define IS_UART3_SLAVE_OK(Mode) \
(((Mode) == UART3_LIN_MODE_MASTER) || \
((Mode) == UART3_LIN_MODE_SLAVE))
/**
* @brief Macro used by the assert_param function in order to check the LIN
* automatic resynchronization mode
*/
#define IS_UART3_AUTOSYNC_OK(AutosyncMode) \
(((AutosyncMode) == UART3_LIN_AUTOSYNC_ENABLE) || \
((AutosyncMode) == UART3_LIN_AUTOSYNC_DISABLE))
/**
* @brief Macro used by the assert_param function in order to check the LIN
* divider update method
*/
#define IS_UART3_DIVUP_OK(DivupMethod) \
(((DivupMethod) == UART3_LIN_DIVUP_LBRR1) || \
((DivupMethod) == UART3_LIN_DIVUP_NEXTRXNE))
/**
* @}
*/
/* Exported functions ------------------------------------------------------- */
/** @addtogroup UART3_Exported_Functions
* @{
*/
void UART3_DeInit(void);
void UART3_Init(uint32_t BaudRate, UART3_WordLength_TypeDef WordLength,
UART3_StopBits_TypeDef StopBits, UART3_Parity_TypeDef Parity,
UART3_Mode_TypeDef Mode);
void UART3_Cmd(FunctionalState NewState);
void UART3_ITConfig(UART3_IT_TypeDef UART3_IT, FunctionalState NewState);
void UART3_LINBreakDetectionConfig(UART3_LINBreakDetectionLength_TypeDef UART3_LINBreakDetectionLength);
void UART3_LINConfig(UART3_LinMode_TypeDef UART3_Mode,
UART3_LinAutosync_TypeDef UART3_Autosync,
UART3_LinDivUp_TypeDef UART3_DivUp);
void UART3_LINCmd(FunctionalState NewState);
void UART3_ReceiverWakeUpCmd(FunctionalState NewState);
void UART3_WakeUpConfig( UART3_WakeUp_TypeDef UART3_WakeUp);
uint8_t UART3_ReceiveData8(void);
uint16_t UART3_ReceiveData9(void);
void UART3_SendData8(uint8_t Data);
void UART3_SendData9(uint16_t Data);
void UART3_SendBreak(void);
void UART3_SetAddress(uint8_t UART3_Address);
FlagStatus UART3_GetFlagStatus(UART3_Flag_TypeDef UART3_FLAG);
void UART3_ClearFlag(UART3_Flag_TypeDef UART3_FLAG);
ITStatus UART3_GetITStatus(UART3_IT_TypeDef UART3_IT);
void UART3_ClearITPendingBit(UART3_IT_TypeDef UART3_IT);
/**
* @}
*/
#endif /* __STM8S_UART3_H */
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s_uart4.h
================================================
/**
********************************************************************************
* @file stm8s_uart4.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all functions prototypes and macros for the UART4 peripheral.
******************************************************************************
* @attention
*
*
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM8S_UART4_H
#define __STM8S_UART4_H
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
/** @addtogroup STM8S_StdPeriph_Driver
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @addtogroup UART4_Exported_Types
* @{
*/
/**
* @brief UART4 Irda Modes
*/
typedef enum { UART4_IRDAMODE_NORMAL = (uint8_t)0x00, /**< 0x00 Irda Normal Mode */
UART4_IRDAMODE_LOWPOWER = (uint8_t)0x01 /**< 0x01 Irda Low Power Mode */
} UART4_IrDAMode_TypeDef;
/**
* @brief UART4 WakeUP Modes
*/
typedef enum { UART4_WAKEUP_IDLELINE = (uint8_t)0x00, /**< 0x01 Idle Line wake up */
UART4_WAKEUP_ADDRESSMARK = (uint8_t)0x08 /**< 0x02 Address Mark wake up */
} UART4_WakeUp_TypeDef;
/**
* @brief UART4 LIN Break detection length possible values
*/
typedef enum { UART4_LINBREAKDETECTIONLENGTH_10BITS = (uint8_t)0x00, /**< 0x01 10 bits Lin Break detection */
UART4_LINBREAKDETECTIONLENGTH_11BITS = (uint8_t)0x01 /**< 0x02 11 bits Lin Break detection */
} UART4_LINBreakDetectionLength_TypeDef;
/**
* @brief UART4 stop bits possible values
*/
typedef enum { UART4_STOPBITS_1 = (uint8_t)0x00, /**< One stop bit is transmitted at the end of frame*/
UART4_STOPBITS_0_5 = (uint8_t)0x10, /**< Half stop bits is transmitted at the end of frame*/
UART4_STOPBITS_2 = (uint8_t)0x20, /**< Two stop bits are transmitted at the end of frame*/
UART4_STOPBITS_1_5 = (uint8_t)0x30 /**< One and half stop bits*/
} UART4_StopBits_TypeDef;
/**
* @brief UART4 parity possible values
*/
typedef enum { UART4_PARITY_NO = (uint8_t)0x00, /**< No Parity*/
UART4_PARITY_EVEN = (uint8_t)0x04, /**< Even Parity*/
UART4_PARITY_ODD = (uint8_t)0x06 /**< Odd Parity*/
} UART4_Parity_TypeDef;
/**
* @brief UART4 Mode possible values
*/
typedef enum { UART4_LIN_MODE_MASTER = (uint8_t)0x00, /**< LIN Master Mode*/
UART4_LIN_MODE_SLAVE = (uint8_t)0x01 /**< LIN Slave Mode*/
} UART4_LinMode_TypeDef;
/**
* @brief UART4 automatic resynchronisation possible values
*/
typedef enum { UART4_LIN_AUTOSYNC_DISABLE = (uint8_t)0x00, /**< LIN Autosynchronization Disable*/
UART4_LIN_AUTOSYNC_ENABLE = (uint8_t)0x01 /**< LIN Autosynchronization Enable*/
} UART4_LinAutosync_TypeDef;
/**
* @brief UART4 Divider Update Method possible values
*/
typedef enum { UART4_LIN_DIVUP_LBRR1 = (uint8_t)0x00, /**< LIN LDIV is updated as soon as LBRR1 is written*/
UART4_LIN_DIVUP_NEXTRXNE = (uint8_t)0x01 /**< LIN LDIV is updated at the next received character*/
} UART4_LinDivUp_TypeDef;
/**
* @brief UART4 Synchrone modes
*/
typedef enum { UART4_SYNCMODE_CLOCK_DISABLE = (uint8_t)0x80, /**< 0x80 Sync mode Disable, SLK pin Disable */
UART4_SYNCMODE_CLOCK_ENABLE = (uint8_t)0x08, /**< 0x08 Sync mode Enable, SLK pin Enable */
UART4_SYNCMODE_CPOL_LOW = (uint8_t)0x40, /**< 0x40 Steady low value on SCLK pin outside transmission window */
UART4_SYNCMODE_CPOL_HIGH = (uint8_t)0x04, /**< 0x04 Steady high value on SCLK pin outside transmission window */
UART4_SYNCMODE_CPHA_MIDDLE = (uint8_t)0x20, /**< 0x20 SCLK clock line activated in middle of data bit */
UART4_SYNCMODE_CPHA_BEGINING = (uint8_t)0x02, /**< 0x02 SCLK clock line activated at beginning of data bit */
UART4_SYNCMODE_LASTBIT_DISABLE = (uint8_t)0x10, /**< 0x10 The clock pulse of the last data bit is not output to the SCLK pin */
UART4_SYNCMODE_LASTBIT_ENABLE = (uint8_t)0x01 /**< 0x01 The clock pulse of the last data bit is output to the SCLK pin */
} UART4_SyncMode_TypeDef;
/**
* @brief UART4 Word length possible values
*/
typedef enum { UART4_WORDLENGTH_8D = (uint8_t)0x00,/**< 0x00 8 bits Data */
UART4_WORDLENGTH_9D = (uint8_t)0x10 /**< 0x10 9 bits Data */
} UART4_WordLength_TypeDef;
/**
* @brief UART4 Mode possible values
*/
typedef enum { UART4_MODE_RX_ENABLE = (uint8_t)0x08, /**< 0x08 Receive Enable */
UART4_MODE_TX_ENABLE = (uint8_t)0x04, /**< 0x04 Transmit Enable */
UART4_MODE_TX_DISABLE = (uint8_t)0x80, /**< 0x80 Transmit Disable */
UART4_MODE_RX_DISABLE = (uint8_t)0x40, /**< 0x40 Single-wire Half-duplex mode */
UART4_MODE_TXRX_ENABLE = (uint8_t)0x0C /**< 0x0C Transmit Enable and Receive Enable */
} UART4_Mode_TypeDef;
/**
* @brief UART4 Flag possible values
*/
typedef enum
{
UART4_FLAG_TXE = (uint16_t)0x0080, /*!< Transmit Data Register Empty flag */
UART4_FLAG_TC = (uint16_t)0x0040, /*!< Transmission Complete flag */
UART4_FLAG_RXNE = (uint16_t)0x0020, /*!< Read Data Register Not Empty flag */
UART4_FLAG_IDLE = (uint16_t)0x0010, /*!< Idle line detected flag */
UART4_FLAG_OR_LHE = (uint16_t)0x0008, /*!< OverRun error flag */
UART4_FLAG_NF = (uint16_t)0x0004, /*!< Noise error flag */
UART4_FLAG_FE = (uint16_t)0x0002, /*!< Framing Error flag */
UART4_FLAG_PE = (uint16_t)0x0001, /*!< Parity Error flag */
UART4_FLAG_SBK = (uint16_t)0x0101, /**< Send Break Complete interrupt flag */
UART4_FLAG_LBDF = (uint16_t)0x0210, /**< LIN Break Detection Flag */
UART4_FLAG_LHDF = (uint16_t)0x0302, /**< LIN Header Detection Flag*/
UART4_FLAG_LSF = (uint16_t)0x0301 /**< LIN Sync Field Flag*/
} UART4_Flag_TypeDef;
/**
* @brief UART4 Interrupt definition
* UART4_IT possible values
* Elements values convention: 0xZYX
* X: Position of the corresponding Interrupt
* - For the following values, X means the interrupt position in the CR2 register.
* UART4_IT_TXE
* UART4_IT_TC
* UART4_IT_RXNE
* UART4_IT_IDLE
* UART4_IT_OR
* - For the UART4_IT_PE value, X means the flag position in the CR1 register.
* - For the UART4_IT_LBDF value, X means the flag position in the CR4 register.
* - For the UART4_IT_LHDF value, X means the flag position in the CR6 register.
* Y: Flag position
* - For the following values, Y means the flag (pending bit) position in the SR register.
* UART4_IT_TXE
* UART4_IT_TC
* UART4_IT_RXNE
* UART4_IT_IDLE
* UART4_IT_OR
* UART4_IT_PE
* - For the UART4_IT_LBDF value, Y means the flag position in the CR4 register.
* - For the UART4_IT_LHDF value, Y means the flag position in the CR6 register.
* Z: Register index: indicate in which register the dedicated interrupt source is:
* - 1==> CR1 register
* - 2==> CR2 register
* - 3==> CR4 register
* - 4==> CR6 register
*/
typedef enum { UART4_IT_TXE = (uint16_t)0x0277, /**< Transmit interrupt */
UART4_IT_TC = (uint16_t)0x0266, /**< Transmission Complete interrupt */
UART4_IT_RXNE = (uint16_t)0x0255, /**< Data Register Not Empty interrupt */
UART4_IT_IDLE = (uint16_t)0x0244, /**< Idle line detected interrupt */
UART4_IT_OR = (uint16_t)0x0235, /**< OverRun error interrupt */
UART4_IT_PE = (uint16_t)0x0100, /**< Parity Error interrupt */
UART4_IT_LBDF = (uint16_t)0x0346, /**< LIN Break Detection interrupt */
UART4_IT_LHDF = (uint16_t)0x0412, /**< LIN Header Detection interrupt*/
UART4_IT_RXNE_OR = (uint16_t)0x0205 /*!< Receive/Overrun interrupt */
} UART4_IT_TypeDef;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/** @addtogroup UART4_Private_Macros
* @{
*/
/**
* @brief Macro used by the assert function to check the different functions parameters.
*/
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the MODEs possible combination should be one of
* the following.
*/
#define IS_UART4_MODE_OK(Mode) \
(((Mode) == (uint8_t)UART4_MODE_RX_ENABLE) || \
((Mode) == (uint8_t)UART4_MODE_RX_DISABLE) || \
((Mode) == (uint8_t)UART4_MODE_TX_ENABLE) || \
((Mode) == (uint8_t)UART4_MODE_TX_DISABLE) || \
((Mode) == (uint8_t)UART4_MODE_TXRX_ENABLE) || \
((Mode) == (uint8_t)((uint8_t)UART4_MODE_TX_ENABLE|(uint8_t)UART4_MODE_RX_ENABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART4_MODE_TX_ENABLE|(uint8_t)UART4_MODE_RX_DISABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART4_MODE_TX_DISABLE|(uint8_t)UART4_MODE_RX_DISABLE)) || \
((Mode) == (uint8_t)((uint8_t)UART4_MODE_TX_DISABLE|(uint8_t)UART4_MODE_RX_ENABLE)))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the WordLengths
*/
#define IS_UART4_WORDLENGTH_OK(WordLength) \
(((WordLength) == UART4_WORDLENGTH_8D) || \
((WordLength) == UART4_WORDLENGTH_9D))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the SyncModes; it should exclude values such
* as UART4_CLOCK_ENABLE|UART4_CLOCK_DISABLE
*/
#define IS_UART4_SYNCMODE_OK(SyncMode) \
(!((((SyncMode)&(((uint8_t)UART4_SYNCMODE_CLOCK_ENABLE)|((uint8_t)UART4_SYNCMODE_CLOCK_DISABLE))) == (((uint8_t)UART4_SYNCMODE_CLOCK_ENABLE)|((uint8_t)UART4_SYNCMODE_CLOCK_DISABLE))) || \
(((SyncMode)&(((uint8_t)UART4_SYNCMODE_CPOL_LOW )|((uint8_t)UART4_SYNCMODE_CPOL_HIGH))) == (((uint8_t)UART4_SYNCMODE_CPOL_LOW )|((uint8_t)UART4_SYNCMODE_CPOL_HIGH))) || \
(((SyncMode)&(((uint8_t)UART4_SYNCMODE_CPHA_MIDDLE)|((uint8_t)UART4_SYNCMODE_CPHA_BEGINING))) == (((uint8_t)UART4_SYNCMODE_CPHA_MIDDLE)|((uint8_t)UART4_SYNCMODE_CPHA_BEGINING))) || \
(((SyncMode)&(((uint8_t)UART4_SYNCMODE_LASTBIT_DISABLE)|((uint8_t)UART4_SYNCMODE_LASTBIT_ENABLE))) == (((uint8_t)UART4_SYNCMODE_LASTBIT_DISABLE)|((uint8_t)UART4_SYNCMODE_LASTBIT_ENABLE)))))
/**
* @brief Macro used by the assert_param function in order to check the
* different sensitivity values for the FLAGs
*/
#define IS_UART4_FLAG_OK(Flag) \
(((Flag) == UART4_FLAG_TXE) || \
((Flag) == UART4_FLAG_TC) || \
((Flag) == UART4_FLAG_RXNE) || \
((Flag) == UART4_FLAG_IDLE) || \
((Flag) == UART4_FLAG_OR_LHE) || \
((Flag) == UART4_FLAG_NF) || \
((Flag) == UART4_FLAG_FE) || \
((Flag) == UART4_FLAG_PE) || \
((Flag) == UART4_FLAG_SBK) || \
((Flag) == UART4_FLAG_LSF) || \
((Flag) == UART4_FLAG_LHDF) || \
((Flag) == UART4_FLAG_LBDF))
/**
* @brief Macro used by the assert_param function in order to check the
* different sensitivity values for the FLAGs that can be cleared by writing 0
*/
#define IS_UART4_CLEAR_FLAG_OK(Flag) \
(((Flag) == UART4_FLAG_RXNE) || \
((Flag) == UART4_FLAG_LHDF) || \
((Flag) == UART4_FLAG_LSF) || \
((Flag) == UART4_FLAG_LBDF))
/**
* @brief Macro used by the assert_param function in order to check
* the different sensitivity values for the Interrupts
*/
#define IS_UART4_CONFIG_IT_OK(Interrupt) \
(((Interrupt) == UART4_IT_PE) || \
((Interrupt) == UART4_IT_TXE) || \
((Interrupt) == UART4_IT_TC) || \
((Interrupt) == UART4_IT_RXNE_OR ) || \
((Interrupt) == UART4_IT_IDLE) || \
((Interrupt) == UART4_IT_LHDF) || \
((Interrupt) == UART4_IT_LBDF))
/**
* @brief Macro used by the assert function in order to check the different
* sensitivity values for the pending bit
*/
#define IS_UART4_GET_IT_OK(ITPendingBit) \
(((ITPendingBit) == UART4_IT_TXE) || \
((ITPendingBit) == UART4_IT_TC) || \
((ITPendingBit) == UART4_IT_RXNE) || \
((ITPendingBit) == UART4_IT_IDLE) || \
((ITPendingBit) == UART4_IT_OR) || \
((ITPendingBit) == UART4_IT_LBDF) || \
((ITPendingBit) == UART4_IT_LHDF) || \
((ITPendingBit) == UART4_IT_PE))
/**
* @brief Macro used by the assert function in order to check the different
* sensitivity values for the pending bit that can be cleared by writing 0
*/
#define IS_UART4_CLEAR_IT_OK(ITPendingBit) \
(((ITPendingBit) == UART4_IT_RXNE) || \
((ITPendingBit) == UART4_IT_LHDF) || \
((ITPendingBit) == UART4_IT_LBDF))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the IrDAModes
*/
#define IS_UART4_IRDAMODE_OK(IrDAMode) \
(((IrDAMode) == UART4_IRDAMODE_LOWPOWER) || \
((IrDAMode) == UART4_IRDAMODE_NORMAL))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the WakeUps
*/
#define IS_UART4_WAKEUP_OK(WakeUp) \
(((WakeUp) == UART4_WAKEUP_IDLELINE) || \
((WakeUp) == UART4_WAKEUP_ADDRESSMARK))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the LINBreakDetectionLengths
*/
#define IS_UART4_LINBREAKDETECTIONLENGTH_OK(LINBreakDetectionLength) \
(((LINBreakDetectionLength) == UART4_LINBREAKDETECTIONLENGTH_10BITS) || \
((LINBreakDetectionLength) == UART4_LINBREAKDETECTIONLENGTH_11BITS))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the UART4_StopBits
*/
#define IS_UART4_STOPBITS_OK(StopBit) (((StopBit) == UART4_STOPBITS_1) || \
((StopBit) == UART4_STOPBITS_0_5) || \
((StopBit) == UART4_STOPBITS_2) || \
((StopBit) == UART4_STOPBITS_1_5 ))
/**
* @brief Macro used by the assert_param function in order to check the different
* sensitivity values for the Paritys
*/
#define IS_UART4_PARITY_OK(Parity) (((Parity) == UART4_PARITY_NO) || \
((Parity) == UART4_PARITY_EVEN) || \
((Parity) == UART4_PARITY_ODD ))
/**
* @brief Macro used by the assert_param function in order to check the maximum
* baudrate value
*/
#define IS_UART4_BAUDRATE_OK(NUM) ((NUM) <= (uint32_t)625000)
/**
* @brief Macro used by the assert_param function in order to check the address
* of the UART4 or UART node
*/
#define UART4_ADDRESS_MAX ((uint8_t)16)
#define IS_UART4_ADDRESS_OK(node) ((node) < UART4_ADDRESS_MAX )
/**
* @brief Macro used by the assert_param function in order to check the LIN mode
*/
#define IS_UART4_SLAVE_OK(Mode) \
(((Mode) == UART4_LIN_MODE_MASTER) || \
((Mode) == UART4_LIN_MODE_SLAVE))
/**
* @brief Macro used by the assert_param function in order to check the LIN
* automatic resynchronization mode
*/
#define IS_UART4_AUTOSYNC_OK(AutosyncMode) \
(((AutosyncMode) == UART4_LIN_AUTOSYNC_ENABLE) || \
((AutosyncMode) == UART4_LIN_AUTOSYNC_DISABLE))
/**
* @brief Macro used by the assert_param function in order to check the LIN divider update method
*/
#define IS_UART4_DIVUP_OK(DivupMethod) \
(((DivupMethod) == UART4_LIN_DIVUP_LBRR1) || \
((DivupMethod) == UART4_LIN_DIVUP_NEXTRXNE))
/**
* @}
*/
/* Exported functions ------------------------------------------------------- */
/** @addtogroup UART4_Exported_Functions
* @{
*/
void UART4_DeInit(void);
void UART4_Init(uint32_t BaudRate, UART4_WordLength_TypeDef WordLength,
UART4_StopBits_TypeDef StopBits, UART4_Parity_TypeDef Parity,
UART4_SyncMode_TypeDef SyncMode, UART4_Mode_TypeDef Mode);
void UART4_Cmd(FunctionalState NewState);
void UART4_ITConfig(UART4_IT_TypeDef UART4_IT, FunctionalState NewState);
void UART4_HalfDuplexCmd(FunctionalState NewState);
void UART4_IrDAConfig(UART4_IrDAMode_TypeDef UART4_IrDAMode);
void UART4_IrDACmd(FunctionalState NewState);
void UART4_LINBreakDetectionConfig(UART4_LINBreakDetectionLength_TypeDef UART4_LINBreakDetectionLength);
void UART4_LINConfig(UART4_LinMode_TypeDef UART4_Mode,
UART4_LinAutosync_TypeDef UART4_Autosync,
UART4_LinDivUp_TypeDef UART4_DivUp);
void UART4_LINCmd(FunctionalState NewState);
void UART4_SmartCardCmd(FunctionalState NewState);
void UART4_SmartCardNACKCmd(FunctionalState NewState);
void UART4_WakeUpConfig(UART4_WakeUp_TypeDef UART4_WakeUp);
void UART4_ReceiverWakeUpCmd(FunctionalState NewState);
uint8_t UART4_ReceiveData8(void);
uint16_t UART4_ReceiveData9(void);
void UART4_SendData8(uint8_t Data);
void UART4_SendData9(uint16_t Data);
void UART4_SendBreak(void);
void UART4_SetAddress(uint8_t UART4_Address);
void UART4_SetGuardTime(uint8_t UART4_GuardTime);
void UART4_SetPrescaler(uint8_t UART4_Prescaler);
FlagStatus UART4_GetFlagStatus(UART4_Flag_TypeDef UART4_FLAG);
void UART4_ClearFlag(UART4_Flag_TypeDef UART4_FLAG);
ITStatus UART4_GetITStatus(UART4_IT_TypeDef UART4_IT);
void UART4_ClearITPendingBit(UART4_IT_TypeDef UART4_IT);
/**
* @}
*/
#endif /* __STM8S_UART4_H */
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
================================================
FILE: src/firmware/tsdz2/stm8s/stm8s_wwdg.h
================================================
/**
********************************************************************************
* @file stm8s_wwdg.h
* @author MCD Application Team
* @version V2.3.0
* @date 16-June-2017
* @brief This file contains all functions prototype and macros for the WWDG peripheral.
******************************************************************************
* @attention
*
*