添加一些关于midi播放的项目

This commit is contained in:
terryLP
2025-03-24 14:30:56 +08:00
parent e31eb22077
commit 498b4ef13b
699 changed files with 186162 additions and 1 deletions
@@ -0,0 +1,11 @@
lemcu.org GPL Exception version 1.0
-----------------------------------
As an additional permission, if Lemcusb library is statically linked with one or more of the following
software libraries, then, these software libraries are not subjected to the TERMS AND CONDITIONS of
GNU General Public License version 3.0.
(1) Silicon Laboratories Inc's "emlib", "emdrv", any software supplied as part of application note and/or examples.
(2) ARM Limited's "CMSIS".
They are bound by their own terms and conditions as specified by their authors.
@@ -0,0 +1,681 @@
The Lemcusb is Copyright (C) 2014 http://lemcu.org
You may use, distribute and copy the Lemcusb under the terms of
GNU General Public License version 3.0, which is displayed below.
-------------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 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 <http://www.gnu.org/licenses/>.
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:
<program> Copyright (C) <year> <name of author>
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
<http://www.gnu.org/licenses/>.
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
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
@@ -0,0 +1,35 @@
/****************************************************************************
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef __C_COMPAT_H__
#define __C_COMPAT_H__
#if defined ( __ICCARM__ )
#define RAMFUNC __ramfunc
#else
#define RAMFUNC __attribute__((__long_call__)) __attribute__((section(".functioninRAM"))) __attribute__ ((noinline))
#endif
#endif
@@ -0,0 +1,381 @@
/****************************************************************************
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "usb.h"
//#include "em_device.h"
//#include "em_cmu.h"
//#include "em_int.h"
//#include "em_timer.h"
#include "gpio.h"
#include "usb_internal_ll.h"
#include "usb_stack.h"
#include "usb_helperfunctions.h"
void usb_reset_received(void)
{
uint32_t cnt;
uint32_t *ptr;
GPIOA->PSOR = (1<<1);
/* zero intitialize endpoint buffers and len/status fields */
ptr = (uint32_t *)usb_ep_buffers;
for (cnt=0; cnt < (sizeof(usb_ep_buffers)>>2); cnt++)
{
*ptr++ = 0;
}
/* preinitialize DATA PIDS for IN endpoints */
usb_ep_buffers[USB_EPBUF_OFFSET_EP0IN_BUF] = 0x4B;
usb_ep_buffers[USB_EPBUF_OFFSET_EP1IN_BUF] = 0x4B;
/* reset usb device address to 0 (will be changed during enumeration) */
usbstack_init();
GPIOA->PSOR = (1<<1);
}
/*
* Pinout information:
* PA2 = D-
* PA3 = D+
* PA1 = debug output (to scope)
*/
/*
* Pre-condition: GPIO clock enabled
*
*/
void usb_init(void)
{
usb_reset_received();
/* Pinout: PA1 = USB connect line (1k5 resistor to PC0)
PA2 = D-
PA3 = D+
*/
/* set PA0 low (disconnected) Will enable the pulldown */
GPIOA->PCOR = (1 << 2);
/* Pin PA0 is configured to Input enabled with pull-down */
//GPIO->P[0].MODEL = (GPIO->P[0].MODEL & ~_GPIO_P_MODEL_MODE0_MASK) | GPIO_P_MODEL_MODE0_INPUTPULL;
/* Pin PC0 is configured to Input enabled */
//GPIO->P[2].MODEL = (GPIO->P[2].MODEL & ~_GPIO_P_MODEL_MODE0_MASK) | GPIO_P_MODEL_MODE0_INPUT;
/* Pin PC1 is configured to Input enabled */
// GPIO->P[2].MODEL = (GPIO->P[2].MODEL & ~_GPIO_P_MODEL_MODE1_MASK) | GPIO_P_MODEL_MODE1_INPUT;
/* set output state of PC0 PC1 (D- D+) to 1 0 */
GPIOA->PSOR = (1<<2); /* D- = 1 */
GPIOA->PCOR = (1<<3); /* D+ = 0 */
/* Pin PE13 is configured to Push-pull */
//GPIO->P[4].MODEH = (GPIO->P[4].MODEH & ~_GPIO_P_MODEH_MODE13_MASK) | GPIO_P_MODEH_MODE13_PUSHPULL;
/* setup PC1 interrupt on rising edge (D+ first SYNC bit) */
/* Configure PC1 interrupt on rising edge */
// GPIO_IntConfig(gpioPortC, 1, true, false, true);
/* Set Interrupt priority to highest */
// NVIC_SetPriority(GPIO_ODD_IRQn, 0);
/* Enable GPIO_EVEN interrupt vector in NVIC */
// NVIC_EnableIRQ(GPIO_ODD_IRQn);
}
void usb_connect(void)
{
GPIOA->PSOR = (1 << 3);
//GPIO->P[0].MODEL = (GPIO->P[0].MODEL & ~_GPIO_P_MODEL_MODE0_MASK) | GPIO_P_MODEL_MODE0_PUSHPULL;
}
void usb_disconnect(void)
{
/* Pin PA0 is configured to Input enabled with pull-down */
// GPIO->P[0].MODEL = (GPIO->P[0].MODEL & ~_GPIO_P_MODEL_MODE0_MASK) | GPIO_P_MODEL_MODE0_INPUTPULL;
/* set PA0 low (disconnected) Will enable the pulldown */
GPIOA->PCOR = (1 << 3);
}
bool usb_check_resetcondition(void)
{
return ( (GPIOA->PDIR & 0x00000006) == 0x00 );
}
/* check if a setup packet was received */
bool usb_setup_available(void)
{
return (usb_ep_buffers[USB_EPBUF_OFFSET_SETUP_BUF + USB_EPBUF_SUBOFFSET_STAT] & (1 << 0)) != 0x00;
}
/* IDEA: The reordering / Bitreversal can be done in place to save some RAM */
void usb_setup_get_data(setupData_t *psetupdata)
{
uint32_t i, j;
uint8_t dat;
uint8_t setupdat[8];
volatile uint8_t *SETUP_BUF;
SETUP_BUF = &usb_ep_buffers[USB_EPBUF_OFFSET_SETUP_BUF];
for (i=0; i<8; i++) /* walk through all bytes */
{
j = i+1;
j = (j & 0xfC) | (3-(j & 0x03)); /* reverse byteorder => TODO: This can be done in the .s file using the REV instruction (single cycle) */
dat = SETUP_BUF[j];
dat = bitreverse(dat); /* reverse bits*/
setupdat[i] = dat; /* store data */
}
usb_ep_buffers[USB_EPBUF_OFFSET_SETUP_BUF + USB_EPBUF_SUBOFFSET_STAT] &= ~(1 << 0); /* flag setup data as empty */
psetupdata->bmRequestType = setupdat[0];
psetupdata->bRequest = setupdat[1];
psetupdata->wValue = setupdat[2];
psetupdata->wValue |= setupdat[3] << 8;
psetupdata->wIndex = setupdat[4];
psetupdata->wIndex |= setupdat[5] << 8;
psetupdata->wLength = setupdat[6];
psetupdata->wLength |= setupdat[7] << 8;
}
bool usb_ep_in_buf_empty(uint32_t epnum)
{
if (epnum)
{
return (usb_ep_buffers[USB_EPBUF_OFFSET_EP1IN_BUF + USB_EPBUF_SUBOFFSET_STAT] & (1 << 0)) == 0x00;
}
else
{
return (usb_ep_buffers[USB_EPBUF_OFFSET_EP0IN_BUF + USB_EPBUF_SUBOFFSET_STAT] & (1 << 0)) == 0x00;
}
}
/* TODO/IDEA: check parameters like len. This can be done e.g. with ASSERTIONS, so
* that checks can be disabled later to save time & space
*/
void usb_ep_in_commit_pkt(uint32_t epnum, bool firstpkt, const uint8_t *pbuf, uint32_t len)
{
uint32_t i;
uint8_t dat;
uint16_t crc_value;
volatile uint8_t *EP0IN_BUF;
if (!len)
{
GPIOA->PSOR = (1<<8);
GPIOA->PCOR = (1<<8);
}
if (epnum)
{
EP0IN_BUF = &usb_ep_buffers[USB_EPBUF_OFFSET_EP1IN_BUF];
}
else
{
EP0IN_BUF = &usb_ep_buffers[USB_EPBUF_OFFSET_EP0IN_BUF];
}
if (firstpkt)
{
EP0IN_BUF[0] = 0x4B; /* first IN packet is always transmitted with DATA1 PID */
}
else
{
EP0IN_BUF[0] ^= 0x88; /* Following packets toggle between DATA0 and DATA1 PID */
}
crc_value = 0xffff;
for (i=0; i<len; i++)
{
dat = *pbuf++;
EP0IN_BUF[i+1] = dat;
crc_value = crc16(crc_value, dat);
}
crc_value = ~crc_value; /* this is described in the USB spec. */
/* ADD CRC */
EP0IN_BUF[1+len+0] = crc_value & 0xff; /* CRC low */
EP0IN_BUF[1+len+1] = crc_value >> 8; /* CRC high */
/* set packet length */
EP0IN_BUF[USB_EPBUF_SUBOFFSET_LEN] = len + 1 +2; /* DATAx PID + CRC16 */
/* Flag endpoint as "ready" for transmission. This needs to be done as the last step */
EP0IN_BUF[USB_EPBUF_SUBOFFSET_STAT] |= (1 << 0);
}
bool usb_ep_out_data_available(uint32_t epnum)
{
if (epnum == 0x00)
{
return (usb_ep_buffers[USB_EPBUF_OFFSET_EP0OUT_BUF + USB_EPBUF_SUBOFFSET_STAT] & (1 << 0)) != 0x00;
}
else
{
return (usb_ep_buffers[USB_EPBUF_OFFSET_EP1OUT_BUF + USB_EPBUF_SUBOFFSET_STAT] & (1 << 0)) != 0x00;
}
}
uint32_t usb_ep_out_get_data(uint32_t epnum, uint8_t *pbuf)
{
uint32_t i, j, len;
uint8_t dat, bytecount;
volatile uint8_t *EP0OUT_BUF;
if (epnum == 0)
{
EP0OUT_BUF = &usb_ep_buffers[USB_EPBUF_OFFSET_EP0OUT_BUF];
}
else
{
EP0OUT_BUF = &usb_ep_buffers[USB_EPBUF_OFFSET_EP1OUT_BUF];
}
len = EP0OUT_BUF[USB_EPBUF_SUBOFFSET_LEN];
bytecount = ((len + 7) >> 3) - 1 - 2; /* -PID -CRC16 */
for (i=0; i<bytecount; i++) /* walk through all bytes */
{
j = i+1;
j = (j & 0xfC) | (3-(j & 0x03)); /* reverse byteorder => TODO: This can be done in the .s file using the REV instruction (single cycle) */
dat = EP0OUT_BUF[j];
dat = bitreverse(dat); /* reverse bits*/
*pbuf++ = dat; /* store data */
}
//bytecount = 0;
if (bytecount > 0)
{
volatile int i;
i=0;
}
/* flag endpoint as empty. Needs to be done as last step */
EP0OUT_BUF[USB_EPBUF_SUBOFFSET_STAT] &= ~(1 << 0);
//usb_ep_buffers[USB_EPBUF_OFFSET_EP0OUT_BUF + USB_EPBUF_SUBOFFSET_STAT] &= ~(1 << 0);
return bytecount;
}
void usb_ep_stall(uint32_t epnum)
{
usb_ep_buffers[epnum + USB_EPBUF_SUBOFFSET_STAT] |= (1 << 1);
}
void usb_ep_unstall(uint32_t epnum)
{
usb_ep_buffers[epnum + USB_EPBUF_SUBOFFSET_STAT] &= ~(1 << 1);
}
bool usb_ep_is_stalled(uint32_t epnum)
{
return (usb_ep_buffers[epnum + USB_EPBUF_SUBOFFSET_STAT] & (1 << 1));
}
/* send a package via EP0IN which is longer as 7 bytes */
void usb_ep_in_commit_pkt_long(uint32_t epnum, const uint8_t *pbuf, uint8_t len, bool sendshortpkt)
{
bool first;
uint8_t curlen;
first = (epnum == 0x00); /* EP0IN packets always start with DATA1 PID, while EP1IN PID toggles between DATA0/1 */
curlen = 0;
while (len)
{
curlen = len;
if (curlen > 8)
{
curlen = 8;
}
while (!usb_ep_in_buf_empty(epnum)); /* wait until endpoint buffer is free */
usb_ep_in_commit_pkt(epnum, first, pbuf, curlen);
len -= curlen;
pbuf += curlen;
first = false;
}
if (!sendshortpkt)
{
return;
}
if ((curlen == 8) || (curlen == 0)) /* in case the last packet has 8 bytes a short packet needs to be sent to signalize the host, that this was the last packet*/
{
while (!usb_ep_in_buf_empty(epnum)); /* wait until endpoint buffer is free */
usb_ep_in_commit_pkt(epnum, false, pbuf, 0);
}
}
/* receive a package via EP0OUT. It is allowed to be longer than 8 bytes */
/* important: ensure, that pbuf has a buffer size with a multiple of 8 Bytes */
/* returns received length */
uint8_t usb_ep_out_get_data_long(uint8_t *pbuf, uint8_t maxlen)
{
uint8_t curlen, len;
curlen = 8;
len = 0;
do
{
if (usb_ep_out_data_available(0))
{
curlen = usb_ep_out_get_data(0, pbuf); /* TODO: Handle this within usb_stack.c. It is part of control transfers. setup */
pbuf += curlen;
if (len >= maxlen) /* at least a little bit of protection against buffer overruns */
{
pbuf -= curlen;
}
len += curlen;
}
} while ( (curlen == 8) && (len < maxlen) ); /* a short packet indicates the last packet */
return len;
}
/* Handle a Control transfer without data stage => transmits a ACK in status stage */
void usb_control_acknowledge(void)
{
uint8_t response[8];
while (!usb_ep_in_buf_empty(0x00))
;
usb_ep_in_commit_pkt(0, true, response, 0);
}
/* Handle a Control IN transfer */
bool usb_control_dataIn(const uint8_t *pbuf, uint8_t len)
{
usb_ep_in_commit_pkt_long(0, pbuf, len, false);//true);
/* wait for status stage - acknowledge from HOST*/
while ( !usb_ep_out_data_available(0) )
{
}
usb_ep_buffers[USB_EPBUF_OFFSET_EP0OUT_BUF + USB_EPBUF_SUBOFFSET_STAT] &= ~(1 << 0); /* ignore ACK (OUT packet) */
return true;
}
/* Handle a Control OUT transfer */
uint8_t usb_control_dataOut(uint8_t *pbuf, uint8_t maxlen)
{
maxlen = usb_ep_out_get_data_long(pbuf, maxlen);
usb_control_acknowledge();
return maxlen;
}
/* TODO: Combine the functions */
@@ -0,0 +1,137 @@
/****************************************************************************//*
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef __USB_H__
#define __USB_H__
#include <stdint.h>
#include <stdbool.h>
#include "usb_config.h"
/* public interface to virtual USB peripheral & Stack */
/* some definitions for USB descriptors */
#define DESCRIPTOR_DEVICE (0x01) /* Get device descriptor: Device */
#define DESCRIPTOR_CONFIGURATION (0x02) /* Get device descriptor: Configuration */
#define DESCRIPTOR_STRING (0x03) /* Get device descriptor: String */
#define DESCRIPTOR_INTERFACE (0x04)
#define DESCRIPTOR_ENDPOINT (0x05)
#ifdef USB_ENABLE_HID
#define DESCRIPTOR_HID (0x21) /* Get descriptor: HID */
#define DESCRIPTOR_REPORT (0x22) /* Get descriptor: Report */
#endif
#define EPTYPE_CONTROL (0x00)
#define EPTYPE_INTERRUPT (0x03)
/* Some defines for endpoint function parameters => TODO, will be used in a later stage */
#define USB_EPSETUP (0)
#define USB_EP0OUT (16)
#define USB_EP0IN (32)
#if USB_ENABLE_EP1OUT_EP1IN == 1
#define USB_EP1OUT (48)
#define USB_EP1IN (64)
#endif
/* struct, which is used for control transfers */
typedef struct
{
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wLength;
uint16_t wValue;
uint16_t wIndex;
} setupData_t;
/* Initialize USB and all used peripherals
It startes with the USB peripheral disconnected from PC.
Call usb_connect after initialization.
*/
void usb_init(void);
void usb_connect(void);
void usb_disconnect(void);
bool usb_check_resetcondition(void);
void usb_reset_received(void);
/* check, if a setup packet was received */
bool usb_setup_available(void);
/* read setup data. Setup data does have a fixed length of 8 Bytes */
void usb_setup_get_data(setupData_t *psetupdata);
/* check, if data can be written to ep0in buffer (== buffer is empty) */
bool usb_ep_in_buf_empty(uint32_t epnum);
/* write data to ep0in buffer */
void usb_ep_in_commit_pkt(uint32_t epnum, bool firstpkt, const uint8_t *pbuf, uint32_t len);
/* check, if received data is in OUT endpoint */
bool usb_ep_out_data_available(uint32_t epnum);
/* get data from EPxOUT. Length [bytes] is returned. */
uint32_t usb_ep_out_get_data(uint32_t epnum, uint8_t *pbuf);
/* stall endpoint */
void usb_ep_stall(uint32_t epnum);
/* remove stall condition from endpoint */
void usb_ep_unstall(uint32_t epnum);
/* returns true if endpoint is stalled */
bool usb_ep_is_stalled(uint32_t epnum);
/* receive a package via EP0OUT. It is allowed to be longer than 8 bytes */
/* important: ensure, that pbuf has a buffer size with a multiple of 8 Bytes */
/* returns received length */
uint8_t usb_ep_out_get_data_long(uint8_t *pbuf, uint8_t maxlen);
/* send a package via EP0IN which is longer as 7 bytes */
//void usb_ep_in_commit_pkt_long(uint32_t epnum, const uint8_t *pbuf, uint8_t len);
void usb_ep_in_commit_pkt_long(uint32_t epnum, const uint8_t *pbuf, uint8_t len, bool sendshortpkt);
/* Handle a Control transfer without data stage => transmits a ACK in status stage */
void usb_control_acknowledge(void);
/* Handle a Control IN transfer */
bool usb_control_dataIn(const uint8_t *pbuf, uint8_t len);
/* Handle a Control OUT transfer */
uint8_t usb_control_dataOut(uint8_t *pbuf, uint8_t maxlen);
#endif
@@ -0,0 +1,40 @@
/***************************************************************************//*
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef __USB_CONFIG_H__
#define __USB_CONFIG_H__
/* Set to 1 to enable 2 additional endpoints.
If set to 0, only control transfers will be supported, because only EP0OUT and EP0IN are present
*/
#define USB_ENABLE_EP1OUT_EP1IN (1)
#define USB_ENABLE_HID
/*
Enable this define, if the USB low level protocol handling should be done in RAM.
This is e.g. mandatory if Flash programming is used, otherwise USB will not be
responsive anymore when flash is erased or programmed, because Flash accesses will
be stalled.
*/
#define USB_PROTOCOL_HANDLING_IN_RAM
#endif
@@ -0,0 +1,162 @@
/***************************************************************************//*
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef __USB_DESCRIPTORS_H__
#define __USB_DESCRIPTORS_H__
#include <stdint.h>
#include <stdbool.h>
#include "usb.h"
/* include this file only once! */
#define WBVAL(x) (x & 0xFF),((x >> 8) & 0xFF)
/* report descriptor for HID keyboard */
const uint8_t hid_report_descriptor[] =
{
0x05, 0x01, 0x09,
0x06, 0xA1,
0x01, 0x05,
0x07, 0x19,
0xE0, 0x29, 0xE7,
0x15, 0x00,
0x25, 0x01,
0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01,
0x75, 0x08, 0x81, 0x01, 0x95, 0x03, 0x75, 0x01,
0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02,
0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06,
0x75, 0x08, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x05,
0x07, 0x19, 0x00, 0x2A, 0xFF, 0x00, 0x81, 0x00,
0xC0
};
const uint8_t device_descriptor[] =
{
0x12, /* descriptor length */
0x01, /* descriptor type */
WBVAL(0x0110), /* USB version */
0x00, /* Devices class */
0x00, /* Device sub class */
0x00, /* Device sub sub class */
0x08, /* max packet size (for EP0IN/OUT) */
WBVAL(0x10C4), /* VID (low, high) */
WBVAL(0x8944), /* PID */
WBVAL(0x0100), /* DID */
0x01, /* manufacturer string index */
0x02, /* product string index */
0x00, /* serial number string index */
0x01 /* number of configurations */
};
const uint8_t config_0_descriptor[] =
{
0x09, /* length of config descriptor */
DESCRIPTOR_CONFIGURATION, /* descriptor type */
0x12+7+9, 0x00, /* Config + Interface + Endpoints length (low, high) */
0x01, /* number of interfaces */
0x01, /* interface number */
0x00, /* configuration string index */
0xA0, /* attributes (buspowered = Bit7, Selfpowered = Bit6, RemoteWakeup = Bit 5) */
50, /* power requirement (multiply by 2 to get current in mA) */
/* interface descriptor */
0x09, /* length of interface descriptor */
DESCRIPTOR_INTERFACE, /* descriptor type */
0x00, /* Index of this interface (starts at 0) */
0x00, /* Alternate setting */
0x01, /* Number of Endpoints */
0x03, /* Interface class */
0x01, /* Interface sub class */
0x01, /* Interface sub sub class */
0x00, /* Interface descriptor string index */
/* HID descriptor - Keyboard */
0x09, /* Length of this descriptor */
DESCRIPTOR_HID, /* bDescriptorType */
WBVAL(0x0100), /* 1.00 */ /* bcdHID */
0x00, /* bCountryCode */
0x01, /* bNumDescriptors */
0x22, /* bDescriptorType */
WBVAL(sizeof(hid_report_descriptor)), /* wDescriptorLength */
/* EP1IN */
0x07, /* length of endpoint descriptor */
DESCRIPTOR_ENDPOINT, /* descriptor type */
0x81, /* Endpoint number and direction (Bit 7) */
EPTYPE_INTERRUPT, /* Endpoint type */
0x08, 0x00, /* Max packet size of this Endpoint (Low, High) */
0x18 /* Polling Interval */
};
const uint8_t string_0_descriptor[] =
{
0x04, /* length of string descriptor */
DESCRIPTOR_STRING, /* descriptor type */
0x09,
0x04
};
const uint8_t string_1_descriptor[] =
{
0x14, /* length of string descriptor */
DESCRIPTOR_STRING, /* descriptor type */
'L', 0,
'E', 0,
'M', 0,
'C', 0,
'U', 0,
'.', 0,
'O', 0,
'R', 0,
'G', 0,
};
const uint8_t string_2_descriptor[] =
{
0x1A, /* length of string descriptor */
DESCRIPTOR_STRING, /* descriptor type */
'I', 0,
't', 0,
' ', 0,
'w', 0,
'o', 0,
'r', 0,
'k', 0,
's', 0,
' ', 0,
':', 0,
'-', 0,
')', 0,
};
const uint8_t hid_descriptor[] =
{
0x09,
DESCRIPTOR_HID,
0x10, 0x01, /* USB version */
0x00, /* Localization*/
};
#endif
@@ -0,0 +1,63 @@
/****************************************************************************
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef __USB_HELPERFUNCTIONS_H__
#define __USB_HELPERFUNCTIONS_H__
#include <stdint.h>
/* from bit twiddling hacks. Did not check efficiency.
My guess is, that the standard assembly way using 8 consecutive ROR/ROL instructions is faster!
so: TODO check and optimize
*/
static inline uint8_t bitreverse(uint8_t b)
{
return ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
}
/* TODO: Make this nice and efficient! Maybe implement this directly in CM0+ assembly
using uint32_t instead of uint8_t can also speed things up
See: http%3A%2F%2Fwww.usb.org%2Fdevelopers%2Fwhitepapers%2Fcrcdes.pdf&ei=
AKrAUtuBD4WMtQakyoCwAQ&usg=AFQjCNE71tY6EAUjJKXWbjtbNvDTiOKKlg&bvm=bv.
58187178,d.Yms&cad=rja
*/
static uint16_t crc16(uint16_t crc, uint8_t c)
{
uint8_t i;
for (i=0; i<8; i++)
{
if ((crc ^ c) & 1)
{
crc = (crc >> 1) ^ 0xa001; /* 0xa001*/
}
else
{
crc >>= 1;
}
c >>= 1;
}
return crc;
}
#endif
@@ -0,0 +1,104 @@
/****************************************************************************
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "usb_stack.h"
#include "usb.h"
#include "usb_helperfunctions.h"
#include "usb_config.h"
#include "usb_hid.h"
//#include "em_device.h" /* removeme. Only needed for debugging */
#ifdef USB_ENABLE_HID
/* HID requests */
#define HID_GET_REPORT (0x01) /* mandatory */
#define HID_GET_IDLE (0x02) /* optional */
#define HID_GET_PROTOCOL (0x03) /* mandatory for BOOT devices */
#define HID_SET_REPORT (0x09) /* mandatory if USB device does not use EP1OUT */
#define HID_SET_IDLE (0x0a) /* optional */
#define HID_SET_PROTOCOL (0x0b) /* mandatory for BOOT devices */
bool usbhid_got_setup_cmd(const setupData_t *psetupdata)
{
uint8_t response[8];
bool doStall;
doStall = false;
switch(psetupdata->bRequest)
{
case HID_GET_REPORT:
doStall = !HID_GetReport(psetupdata->wValue >> 8);
break;
case HID_SET_REPORT:
doStall = !HID_SetReport(psetupdata->wValue >> 8);
if (!doStall)
{
//usb_control_acknowledge(); //TODO: REMOVE UNCOMMENT!!!
}
break;
case HID_GET_PROTOCOL:
doStall = !HID_GetProtocol(response);
if (!doStall)
{
usb_control_dataIn(response, 1);
}
break;
case HID_SET_PROTOCOL:
doStall = !HID_SetProtocol(psetupdata->wValue >> 8); /* low byte of value is interface number */
if (!doStall)
{
usb_control_acknowledge();
}
break;
case HID_GET_IDLE:
doStall = !HID_GetIdle(response);
if (!doStall)
{
usb_control_dataIn(response, 1);
}
break;
case HID_SET_IDLE:
doStall = !HID_SetIdle(psetupdata->wValue >> 8); /* low byte of value is interface number */
if (!doStall)
{
usb_control_acknowledge();
}
break;
}
if (doStall)
{
usb_ep_stall(USB_EP0OUT);
usb_ep_stall(USB_EP0IN);
}
return true;
}
#endif
@@ -0,0 +1,61 @@
/***************************************************************************//*
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef __USB_HID_H__
#define __USB_HID_H__
#include <stdint.h>
#include <stdbool.h>
#include "usb.h"
#include "usb_config.h"
#ifdef USB_ENABLE_HID
/* HID Report Types */
#define HID_RPRT_INPUT (0x01)
#define HID_RPRT_OUTPUT (0x02)
#define HID_RPRT_FEATURE (0x03)
/* HID Requests functions, need to be defined by the user! */
/* They are not implemented as callback functions to get */
/* a more efficient code.*/
/* The functions should false, if they were not handled */
/* return TRUE if function was handled */
extern bool HID_GetReport (uint8_t reportType);
extern bool HID_SetReport (uint8_t reportType);
extern bool HID_GetIdle (uint8_t *pIdleTime);
extern bool HID_SetIdle (uint8_t idleTime);
extern bool HID_GetProtocol (uint8_t *pProtocol);
extern bool HID_SetProtocol (uint8_t protocol);
bool usbhid_got_setup_cmd(const setupData_t *psetupdata);
#else
#warning "HID disabled, but hid includes compiled"
#endif
#endif
@@ -0,0 +1,484 @@
//****************************************************************************
//
// Lemcusb - Firmware USB driver for EFM32 Microcontroller
// Copyright (C) 2014 http://lemcu.org
//
// This library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 3.0 as
// published by the Free Software Foundation and appearing in the file
// LICENSE.txt included in the packaging of this file.
//
// In addition, as a special exception, http://lemcu.org gives you certain
// additional rights. These rights are described in the lemcu.org GPL
// Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
// package.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY// without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
//**************************************************************************/
#if defined ( __IAR_SYSTEMS_ASM__ )
NAME usb_internal_bitbangusb
;; For a description of the purpose of the following part, look here:
;; http://supp.iar.com/Support/?note=80737&from=search+result
;; (TOPIC: IAR assembler ramfunction)
#define SHT_PROGBITS 0x1
#define SHF_WRITE 0x1
#define SHF_EXECINSTR 0x4
RSEG MYCODE:CODE:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, SHF_WRITE | SHF_EXECINSTR
THUMB
EXTERN usb_protocol_handle
PUBLIC GPIO_ODD_IRQHandler
PUBLIC usb_transmit
PUBLIC protocol_handled
#else
.syntax unified
.arch armv6-m
.SECTION .functioninRAM
.thumb
.thumb_func
.extern usb_protocol_handle
.global GPIO_ODD_IRQHandler
.global usb_transmit
.global protocol_handled
.type GPIO_ODD_IRQHandler, %function // IMPORTANT FOR GCC to get lsb of address set to 1
.type protocol_handled, %function // IMPORTANT FOR GCC to get lsb of address set to 1
#endif
#define USBEP_OFS_SETUP ( 0)
#define USBEP_OFS_EP0OUT (16)
#define USBEP_OFS_EP0IN (32)
#define USBEP_OFS_EP1OUT (48)
#define USBEP_OFS_EP1IN (64)
#define USBEP_SOFS_STAT (12)
#define USBEP_SOFS_LEN (13)
// This is the Interrupt handler, triggered by a rising edge on D+ (PC1)
// It is implemented in assembly to minimize latency
// (=> avoid branch from C code to ASM and addition of veneer code)
// This is called for each received USB data packet. received data is unstuffed.
// The data is decoded to R8, R9, R10
// Each data byte is in reversed bitorder. For data bytes, the bitorder
// needs to be reversed. For PIDs, etc. bitorder reversal is not mandatory
// The received bitcount is written to R11
// BYTE ORDER:
// R8. 24-31 Byte 0
// R8. 16-23 Byte 1
// R8. 8-15 Byte 2
// R8. 0- 7 Byte 3
// R9. 24-31 Byte 4
// R9. 16-23 Byte 5
// R9. 8-15 Byte 6
// R9. 0- 7 Byte 7
// R10.24-31 Byte 8
// R10.16-23 Byte 9
// R10. 8-15 Byte 10
// R10. 0- 7 Byte 11
//
// An interupt saves the following register on stack:
// - R0-R3, R12
// - LR, PC & xPSR
GPIO_ODD_IRQHandler:
NOP
NOP
MOV r0, r8
MOV r1, r9
MOV r2, r10
MOV r3, r11
PUSH {r0-r7}
MOV r0, LR
PUSH {r0}
MOVS r3, #3
MOVS r4, #0xff // preload with 0xff to avoid bitunstuffing after start
MOVS r5, #0x80
LSLS r5, r5, #24
MOVS r0, #0
MOV r11, r0
MOVS r1, #1
MOV r12, r1
// r1 = 1
// r3 = 3
// r5 = (1<<13)
// r7 = &GPIO_PE_DOUTSET
LDR r7, GPIO_PC_DIN // r7 = address of register GPIO_PC_DIN
// wait until a 1 is detected. Unfolded loop to be able to detect a timeout condition
usb_sync_wait_while_0:
LDR r0, [r7] // read port state
TST r0, r1
BEQ usb_sync_found
LDR r0, [r7] // read port state
TST r0, r1
BEQ usb_sync_found
LDR r0, [r7] // read port state
TST r0, r1
BEQ usb_sync_found
LDR r0, [r7] // read port state
TST r0, r1
BEQ usb_sync_found
LDR r0, [r7] // read port state
TST r0, r1
BEQ usb_sync_found
LDR r0, [r7] // read port state
TST r0, r1
BEQ usb_sync_found
LDR r0, [r7] // read port state
TST r0, r1
BEQ usb_sync_found
B protocol_handled // State was zero for more than 1 bittime => exit (timeout condition)
usb_sync_found:
// delay 1 bittime
LDR r0, [r7] // read port state
TST r0, r1
BNE usb_sync_wait_while_0
LDR r0, [r7] // read port state
TST r0, r1
BNE usb_sync_wait_while_0
LDR r0, [r7] // read port state
TST r0, r1
BNE usb_sync_wait_while_0
LDR r0, [r7] // read port state
TST r0, r1
BNE usb_sync_wait_while_0
LDR r0, [r7] // read port state
TST r0, r1
BNE usb_sync_wait_while_0
NOP
// check, if bitstate is still 1 (=> if 2 consecutive 1 bits received)
LDR r2, [r7] // read port state
TST r2, r1
BNE usb_sync_wait_while_0
BL _delay_13
// here: We are in the middle of the very first bit of this packet
// r0 = port state current
// r1 = 1
// r2 = port state old
// r3 = 3
// r4/5/6 = received data (parallel)
// r7 = address of GPIO_PC_DIN
// r11 = bitcounter
MOVS r1, #0
rcv_bits: LDR r0, [r7] // read port state
ANDS r0, r3 // check for SE0 and mask out unneeded bits
BEQ se0_detected // end of receive loop!
EORS r2, r0 // NRZ decoding (XOR bitstate with old bitstate) => inverts data, USB uses NRZI!
LSRS r2, r2, #1
ADCS r4, r4, r4 // Shift carry into receive chain
ADCS r5, r5, r5
ADCS r6, r6, r6
ADD r11, r11, r12 // increment bitcounter
MOV r2, r0 // Store old bitstate
NOP
LSLS r1, r1, #1 // Shift bitunstuffing EOR mask
LSLS r0, r4, #26 // Mask out last 6 received bits
EORS r0, r0, r1 // check if 6 consecutive 0s have been received
BNE rcv_bits
// here we get when bitunstuffing needs to be done
// 15/16 cycles over
NOP //16
LDR r2, [r7] // 1 // read port state to save it as "old" bitstate
BL _delay_11 //12
MOVS r1, #1 //13 // save bitunstuffing EOR mask
LSLS r1, r1, #26 //14
B rcv_bits //16
se0_detected:
// left align data (rough: 32 Bit steps)
MOV r0, r11
CMP r0, #64
BHI se0_detected_align_0
MOVS r6, r5
MOVS r5, r4
SUBS r4, r4, r4 // not mandatory
CMP r0, #32
BHI se0_detected_align_0
MOVS r6, r5
MOVS r5, r4
SUBS r4, r4, r4 // not mandatory
// left align data (fine alignment: 0..31 bits)
se0_detected_align_0: MOV r0, r11
MOVS r1, #31
ANDS r1, r1, r0 // r1 = bitcount & 31
CMP r1, #0
BEQ se0_alginment_done
MOVS r0, #0
MVNS r0, r0 // r0 = 0xffffffff
LSRS r0, r0, r1 // 8 => 0x00ffffff, 24 => 0x000000ff r0 = Mask of bytes to copy from lower word to upper one
RORS r6, r6, r1 //
BICS r6, r6, r0 // r6 = r6 and not r0 (reset lower bytes to 0)
RORS r5, r5, r1 //
MOVS r2, r5
ANDS r2, r2, r0
ORRS r6, r6, r2 //
BICS r5, r5, r0 // r6 = r6 and not r0 (reset lower bytes to 0)
RORS r4, r4, r1 //
MOVS r2, r4
ANDS r2, r2, r0
ORRS r5, r5, r2
BICS r4, r4, r0 // not mandatory
// Invert data (NRZ => NRZI)
se0_alginment_done: MVNS r0, r4
MOV r10, r0
MVNS r0, r5
MOV r9, r0
MVNS r0, r6
MOV r8, r0
LDR r0, LABEL_USB_PROT_HDL
BX r0 // Jump to protocol state machine code located in Flash
protocol_handled:
// This was for debugging. enable it, if you want to debug host packets only
// MOVS r5, #255
//delayloop:
// SUBS r5, r5, #1
// BNE delayloop
// acknowledge GPIO interrupt
LDR r6, GPIO_IFC
MOVS r5, #2
STR r5, [r6]
POP {r0}
MOV LR, r0
POP {r0-r7}
MOV r8, r0
MOV r9, r1
MOV r10, r2
MOV r11, r3 // r0-r3 are restored by ISR return
BX LR // return
////////////////////////////////////////
#if defined ( __IAR_SYSTEMS_ASM__ )
DATA
ALIGNROM 2
GPIO_PC_DIN: DC32 0x40006064 ; GPIO_PC_DIN
GPIO_PE_DOUTSET DC32 0x400060a0 ; GPIO_PE_DOUTSET.DOUTSET
GPIO_IFC: DC32 0x4000611c ; GPIO.IFC
LABEL_USB_PROT_HDL: DC32 usb_protocol_handle
//GPIO_PB_TOGGLE: DC32 0x4000603C ; REMOVEME
#else
.BALIGN 4
GPIO_PC_DIN: .INT 0x40006064 // GPIO_PC_DIN
GPIO_PE_DOUTSET: .INT 0x400060a0 // GPIO_PE_DOUTSET.DOUTSET
GPIO_IFC: .INT 0x4000611c // GPIO.IFC
LABEL_USB_PROT_HDL: .INT usb_protocol_handle
#endif
#if defined ( __IAR_SYSTEMS_ASM__ )
CODE
THUMB
#else
.SECTION .functioninRAM
.THUMB
#endif
// This function transmits a USB packet as response to the host
// Used for : ACK, NAK, STALL, DATA0 & DATA1 PIDs
// Parameters:
// r0/r1/r2 = Data to transmit
// r5 = Bitcount
// The Bitorder of the transmission is the right one (no bitreversal as in receive function)
// transmit order:
// r0.0-7 => r0.8-15 => r0.16-23 => r0.24-31 =>
// r1.0-7 => r1.8-15 => r1.16-23 => r1.24-31 =>
// r2.0-7 => r2.8-15 => r2.16-23 => r2.24-31
usb_transmit:
MOV r7, LR
PUSH {r7}
// Switch PC0 & PC1 to output
LDR r7, GPIO_PC_BASE
LDR r3, [r7, #4] // read pin mode low register
ADDS r3, r3, #0x33 // mode Input = 0x11, Output = 0x44
STR r3, [r7, #4] // writepin mode low register
// IO state = push pull & IDLE (D-=1 D+=0)
// 1.) Send SYNC Byte
MOVS r3, #0x03 // bitmask for toggling IO pin
MOVS r4, #7
usb_tx_syncloop: STR r3, [r7, #24] // Toggle IOs to transmit a 0
BL _delay_12
SUBS r4, r4, #1
BNE usb_tx_syncloop
//15
// transmit a "1" - last bit of SYNC sequence
BL _delay_12
// 2.) Send data given in registers r0/r1/r2 and bitcount in r5
// Here all bits get transmitted. Bitstuffing is also applied
// The minimal version of this would only need 6 cycles
MOVS r4, #5 // consecutive 1-Bit counter (used for bitstuffing). Last transmitted Bit was 1, so initialize it with 5 rather than 6
MOVS r6, #32 // Needed to check if a new 32 Bit word should be transmitted
usb_tx_bitloop: LSRS r0, r0, #1 // shift out bit to carry flag for transmitting
BCS usb_txbitloop_send1 //do nothing if bit is 1 (only a zero causes toggling
usb_txbitloop_send0: STR r3, [r7, #24] // Toggle IOs to transmit a 0
MOVS r4, #6 // Reset 1-Bit counter
B usb_txbitloop_sent1
usb_txbitloop_send1: SUBS r4, #1
BEQ usb_tx_sendstuffbit
usb_tx_bitstutt_ret: NOP // equalize execution time for 2 branch paths
usb_txbitloop_sent1: SUBS r5, r5, #1
BEQ usb_tx_send_eop // final word transmitted
SUBS r6, r6, #1
BEQ usb_txbit_nextword
NOP
NOP
NOP
NOP
B usb_tx_bitloop
// select next word for transmission
usb_txbit_nextword: MOVS r0, r1
MOVS r1, r2
MOVS r6, #32
B usb_tx_bitloop
// Send stuffbit
// 4 cycles over since last bit
usb_tx_sendstuffbit: BL _delay_11
MOVS r4, #6 // Reset 1-Bit counter
STR r3, [r7, #24] // Toggle IOs to transmit a 0
B usb_tx_bitstutt_ret
// send EOP (2*SE0)
// 7 cycles over since last bit
usb_tx_send_eop:
BL _delay_9
STR r3, [r7, #20] // write to GPIO_PC_DOUTCLR to set D+ and D- to LOW
BL _delay_10
BL _delay_10
BL _delay_10
MOVS r1, #1
STR r1, [r7, #16] // Set D- back to HIGH
// Switch PC0 & PC1 to input
LDR r7, GPIO_PC_BASE
LDR r0, [r7, #4] // read pin mode low register
SUBS r0, r0, #0x33 // set from 0x44 to 0x11 (push pull to input)
STR r0, [r7, #4] // writepin mode low register
// // delay some time for easier debugging
// MOVS r5, #255
//delayloop_x: MOVS r4, #6 // reset 1-bit counter
// SUBS r5, r5, #1
// BNE delayloop_x
POP {r0}
MOV LR, r0
BX LR
// some delay functions:
_delay_14: NOP
_delay_13: NOP
_delay_12: NOP
_delay_11: NOP
_delay_10: NOP
_delay_9: NOP
_delay_8: NOP
_delay_7: NOP
_delay_6: NOP
_delay_5: BX LR
#if defined ( __IAR_SYSTEMS_ASM__ )
DATA
ALIGNROM 2
GPIO_PC_BASE: DC32 0x40006048 ; GPIO_PC_DIN - This is redundant, has already been defined in the RX function
GPIO_PE_DOUTSET_ DC32 0x400060a0 ; GPIO_PE_DOUTSET.DOUTSET
END
#else
.BALIGN 4
GPIO_PC_BASE: .INT 0x40006048 // GPIO_PC_DIN - This is redundant, has already been defined in the RX function
GPIO_PE_DOUTSET_: .INT 0x400060a0 // GPIO_PE_DOUTSET.DOUTSET
.END
#endif
/*
TODO:
- Flag endpoint status based on Host reply
- interpret CRC5 ??
- detect RESET condition on bus (very long SE0 phase, check USB spec. for duration). This should reset the usb address
- RESET = SE0 for >= 10ms
- codesize optimization:
* use branches to identical code secitions
*/
@@ -0,0 +1,59 @@
/****************************************************************************
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
/*
* Low level internal functions.
* These functions are internal.
*/
//#include "em_device.h"
#include <stdint.h>
//#include "em_chip.h"
//#include "em_int.h"
#include "gpio.h"
//#include "em_cmu.h"
#include "usb_config.h"
/* Endpoint buffers
Offset 0: SETUP packets
Offset 16: EP0OUT
Offset 32: EP0IN
(Offset 48: EP1OUT)
(Offset 64: EP1IN)
Offsets within one of theese buffers:
0-11: Raw data
Offset 12: _STAT Status empty/filled (0x00/0x01)
Offset 13: _LEN Length of data in buffer
14 & 15 are free for future used - would be added anyway by codegen tools for alignment
*/
volatile uint8_t usb_ep_buffers[ (3+2*USB_ENABLE_EP1OUT_EP1IN)*16 ];
/* low level protocol handling state */
/* Bit 0- 7 = state machine index*/
/* Bit 8-15 = last received USB Address (bitreversed: a0 a1 a2 a3 a4 a5 a6 0) */
/* Bit 16-23 = last received USB Endpoint (bitreversed: e0 e1 e2 e3 0 0 0 0) */
/* Bit 24-31 = not used yet */
uint32_t USB_PROT_STATE;
@@ -0,0 +1,60 @@
/***************************************************************************//*
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef __USB_INTERNAL_H__
#define __USB_INTERNAL_H__
#include <stdint.h>
#include <stdbool.h>
#include "usb_config.h"
#define USB_EPBUF_OFFSET_SETUP_BUF ( 0)
#define USB_EPBUF_OFFSET_EP0OUT_BUF (16)
#define USB_EPBUF_OFFSET_EP0IN_BUF (32)
#define USB_EPBUF_OFFSET_EP1OUT_BUF (48)
#define USB_EPBUF_OFFSET_EP1IN_BUF (64)
#define USB_EPBUF_SUBOFFSET_STAT (12)
#define USB_EPBUF_SUBOFFSET_LEN (13)
/* Endpoint buffers
Offset 0: SETUP packets
Offset 16: EP0OUT
Offset 32: EP0IN
(Offset 48: EP1OUT)
(Offset 64: EP1IN)
Sub-offsets within one of these buffers:
0-11: Raw data
Offset 12: _STAT Status empty/filled (0x00/0x01)
Offset 13: _LEN Length of data in buffer
14 & 15 are free for future used - would be added anyway by codegen tools for alignment
*/
/* Endpoint buffers */
extern volatile uint8_t usb_ep_buffers[ (3+2*USB_ENABLE_EP1OUT_EP1IN)*16 ];
extern uint32_t USB_PROT_STATE;
#endif
@@ -0,0 +1,329 @@
#include "usb_config.h"
#if defined ( __IAR_SYSTEMS_ASM__ )
NAME usb_internal_prot_handling
#ifdef USB_PROTOCOL_HANDLING_IN_RAM
#define SHT_PROGBITS 0x1
#define SHF_WRITE 0x1
#define SHF_EXECINSTR 0x4
RSEG MYCODE:CODE:NOROOT(2)
SECTION_TYPE SHT_PROGBITS, SHF_WRITE | SHF_EXECINSTR
THUMB
#else
section CODE:CODE (2)
CODE
#endif
THUMB
EXTERN usb_dev_address
EXTERN USB_PROT_STATE
EXTERN usb_ep_buffers
EXTERN protocol_handled
EXTERN usb_transmit
PUBLIC usb_protocol_handle
#else
.syntax unified
.arch armv6-m
#ifdef USB_PROTOCOL_HANDLING_IN_RAM
.THUMB
.section .functioninRAM
#else
.BALIGN 4
.TEXT
#endif
.THUMB
.EXTERN usb_dev_address
.EXTERN USB_PROT_STATE
.EXTERN usb_ep_buffers
.EXTERN protocol_handled
.EXTERN usb_transmit
.GLOBAL usb_protocol_handle
.type usb_protocol_handle, %function // IMPORTANT FOR GCC to get lsb of address set to 1
#endif
/* Endpoint buffer offsets and suboffsets*/
#define USBEP_OFS_SETUP ( 0)
#define USBEP_OFS_EP0OUT (16)
#define USBEP_OFS_EP0IN (32)
#define USBEP_OFS_EP1OUT (48)
#define USBEP_OFS_EP1IN (64)
#define USBEP_SOFS_STAT (12)
#define USBEP_SOFS_LEN (13)
/* some internal C-Style MACROs */
#define REV2(x) ((((x)&1)<<1) | (((x)>>1)&1))
#define REV4(x) ((REV2(x)<<2) | (REV2((x)>>2)))
#define REV8(x) ((REV4(x)<<4) | (REV4((x)>>4)))
#define CREATE_PID(x) (x & 0x0F) | (((~x) & 0x0f)<<4)
/* define Bitreversed PIDs */
#define USB_TOKEN_BR_OUT REV8(CREATE_PID( 0x01 ))
#define USB_TOKEN_BR_IN REV8(CREATE_PID( 0x09 ))
#define USB_TOKEN_BR_SETUP REV8(CREATE_PID( 0x0d ))
#define USB_TOKEN_BR_DATA0 REV8(CREATE_PID( 0x03 ))
#define USB_TOKEN_BR_DATA1 REV8(CREATE_PID( 0x0b ))
#define USB_TOKEN_BR_ACK REV8(CREATE_PID( 0x02 ))
#define USB_TOKEN_BR_NAK REV8(CREATE_PID( 0x0a ))
/* define PIDs used for transmit (not bitreversed) */
#define USB_TOKEN_ACK CREATE_PID( 0x02 )
#define USB_TOKEN_NAK CREATE_PID( 0x0a )
#define USB_TOKEN_STALL CREATE_PID( 0x0e )
// The following registers are saved externally on stack:
// r0-r11
// Registers that are not allowed to be modified:
// r12, LR
// Input data:
// -----------
// r11 = received bitcount
// r8...r10 = received data
//
// Output data:
// ------------
// none
// A complete packet was received.
// Now do some protocol handling
// 1.) Identify PID R8.24-31
usb_protocol_handle:
LDR r7, ASM_USB_PROT_STATE // r7 = pointer to protocol state variable
LDRB r6, [r7] // r6 = state machine state
LDRB r5, [r7, #1] // r5 = Address from state variable
LDRB r4, [r7, #2] // r4 = Endpoint from state variable
LDR r3, ASM_USB_DEV_ADDRESS
LDRB r3, [r3] // r3 = USB Addresss of this device
MOV r0, r8
LSRS r0, r0, #24 // r0 now contains the PID only
CMP r0, #USB_TOKEN_BR_SETUP // sends address and endpoint as parameter
BEQ pid_setup
CMP r0, #USB_TOKEN_BR_DATA0
BEQ pid_data0
CMP r0, #USB_TOKEN_BR_DATA1
BEQ pid_data1
CMP r0, #USB_TOKEN_BR_IN // sends address and endpoint as parameter
BEQ pid_in
CMP r0, #USB_TOKEN_BR_OUT // sends address and endpoint as parameter
BEQ pid_out
jump_exit: LDR r0, LBL_PROT_HANDLED
BX r0
////////////// Protocol handling statemachine
// r7 = pointer to protocol state variable
// r6 = state machine state (Byte 0)
// r5 = Address & endpoint from state variable (Byte 1)
pid_setup: MOVS r0, #0
STRB r0, [r7] // Flag, that the next data package is a setup packet
MOV r0, r8
// extract address
LSRS r1, r0, #16
MOVS r2, #0xfe
ANDS r1, r1, r2 // Mask out address bits a0-a6. Order: a0 a1 a2 a3 a4 a5 a6 0
STRB r1, [r7, #1] // Store address in protocol state
// extract endpoint number
LSRS r1, r0, #9
MOVS r2, #0xf0
ANDS r1, r1, r2
STRB r1, [r7, #2] // Store endpoint in protocol state => TODO: APPLY MASK! Bitorder e0 e1 e2 e3 0 0 0 0
B jump_exit
pid_data0:
pid_data1:
// Check the usb address
CMP r5, r3
BNE jump_exit // This device is not addressed => Don't react on DATA PID
CMP r6, #0 // check if this is data is a setup phase or out phase
BEQ pid_data_setup
// Here: data PID is for OUT phase
// Create pointer to addressed endpoint buffer
LDR r6, ASM_USB_EP_BUFFERS
LDRB r1, [r7, #2] // Store endpoint in protocol state => TODO: APPLY MASK! Bitorder e0 e1 e2 e3 0 0 0 0
CMP r1, #0
BEQ pid_da_ep0_addressed
ADDS r6, r6, #USBEP_OFS_EP1OUT
B pid_da_ep1_addressed
pid_da_ep0_addressed: ADDS r6, r6, #USBEP_OFS_EP0OUT
pid_da_ep1_addressed:
LDRB r0, [r6, #USBEP_SOFS_STAT]
// check if endpoint is stalled
MOVS r2, #2
TST r0, r2
BNE send_STALL
// check if endpoint contains data
MOVS r1, #1
TST r0, r1 // if equal => Endpoint buffer is free
BNE send_NAK
// here: buffer available and endpoint not stalled, so copy data to buffer...
MOV r0, r8
MOV r1, r9
MOV r2, r10
MOV r5, r6 // generate address to EP0buffer data
STM r5!, {r0, r1, r2} // copy data to EP0OUT buffer
MOV r0, r11 // EP0OUT_LEN is filled with the received bitcount (includes PID & CRC)
STRB r0, [r6, #USBEP_SOFS_LEN]
LDRB r1, [r6, #USBEP_SOFS_STAT]
MOVS r0, #1
ORRS r1, r1, r0
STRB r1, [r6, #USBEP_SOFS_STAT] // set "data available" flag for EP0OUT Buffer
B send_ACK
pid_data_setup: LDR r6, ASM_USB_EP_BUFFERS // copy setup data to buffer
MOV r0, r8
MOV r1, r9
MOV r2, r10
MOV r5, r6 // generate address to EP0buffer data
ADDS r5, r5, #USBEP_OFS_SETUP
STM r5!, {r0, r1, r2} // copy data to SETUP buffer
LDRB r1, [r6, #(USBEP_OFS_SETUP + USBEP_SOFS_STAT)]
MOVS r0, #1
ORRS r1, r1, r0
STRB r1, [r6, #(USBEP_OFS_SETUP + USBEP_SOFS_STAT)] // set "data available" flag for SETUP BUFFER
// SEND ACK... This is the only option. NAK is not allowed in a setup phase
B send_ACK
pid_in: MOVS r0, #2
STRB r0, [r7] // Flag, that an IN PID was received
// extract address
MOV r0, r8
LSRS r1, r0, #16
MOVS r2, #0xfe
ANDS r1, r1, r2 // Mask out address bits a0-a6. Order: a0 a1 a2 a3 a4 a5 a6 0
STRB r1, [r7, #1] // Store address in protocol state
// check if USB Address is for this device
CMP r1, r3
BNE jump_exit // This device is not addressed => Don't react on DATA PID
// extract endpoint number
LSRS r1, r0, #9
MOVS r2, #0xf0
ANDS r1, r1, r2
STRB r1, [r7, #2] // Store endpoint in protocol state => TODO: APPLY MASK! Bitorder e0 e1 e2 e3 0 0 0 0
// build pointer to correct endpoint buffer
LDR r5, ASM_USB_EP_BUFFERS
CMP r1, #0
BEQ pid_in_ep0_addressed
ADDS r5, r5, #USBEP_OFS_EP1IN
B pid_in_ep1_addressed
pid_in_ep0_addressed: ADDS r5, r5, #USBEP_OFS_EP0IN
pid_in_ep1_addressed:
// check stall condition
LDRB r0, [r5, #USBEP_SOFS_STAT] // Bit0 = 0 = no data available => send NAK, Bit 0 = 1 = data availabe => send data
MOVS r2, #2
TST r0, r2
BNE send_STALL // Check and handle Endpoint STALL condition
// check if data is available in addressed endpoint
MOVS r1, #1
TST r0, r1
BEQ send_NAK
// send Data. Important: First byte contains correct DATA PID (DATA0/DATA1)
PUSH {r5}
LDM r5!, {r0, r1, r2}
LDRB r5, [r5, #1] // => USBEP_SOFS_LEN
LSLS r5, r5, #3 //Count of bits to transmit
BL usb_transmit
POP {r5}
LDRB r1, [r5, #USBEP_SOFS_STAT]
MOVS r0, #0xfe
ANDS r1, r1, r0
STRB r1, [r5, #USBEP_SOFS_STAT] // Flag EP0IN as empty
B jump_exit
pid_out: MOVS r0, #1
STRB r0, [r7] // Flag, that the next data package is for an endpoint
MOV r0, r8
// extract address
LSRS r1, r0, #16
MOVS r2, #0xfe
ANDS r1, r1, r2 // Mask out address bits a0-a6. Order: a0 a1 a2 a3 a4 a5 a6 0
STRB r1, [r7, #1] // Store address in protocol state
// extract endpoint number
LSRS r1, r0, #9
MOVS r2, #0xf0
ANDS r1, r1, r2
STRB r1, [r7, #2] // Store endpoint in protocol state => TODO: APPLY MASK! Bitorder e0 e1 e2 e3 0 0 0 0
B jump_exit
// Status return functions (function => host)
send_STALL: MOVS r0, #USB_TOKEN_STALL
MOVS r5, #8 //Count of bits to transmit
BL usb_transmit
B jump_exit
send_NAK: MOVS r0, #USB_TOKEN_NAK
MOVS r5, #8 //Count of bits to transmit
BL usb_transmit
B jump_exit
send_ACK: MOVS r0, #USB_TOKEN_ACK
MOVS r5, #8 //Count of bits to transmit
BL usb_transmit
B jump_exit
#if defined ( __IAR_SYSTEMS_ASM__ )
DATA
ALIGNROM 2
ASM_USB_PROT_STATE: DC32 USB_PROT_STATE
ASM_USB_EP_BUFFERS: DC32 usb_ep_buffers
ASM_USB_DEV_ADDRESS: DC32 usb_dev_address
LBL_PROT_HANDLED: DC32 protocol_handled
END
#else
.BALIGN 4
ASM_USB_PROT_STATE: .long USB_PROT_STATE
ASM_USB_EP_BUFFERS: .long usb_ep_buffers
ASM_USB_DEV_ADDRESS: .long usb_dev_address
LBL_PROT_HANDLED: .long protocol_handled
.END
#endif
@@ -0,0 +1,257 @@
/****************************************************************************
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "usb_stack.h"
#include "usb.h"
#include "usb_descriptors.h"
#include "usb_helperfunctions.h"
#ifdef USB_ENABLE_HID
#include "usb_hid.h"
#endif
/* Standard Request codes for Control */
#define SRQ_GET_STATUS (0x00) /* Standard Request : Get Status */
#define SRQ_CLEAR_FEATURE (0x01) /* Standard Request : Clear Feature */
#define SRQ_RESERVED1 (0x02) /* Standard Request : Reserved for future use */
#define SRQ_SET_FEATURE (0x03) /* Standard Request : Set Feature */
#define SRQ_RESERVED2 (0x04) /* Standard Request : Reserved for future use */
#define SRQ_SET_ADDRESS (0x05) /* Standard Request : Set Address */
#define SRQ_GET_DESCRIPTOR (0x06) /* Standard Request : Get Descriptor */
#define SRQ_SET_DESCRIPTOR (0x07) /* Standard Request : Set Descriptor */
#define SRQ_GET_CONFIGURATION (0x08) /* Standard Request : Get Configuration */
#define SRQ_SET_CONFIGURATION (0x09) /* Standard Request : Set Configuration */
#define SRQ_GET_INTERFACE (0x0a) /* Standard Request : Get Interface */
#define SRQ_SET_INTERFACE (0x0b) /* Standard Request : Set Interface */
#define SRQ_SYNCH_FRAME (0x0c) /* Standard Request : Synch Frame */
/* Status type codes used in SRQ_GET_STATUS request */
#define STATUS_DEVICE (0x80) /* Get Status: Device */
#define STATUS_INTERFACE (0x81) /* Get Status: Interface */
#define STATUS_ENDPOINT (0x82) /* Get Status: End Point */
/* Feature type codes used in SRQ_SET_FEATURE request */
#define FEATURE_DEVICE (0x00) /* Feature: Device */
#define FEATURE_ENDPOINT (0x02) /* Feature: End Point */
uint8_t usb_dev_address; /* default address is 0x00 TODO: Reset to zero when a reset condition is present on BUS (SE0 long duration) */
static uint8_t usb_dev_configuration;
static uint8_t usb_dev_alternatesetting;
static uint8_t usb_dev_Rwuen;
static uint8_t usb_dev_selfpwr;
void usbstack_init(void)
{
usb_dev_address = 0x00;
usb_dev_configuration = 0;
usb_dev_alternatesetting = 0;
usb_dev_Rwuen = 0;
usb_dev_selfpwr = 0;
}
bool usbstack_got_setup_cmd(const setupData_t *psetupdata)
{
uint8_t response[8];
uint16_t clen;
bool handled;
handled = true;
switch(psetupdata->bRequest)
{
case SRQ_SET_ADDRESS: /* This needs to be done within 50ms after receiving the setup packet! */
usb_control_acknowledge();
while (!usb_ep_in_buf_empty(0)); /* Wait until the complete setup transfer is finished, before setting the usb device address */
usb_dev_address = bitreverse(psetupdata->wValue);
/* set Address does not have an OUT stage */
break;
case SRQ_GET_DESCRIPTOR: // *** Get Descriptor
switch (psetupdata->wValue >> 8)
{
case DESCRIPTOR_DEVICE: // Device
clen = psetupdata->wLength;
if (clen > sizeof(device_descriptor)) clen = sizeof(device_descriptor);
usb_control_dataIn(device_descriptor, clen);
break;
case DESCRIPTOR_CONFIGURATION: // Configuration setupdat[2] contains configuration number
clen = psetupdata->wLength;
if (clen > sizeof(config_0_descriptor))
{
clen = sizeof(config_0_descriptor);
}
usb_control_dataIn(config_0_descriptor, clen); /* setupdat[2] specifies configurationnumber, currently fixed to 0 */
if (clen == 0x09)
{
volatile int i;
i++;
}
break;
case DESCRIPTOR_STRING: // String setupdat[2] contains string index
switch (psetupdata->wValue & 0xff)
{
case 0:
clen = psetupdata->wLength;
if (clen > sizeof(string_0_descriptor)) clen = sizeof(string_0_descriptor);
usb_control_dataIn(string_0_descriptor, clen);
break;
case 1:
clen = psetupdata->wLength;
if (clen > sizeof(string_1_descriptor)) clen = sizeof(string_1_descriptor);
usb_control_dataIn(string_1_descriptor, clen);
break;
case 2:
clen = psetupdata->wLength;
if (clen > sizeof(string_2_descriptor)) clen = sizeof(string_2_descriptor);
usb_control_dataIn(string_2_descriptor, clen);
break;
default:
usb_control_dataIn(response, 0);
break;
/* INFO: more/less string descriptors can be used. String descriptors are not mandatory! */
}
break;
#ifdef USB_ENABLE_HID
case DESCRIPTOR_REPORT:
clen = psetupdata->wLength;
if (clen > sizeof(hid_report_descriptor)) clen = sizeof(hid_report_descriptor);
usb_control_dataIn(hid_report_descriptor, clen);
break;
#endif
default:
usb_ep_stall(USB_EP0OUT);
usb_ep_stall(USB_EP0IN);
handled = false;
}
break;
case SRQ_GET_INTERFACE:
response[0] = usb_dev_alternatesetting;
usb_control_dataIn(response, 1);
break;
case SRQ_SET_INTERFACE:
usb_dev_alternatesetting = psetupdata->wValue;
usb_control_acknowledge();
break;
case SRQ_SET_CONFIGURATION:
usb_dev_configuration = psetupdata->wValue;
usb_control_acknowledge();
break;
case SRQ_GET_CONFIGURATION:
response[0] = usb_dev_configuration;
usb_control_dataIn(response, 1);
break;
case SRQ_GET_STATUS:
switch(psetupdata->bmRequestType)
{
case STATUS_DEVICE:
response[0] = (usb_dev_Rwuen << 1) | usb_dev_selfpwr;
response[1] = 0;
usb_control_dataIn(response, 2);
break;
case STATUS_INTERFACE:
response[0] = 0;
response[1] = 0;
usb_control_dataIn(response, 2);
break;
case STATUS_ENDPOINT:
response[0] = 0; /* TODO: return if endpoint is stalled */
response[1] = 0;
usb_control_dataIn(response, 2);
break;
default:
usb_ep_stall(USB_EP0OUT);
usb_ep_stall(USB_EP0IN);
handled = false;
}
break;
case SRQ_CLEAR_FEATURE:
switch(psetupdata->bmRequestType)
{
case FEATURE_DEVICE:
if(psetupdata->wValue == 1)
usb_dev_Rwuen = 0; /* Disable Remote Wakeup */
else
{
usb_ep_stall(USB_EP0OUT);
usb_ep_stall(USB_EP0IN);
}
usb_control_acknowledge();
break;
case FEATURE_ENDPOINT:
if ( (psetupdata->wValue & 0x0f) == 0 )
{
usb_ep_unstall(USB_EP0OUT);
usb_ep_unstall(USB_EP0IN);
}
else
{
usb_ep_unstall(USB_EP1OUT);
usb_ep_unstall(USB_EP1IN);
}
usb_control_acknowledge();
break;
}
break;
case SRQ_SET_FEATURE:
switch(psetupdata->bmRequestType)
{
case FEATURE_DEVICE:
if (psetupdata->wValue == 1)
usb_dev_Rwuen = 1; /* enable remote wakeup */
else
{
usb_ep_stall(USB_EP0OUT);
usb_ep_stall(USB_EP0IN);
}
break;
case FEATURE_ENDPOINT:
if ( (psetupdata->wValue & 0x0f) == 0 )
{
usb_ep_stall(USB_EP0OUT);
usb_ep_stall(USB_EP0IN);
}
else
{
usb_ep_stall(USB_EP1OUT);
usb_ep_stall(USB_EP1IN);
}
break;
}
break;
default:
usb_ep_stall(USB_EP0OUT);
usb_ep_stall(USB_EP0IN);
handled = false;
}
return handled;
}
@@ -0,0 +1,58 @@
/****************************************************************************
**
** Lemcusb - Firmware USB driver for EFM32 Microcontroller
** Copyright (C) 2014 http://lemcu.org
**
** This library is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 3.0 as
** published by the Free Software Foundation and appearing in the file
** LICENSE.txt included in the packaging of this file.
**
** In addition, as a special exception, http://lemcu.org gives you certain
** additional rights. These rights are described in the lemcu.org GPL
** Exception version 1.0, included in the file GPL_EXCEPTION.txt in this
** package.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef __USB_STACK_H__
#define __USB_STACK_H__
#include <stdint.h>
#include <stdbool.h>
#include "usb.h"
/* These defines can be used to mask out the bmRequestType bits */
#define USB_SETUP_BM_DIRECTION (0x80)
#define USB_SETUP_BM_TYPE (0x60)
#define USB_SETUP_BM_RECIPIENT (0x1f)
#define USB_SETUP_DIR_DEV_TO_HOST (0x80)
#define USB_SETUP_TYPE_STANDARD (0 << 5)
#define USB_SETUP_TYPE_CLASS (1 << 5)
#define USB_SETUP_TYPE_VENDOR (2 << 5)
#define USB_SETUP_DEVICE (0x00)
#define USB_SETUP_INTERFACE (0x01)
#define USB_SETUP_ENDPOINT (0x02)
#define USB_SETUP_OTHER (0x03)
void usbstack_init(void);
/* call this function when setup data was received
TODO: allow user to call this also, when no setup data was received.
I think the best way is to let the user only call functions from this file and not from usb.h */
bool usbstack_got_setup_cmd(const setupData_t *psetupdata);
#endif
@@ -0,0 +1,83 @@
/*****************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file pmc.c
* @brief 电源管理模块(PMC)函数库
* @author Navota
* @date 2018-3-1
*****************************************************************************/
#include "common.h"
#include "pmc.h"
/*****************************************************************************//*!
*
* @brief PMC模块初始化函数
*
* @param[in] pPMC_Config PMC 配置结构体.
* @param[in] pPMC PMC
*
* @return none.
*
*****************************************************************************/
void PMC_Init(PMC_Type *pPMC, PMC_ConfigType *pPMC_Config)
{
pPMC->SPMSC1 = pPMC_Config->sCtrlstatus.byte;
pPMC->SPMSC2 = pPMC_Config->sDetectVoltSelect.byte;
if(pPMC_Config->sCtrlstatus.bits.bLvwIrqEn)
NVIC_EnableIRQ(LVD_LVW_IRQn);
}
/*****************************************************************************//*!
*
* @brief 复位PMC模块.
*
* @param[in] pPMC PMC
*
* @return none.
*
*****************************************************************************/
void PMC_DeInit(PMC_Type *pPMC)
{
pPMC->SPMSC1 = 0x1C;
pPMC->SPMSC2 = 0;
}
/*****************************************************************************//*!
*
* @brief MCU工作模式选择函数
*
* @param[in] u8PmcMode 选择MCU工作模式.
* @param[in] pPMC PMC
*
* @return none.
*
*****************************************************************************/
void PMC_SetMode(PMC_Type *pPMC,uint8_t u8PmcMode)
{
switch(u8PmcMode & 0x3)
{
case PmcModeRun:
break;
case PmcModeWait: //等待模式
wait();
break;
case PmcModeStop4:
/* 停止模式下,使能低压检测*/
pPMC->SPMSC1 |= (PMC_SPMSC1_LVDE_MASK | PMC_SPMSC1_LVDSE_MASK);
stop();
break;
case PmcModeStop3:
/* 在停止模式下,禁用低压检测*/
pPMC->SPMSC1 &= ~(PMC_SPMSC1_LVDE_MASK | PMC_SPMSC1_LVDRE_MASK | PMC_SPMSC1_LVDSE_MASK);
stop();
break;
default:
break;
}
}
@@ -0,0 +1,298 @@
/******************************************************************************
*
* @brief PMC 驱动头文件.
*
******************************************************************************/
#ifndef PMC_H_
#define PMC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
/******************************************************************************
* PCM系统(MCU工作模式)模式定义
*
*******************************************************************************/
#define PmcModeRun 0 /*!< 运行模式 */
#define PmcModeWait 1 /*!< 等到模式 */
#define PmcModeStop4 2 /*!< 停止模式4 */
#define PmcModeStop3 3 /*!< 停止模式3 */
/******************************************************************************
* PMC 低压检测和低压报警电压定义
*
*******************************************************************************/
#define PmcLVDTrip_Low 0 /*!< LVD 低电平调变点 */
#define PmcLVDTrip_High 1 /*!< LVD 高电平调变点 */
#define PmcLVWTrip_Low 0 /*!< LVW 低电平跳变点 */
#define PmcLVWTrip_Mid1 1 /*!< LVW 中间电平1跳变点 */
#define PmcLVWTrip_Mid2 2 /*!< LVW 中间电平2跳变点*/
#define PmcLVWTrip_High 3 /*!< LVW 高电平跳变点*/
/******************************************************************************
* PMC 控制结构体
*******************************************************************************/
/*!
* @brief PMC控制结构体类型
*
*/
typedef union
{
uint8_t byte; /*!< 联合体的类型-字节*/
struct
{
uint8_t bBandgapEn :1; /*!< 使能带隙缓冲区 */
uint8_t bBandgapDrv :1; /*!< 选择带隙驱动*/
uint8_t bLvdEn :1; /*!< 使能低压检测*/
uint8_t bLvdStopEn :1; /*!< 低压检测在停止模式下使能*/
uint8_t bLvdRstEn :1; /*!< 使能低压检测复位 */
uint8_t bLvwIrqEn :1; /*!< 使能低压报警中断 */
uint8_t bLvwAck :1; /*!< 低压报警应答 */
uint8_t bLvwFlag :1; /*!< 低压报警标志 */
}bits; /*!< 联合体类型-位 */
}PMC_Ctrl1Type, *PMC_Ctrl1Ptr; /*!< PMC 控制寄存器1结构体 */
/******************************************************************************
* PMC 控制-- 低压选择.
*******************************************************************************/
/*!
* @brief PMC 控制-- 电压类型选择.
*
*/
typedef union
{
uint8_t byte; /*!< 联合体类型-字节 */
struct
{
uint8_t :4; /*!< none */
uint8_t bLVWV :2; /*!< 低压报警电压选择 */
uint8_t bLVDV :1; /*!< 低压复位电压选择 */
uint8_t :1; /*!< none */
}bits; /*!< 结构体类型——位 */
}PMC_Ctrl2Type, *PMC_Ctrl2Ptr; /*!< PMC 控制寄存器2结构体*/
/******************************************************************************
* PMC 配置结构体
*******************************************************************************/
typedef struct
{
PMC_Ctrl1Type sCtrlstatus; /*!< PMC 控制和状态 */
PMC_Ctrl2Type sDetectVoltSelect; /*!< 低压报警电压和低压复位电压选择*/
}PMC_ConfigType, *PMC_ConfigPtr; /*!< PMC 配置结构体 */
/*****************************************************************************//*!
*
* @brief 在停止模式下使能低压检测.
*
* @param[in] pPMC 指向PMC模块
*
* @return none.
*
* @see PMC_DisableLVDInStopMode.
*
*****************************************************************************/
__STATIC_INLINE void PMC_EnableLVDInStopMode(PMC_Type *pPMC)
{
pPMC->SPMSC1 |= PMC_SPMSC1_LVDSE_MASK;
}
/*****************************************************************************//*!
*
* @brief 在停止模式下禁用低压检测
*
* @param[in] pPMC 指向PMC模块
*
* @return none.
*
* @see PMC_EnableLVDInStopMode.
*
*****************************************************************************/
__STATIC_INLINE void PMC_DisableLVDInStopMode(PMC_Type *pPMC)
{
pPMC->SPMSC1 &= ~PMC_SPMSC1_LVDSE_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能低压检测复位 注: 复位后该字段仅可写一次
*
* @param[in] pPMC 指向PMC模块.
*
* @return none.
*
* @see PMC_DisableLVDRst.
*
*****************************************************************************/
__STATIC_INLINE void PMC_EnableLVDRst(PMC_Type *pPMC)
{
pPMC->SPMSC1 |= PMC_SPMSC1_LVDRE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用低压检测复位 注: 复位后该字段仅可写一次
*
* @param[in] pPMC 指向PMC模块
*
* @return none.
*
* @see PMC_EnableLVDRst.
*
*****************************************************************************/
__STATIC_INLINE void PMC_DisableLVDRst(PMC_Type *pPMC)
{
pPMC->SPMSC1 &= ~PMC_SPMSC1_LVDRE_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能低压检测, 注: 复位后该字段仅可写一次
*
* @param[in] pPMC 指向PMC模块
*
* @return none.
*
* @see PMC_DisableLVD.
*
*****************************************************************************/
__STATIC_INLINE void PMC_EnableLVD(PMC_Type *pPMC)
{
pPMC->SPMSC1 |= PMC_SPMSC1_LVDE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用低压检测, 注: 复位后该字段仅可写一次
*
* @param[in] pPMC 指向PMC模块
*
* @return none.
*
* @see PMC_EnableLVD.
*
*****************************************************************************/
__STATIC_INLINE void PMC_DisableLVD(PMC_Type *pPMC)
{
pPMC->SPMSC1 &= ~PMC_SPMSC1_LVDE_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置低压检测跳变点,
*
* @param[in] pPMC 指向PMC模块
* @param[in] Trippoint 电压检测跳变点选择,1-高电平跳变 0-低电平跳变
*
* @return none.
*
* @see PMC_SetLVWTripVolt.
*
*****************************************************************************/
__STATIC_INLINE void PMC_SetLVDTripVolt(PMC_Type *pPMC, uint8_t Trippoint)
{
if(Trippoint)
pPMC->SPMSC2 |= PMC_SPMSC2_LVDV_MASK;
else
pPMC->SPMSC2 &= ~PMC_SPMSC2_LVDV_MASK;
}
/*****************************************************************************//*!
*
* @brief 选择电压报警跳变点电压
*
* @param[in] pPMC 指向PMC模块
* @param[in] Trippoint 低压报警跳变点电压 0 低电平跳变 1 中间电平1跳变
* 2 中间电平2跳变 3 高电平跳变
*
* @return none.
*
* @see PMC_SetLVDTripVolt.
*
*****************************************************************************/
__STATIC_INLINE void PMC_SetLVWTripVolt(PMC_Type *pPMC, uint8_t Trippoint)
{
pPMC->SPMSC2 &= ~PMC_SPMSC2_LVWV_MASK;
pPMC->SPMSC2 |= PMC_SPMSC2_LVWV(Trippoint);
}
/*****************************************************************************//*!
*
* @brief 使能低压报警中断
*
* @param[in] pPMC 指向PMC模块
*
* @return none.
*
* @see PMC_DisableLVWInterrupt.
*
*****************************************************************************/
__STATIC_INLINE void PMC_EnableLVWInterrupt(PMC_Type *pPMC)
{
pPMC->SPMSC1 |= PMC_SPMSC1_LVWIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用低压报警中断
*
* @param[in] pPMC 指向PMC模块.
*
* @return none.
*
*
* @see PMC_EnableLVWInterrupt.
*
*****************************************************************************/
__STATIC_INLINE void PMC_DisableLVWInterrupt(PMC_Type *pPMC)
{
pPMC->SPMSC1 &= ~PMC_SPMSC1_LVWIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 读取低压报警标志位.
*
* @param[in] pPMC 指向PMC模块.
*
* @return 低压报警标志位值
*
* @see PMC_ClrLVWFlag.
*
*****************************************************************************/
__STATIC_INLINE uint8_t PMC_GetLVWFlag(PMC_Type *pPMC)
{
return (pPMC->SPMSC1 & PMC_SPMSC1_LVWF_MASK);
}
/*****************************************************************************//*!
*
* @brief 清除低压报警标志位
*
* @param[in] pPMC 指向PMC模块.
*
* @return none.
*
* @see PMC_GetLVWFlag.
*
*****************************************************************************/
__STATIC_INLINE void PMC_ClrLVWFlag(PMC_Type *pPMC)
{
pPMC->SPMSC1 |= PMC_SPMSC1_LVWACK_MASK;
}
/**************************************************************************/
void PMC_Init(PMC_Type *pPMC, PMC_ConfigType *pPMC_Config);
void PMC_DeInit(PMC_Type *pPMC);
void PMC_SetMode(PMC_Type *pPMC,uint8_t u8PmcMode);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,169 @@
/**************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file acmp.c
* @brief 模拟比较器(ACMP)函数库
* @author Navota
* @date 2018-3-1
****************************************************************************/
#include "common.h"
#include "acmp.h"
/****************************************************************************!
* @ 存放ACMP回调函数接口
****************************************************************************/
ACMP_CallbackPtr ACMP_Callback[2] = {(ACMP_CallbackPtr)NULL};
/**************************************************************************/
void ACMP0_Isr(void);
void ACMP1_Isr(void);
/*****************************************************************************//*!
*
* @brief 初始化ACMP模块
*
* @param pACMPx 指向ACMP寄存器基址
* @param pConfig 控制参数
*
* @return none.
*
* @see ACMP_DeInit.
*
*****************************************************************************/
void ACMP_Init(ACMP_Type *pACMPx, ACMP_ConfigType *pConfig)
{
if(ACMP0 == pACMPx)
{
/* 使能ACMP模块的总线时钟 */
SIM->SCGC |= SIM_SCGC_ACMP0_MASK;
/* 使能ACMP中断 */
if(pConfig->sCtrlStatus.bits.bIntEn)
NVIC_EnableIRQ(ACMP0_IRQn);
}
else
{
SIM->SCGC |= SIM_SCGC_ACMP1_MASK;
if(pConfig->sCtrlStatus.bits.bIntEn)
NVIC_EnableIRQ(ACMP1_IRQn);
}
/*选择ACMP正输入和负输入,正输入和负输入引脚不同*/
pACMPx->C0 = pConfig->sPinSelect.byte;
ACMP_ConfigDAC(pACMPx, &pConfig->sDacSet );
//pACMPx->C1 = pConfig->sDacSet.byte;
pACMPx->C2 = pConfig->sPinEnable.byte;
pACMPx->CS = pConfig->sCtrlStatus.byte;
}
/*****************************************************************************//*!
*
* @brief 配置ACMP控制寄存器1.
*
* @param pACMPx 指向ACMP模块寄存器基地址
* @param pDACConfig 指向 ACMP DAC 控制结构体.
*
* @return none.
*
*****************************************************************************/
void ACMP_ConfigDAC(ACMP_Type *pACMPx, ACMP_DACType *pDACConfig)
{
pACMPx->C1 = pDACConfig->byte;
}
/*****************************************************************************//*!
*
* @brief 复位ACMP模块.
*
* @param pACMPx 指向ACMP模块寄存器基地址
*
* @return none.
*
* @see ACMP_Init.
*
*****************************************************************************/
void ACMP_DeInit(ACMP_Type *pACMPx)
{
if(ACMP0 == pACMPx)
{
if(pACMPx->CS & ACMP_CS_ACIE_MASK)
NVIC_DisableIRQ(ACMP0_IRQn);
}
else
{
if(pACMPx->CS & ACMP_CS_ACIE_MASK)
NVIC_DisableIRQ(ACMP1_IRQn);
}
pACMPx->CS = 0;
pACMPx->C0 = 0;
pACMPx->C1 = 0;
pACMPx->C2 = 0;
if(ACMP0 == pACMPx)
{
SIM->SCGC &= ~SIM_SCGC_ACMP0_MASK;
}
else
{
SIM->SCGC &= ~SIM_SCGC_ACMP1_MASK;
}
}
/*****************************************************************************//*!
*
* @brief 设置ACMP回调函数,通过中断服务函数调用回调函数.
*
* @param pACMPx 指向ACMP模块寄存器基地址.
* @param pfnCallback 回调函数.
*
* @return none.
*
*
*****************************************************************************/
void ACMP_SetCallback(ACMP_Type *pACMPx, ACMP_CallbackPtr pfnCallback)
{
if(ACMP0 == pACMPx)
{
ACMP_Callback[0] = pfnCallback;
}
else
{
ACMP_Callback[1] = pfnCallback;
}
}
/*****************************************************************************//*!
*
* @brief ACMP0 中断服务函数.
*
* @param none.
*
* @return none.
*
*****************************************************************************/
void ACMP0_Isr(void)
{
if(ACMP_Callback[0])
{
ACMP_Callback[0](); /*调用回调函数*/
}
}
/*****************************************************************************//*!
*
* @brief ACMP1 中断服务函数
*
* @param none.
*
* @return none.
*
*****************************************************************************/
void ACMP1_Isr(void)
{
if(ACMP_Callback[1])
{
ACMP_Callback[1](); /* 调用回调函数*/
}
}
@@ -0,0 +1,455 @@
/******************************************************************************
*
* @brief ACMP 驱动头文件.
*
******************************************************************************/
#ifndef _MY_ACMP_H_
#define _MY_ACMP_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
/* 选择DAC基准 */
enum
{
DAC_REF_BANDGAP = 0,
DAC_REF_VDDA
};
/******************************************************************************
* ACMP 模块数定义
******************************************************************************/
#define MAX_ACMP_NO 2
/*******************************************************************************
*
* 定义ACMP 正输入和负输入引脚
*
*******************************************************************************/
#define ACMP_INPUT_P_EXT0 (0<<4) /*!< ACMP正输入选择外部基准0 */
#define ACMP_INPUT_P_EXT1 (1<<4) /*!< ACMP正输入选择外部基准1 */
#define ACMP_INPUT_P_EXT2 (2<<4) /*!< ACMP正输入选择外部基准2 */
#define ACMP_INPUT_P_DAC (3<<4) /*!< ACMP正输入选择DAC输出 */
#define ACMP_INPUT_N_EXT0 0 /*!< ACMP负输入选择外部基准0 */
#define ACMP_INPUT_N_EXT1 1 /*!< ACMP负输入选择外部基准1 */
#define ACMP_INPUT_N_EXT2 2 /*!< ACMP负输入选择外部基准2 */
#define ACMP_INPUT_N_DAC 3 /*!< ACMP负输入选择DAC输出 */
/******************************************************************************
*
* 定义ACMP中断触发器的触发模式
*
*******************************************************************************/
#define ACMP_SENSITIVITYMODE_FALLING 0 /*!< ACMP中断在输出下降沿发生 */
#define ACMP_SENSITIVITYMODE_RISING 1 /*!< ACMP中断在输出上升沿发生 */
#define ACMP_SENSITIVITYMODE_ANY 3 /*!< ACMP中断在输出上升沿或下降沿触发 */
/******************************************************************************
*
* 定义ACMP 迟滞
*
*******************************************************************************/
#define ACMP_HYST_20MV (0<<6) /*!< 20mv */
#define ACMP_HYST_30MV (1<<6) /*!< 30mv */
/******************************************************************************
*
* 定义内部DAC参考基准
*
*******************************************************************************/
#define ACMP_DAC_REFERENCE_BANDGAP (0<<6) /*!< 选择带隙为基准 */
#define ACMP_DAC_REFERENCE_VDDA (1<<6) /*!< 选择VDDA为基准 */
/******************************************************************************
*
* ACMP回调函数声明
*
******************************************************************************/
typedef void (*ACMP_CallbackPtr)(void);
/******************************************************************************
*
* ACMP 控制和状态字寄存器结构体
*
*******************************************************************************/
typedef union
{
uint8_t byte; /*!<联合体类型-字节*/
struct
{
uint8_t bMod : 2; /*!< 中断触发模式 */
uint8_t bOutEn : 1; /*!< ACMP输出置于外部引脚 */
uint8_t bOutState : 1; /*!< 模拟比较强输出的当前值 */
uint8_t bIntEn : 1; /*!< 使能ACMP中断 */
uint8_t bIntFlag : 1; /*!< ACMP 中断标志位 */
uint8_t bHyst : 1; /*!< 选择ACMP迟滞 */
uint8_t bEn : 1; /*!< 使能ACMP模块 */
}bits; /*!< 联合体类型-位域 */
}ACMP_CtrlStatusType, *ACMP_CtrlStatusPtr; /*!< ACMP 控制和状态寄存器结构*/
/******************************************************************************
*
* ACMP 外部输入引脚控制结构体
*
*******************************************************************************/
typedef union
{
uint8_t byte; /*!<联合体类型-字节*/
struct
{
uint8_t bNegPin : 2; /*!< 负输入选择*/
uint8_t : 2;
uint8_t bPosPin : 2; /*!< 正输入选择 */
uint8_t : 2;
}bits; /*!< 联合体类型-位域 */
}ACMP_PinSelType, *ACMP_PinSelPtr; /*!< ACMP 输入选择结构体 */
/******************************************************************************
*
* ACMP 内部DAC控制结构体
*
*******************************************************************************/
typedef union
{
uint8_t byte; /*!<联合体类型-字节*/
struct
{
uint8_t bVal : 6; /*!< DAC输出电平选择*/
uint8_t bRef : 1; /*!< DAC基准选择 */
uint8_t bEn : 1; /*!< DAC使能 */
}bits; /*!< 联合体类型-位域 */
}ACMP_DACType, *ACMP_DACPtr; /*!< ACMP DAC 控制结构体 */
/******************************************************************************
*
* ACMP 外部输入引脚使能控制结构体
*
*******************************************************************************/
typedef union
{
uint8_t byte; /*!<联合体类型-字节*/
struct
{
uint8_t bEn : 3; /*!< ACMP 外部输入引脚使能 */
uint8_t bRsvd : 5;
}bits; /*!< 联合体类型-位域 */
}ACMP_PinEnType, *ACMP_PinEnPtr; /*!< ACMP 引脚使能结构体 */
/******************************************************************************
*
* ACMP 模块配置结构体
*
*******************************************************************************/
typedef struct
{
ACMP_CtrlStatusType sCtrlStatus; /*!< ACMP 控制和状体 */
ACMP_PinSelType sPinSelect; /*!< ACMP 输入选择 */
ACMP_DACType sDacSet; /*!< ACMP 内部DAC控制 */
ACMP_PinEnType sPinEnable; /*!< ACMP 外部输入引脚使能控制 */
}ACMP_ConfigType, *ACMP_ConfigPtr;
/*****************************************************************************//*!
*
* @brief 使能ACMP模块
*
* @param[in] pACMPx 指向ACMP模块
*
* @return none.
*
* @see ACMP_Disable.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_Enable(ACMP_Type *pACMPx)
{
pACMPx->CS |= ACMP_CS_ACE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用ACMP模块
*
* @param[in] pACMPx 指向ACMP模块
*
* @return none.
*
* @see ACMP_Enable.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_Disable(ACMP_Type *pACMPx)
{
pACMPx->CS &= ~ACMP_CS_ACE_MASK;
}
/*****************************************************************************//*!
*
* @brief 选择ACMP中断触发器的触发模式.
*
* @param[in] pACMPx 指向ACMP模块
* @param[in] u8EdgeSelect 上升沿或下降沿选择, 0~3.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_SelectIntMode(ACMP_Type *pACMPx, uint8_t u8EdgeSelect)
{
pACMPx->CS &= ~ACMP_CS_ACMOD_MASK;
pACMPx->CS |= ACMP_CS_ACMOD(u8EdgeSelect & 0x3);
}
/*****************************************************************************//*!
*
* @brief 使能ACMP输出置于外部引脚上
*
* @param[in] pACMPx 指向ACMP模块
*
* @return none.
*
* @see ACMP_DisablePinOut.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_EnablePinOut(ACMP_Type *pACMPx)
{
pACMPx->CS |= ACMP_CS_ACOPE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用ACMP输出置于外部引脚上
*
* @param[in] pACMPx 指向ACMP模块
*
* @return none.
*
* @see ACMP_EnablePinOut.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_DisablePinOut(ACMP_Type *pACMPx)
{
pACMPx->CS &= ~ACMP_CS_ACOPE_MASK;
}
/*****************************************************************************//*!
*
* @brief 选择ACMP迟滞
*
* @param[in] pACMPx 指向ACMP模块.
* @param[in] u8HystSelect 2mv or 30mv.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_SelectHyst(ACMP_Type *pACMPx, uint8_t u8HystSelect)
{
pACMPx->CS &= ~ACMP_CS_HYST_MASK;
pACMPx->CS |= u8HystSelect;
}
/*****************************************************************************//*!
*
* @brief 使能ACMP模块中断
*
* @param[in] pACMPx 指向ACMP模块.
*
* @return none.
*
*
* @see ACMP_DisableInterrupt.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_EnableInterrupt(ACMP_Type *pACMPx)
{
pACMPx->CS |= ACMP_CS_ACIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用ACMP模块中断
*
* @param[in] pACMPx 指向ACMP模块
*
* @return none.
*
* @see ACMP_EnableInterrupt.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_DisableInterrupt(ACMP_Type *pACMPx)
{
pACMPx->CS &= ~ACMP_CS_ACIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 读取中断标志位
*
* @param[in] pACMPx 指向ACMP模块.
*
* @return none.
*
* @see ACMP_ClrFlag.
*
*****************************************************************************/
__STATIC_INLINE uint8_t ACMP_GetFlag(ACMP_Type *pACMPx)
{
return (pACMPx->CS & ACMP_CS_ACF_MASK);
}
/*****************************************************************************//*!
*
* @brief 清除中断标志位
*
* @param[in] pACMPx 指向ACMP模块
*
* @return none.
*
* @see ACMP_GetFlag.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_ClrFlag(ACMP_Type *pACMPx)
{
pACMPx->CS &= ~ACMP_CS_ACF_MASK;
}
/*****************************************************************************//*!
*
* @brief ACMP正输入选择
*
* @param[in] pACMPx 指向ACMP模块
* @param[in] u8PosPinSel 正输入选择, 外部基准0~2 或DAC输出.
*
* @return none.
*
* @see ACMP_NegativeInputSelect.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_PositiveInputSelect(ACMP_Type *pACMPx, uint8_t u8PosPinSel)
{
pACMPx->C0 &= ~ACMP_C0_ACPSEL_MASK;
pACMPx->C0 |= u8PosPinSel;
}
/*****************************************************************************//*!
*
* @brief ACMP负输入选择.
*
* @param[in] pACMPx 指向ACMP模块
* @param[in] u8NegPinSel 负输入选择, 外部基准0~2 或DAC输出.
*
* @return none.
*
* @see ACMP_PositiveInputSelect.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_NegativeInputSelect(ACMP_Type *pACMPx, uint8_t u8NegPinSel)
{
pACMPx->C0 &= ~ACMP_C0_ACNSEL_MASK;
pACMPx->C0 |= u8NegPinSel;
}
/*****************************************************************************//*!
*
* @brief 使能内部DAC
*
* @param[in] pACMPx 指向ACMP模块
*
* @return none.
*
* @see ACMP_DacDisable.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_DacEnable(ACMP_Type *pACMPx)
{
pACMPx->C1 |= ACMP_C1_DACEN_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用内部DAC
*
* @param[in] pACMPx 指向ACMP模块.
*
* @return none.
*
* @see ACMP_DacEnable.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_DacDisable(ACMP_Type *pACMPx)
{
pACMPx->C1 &= ~ACMP_C1_DACEN_MASK;
}
/*****************************************************************************//*!
*
* @brief DAC基准选择
*
* @param[in] pACMPx 指向ACMP模块.
* @param[in] u8RefSelect DAC参考选择: 带隙 or VDDA.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_DacReferenceSelect(ACMP_Type *pACMPx, uint8_t u8RefSelect)
{
pACMPx->C1 &= ~ACMP_C1_DACREF_MASK;
pACMPx->C1 |= u8RefSelect;
}
/*****************************************************************************//*!
*
* @brief DAC输出电平选择
*
* @param[in] pACMPx 指向ACMP模块.
* @param[in] u8DacValue DAC输出选择, Voutput= (Vin/64)x(DACVAL[5:0]+1).
*
* @return none.
*
*
*****************************************************************************/
__STATIC_INLINE void ACMP_DacOutputSet(ACMP_Type *pACMPx, uint8_t u8DacValue)
{
ASSERT(!(u8DacValue & (~ACMP_C1_DACVAL_MASK)));
pACMPx->C1 &= ~ACMP_C1_DACVAL_MASK;
pACMPx->C1 |= ACMP_C1_DACVAL(u8DacValue);
}
/*****************************************************************************//*!
*
* @brief 使能ACMP外部输入引脚.
*
* @param[in] pACMPx 指向ACMP模块.
* @param[in] u8InputPin ACMP 外部输入引脚, 0~2.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_InputPinEnable(ACMP_Type *pACMPx, uint8_t u8InputPin)
{
ASSERT(!(u8InputPin & (~ACMP_C2_ACIPE_MASK)));
pACMPx->C2 |= ACMP_C2_ACIPE(u8InputPin);
}
/*****************************************************************************//*!
*
* @brief 禁用ACMP外部输入引脚.
*
* @param[in] pACMPx 指向ACMP模块.
* @param[in] u8InputPin ACMP 外部输入引脚, 0~2.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void ACMP_InputPinDisable(ACMP_Type *pACMPx, uint8_t u8InputPin)
{
ASSERT(!(u8InputPin & (~ACMP_C2_ACIPE_MASK)));
pACMPx->C2 &= ~ACMP_C2_ACIPE(u8InputPin);
}
/******************************************************************************/
void ACMP_Init(ACMP_Type *pACMPx, ACMP_ConfigType *pConfig);
void ACMP_DeInit(ACMP_Type *pACMPx);
void ACMP_ConfigDAC(ACMP_Type *pACMPx, ACMP_DACType *pDACConfig);
void ACMP_SetCallback(ACMP_Type *pACMPx, ACMP_CallbackPtr pfnCallback);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,256 @@
/**************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file adc.c
* @brief 数模转换模块(ADC)库函数
* @author Navota
* @date 2018-3-1
****************************************************************************/
#include "common.h"
#include "adc.h"
/****************************************************************************!
* @ 存放ACMP回调函数接口
****************************************************************************/
ADC_CallbackType ADC_Callback[1] = {NULL};
/*****************************************************************************//**
*
* @brief 初始化ADC模块.
*
* @param[in] pADC 指向ADC模块类型.
* @param[in] pADC_Config 指向ADC模块配置结构体
*
* @return none
*
*****************************************************************************/
void ADC_Init(ADC_Type *pADC, ADC_ConfigTypePtr pADC_Config)
{
if( pADC == ADC)
{
SIM->SCGC |= SIM_SCGC_ADC_MASK;
}
/* 选择ADC模块时钟源 */
ADC_SelectClock(pADC,pADC_Config->u8ClockSource);
/* 设定时钟分频 */
ADC_SelectClockDivide(pADC,pADC_Config->u8ClockDiv);
/* 设置ADC转换模式 */
ADC_SetMode(pADC,pADC_Config->u8Mode);
/* 设置FIFO深度 */
ADC_SetFifoLevel(pADC,pADC_Config->u8FiFoLevel);
/* ADC输入引脚控制 */
pADC->APCTL1 = pADC_Config->u16PinControl;
if( pADC_Config->sSetting.bCompareEn )
{
ADC_CompareEnable(pADC); //使能ADC比较功能
}
if( pADC_Config->sSetting.bCompareGreaterEn )
{
ADC_CompareGreaterFunction(pADC); //输入大于或等于比较电平时比较触发
}
if( pADC_Config->sSetting.bContinuousEn )
{
ADC_ContinuousConversion(pADC); // 使能ADC连续转换.
}
if( pADC_Config->sSetting.bCompareAndEn )
{
ADC_CompareFifoAnd(pADC); //对所有比较触发做与运算
}
if( pADC_Config->sSetting.bFiFoScanModeEn )
{
ADC_FifoScanModeEnable(pADC); //使能FIFO扫描模式
}
if( pADC_Config->sSetting.bHardwareTriggerEn )
{
ADC_SetHardwareTrigger(pADC); // 设置ADC硬件触发.
}
if( pADC_Config->sSetting.bIntEn ) //使能中断
{
ADC_IntEnable(pADC);
NVIC_EnableIRQ( ADC0_IRQn );
}
if( pADC_Config->sSetting.bLongSampleEn )
{
ADC_SetLongSample(pADC); // 设置ADC长采样.
}
if( pADC_Config->sSetting.bLowPowerEn )
{
ADC_SetLowPower(pADC); // 设置ADC为低功耗模式
}
}
/*****************************************************************************//*!
*
* @brief 禁用ADC模块
*
* @param[in] pADC 指向ADC模块类型
*
* @return none.
*
*****************************************************************************/
void ADC_DeInit( ADC_Type *pADC )
{
ADC_SetChannel(pADC,ADC_CHANNEL_DISABLE);
SIM->SCGC &= ~SIM_SCGC_ADC_MASK;
}
/*****************************************************************************//*!
*
* @brief 开始转换和读取转换结果
*
* @param[in] pADC 指向ADC模块
* @param[in] u8Channel ADC转换通道
*
* @return ADC 转换结果.
*
*****************************************************************************/
unsigned int ADC_PollRead( ADC_Type *pADC, uint8_t u8Channel )
{
ADC_SetChannel(pADC,u8Channel);
while( !ADC_IsCOCOFlag(pADC) )
{
;
}
return ADC_ReadResultReg(pADC);
}
/*****************************************************************************//*!
*
* @brief 注册 ADC 回调函数,通过中断服务函数调用
*
* @param[in] pADC_CallBack 指向ADC回调函数地址.
*
* @return none.
*
*****************************************************************************/
void ADC_SetCallBack(ADC_CallbackType pADC_CallBack)
{
ADC_Callback[0] = pADC_CallBack;
}
/*****************************************************************************//*!
*
* @brief 选择ADC输入通道.
*
* @param[in] pADC 指向ADC模块.
* @param[in] u8Channel ADC转换通道
*
* @return none
*
*****************************************************************************/
void ADC_SetChannel( ADC_Type *pADC, uint8_t u8Channel )
{
uint32_t u32temp;
u32temp = pADC->SC1;
u32temp &= ~ADC_SC1_ADCH_MASK;
pADC->SC1 = u32temp|ADC_SC1_ADCH(u8Channel);
}
/*****************************************************************************//*!
*
* @brief 选择ADC基准电压.
*
* @param[in] pADC 指向ADC模块
* @param[in] u8Vref 选择ADC基准电压.
*
* @return none
*
*****************************************************************************/
void ADC_VrefSelect( ADC_Type *pADC, uint8_t u8Vref )
{
uint32_t u32Temp;
u32Temp = pADC->SC2;
u32Temp &= ~ADC_SC2_REFSEL_MASK;
pADC->SC2 = u32Temp|ADC_SC2_REFSEL(u8Vref);
}
/*****************************************************************************//*!
*
* @brief 设置ADC时钟源分频
*
* @param[in] pADC 指向ADC模块.
* @param[in] u8Div 选择分频系数.
*
* @return none
*
*****************************************************************************/
void ADC_SelectClockDivide( ADC_Type *pADC, uint8_t u8Div )
{
uint32_t u32Temp;
u32Temp = pADC->SC3;
u32Temp &= ~ADC_SC3_ADIV_MASK;
pADC->SC3 = u32Temp|ADC_SC3_ADIV(u8Div);
}
/*****************************************************************************//*!
*
* @brief 设置ADC转换模式
*
* @param[in] pADC 指向ADC模块
* @param[in] u8Mode 选择ADC转换参数.
*
* @return none
*
*****************************************************************************/
void ADC_SetMode( ADC_Type *pADC, uint8_t u8Mode )
{
uint32_t u32Temp;
u32Temp = pADC->SC3;
u32Temp &= ~ADC_SC3_MODE_MASK;
pADC->SC3 = u32Temp|ADC_SC3_MODE(u8Mode);
}
/*****************************************************************************//*!
*
* @brief 设置ADC输入时钟.
*
* @param[in] pADC 指向ADC模块
* @param[in] u8Clock 选择输入时钟源.
*
* @return none
*
*****************************************************************************/
void ADC_SelectClock( ADC_Type *pADC, uint8_t u8Clock )
{
uint32_t u32Temp;
u32Temp = pADC->SC3;
u32Temp &= ~ADC_SC3_ADICLK_MASK;
pADC->SC3 = u32Temp|ADC_SC3_ADICLK(u8Clock);
}
/*****************************************************************************//*!
*
* @brief 设置FIFO深度
*
* @param[in] pADC 指向ADC模块.
* @param[in] u8FifoLevel 选择FIFO深度.
*
* @return none
*
*****************************************************************************/
void ADC_SetFifoLevel( ADC_Type *pADC, uint8_t u8FifoLevel )
{
uint32_t u32Temp;
u32Temp = pADC->SC4;
u32Temp &= ~ADC_SC4_AFDEP_MASK;
pADC->SC4 = u32Temp|ADC_SC4_AFDEP(u8FifoLevel);
}
/*****************************************************************************//*!
*
* @brief ADC 中断服务函数.
*
* @param none.
*
* @return none.
*
*****************************************************************************/
void ADC_Isr(void)
{
if( ADC_Callback[0] )
{
ADC_Callback[0]();
}
}
@@ -0,0 +1,655 @@
/******************************************************************************
*
* @brief ADC 驱动头文件.
*
******************************************************************************/
#ifndef ADC_H_
#define ADC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
/******************************************************************************
*
*定义ADC参考电压
*
*******************************************************************************/
#define ADC_VREF_VREFH 0x00 /*!< ADC 参考电压 VREFH*/
#define ADC_VREF_VDDA 0x01 /*!< ADC 参考电压 VDDA*/
/******************************************************************************
*
* 定义ADC时钟源
*
*******************************************************************************/
#define CLOCK_SOURCE_BUS_CLOCK 0x00 /*!< ADC时钟源选择总线时钟*/
#define CLOCK_SOURCE_BUS_CLOCK_DIVIDE_2 0x01 /*!< ADC时钟源选择总线时钟2分频*/
#define CLOCK_SOURCE_ALTCLK 0x02 /*!< ADC时钟源选择备用时钟*/
#define CLOCK_SOURCE_ADACK 0x03 /*!< ADC时钟源选择异步时钟*/
/******************************************************************************
*
* 定义ADC源分频系数
*
*******************************************************************************/
#define ADC_ADIV_DIVIDE_1 0x00 /*!< ADC时钟源分频系数为1*/
#define ADC_ADIV_DIVIDE_2 0x01 /*!< ADC时钟源分频系数为2*/
#define ADC_ADIV_DIVIDE_4 0x02 /*!< ADC时钟源分频系数为4*/
#define ADC_ADIV_DIVIDE_8 0x03 /*!< ADC时钟源分频系数为8*/
/******************************************************************************
*
* 定义ADC转换模式
*
*******************************************************************************/
#define ADC_MODE_8BIT 0x00 /*!< 8位转换*/
#define ADC_MODE_10BIT 0x01 /*!< 10位转换*/
#define ADC_MODE_12BIT 0x02 /*!< 12位转换*/
/*****************************************************************************
*
* 定义ADC输入通道
*
*******************************************************************************/
#define ADC_CHANNEL_AD0 0x0 /*!< ADC输入通道0*/
#define ADC_CHANNEL_AD1 0x1 /*!< ADC输入通道1*/
#define ADC_CHANNEL_AD2 0x2 /*!< ADC输入通道2*/
#define ADC_CHANNEL_AD3 0x3 /*!< ADC输入通道3*/
#define ADC_CHANNEL_AD4 0x4 /*!< ADC输入通道4*/
#define ADC_CHANNEL_AD5 0x5 /*!< ADC输入通道5*/
#define ADC_CHANNEL_AD6 0x6 /*!< ADC输入通道6*/
#define ADC_CHANNEL_AD7 0x7 /*!< ADC输入通道7*/
#define ADC_CHANNEL_AD8 0x8 /*!< ADC输入通道8*/
#define ADC_CHANNEL_AD9 0x9 /*!< ADC输入通道9*/
#define ADC_CHANNEL_AD10 0xa /*!< ADC输入通道10*/
#define ADC_CHANNEL_AD11 0xb /*!< ADC输入通道11*/
#define ADC_CHANNEL_AD12 0xc /*!< ADC输入通道12*/
#define ADC_CHANNEL_AD13 0xd /*!< ADC输入通道13*/
#define ADC_CHANNEL_AD14 0xe /*!< ADC输入通道14*/
#define ADC_CHANNEL_AD15 0xf /*!< ADC输入通道15*/
#define ADC_CHANNEL_AD18_VSS 0x12 /*!< ADC输入通道 VSS */
#define ADC_CHANNEL_AD22_TEMPSENSOR 0x16 /*!< ADC输入通道温度传感器 */ //Modify
#define ADC_CHANNEL_AD23_BANDGAP 0x17 /*!< ADC输入通道带隙 */
#define ADC_CHANNEL_AD29_VREFH 0x1D /*!< ADC输入通道 Vrefh */
#define ADC_CHANNEL_AD30_VREFL 0x1E /*!< ADC输入通道 Vrefl */
#define ADC_CHANNEL_DISABLE 0x1F /*!< ADC输入通道禁用 */
/******************************************************************************
*
* 定义 ADC FIFO 深度
*
*******************************************************************************/
#define ADC_FIFO_DISABLE 0 /*!< FIFO禁用*/
#define ADC_FIFO_LEVEL2 1 /*!< 2级FIFO */
#define ADC_FIFO_LEVEL3 2 /*!< 3级FIFO */
#define ADC_FIFO_LEVEL4 3 /*!< 4级FIFO */
#define ADC_FIFO_LEVEL5 4 /*!< 5级FIFO */
#define ADC_FIFO_LEVEL6 5 /*!< 6级FIFO */
#define ADC_FIFO_LEVEL7 6 /*!< 7级FIFO */
#define ADC_FIFO_LEVEL8 7 /*!< 8级FIFO */
/******************************************************************************
*
* 定义ADC转换触发源
*
*******************************************************************************/
#define ADC_HARDWARE_TRIGGER 0x01 /*!< 硬件触发 */
#define ADC_SOFTWARE_TRIGGER 0x00 /*!< 软件触发 */
#define ADC_TRIGGER_RTC 0x00 /*!< 选择RTC溢出作为硬件触发源*/
#define ADC_TRIGGER_PIT 0x01 /*!< 选择PIT0溢出作为硬件触发源*/
#define ADC_TRIGGER_ETM2INIT 0x10 /*!< 选择ETM2初始化化作为硬件触发源 */
#define ADC_TRIGGER_ETM2MATCH 0x11 /*!< 选择ETM2匹配作为硬件触发源 */
/******************************************************************************
*
* 定义ADC比较触发模式
*
*******************************************************************************/
#define ADC_COMPARE_LESS 0x00 /*!< 输入小于比较电平时比较触发*/
#define ADC_COMPARE_GREATER 0x01 /*!< 输入大于比价电平时比较触发*/
/******************************************************************************
*
* ADC回调函数声明
*
******************************************************************************/
typedef void (*ADC_CallbackType)(void); /*!< ADC回调函数 */
/******************************************************************************
*
* 定义ADC结构体变量
*
*******************************************************************************/
typedef struct
{
uint16_t bIntEn :1; /*!< 1: 中断使能, 0: 禁用中断 */
uint16_t bContinuousEn :1; /*!< 1: 使能连续转换模式, 0: 禁用连续转换模式 */
uint16_t bHardwareTriggerEn :1; /*!< 1: 硬件触发, 0: 软件触发 */
uint16_t bCompareEn :1; /*!< 1: 使能比较模式, 0: 禁用比较模式 */
uint16_t bCompareGreaterEn :1; /*!< 1: 输入大于或等于比较电平时比较触发, 0: 输入小于比较电平时比较触发 */
uint16_t bLowPowerEn :1; /*!< 1: 低功耗模式, 0: 高速模式 */
uint16_t bLongSampleEn :1; /*!< 1: 长采样模式, 0: 短采样模式 */
uint16_t bFiFoScanModeEn :1; /*!< 1: 使能FIFO扫描模式, 0: 禁用FIFO扫描模式 */
uint16_t bCompareAndEn :1; /*!< 1: 对所有比较触发做与运算, 0: 对所有比较触发做或运算*/
#ifdef CPU_NV32
uint16_t bReverse :7;
#else
uint16_t bHTRGMEn :1; /*!< one hardware trigger pulse trigger multiple conversions in fifo mode */
uint16_t bHTRGMASKEn :1; /*!< Hardware trigger mask enable. */
uint16_t bHTRGMASKSEL :1; /*!< This field selects hardware trigger mask mode. */
uint16_t Reserve :4;
#endif
} ADC_SettingType;
/******************************************************************************
*
* ADC配置结构体
*
*******************************************************************************/
typedef struct
{
ADC_SettingType sSetting; /*!< ADC配置结构体*/
uint16_t u16PinControl; /*!< 引脚控制 */
uint8_t u8ClockSource; /*!< 选择时钟源 */
uint8_t u8ClockDiv; /*!< 设置时钟分频 */
uint8_t u8Mode; /*!< 设置转换模式(8/10/12 bit mode) */
uint8_t u8FiFoLevel; /*!< 设置FIFO深度 */
} ADC_ConfigType,*ADC_ConfigTypePtr;
/*****************************************************************************//*!
*
* @brief 使能ADC中断.
*
* @param[in] pADC 指向ADC模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_IntEnable( ADC_Type *pADC )
{
pADC->SC1 |= ADC_SC1_AIEN_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用ADC中断
*
* @param[in] pADC 指向ADC模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_IntDisable( ADC_Type *pADC )
{
pADC->SC1 &= ~ADC_SC1_AIEN_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能ADC连续转换.
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_ContinuousConversion( ADC_Type *pADC )
{
pADC->SC1 |= ADC_SC1_ADCO_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能ADC单次转换
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SingleConversion( ADC_Type *pADC )
{
pADC->SC1 &= ~ADC_SC1_ADCO_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC硬件触发.
*
* @param[in] pADC 指向ADC模块 .
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetHardwareTrigger( ADC_Type *pADC )
{
pADC->SC2 |= ADC_SC2_ADTRG_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC软件触发.
*
* @param[in] pADC 指向ADC模块 .
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetSoftwareTrigger( ADC_Type *pADC )
{
pADC->SC2 &= ~ADC_SC2_ADTRG_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能ADC比较功能
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareEnable( ADC_Type *pADC )
{
pADC->SC2 |= ADC_SC2_ACFE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用ADC比较功能.
*
* @param[in] pADC 指向ADC模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareDisable( ADC_Type *pADC )
{
pADC->SC2 &= ~ADC_SC2_ACFE_MASK;
}
/*****************************************************************************//*!
*
* @brief 输入大于或等于比较电平时比较触发
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareGreaterFunction( ADC_Type *pADC )
{
pADC->SC2 |= ADC_SC2_ACFGT_MASK;
}
/*****************************************************************************//*!
*
* @brief 输入小于比价电平时比较触发
*
* @param[in] pADC 指向ADC模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareLessFunction( ADC_Type *pADC )
{
pADC->SC2 &= ~ADC_SC2_ACFGT_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC为低功耗模式
*
* @param[in] pADC 指向ADC模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetLowPower( ADC_Type *pADC )
{
pADC->SC3 |= ADC_SC3_ADLPC_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC为高速模式.
*
* @param[in] pADC 指向ADC模块..
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetHighSpeed( ADC_Type *pADC )
{
pADC->SC3 &= ~ADC_SC3_ADLPC_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC长采样.
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetLongSample( ADC_Type *pADC )
{
pADC->SC3 |= ADC_SC3_ADLSMP_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC短采样
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetShortSample( ADC_Type *pADC )
{
pADC->SC3 &= ~ADC_SC3_ADLSMP_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能FIFO扫描模式
*
* @param[in] pADC 指向ADC模块.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void ADC_FifoScanModeEnable( ADC_Type *pADC )
{
pADC->SC4 |= ADC_SC4_ASCANE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用FIFO扫描模式.
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_FifoScanModeDisable( ADC_Type *pADC )
{
pADC->SC4 &= ~ADC_SC4_ASCANE_MASK;
}
/*****************************************************************************//*!
*
* @brief 对所有比较触发做或运算.
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareFifoOr( ADC_Type *pADC )
{
pADC->SC4 &= ~ADC_SC4_ACFSEL_MASK;
}
/*****************************************************************************//*!
*
* @brief 对所有比较触发做与运算
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareFifoAnd( ADC_Type *pADC )
{
pADC->SC4 |= ADC_SC4_ACFSEL_MASK;
}
/*****************************************************************************//*!
*
* @brief 对ADC转换结果寄存器.
*
* @param[in] pADC 指向ADC模块.
*
* @return ADC result value.
*
*****************************************************************************/
__STATIC_INLINE uint16_t ADC_ReadResultReg( ADC_Type *pADC )
{
return (uint16_t)pADC->R;
}
/*****************************************************************************//*!
*
* @brief 设置比较值.
*
* @param[in] pADC 指向ADC模块.
* @param[in] u16Compare 比较值
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetCompareValue( ADC_Type *pADC, uint16_t u16Compare )
{
pADC->CV = u16Compare;
}
/*****************************************************************************//*!
*
* @brief 使能ADC输入引脚.
*
* @param[in] pADC 指向ADC模块.
* @param[in] u16PinNumber 使能的ADC引脚
*
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void ADC_PinControlEnable( ADC_Type *pADC, uint16_t u16PinNumber)
{
ASSERT((u16PinNumber<16));
pADC->APCTL1 &= ~(0x01<<u16PinNumber);
}
/*****************************************************************************//*!
*
* @brief 禁用ADC输入引脚.
*
* @param[in] pADC 指向ADC模块.
* @param[in] u16PinNumber 禁用的ADC引脚.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_PinControlDisable( ADC_Type *pADC, uint16_t u16PinNumber)
{
ASSERT((u16PinNumber<16));
pADC->APCTL1 |= (0x01<<u16PinNumber);
}
/*****************************************************************************//*!
*
* @brief 查看ADC转换状态
*
* @param[in] pADC 指向ADC模块..
*
* @return 1 or 0
*
*****************************************************************************/
__STATIC_INLINE uint8_t ADC_IsConversionActiveFlag( ADC_Type *pADC )
{
return(pADC->SC2 & ADC_SC2_ADACT_MASK);
}
/*****************************************************************************//*!
*
* @brief 读取转换完成标准位
*
* @param[in] pADC 指向ADC模块..
*
* @return 1 or 0
*
*****************************************************************************/
__STATIC_INLINE uint8_t ADC_IsCOCOFlag( ADC_Type *pADC )
{
return(pADC->SC1 & ADC_SC1_COCO_MASK);
}
/*****************************************************************************//*!
*
* @brief 读取结果FIFO中是否有有效新数据标志位
*
* @param[in] pADC point to ADC module type.
*
* @return 1 or 0
*
*****************************************************************************/
__STATIC_INLINE uint8_t ADC_IsFIFOEmptyFlag( ADC_Type *pADC )
{
return(pADC->SC2 & ADC_SC2_FEMPTY_MASK);
}
/*****************************************************************************//*!
*
* @brief 读取结果FIFO是否满标志位
*
* @param[in] pADC 指向ADC模块.
*
* @return 1 or 0
*
*****************************************************************************/
__STATIC_INLINE uint8_t ADC_IsFIFOFullFlag( ADC_Type *pADC )
{
return(pADC->SC2 & ADC_SC2_FFULL_MASK);
}
#ifndef CPU_NV32
/*****************************************************************************//*!
*
* @brief Hardware Trigger Multiple Conversion Enable
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerMultiple( ADC_Type *pADC )
{
pADC->SC4 |= ADC_SC4_HTRGME_MASK;
}
/*****************************************************************************//*!
*
* @brief Hardware Trigger Single Conversion
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerSingle( ADC_Type *pADC )
{
pADC->SC4 &= ~ADC_SC4_HTRGME_MASK;
}
/*****************************************************************************//*!
*
* @brief Hardware Trigger Mask Enable
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerMaskEnable( ADC_Type *pADC )
{
pADC->SC5 |= ADC_SC5_HTRGMASKE_MASK;
}
/*****************************************************************************//*!
*
* @brief Hardware Trigger Mask Disable
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerMaskDisable( ADC_Type *pADC )
{
pADC->SC5 &= ~ADC_SC5_HTRGMASKE_MASK;
}
/*****************************************************************************//*!
*
* @brief Hardware Trigger Mask Mode Select Automatic Mode
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerMaskAuto( ADC_Type *pADC )
{
pADC->SC5 |= ADC_SC5_HTRGMASKSEL_MASK;
}
/*****************************************************************************//*!
*
* @brief Hardware Trigger Mask Mode Select to be with HTRGMASKE
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerMaskNonAuto( ADC_Type *pADC )
{
pADC->SC5 &= ~ADC_SC5_HTRGMASKSEL_MASK;
}
#endif
/******************************************************************************
* Global function
******************************************************************************/
void ADC_SetChannel( ADC_Type *pADC, uint8_t u8Channel );
void ADC_IntEnable( ADC_Type *pADC );
void ADC_IntDisable( ADC_Type *pADC );
void ADC_ContinuousConversion( ADC_Type *pADC );
void ADC_SingleConversion( ADC_Type *pADC );
void ADC_SetSoftwareTrigger( ADC_Type *pADC );
void ADC_SetHardwareTrigger( ADC_Type *pADC );
void ADC_VrefSelect( ADC_Type *pADC, uint8_t u8Vref );
void ADC_CompareEnable( ADC_Type *pADC );
void ADC_CompareDisable( ADC_Type *pADC );
void ADC_CompareGreaterFunction( ADC_Type *pADC );
void ADC_CompareLessFunction( ADC_Type *pADC );
void ADC_SetLowPower( ADC_Type *pADC );
void ADC_SetHighSpeed( ADC_Type *pADC );
void ADC_SelectClockDivide( ADC_Type *pADC, uint8_t u8Div);
void ADC_SetLongSample(ADC_Type *pADC);
void ADC_SetShortSample(ADC_Type *pADC);
void ADC_SetMode(ADC_Type *pADC, uint8_t u8Mode);
void ADC_SelectClock(ADC_Type *pADC, uint8_t u8Clock);
void ADC_FifoScanModeEnable(ADC_Type *pADC);
void ADC_FifoScanModeDisable(ADC_Type *pADC);
void ADC_CompareFifoOr(ADC_Type *pADC);
void ADC_CompareFifoAnd(ADC_Type *pADC);
void ADC_SetFifoLevel(ADC_Type *pADC, uint8_t u8FifoLevel);
uint16_t ADC_ReadResultReg(ADC_Type *pADC );
void ADC_SetCompareValue(ADC_Type *pADC, uint16_t u16Compare );
void ADC_PinControlEnable(ADC_Type *pADC, uint16_t u16PinNumber);
void ADC_PinControlDisable(ADC_Type *pADC, uint16_t u16PinNumber);
uint8_t ADC_IsConversionActiveFlag(ADC_Type *pADC);
uint8_t ADC_IsCOCOFlag(ADC_Type *pADC);
uint8_t ADC_IsFIFOEmptyFlag(ADC_Type *pADC);
uint8_t ADC_IsFIFOFullFlag(ADC_Type *pADC);
void ADC_HardwareTriggerMaskNonAuto(ADC_Type *pADC);
void ADC_HardwareTriggerMaskAuto(ADC_Type *pADC);
void ADC_HardwareTriggerMaskDisable( ADC_Type *pADC );
void ADC_HardwareTriggerMaskEnable( ADC_Type *pADC );
void ADC_HardwareTriggerSingle( ADC_Type *pADC );
void ADC_HardwareTriggerMultiple( ADC_Type *pADC );
unsigned int ADC_PollRead( ADC_Type *pADC, uint8_t u8Channel);
void ADC_SetCallBack(ADC_CallbackType pADC_CallBack);
void ADC_DeInit(ADC_Type *pADC);
void ADC_Init(ADC_Type *pADC, ADC_ConfigTypePtr pADC_Config);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,655 @@
/******************************************************************************
*
* @brief ADC 驱动头文件.
*
******************************************************************************/
#ifndef ADC_H_
#define ADC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
/******************************************************************************
*
*定义ADC参考电压
*
*******************************************************************************/
#define ADC_VREF_VREFH 0x00 /*!< ADC 参考电压 VREFH*/
#define ADC_VREF_VDDA 0x01 /*!< ADC 参考电压 VDDA*/
/******************************************************************************
*
* 定义ADC时钟源
*
*******************************************************************************/
#define CLOCK_SOURCE_BUS_CLOCK 0x00 /*!< ADC时钟源选择总线时钟*/
#define CLOCK_SOURCE_BUS_CLOCK_DIVIDE_2 0x01 /*!< ADC时钟源选择总线时钟2分频*/
#define CLOCK_SOURCE_ALTCLK 0x02 /*!< ADC时钟源选择备用时钟*/
#define CLOCK_SOURCE_ADACK 0x03 /*!< ADC时钟源选择异步时钟*/
/******************************************************************************
*
* 定义ADC源分频系数
*
*******************************************************************************/
#define ADC_ADIV_DIVIDE_1 0x00 /*!< ADC时钟源分频系数为1*/
#define ADC_ADIV_DIVIDE_2 0x01 /*!< ADC时钟源分频系数为2*/
#define ADC_ADIV_DIVIDE_4 0x02 /*!< ADC时钟源分频系数为4*/
#define ADC_ADIV_DIVIDE_8 0x03 /*!< ADC时钟源分频系数为8*/
/******************************************************************************
*
* 定义ADC转换模式
*
*******************************************************************************/
#define ADC_MODE_8BIT 0x00 /*!< 8位转换*/
#define ADC_MODE_10BIT 0x01 /*!< 10位转换*/
#define ADC_MODE_12BIT 0x02 /*!< 12位转换*/
/*****************************************************************************
*
* 定义ADC输入通道
*
*******************************************************************************/
#define ADC_CHANNEL_AD0 0x0 /*!< ADC输入通道0*/
#define ADC_CHANNEL_AD1 0x1 /*!< ADC输入通道1*/
#define ADC_CHANNEL_AD2 0x2 /*!< ADC输入通道2*/
#define ADC_CHANNEL_AD3 0x3 /*!< ADC输入通道3*/
#define ADC_CHANNEL_AD4 0x4 /*!< ADC输入通道4*/
#define ADC_CHANNEL_AD5 0x5 /*!< ADC输入通道5*/
#define ADC_CHANNEL_AD6 0x6 /*!< ADC输入通道6*/
#define ADC_CHANNEL_AD7 0x7 /*!< ADC输入通道7*/
#define ADC_CHANNEL_AD8 0x8 /*!< ADC输入通道8*/
#define ADC_CHANNEL_AD9 0x9 /*!< ADC输入通道9*/
#define ADC_CHANNEL_AD10 0xa /*!< ADC输入通道10*/
#define ADC_CHANNEL_AD11 0xb /*!< ADC输入通道11*/
#define ADC_CHANNEL_AD12 0xc /*!< ADC输入通道12*/
#define ADC_CHANNEL_AD13 0xd /*!< ADC输入通道13*/
#define ADC_CHANNEL_AD14 0xe /*!< ADC输入通道14*/
#define ADC_CHANNEL_AD15 0xf /*!< ADC输入通道15*/
#define ADC_CHANNEL_AD18_VSS 0x12 /*!< ADC输入通道 VSS */
#define ADC_CHANNEL_AD22_TEMPSENSOR 0x15 /*!< ADC输入通道温度传感器 */
#define ADC_CHANNEL_AD23_BANDGAP 0x17 /*!< ADC输入通道带隙 */
#define ADC_CHANNEL_AD29_VREFH 0x1D /*!< ADC输入通道 Vrefh */
#define ADC_CHANNEL_AD30_VREFL 0x1E /*!< ADC输入通道 Vrefl */
#define ADC_CHANNEL_DISABLE 0x1F /*!< ADC输入通道禁用 */
/******************************************************************************
*
* 定义 ADC FIFO 深度
*
*******************************************************************************/
#define ADC_FIFO_DISABLE 0 /*!< FIFO禁用*/
#define ADC_FIFO_LEVEL2 1 /*!< 2级FIFO */
#define ADC_FIFO_LEVEL3 2 /*!< 3级FIFO */
#define ADC_FIFO_LEVEL4 3 /*!< 4级FIFO */
#define ADC_FIFO_LEVEL5 4 /*!< 5级FIFO */
#define ADC_FIFO_LEVEL6 5 /*!< 6级FIFO */
#define ADC_FIFO_LEVEL7 6 /*!< 7级FIFO */
#define ADC_FIFO_LEVEL8 7 /*!< 8级FIFO */
/******************************************************************************
*
* 定义ADC转换触发源
*
*******************************************************************************/
#define ADC_HARDWARE_TRIGGER 0x01 /*!< 硬件触发 */
#define ADC_SOFTWARE_TRIGGER 0x00 /*!< 软件触发 */
#define ADC_TRIGGER_RTC 0x00 /*!< 选择RTC溢出作为硬件触发源*/
#define ADC_TRIGGER_PIT 0x01 /*!< 选择PIT0溢出作为硬件触发源*/
#define ADC_TRIGGER_ETM2INIT 0x10 /*!< 选择ETM2初始化化作为硬件触发源 */
#define ADC_TRIGGER_ETM2MATCH 0x11 /*!< 选择ETM2匹配作为硬件触发源 */
/******************************************************************************
*
* 定义ADC比较触发模式
*
*******************************************************************************/
#define ADC_COMPARE_LESS 0x00 /*!< 输入小于比较电平时比较触发*/
#define ADC_COMPARE_GREATER 0x01 /*!< 输入大于比价电平时比较触发*/
/******************************************************************************
*
* ADC回调函数声明
*
******************************************************************************/
typedef void (*ADC_CallbackType)(void); /*!< ADC回调函数 */
/******************************************************************************
*
* 定义ADC结构体变量
*
*******************************************************************************/
typedef struct
{
uint16_t bIntEn :1; /*!< 1: 中断使能, 0: 禁用中断 */
uint16_t bContinuousEn :1; /*!< 1: 使能连续转换模式, 0: 禁用连续转换模式 */
uint16_t bHardwareTriggerEn :1; /*!< 1: 硬件触发, 0: 软件触发 */
uint16_t bCompareEn :1; /*!< 1: 使能比较模式, 0: 禁用比较模式 */
uint16_t bCompareGreaterEn :1; /*!< 1: 输入大于或等于比较电平时比较触发, 0: 输入小于比较电平时比较触发 */
uint16_t bLowPowerEn :1; /*!< 1: 低功耗模式, 0: 高速模式 */
uint16_t bLongSampleEn :1; /*!< 1: 长采样模式, 0: 短采样模式 */
uint16_t bFiFoScanModeEn :1; /*!< 1: 使能FIFO扫描模式, 0: 禁用FIFO扫描模式 */
uint16_t bCompareAndEn :1; /*!< 1: 对所有比较触发做与运算, 0: 对所有比较触发做或运算*/
#ifdef CPU_NV32
uint16_t bReverse :7;
#else
uint16_t bHTRGMEn :1; /*!< one hardware trigger pulse trigger multiple conversions in fifo mode */
uint16_t bHTRGMASKEn :1; /*!< Hardware trigger mask enable. */
uint16_t bHTRGMASKSEL :1; /*!< This field selects hardware trigger mask mode. */
uint16_t Reserve :4;
#endif
} ADC_SettingType;
/******************************************************************************
*
* ADC配置结构体
*
*******************************************************************************/
typedef struct
{
ADC_SettingType sSetting; /*!< ADC配置结构体*/
uint16_t u16PinControl; /*!< 引脚控制 */
uint8_t u8ClockSource; /*!< 选择时钟源 */
uint8_t u8ClockDiv; /*!< 设置时钟分频 */
uint8_t u8Mode; /*!< 设置转换模式(8/10/12 bit mode) */
uint8_t u8FiFoLevel; /*!< 设置FIFO深度 */
} ADC_ConfigType,*ADC_ConfigTypePtr;
/*****************************************************************************//*!
*
* @brief 使能ADC中断.
*
* @param[in] pADC 指向ADC模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_IntEnable( ADC_Type *pADC )
{
pADC->SC1 |= ADC_SC1_AIEN_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用ADC中断
*
* @param[in] pADC 指向ADC模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_IntDisable( ADC_Type *pADC )
{
pADC->SC1 &= ~ADC_SC1_AIEN_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能ADC连续转换.
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_ContinuousConversion( ADC_Type *pADC )
{
pADC->SC1 |= ADC_SC1_ADCO_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能ADC单次转换
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SingleConversion( ADC_Type *pADC )
{
pADC->SC1 &= ~ADC_SC1_ADCO_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC硬件触发.
*
* @param[in] pADC 指向ADC模块 .
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetHardwareTrigger( ADC_Type *pADC )
{
pADC->SC2 |= ADC_SC2_ADTRG_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC软件触发.
*
* @param[in] pADC 指向ADC模块 .
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetSoftwareTrigger( ADC_Type *pADC )
{
pADC->SC2 &= ~ADC_SC2_ADTRG_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能ADC比较功能
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareEnable( ADC_Type *pADC )
{
pADC->SC2 |= ADC_SC2_ACFE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用ADC比较功能.
*
* @param[in] pADC 指向ADC模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareDisable( ADC_Type *pADC )
{
pADC->SC2 &= ~ADC_SC2_ACFE_MASK;
}
/*****************************************************************************//*!
*
* @brief 输入大于或等于比较电平时比较触发
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareGreaterFunction( ADC_Type *pADC )
{
pADC->SC2 |= ADC_SC2_ACFGT_MASK;
}
/*****************************************************************************//*!
*
* @brief 输入小于比价电平时比较触发
*
* @param[in] pADC 指向ADC模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareLessFunction( ADC_Type *pADC )
{
pADC->SC2 &= ~ADC_SC2_ACFGT_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC为低功耗模式
*
* @param[in] pADC 指向ADC模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetLowPower( ADC_Type *pADC )
{
pADC->SC3 |= ADC_SC3_ADLPC_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC为高速模式.
*
* @param[in] pADC 指向ADC模块..
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetHighSpeed( ADC_Type *pADC )
{
pADC->SC3 &= ~ADC_SC3_ADLPC_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC长采样.
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetLongSample( ADC_Type *pADC )
{
pADC->SC3 |= ADC_SC3_ADLSMP_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置ADC短采样
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetShortSample( ADC_Type *pADC )
{
pADC->SC3 &= ~ADC_SC3_ADLSMP_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能FIFO扫描模式
*
* @param[in] pADC 指向ADC模块.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void ADC_FifoScanModeEnable( ADC_Type *pADC )
{
pADC->SC4 |= ADC_SC4_ASCANE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用FIFO扫描模式.
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_FifoScanModeDisable( ADC_Type *pADC )
{
pADC->SC4 &= ~ADC_SC4_ASCANE_MASK;
}
/*****************************************************************************//*!
*
* @brief 对所有比较触发做或运算.
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareFifoOr( ADC_Type *pADC )
{
pADC->SC4 &= ~ADC_SC4_ACFSEL_MASK;
}
/*****************************************************************************//*!
*
* @brief 对所有比较触发做与运算
*
* @param[in] pADC 指向ADC模块.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_CompareFifoAnd( ADC_Type *pADC )
{
pADC->SC4 |= ADC_SC4_ACFSEL_MASK;
}
/*****************************************************************************//*!
*
* @brief 对ADC转换结果寄存器.
*
* @param[in] pADC 指向ADC模块.
*
* @return ADC result value.
*
*****************************************************************************/
__STATIC_INLINE uint16_t ADC_ReadResultReg( ADC_Type *pADC )
{
return (uint16_t)pADC->R;
}
/*****************************************************************************//*!
*
* @brief 设置比较值.
*
* @param[in] pADC 指向ADC模块.
* @param[in] u16Compare 比较值
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_SetCompareValue( ADC_Type *pADC, uint16_t u16Compare )
{
pADC->CV = u16Compare;
}
/*****************************************************************************//*!
*
* @brief 使能ADC输入引脚.
*
* @param[in] pADC 指向ADC模块.
* @param[in] u16PinNumber 使能的ADC引脚
*
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void ADC_PinControlEnable( ADC_Type *pADC, uint16_t u16PinNumber)
{
ASSERT((u16PinNumber<16));
pADC->APCTL1 &= ~(0x01<<u16PinNumber);
}
/*****************************************************************************//*!
*
* @brief 禁用ADC输入引脚.
*
* @param[in] pADC 指向ADC模块.
* @param[in] u16PinNumber 禁用的ADC引脚.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_PinControlDisable( ADC_Type *pADC, uint16_t u16PinNumber)
{
ASSERT((u16PinNumber<16));
pADC->APCTL1 |= (0x01<<u16PinNumber);
}
/*****************************************************************************//*!
*
* @brief 查看ADC转换状态
*
* @param[in] pADC 指向ADC模块..
*
* @return 1 or 0
*
*****************************************************************************/
__STATIC_INLINE uint8_t ADC_IsConversionActiveFlag( ADC_Type *pADC )
{
return(pADC->SC2 & ADC_SC2_ADACT_MASK);
}
/*****************************************************************************//*!
*
* @brief 读取转换完成标准位
*
* @param[in] pADC 指向ADC模块..
*
* @return 1 or 0
*
*****************************************************************************/
__STATIC_INLINE uint8_t ADC_IsCOCOFlag( ADC_Type *pADC )
{
return(pADC->SC1 & ADC_SC1_COCO_MASK);
}
/*****************************************************************************//*!
*
* @brief 读取结果FIFO中是否有有效新数据标志位
*
* @param[in] pADC point to ADC module type.
*
* @return 1 or 0
*
*****************************************************************************/
__STATIC_INLINE uint8_t ADC_IsFIFOEmptyFlag( ADC_Type *pADC )
{
return(pADC->SC2 & ADC_SC2_FEMPTY_MASK);
}
/*****************************************************************************//*!
*
* @brief 读取结果FIFO是否满标志位
*
* @param[in] pADC 指向ADC模块.
*
* @return 1 or 0
*
*****************************************************************************/
__STATIC_INLINE uint8_t ADC_IsFIFOFullFlag( ADC_Type *pADC )
{
return(pADC->SC2 & ADC_SC2_FFULL_MASK);
}
#ifndef CPU_NV32
/*****************************************************************************//*!
*
* @brief Hardware Trigger Multiple Conversion Enable
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerMultiple( ADC_Type *pADC )
{
pADC->SC4 |= ADC_SC4_HTRGME_MASK;
}
/*****************************************************************************//*!
*
* @brief Hardware Trigger Single Conversion
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerSingle( ADC_Type *pADC )
{
pADC->SC4 &= ~ADC_SC4_HTRGME_MASK;
}
/*****************************************************************************//*!
*
* @brief Hardware Trigger Mask Enable
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerMaskEnable( ADC_Type *pADC )
{
pADC->SC5 |= ADC_SC5_HTRGMASKE_MASK;
}
/*****************************************************************************//*!
*
* @brief Hardware Trigger Mask Disable
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerMaskDisable( ADC_Type *pADC )
{
pADC->SC5 &= ~ADC_SC5_HTRGMASKE_MASK;
}
/*****************************************************************************//*!
*
* @brief Hardware Trigger Mask Mode Select Automatic Mode
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerMaskAuto( ADC_Type *pADC )
{
pADC->SC5 |= ADC_SC5_HTRGMASKSEL_MASK;
}
/*****************************************************************************//*!
*
* @brief Hardware Trigger Mask Mode Select to be with HTRGMASKE
*
* @param[in] pADC point to ADC module type.
*
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void ADC_HardwareTriggerMaskNonAuto( ADC_Type *pADC )
{
pADC->SC5 &= ~ADC_SC5_HTRGMASKSEL_MASK;
}
#endif
/******************************************************************************
* Global function
******************************************************************************/
void ADC_SetChannel( ADC_Type *pADC, uint8_t u8Channel );
void ADC_IntEnable( ADC_Type *pADC );
void ADC_IntDisable( ADC_Type *pADC );
void ADC_ContinuousConversion( ADC_Type *pADC );
void ADC_SingleConversion( ADC_Type *pADC );
void ADC_SetSoftwareTrigger( ADC_Type *pADC );
void ADC_SetHardwareTrigger( ADC_Type *pADC );
void ADC_VrefSelect( ADC_Type *pADC, uint8_t u8Vref );
void ADC_CompareEnable( ADC_Type *pADC );
void ADC_CompareDisable( ADC_Type *pADC );
void ADC_CompareGreaterFunction( ADC_Type *pADC );
void ADC_CompareLessFunction( ADC_Type *pADC );
void ADC_SetLowPower( ADC_Type *pADC );
void ADC_SetHighSpeed( ADC_Type *pADC );
void ADC_SelectClockDivide( ADC_Type *pADC, uint8_t u8Div);
void ADC_SetLongSample(ADC_Type *pADC);
void ADC_SetShortSample(ADC_Type *pADC);
void ADC_SetMode(ADC_Type *pADC, uint8_t u8Mode);
void ADC_SelectClock(ADC_Type *pADC, uint8_t u8Clock);
void ADC_FifoScanModeEnable(ADC_Type *pADC);
void ADC_FifoScanModeDisable(ADC_Type *pADC);
void ADC_CompareFifoOr(ADC_Type *pADC);
void ADC_CompareFifoAnd(ADC_Type *pADC);
void ADC_SetFifoLevel(ADC_Type *pADC, uint8_t u8FifoLevel);
uint16_t ADC_ReadResultReg(ADC_Type *pADC );
void ADC_SetCompareValue(ADC_Type *pADC, uint16_t u16Compare );
void ADC_PinControlEnable(ADC_Type *pADC, uint16_t u16PinNumber);
void ADC_PinControlDisable(ADC_Type *pADC, uint16_t u16PinNumber);
uint8_t ADC_IsConversionActiveFlag(ADC_Type *pADC);
uint8_t ADC_IsCOCOFlag(ADC_Type *pADC);
uint8_t ADC_IsFIFOEmptyFlag(ADC_Type *pADC);
uint8_t ADC_IsFIFOFullFlag(ADC_Type *pADC);
void ADC_HardwareTriggerMaskNonAuto(ADC_Type *pADC);
void ADC_HardwareTriggerMaskAuto(ADC_Type *pADC);
void ADC_HardwareTriggerMaskDisable( ADC_Type *pADC );
void ADC_HardwareTriggerMaskEnable( ADC_Type *pADC );
void ADC_HardwareTriggerSingle( ADC_Type *pADC );
void ADC_HardwareTriggerMultiple( ADC_Type *pADC );
unsigned int ADC_PollRead( ADC_Type *pADC, uint8_t u8Channel);
void ADC_SetCallBack(ADC_CallbackType pADC_CallBack);
void ADC_DeInit(ADC_Type *pADC);
void ADC_Init(ADC_Type *pADC, ADC_ConfigTypePtr pADC_Config);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,93 @@
/******************************************************************************
* @brief Provide Bit-band utilities.
******************************************************************************/
#ifndef __BIT_BAND_H
#define __BIT_BAND_H
#ifdef __cplusplus
extern "C" {
#endif
/******************************************************************************
*
*
*//*! @addtogroup BIT_BandType
* @{
*******************************************************************************/
/*!
* @brief bit band type.
*
*/
typedef struct
{
uint32_t bBit0; /*!< aliase to 0th bit */
uint32_t bBit1; /*!< aliase to 1th bit */
uint32_t bBit2; /*!< aliase to 2th bit */
uint32_t bBit3; /*!< aliase to 3th bit */
uint32_t bBit4; /*!< aliase to 4th bit */
uint32_t bBit5; /*!< aliase to 5th bit */
uint32_t bBit6; /*!< aliase to 6th bit */
uint32_t bBit7; /*!< aliase to 7th bit */
uint32_t bBit8; /*!< aliase to 8th bit */
uint32_t bBit9; /*!< aliase to 9th bit */
uint32_t bBit10; /*!< aliase to 10th bit */
uint32_t bBit11; /*!< aliase to 11th bit */
uint32_t bBit12; /*!< aliase to 12th bit */
uint32_t bBit13; /*!< aliase to 13th bit */
uint32_t bBit14; /*!< aliase to 14th bit */
uint32_t bBit15; /*!< aliase to 15th bit */
uint32_t bBit16; /*!< aliase to 16th bit */
uint32_t bBit17; /*!< aliase to 17th bit */
uint32_t bBit18; /*!< aliase to 18th bit */
uint32_t bBit19; /*!< aliase to 19th bit */
uint32_t bBit20; /*!< aliase to 20th bit */
uint32_t bBit21; /*!< aliase to 21th bit */
uint32_t bBit22; /*!< aliase to 22th bit */
uint32_t bBit23; /*!< aliase to 23th bit */
uint32_t bBit24; /*!< aliase to 24th bit */
uint32_t bBit25; /*!< aliase to 25th bit */
uint32_t bBit26; /*!< aliase to 26th bit */
uint32_t bBit27; /*!< aliase to 27th bit */
uint32_t bBit28; /*!< aliase to 28th bit */
uint32_t bBit29; /*!< aliase to 29th bit */
uint32_t bBit30; /*!< aliase to 30th bit */
uint32_t bBit31; /*!< aliase to 31th bit */
}BIT_BandType,*BIT_BandPtr;
/*! @} End of BIT_BandType */
/******************************************************************************
* define API list
*
*//*! @addtogroup bit_band_api_list
* @{
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief bit-band initialize pointer, so that invoke the pointer to access alisaed bitband.
*
* @param[in] pVariableAddress - point to variable.
* @param[in] pBitbandPtr - point to alisaed bitband address.
*
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void BIT_BandVariableInit( uint32_t *pVariableAddress,BIT_BandPtr *pBitbandPtr )
{
#if defined(CPU_NV32M3)
ASSERT( ((uint32)pVariableAddress >= 0x20000000)&&((uint32_t)pVariableAddress <= 0x200002FF) );
#elif defined(CPU_NV32M4)
ASSERT( ((uint32)pVariableAddress >= 0x20000000)&&((uint32_t)pVariableAddress <= (0x20000000+12*1024)));
#else
#error "don't support this function on this device"
#endif
*pBitbandPtr = (BIT_BandPtr)(((uint32_t)pVariableAddress-0x20000000)*32+0x22000000);
}
/*! @} End of bit_band_api_list */
#ifdef __cplusplus
}
#endif
#endif /* __BIT_BAND_H */
@@ -0,0 +1,559 @@
/*************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file bos.h
* @brief 位操作存储模块(BOS)函数库
* @author Navota
* @date 2017-1-1
***************************************************************************/
/******************************************************************************
******************************************************************************/
#ifndef __BOS_H
#define __BOS_H
#ifdef __cplusplus
extern "C" {
#endif
/******************************************************************************
*
* BOS 操作码(opcode
*
*******************************************************************************/
#define BOS_OPCODE_AND 1 /*!< AND 操作码 */
#define BOS_OPCODE_OR 2 /*!< OR 操作码 */
#define BOS_OPCODE_XOR 3 /*!< XOR 操作码 */
#define BOS_OPCODE_BITFIELD 4 /*!< 位字段操作码 */
#define BOS_OPCODE_BIT_CLEAR 2 /*!< 位清零操作码 */
#define BOS_OPCODE_BIT_SET 3 /*!< 置位操作码 */
/******************************************************************************
*
* BOS宏定义,用来生成BOS硬件编码地址
*
*******************************************************************************/
/******************************************************************************
* 宏定义,用于生成逻辑与硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作逻辑与操作地址(32位硬件编码地址)
*
* @param[in] ADDR 32位地址.
*
* @return hardcoded 32位地址.
*
*
*****************************************************************************/
#define BOS_AND(ADDR) (*(volatile uint32_t *)(((uint32_t)ADDR) | (BOS_OPCODE_AND<<26)))
/******************************************************************************
* 宏定义,用于生成逻辑或硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作逻辑或操作地址(32位硬件编码地址)
*
* @param[in] ADDR 32位地址.
*
* @return hardcoded 32位地址.
*
*****************************************************************************/
#define BOS_OR(ADDR) (*(volatile uint32_t *)(((uint32_t)ADDR) | (BOS_OPCODE_OR<<26)))
/******************************************************************************
* 宏定义,用于生成逻辑异或硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作逻辑或操作地址(32位硬件编码地址)
*
* @param[in] ADDR 32位地址.
*
* @return hardcoded 32位地址.
*
*****************************************************************************/
#define BOS_XOR(ADDR) (*(volatile uint32_t *)(((uint32_t)ADDR) | (BOS_OPCODE_XOR<<26)))
#if !defined(BOS_SANITY_CHECK)
/*!
* @brief This is fastest way for BOS without sanity check.
*/
/******************************************************************************
* 宏定义,用于生成一位加载-清零(LAC1)硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作:1位加载清零操作地址(32位硬件编码地址)
*
* @param[in] ADDR 32位地址
* @param[in] bit 要清零的位, 0-based.
*
* @return hardcoded 32-bit address.
*
*****************************************************************************/
#define BOS_BIT_CLEAR(ADDR,bit) (*(volatile uint32_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_CLEAR <<26) \
| ((bit)<<21)))
/******************************************************************************
* 宏定义,用于生成一位加载-置位(LAS1)硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作:1位加载置位操作地址(32位硬件编码地址)
*
* @param[in] ADDR 32位地址.
* @param[in] bit 要置1的位, 0-based.
*
* @return hardcoded 32-bit address.
*
*****************************************************************************/
#define BOS_BIT_SET(ADDR,bit) (*(volatile uint32_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_SET <<26) \
| ((bit)<<21)))
/******************************************************************************
*宏定义,用于生成位操作存储字段插入(BFI)硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作存储字段插入硬件编码地址 (32位硬件编码地址).
*
* @param[in] ADDR 32位地址
* @param[in] bit 插入字段的起始位, 0-based.
* @param[in] width 插入字段的宽度, 1-based.
*
* @return hardcoded 32-bit address.
*
*****************************************************************************/
#define BOS_BITFIELD_INSERT(ADDR,bit,width) (*(volatile uint32_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit)<<23) | ((width-1))<<19))
/******************************************************************************
* *宏定义,用于生位操作存储加载无符号字段提取(UBFX)硬件编码地址 .
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 用于生位操作存储加载无符号字段提取(UBFX)操作地址 (32位硬件编码地址).
*
* @param[in] ADDR 32位地址.
* @param[in] bit 读取起始位, 0-based.
* @param[in] width 读取字段宽度, 1-based.
*
* @return hardcoded 32-bit address.
*
*****************************************************************************/
#define BOS_BITFIELD_EXTRACT(ADDR,bit,width) (*(volatile uint32_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit)<<23) | ((width-1))<<19))
#else
/*!
* @brief This is slow way for BOS as it has sanity check.
*/
/******************************************************************************
* 宏定义,用于生成一位加载-清零(LAC1)地址.
*
*******************************************************************************/
#define BOS_BIT_CLEAR(ADDR,bit) (*(volatile uint32_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_CLEAR <<26) \
| ((bit & 0x1F)<<21))) /*!< 位清零操作 */
/*****************************************************************************
* 宏定义,用于生成一位加载-置位(LAS1)硬件编码地址.
*
*******************************************************************************/
#define BOS_BIT_SET(ADDR,bit) (*(volatile uint32_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_SET <<26) \
| ((bit & 0x1F)<<21))) /*!< 置位操作 */
/******************************************************************************
*宏定义,用于生成位操作存储字段插入(BFI)硬件编码地址.
*
*******************************************************************************/
#define BOS_BITFIELD_INSERT(ADDR,bit,width) (*(volatile uint32_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit & 0x1F)<<23) | ((width-1) & 0xF)<<19)) /*!< 字段插入操作 */
/******************************************************************************
*宏定义,用于生位操作存储加载无符号字段提取(UBFX)硬件编码地址
*
*******************************************************************************/
#define BOS_BITFIELD_EXTRACT(ADDR,bit,width) (*(volatile uint32_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit & 0x1F)<<23) | ((width-1) & 0xF)<<19)) /*!< 字段提取操作 */
#endif
/******************************************************************************
* BOS宏定义,用来生成BOS硬件编码地址(8位地址)
*
*******************************************************************************/
/******************************************************************************
* 宏定义,用于生成逻辑或硬件编码地址.(8位地址)
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作逻辑与(AND)操作地址(32位硬件编码地址),对8位数据进行与操作
*
* @param[in] ADDR 32位地址.
*
* @return hardcoded 32-bit address.
*
*****************************************************************************/
#define BOS_AND_8b(ADDR) (*(volatile uint8_t *)(((uint32_t)ADDR) | (BOS_OPCODE_AND<<26)))
/******************************************************************************
* 宏定义,用于生成逻辑或硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作逻辑或(OR)操作地址(32位硬件编码地址),对8位数据进行或操作.
*
* @param[in] ADDR 32位地址.
*
* @return hardcoded 32位地址.
*
*****************************************************************************/
#define BOS_OR_8b(ADDR) (*(volatile uint8_t *)(((uint32_t)ADDR) | (BOS_OPCODE_OR<<26)))
/******************************************************************************
* 宏定义,用于生成逻辑异或硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作逻辑异或(XOR)操作地址(32位硬件编码地址),对8位数据进行异或操作..
*
* @param[in] ADDR 32位地址.
*
* @return hardcoded 32位地址.
*
*****************************************************************************/
#define BOS_XOR_8b(ADDR) (*(volatile uint8_t *)(((uint32_t)ADDR) | (BOS_OPCODE_XOR<<26)))
#if !defined(BOS_SANITY_CHECK)
/*!
* @brief This is fastest way for BOS without sanity check.
*/
/******************************************************************************
* 宏定义用于生成 1位加载清零(LAC1)硬件编码地址
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作:1位加载清零操作地址(32位硬件编码地址)用于8位数据操作.
*
* @param[in] ADDR 32位地址
* @param[in] bit 要清零的位, 0-based.
*
* @return hardcoded 32位地址.
*
*****************************************************************************/
#define BOS_BIT_CLEAR_8b(ADDR,bit) (*(volatile uint8_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_CLEAR <<26) \
| ((bit)<<21)))
/******************************************************************************
* 宏定义用于生成 1位加载置1(LAS1)硬件编码地址
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作1位加载置1(LAS1)操作码(32位硬件编码地址)用于8位数据操作
*
* @param[in] ADDR 32位地址
* @param[in] bit 要置1的位, 0-based.
*
* @return hardcoded 32位地址.
*
*****************************************************************************/
#define BOS_BIT_SET_8b(ADDR,bit) (*(volatile uint8_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_SET <<26) \
| ((bit)<<21)))
/******************************************************************************
*宏定义,用于生成位操作存储字段插入(BFI)硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作存储字段插入硬件编码地址 (32位硬件编码地址).用于8位数据操作
*
* @param[in] ADDR 32位地址
* @param[in] bit 插入字段的起始位, 0-based.
* @param[in] width 插入字段的宽度, 1-based.
*
* @return hardcoded 32位地址.
*
*****************************************************************************/
#define BOS_BITFIELD_INSERT_8b(ADDR,bit,width) (*(volatile uint8_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit)<<23) | ((width-1))<<19))
/******************************************************************************
*宏定义,用于生位操作存储加载无符号字段提取(UBFX)硬件编码地址 .
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 用于生位操作存储加载无符号字段提取(UBFX)操作地址 (32位硬件编码地址).用于8位操作
*
* @param[in] ADDR 32位地址.
* @param[in] bit 读取起始位, 0-based.
* @param[in] width 读取字段宽度, 1-based.
*
* @return hardcoded 32-bit address.
*
*****************************************************************************/
#define BOS_BITFIELD_EXTRACT_8b(ADDR,bit,width) (*(volatile uint8_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit<<23) | ((width-1))<<19))
#else
/*!
* @brief This is slow way for BOS as it has sanity check.
*/
/******************************************************************************
* 宏定义,用于生成一位加载-清零(LAC1)地址.
*
*******************************************************************************/
#define BOS_BIT_CLEAR_8b(ADDR,bit) (*(volatile uint8_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_CLEAR <<26) \
| ((bit & 0x1F)<<21))) /*!< 位清零操作,8位模式*/
/******************************************************************************
* 宏定义,用于生成一位加载-置位(LAS1)硬件编码地址.
*
*******************************************************************************/
#define BOS_BIT_SET_8b(ADDR,bit) (*(volatile uint8_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_SET <<26) \
| ((bit & 0x1F)<<21))) /*!< 位置1操作,8位模式*/
/******************************************************************************
* 宏定义,用于生成位操作存储字段插入(BFI)硬件编码地址.
*
*******************************************************************************/
#define BOS_BITFIELD_INSERT_8b(ADDR,bit,width) (*(volatile uint8_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit & 0x1F)<<23) | ((width-1) & 0xF)<<19)) /*!< 字段插入操作,8位模式 */
/******************************************************************************
*宏定义,用于生位操作存储加载无符号字段提取(UBFX)硬件编码地址
*******************************************************************************/
#define BOS_BITFIELD_EXTRACT_8b(ADDR,bit,width) (*(volatile uint8_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit & 0x1F)<<23) | ((width-1) & 0xF)<<19)) /*!< 字段提取操作,8位 */
#endif
/******************************************************************************
* BOS宏定义,用来生成BOS硬件编码地址(16位地址)
*
*******************************************************************************/
/******************************************************************************
* 宏定义,用于生成逻辑或硬件编码地址.(16位地址)
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作逻辑与(AND)操作地址(32位硬件编码地址),对8位数据进行与操作
*
* @param[in] ADDR 32位地址.
*
* @return hardcoded 32-bit address.
*
*****************************************************************************/
#define BOS_AND_16b(ADDR) (*(volatile uint16_t *)(((uint32_t)ADDR) | (BOS_OPCODE_AND<<26)))
/******************************************************************************
* 宏定义,用于生成逻辑或硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作逻辑或(OR)操作地址(32位硬件编码地址),对8位数据进行或操作.
*
* @param[in] ADDR 32位地址.
*
* @return hardcoded 32位地址.
*
*****************************************************************************/
#define BOS_OR_16b(ADDR) (*(volatile uint16_t *)(((uint32_t)ADDR) | (BOS_OPCODE_OR<<26)))
/******************************************************************************
* 宏定义,用于生成逻辑异或硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作逻辑异或(XOR)操作地址(32位硬件编码地址),对8位数据进行异或操作..
*
* @param[in] ADDR 32位地址.
*
* @return hardcoded 32位地址.
*
***************************************************************************/
#define BOS_XOR_16b(ADDR) (*(volatile uint16_t *)(((uint32_t)ADDR) | (BOS_OPCODE_XOR<<26)))
#if !defined(BOS_SANITY_CHECK)
/*!
* @brief This is fastest way for BOS without sanity check.
*/
/******************************************************************************
* 宏定义用于生成 1位加载清零(LAC1)硬件编码地址
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作:1位加载清零操作地址(32位硬件编码地址)用于16位数据操作.
*
* @param[in] ADDR 32位地址
* @param[in] bit 要清零的位, 0-based.
*
* @return hardcoded 32位地址.
*
****************************************************************************/
#define BOS_BIT_CLEAR_16b(ADDR,bit) (*(volatile uint16_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_CLEAR <<26) \
| ((bit)<<21)))
/******************************************************************************
* 宏定义用于生成 1位加载置1(LAS1)硬件编码地址
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作1位加载置1(LAS1)操作码(32位硬件编码地址)用于8位数据操作
*
* @param[in] ADDR 32位地址
* @param[in] bit 要置1的位, 0-based.
*
* @return hardcoded 32位地址.
*
*****************************************************************************/
#define BOS_BIT_SET_16b(ADDR,bit) (*(volatile uint16_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_SET <<26) \
| ((bit)<<21)))
/******************************************************************************
*宏定义,用于生成位操作存储字段插入(BFI)硬件编码地址.
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 生成BOS位操作存储字段插入硬件编码地址 (32位硬件编码地址).用于16位数据操作
*
* @param[in] ADDR 32位地址
* @param[in] bit 插入字段的起始位, 0-based.
* @param[in] width 插入字段的宽度, 1-based.
*
* @return hardcoded 32位地址.
*
*****************************************************************************/
#define BOS_BITFIELD_INSERT_16b(ADDR,bit,width) (*(volatile uint16_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit)<<23) | ((width-1))<<19))
/******************************************************************************
*宏定义,用于生位操作存储加载无符号字段提取(UBFX)硬件编码地址 .
*
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 用于生位操作存储加载无符号字段提取(UBFX)操作地址 (32位硬件编码地址).用于16位操作
*
* @param[in] ADDR 32位地址.
* @param[in] bit 读取起始位, 0-based.
* @param[in] width 读取字段宽度, 1-based.
*
* @return hardcoded 32-bit address.
*
*****************************************************************************/
#define BOS_BITFIELD_EXTRACT_16b(ADDR,bit,width) (*(volatile uint16_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit)<<23) | ((width-1))<<19))
#else
/*!
* @brief This is slow way for BOS as it has sanity check.
*/
/******************************************************************************
* 宏定义,用于生成一位加载-清零(LAC1)地址.
*
*******************************************************************************/
#define BOS_BIT_CLEAR_16b(ADDR,bit) (*(volatile uint16_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_CLEAR <<26) \
| ((bit & 0x1F)<<21))) /*!< 位清零操作,16位模式*/
/******************************************************************************
* 宏定义,用于生成一位加载-置位(LAS1)硬件编码地址.
*
*******************************************************************************/
#define BOS_BIT_SET_16b(ADDR,bit) (*(volatile uint16_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BIT_SET <<26) \
| ((bit & 0x1F)<<21))) /*!< 位置1操作,16位模式*/
/******************************************************************************
* 宏定义,用于生成位操作存储字段插入(BFI)硬件编码地址.
*
*******************************************************************************/
#define BOS_BITFIELD_INSERT_16b(ADDR,bit,width) (*(volatile uint16_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit & 0x1F)<<23) | ((width-1) & 0xF)<<19)) /*!< 字段插入操作,16位模式 */
/******************************************************************************
*宏定义,用于生位操作存储加载无符号字段提取(UBFX)硬件编码地址
*******************************************************************************/
#define BOS_BITFIELD_EXTRACT_16b(ADDR,bit,width) (*(volatile uint16_t *)(((uint32_t)ADDR) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit & 0x1F)<<23) | ((width-1) & 0xF)<<19)) /*!< 字段提取操作,16位 */
#endif
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,228 @@
/**************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file crc.c
* @brief 冗余校验模块(CRC)函数库
* @author Navota
* @date 2018-3-1
****************************************************************************/
#include "common.h"
#include "crc.h"
/*****************************************************************************//*!
*
* @brief 初始化CRC
*
* @param[in] pConfig 指向CRC配置结构体.
*
* @return none
*
*****************************************************************************/
void CRC_Init(CRC_ConfigType *pConfig)
{
uint32_t u32Sc ;
u32Sc = 0;
SIM->SCGC |= SIM_SCGC_CRC_MASK; //使能CRC控制模块时钟
u32Sc |= ((pConfig->bWidth & 0x01)<<24); //CRC模式选择
u32Sc |= CRC_CTRL_TOTR(pConfig->bTransposeReadType & 0x03); //设置数据读取的转置类型
u32Sc |= CRC_CTRL_TOT(pConfig->bTransposeWriteType & 0x03); //设置数据写入的转置类型
if (pConfig->bFinalXOR)
{
u32Sc |= CRC_CTRL_FXOR_MASK; //对CRC数据寄存的读取值进行异或操作
}
CRC0->CTRL = u32Sc;
if ( pConfig->bWidth )
{
CRC0->GPOLY = pConfig->u32PolyData; //写入32位多项式
}
else
{
CRC0->GPOLY_ACCESS16BIT.GPOLYL = pConfig->u32PolyData; /*!< 仅允许写16位多项式*/
}
}
/*****************************************************************************//*!
*
* @brief 16位模式下CRC计算函数.
*
* @param[in] seed 种子值
* @param[in] msg 指向数据数组
* @param[in] sizeBytes 数据大小
*
* @return data_out convertion result
*
*****************************************************************************/
uint32_t CRC_Cal16(uint32_t seed, uint8_t *msg, uint32_t sizeBytes)
{
uint32_t ctrl_reg,data_out,data_in;
uint8_t *pCRCBytes;
uint32_t sizeWords;
uint32_t i,j;
/* 设置WaS=1,写入种子值 */
ctrl_reg = CRC0->CTRL;
CRC0->CTRL = ctrl_reg | CRC_CTRL_WAS_MASK;
CRC0->ACCESS16BIT.DATAL = seed;
/* Set WaS=0,准备写入数据*/
CRC0->CTRL = ctrl_reg & 0xFD000000;
/*等待计算完成*/
sizeWords = sizeBytes>>1;
j = 0;
for(i=0;i<sizeWords;i++){
data_in = (msg[j] << 8) | (msg[j+1]); /*将数据写入CRC数据寄存器,以16位方式写入*/
j += 2;
CRC0->ACCESS16BIT.DATAL =data_in;
}
if (j<sizeBytes)
{
pCRCBytes = (uint8_t*)&CRC0->ACCESS8BIT.DATALL; /*以8位的方式写入剩余的数据*/
*pCRCBytes++ = msg[j];
}
if ((CRC0->CTRL& CRC_CTRL_TOTR_MASK)>1) //Modify
{
data_out=CRC0->ACCESS16BIT.DATAH; //读出字节转置后16位计算结果
}
else
{
data_out=CRC0->ACCESS16BIT.DATAL; //读出16位计算结果
}
return(data_out);
}
/*****************************************************************************//*!
*
* @brief 32位模式下CRC计算.
*
* @param[in] seed
* @param[in] msg 指向数据数组
* @param[in] sizeBytes 数据大小
*
* @return data_out convertion result
*
*****************************************************************************/
uint32_t CRC_Cal32(uint32_t seed, uint8_t *msg, uint32_t sizeBytes)
{
uint32_t ctrl_reg,data_out,data_in;
uint32_t sizeDwords;
uint8_t *pCRCBytes;
uint32_t i,j;
/* 设置WaS=1,写入种子值 */
ctrl_reg = CRC0->CTRL;
CRC0->CTRL = ctrl_reg | 0x02000000;
CRC0->DATA = seed;
/* Set WaS=0,准备写入数据*/
CRC0->CTRL = ctrl_reg & 0xFD000000;
/*等待数据计算完成*/
sizeDwords = sizeBytes>>2;
j = 0;
for(i=0;i<sizeDwords;i++)
{
data_in = ((msg[j] << 24) | (msg[j+1] << 16) | (msg[j+2] << 8) | msg[j+3]); /*将数据写入CRC数据寄存器,以32方式写入*/
j += 4;
CRC0->DATA = data_in;
}
if (j<sizeBytes)
{
pCRCBytes = (uint8_t*)&CRC0->ACCESS8BIT.DATALL; /*以8位的方式写入剩余的数据*/
#if defined(BYTE_ENABLES_1_2_4_8)
/*只写单个字节*/
for(;j<sizeBytes;j++)
{
*pCRCBytes++ = msg[j];
}
#elif defined(BYTE_ENABLES_3_6_C)
/*写入两个字节*/
data_in = 0;
i = 0;
for(;j<sizeBytes;j++)
{
data_in = (data_in <<8) | msg[j];
i++;
if (i==2)
{
i = 0;
CRC0->ACCESS16BIT.DATAL = data_in;
}
}
if (i==1)
{
CRC0->ACCESS8BIT.DATALL = data_in; /*!< 写入最后一个字节 */
}
#elif defined(BYTE_ENABLES_7_E)
/*!< 写入三个字节*/
data_in = 0;
i = 0;
for(;j<sizeBytes;j++)
{
data_in = (data_in <<8) | msg[j];
i++;
if (i==3)
{
i = 0;
/*写入第一个字符*/
CRC0->ACCESS8BIT.DATAHL = (data_in>>16) & 0xff; /*!< 写入高字的低字节 */
/*写入最后两个字节*/
CRC0->ACCESS16BIT.DATAL = data_in & 0x00ffff; /*!< 写入低字 */
}
}
if ( i == 2)
{
CRC0->ACCESS16BIT.DATAL = (data_in); /*!< 写最后两个字节 */
}
else if (i == 1)
{
CRC0->ACCESS8BIT.DATALL = data_in; /*!< 写最后一个字节 */
}
#else /*!< 只写低字节 */
for(;j<sizeBytes;j++)
{
*pCRCBytes = msg[j];
}
#endif
}
data_out=CRC0->DATA;
return(data_out); //读出32位计算结果
}
/*****************************************************************************//*!
*
* @brief 复位CRC模块
*
* @param none
*
* @return none
*
*****************************************************************************/
void CRC_DeInit(void)
{
CRC0->CTRL = 0x3000000; /*!<设置CRC位32位模式*/
CRC0->DATA = 0xFFFFFFFF;/*!< 写32位种子值到CRC数据寄存器*/
while(!(CRC0->DATA == 0xFFFFFFFF));
CRC0->GPOLY = 0x00001021;
CRC0->CTRL = 0; /*!<CRC控制寄存器清零*/
SIM->SCGC &= ~SIM_SCGC_CRC_MASK;
}
@@ -0,0 +1,66 @@
/******************************************************************************
*
* @brief CRC 驱动头文件.
*
******************************************************************************/
#ifndef CRC_H_
#define CRC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
/**********************************************************************!
* @brief CRC控制寄存器位定义
*
*******************************************************************/
#define CRC_WIDTH_16BIT 0 /*!< 选择16位CRC协议 */
#define CRC_WIDTH_32BIT 1 /*!< 选择32位CRC协议 */
#define CRC_DATA_SEED 1 /*!< 写入CRC数据寄存器的值为种子值 */
#define CRC_DATA_DATA 0 /*!< 写入CRC数据寄存器的值为数据值 */
#define CRC_READ_COMPLETE 1 /*!< 反转或补充CRC数据寄存器的读取值 */
#define CRC_READ_NONE 0 /*!< 读取数据寄存器时不执行异或运算*/
#define CRC_READ_TRANSPOSE_NONE 0 /*!< 读取数据寄存器的值无转置 */
#define CRC_READ_TRANSPOSE_BIT 1 /*!< 读取数据寄存器的值,字节中的位转置,字不转置*/
#define CRC_READ_TRANSPOSE_ALL 2 /*!< 读取数据寄存器的值,字节中的位和字节均转置 */
#define CRC_READ_TRANSPOSE_BYTE 3 /*!< 读取数据寄存器的值,仅字节转置,字节中的位不转置 */
#define CRC_WRITE_TRANSPOSE_NONE 0 /*!< 写数据时无转置 */
#define CRC_WRITE_TRANSPOSE_BIT 1 /*!< 写数据时,字节中的位转置,字节不转置 */
#define CRC_WRITE_TRANSPOSE_ALL 2 /*!< 写数据时,字节中的位和字节均转置 */
#define CRC_WRITE_TRANSPOSE_BYTE 3 /*!< 写数据时,仅字节转置,字节中的位不转置 */
/******************************************************************************
*
* CRC 配置结构体类型.
*
*******************************************************************************/
typedef struct
{
uint8_t bWidth : 1; /*!< 1: 32位CRC协议 0: 16位CRC协议 */
uint8_t bDataType : 1; /*!< 1: 写入种子值 , 0: 写入数据 */
uint8_t bFinalXOR : 1; /*!< 1: 读数据是反转或补充 , 0: 读数据时不执行异或*/
uint8_t bRESERVED : 1; /*!< 保留位 */
uint8_t bTransposeReadType : 2; /*!< 读取数据时的转置类型, 参阅参考手册 */
uint8_t bTransposeWriteType : 2; /*!< 写数据时的转置类型, 参阅参考手册 */
uint32_t u32PolyData ; /*!< 32位或16位多项式*/
} CRC_ConfigType, *CRC_ConfigPtr ;
/******************************************************************************/
void CRC_Init(CRC_ConfigType *pConfig);
uint32_t CRC_Cal16(uint32_t u32Seed, uint8_t *msg, uint32_t u32SizeBytes);
uint32_t CRC_Cal32(uint32_t u32Seed, uint8_t *msg, uint32_t u32SizeBytes);
void CRC_DeInit(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,63 @@
/***********************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file delay.c
* @brief systic函数库
* @author Navota
* @date 2018-3-1
************************************************************************/
#include "delay.h"
//延时驱动C 文件
/***********************************************************************************************
功能:初始化延时模块
形参:0
返回:0
详解:此函数用于初始化延时模块,使用函数时必须调用。否则会造成延时函数出错
************************************************************************************************/
void DelayInit(void)
{
SysTick->CTRL = 0;//选取systick的时钟为内核时钟/16
}
/***********************************************************************************************
功能:US级延时函数
形参:US 需要延时多少US
返回:0
详解:裸机下的延时US
************************************************************************************************/
void DelayUs(uint32_t us)
{
uint32_t temp;
SysTick->LOAD = (us*BUS_CLK_HZ/10000)/(1600); //时间加载
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL |= 0x01 ; //开始倒数
do
{
temp = SysTick->CTRL;
}while(temp & 0x01 && !(temp & (1<<16))); //等待时间到达
SysTick->CTRL &= ~0x01; //关闭计数器
}
/***********************************************************************************************
功能:MS级延时函数
形参:MS需要延时多少MS
返回:0
详解:裸机下的延时MS
************************************************************************************************/
void DelayMs(uint32_t ms)
{
uint32_t temp;
uint16_t i;
for(i = 0;i < ms;i++) //延时 MS
{
SysTick->LOAD = (BUS_CLK_HZ/1000)/16; //时间加载1ms
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL |= 0x01; //开始倒数
do
{
temp = SysTick->CTRL;
}while(temp & 0x01 && !(temp & (1<<16))); //等待时间到达
SysTick->CTRL &= ~0x01; //关闭计数器
}
}
@@ -0,0 +1,18 @@
#ifndef __DELAY_H__
#define __DELAY_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "sysinit.h"
#include "common.h"
#include "core_cm0plus.h"
//本构件实现的接口函数列表
void DelayInit(void); //延时初始化
void DelayUs(uint32_t us); //延时us
void DelayMs(uint32_t ms); //延时ms
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,270 @@
/*****************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file eeprom.c
* @brief flash模拟eeprom库函数
* @author Navota
* @date 2018-1-1
***************************************************************************/
#include "flash.h"
#include "eeprom.h"
#include <string.h>
/******************************************************************************
*
* EEPROM 擦除命令,擦掉eeprom
*输入参数:地址,函数将会擦除adr所在的扇区(512字节)
*
******************************************************************************/
uint16_t Adress_Js(uint32_t adr)
{
uint16_t err = EEPROM_ERR_SUCCESS;
if (adr & 0x03)
{
err = EEPROM_ERR_INVALID_PARAM;
return (err);
}
if (adr > 1024)
{
err = EEPROM_ADR_OverFlow;
return (err);
}
return (err);
}
/******************************************************************************
*
* EEPROM 擦除命令,擦掉eeprom
*输入参数:地址,函数将会擦除adr所在的512bytes eeprom
*
******************************************************************************/
uint16_t EEPROM_Erase(uint32_t adr)
{
uint16_t err = EEPROM_ERR_SUCCESS;
uint32_t e_adr;
if (adr & 0x03)
{
err = EEPROM_ERR_INVALID_PARAM;
return (err);
}
if (adr > 1024)
{
err = EEPROM_ADR_OverFlow;
return (err);
}
e_adr = adr + EEPROM_START_ADR;
err = Flash_EraseSector(e_adr);
return (err);
}
/******************************************************************************
*
* EEPROM 读取函数,读取地址所在的eeprom
*输入参数:地址
*
******************************************************************************/
uint32_t EEPROM_Read(uint32_t adr)
{
uint16_t err = EEPROM_ERR_SUCCESS;
uint32_t e_adr;
uint32_t data;
if (adr & 0x03)
{
err = EEPROM_ERR_INVALID_PARAM;
return (err);
}
if (adr > 1024)
{
err = EEPROM_ADR_OverFlow;
return (err);
}
e_adr = adr + EEPROM_START_ADR;
data = M32(e_adr);
return (data);
}
/******************************************************************************
*
* EEPROM 写函数,写地址所在的eeprom
* 写之前读取出来,判断eeprom是否为空,如果为空,则直接写
* 如果非空,则先把整个512bytes sector读取到sram,修改要写的位置
* 然后再写入到flash,模拟一个eeprom的写过程
* 输入参数:地址
*
******************************************************************************/
uint16_t EEPROM_Write(uint32_t adr, uint32_t Data)
{
uint32_t err = EEPROM_ERR_SUCCESS;
uint32_t e_adr;
uint32_t r_data;
uint16_t i;
uint32_t start_adr;
// uint32_t modify_adr;
uint32_t EEPROM_DATA[128];
if (adr & 0x03)
{
err = EEPROM_ERR_INVALID_PARAM;
return (err);
}
if (adr > 1024)
{
err = EEPROM_ADR_OverFlow;
return (err);
}
r_data = EEPROM_Read(adr);
e_adr = adr + EEPROM_START_ADR;
if (r_data == EEPROM_BLANK) //如果要写的位置是空的,则直接写
{
err = Flash_Program1LongWord(e_adr, Data);
}
else if ((r_data & Data) == Data) //如果要写的位置对应的bit,和要写的数据一致,或者是1,也是可以直接写
{
err = Flash_Program1LongWord(e_adr, Data);
}
else if (r_data == Data) //如果要写的数据和现有的数据一致,就不进行任何操作,直接返回
{
return (err);
}
else
{
start_adr = e_adr & EEPROM_SECTOR_MASK; //计算出sector的头地址
for (i = 0; i < 128; i++) //如果要写的位置不为空,则先把flash内容读取出来,放在sram中,修改
{
EEPROM_DATA[i] = M32(start_adr + 4 * i);
}
EEPROM_DATA[(adr & EEPROM_ARRAY_ADR_MASK) >> 2] = Data; //修改SRAM 中的数据
err = EEPROM_Erase(adr);
err = Flash_Program(start_adr, (uint8_t *)EEPROM_DATA, 512); //然后写入flash
}
return (err);
}
/******************************************************************************
*
*Byte 写函数
*
******************************************************************************/
uint16_t EEPROM_WriteByte(uint32_t adr, uint8_t Data)
{
uint32_t err = EEPROM_ERR_SUCCESS;
uint32_t data_mask;
uint32_t r_data;
uint32_t data_m0;
uint32_t data_m1;
uint32_t word_adr = adr & 0x3fc;
uint32_t b_sit = adr & 0x3;
//先让高位为FF
data_m0 = Data << b_sit * 8;
data_mask = 0xFFFFFFFF << (b_sit + 1) * 8;
//然后让低位为FF
data_m1 = 0xFFFFFFFF >> (32 - b_sit * 8);
data_m1 = data_m1 | data_m0 | data_mask;
r_data = EEPROM_Read(word_adr);
r_data |= 0xFF << b_sit * 8;
data_m1 = data_m1 & r_data;
err = EEPROM_Write(word_adr, data_m1);
return (err);
}
/******************************************************************************
*
*Byte 读函数
*
******************************************************************************/
uint8_t EEPROM_ReadByte(uint32_t adr)
{
uint32_t r_data;
uint32_t word_adr = adr & 0x3fc;
uint32_t b_sit = adr & 0x3;
uint8_t data;
r_data = EEPROM_Read(word_adr);
data = (r_data >> b_sit * 8) & 0xff;
return (data);
}
/******************************************************************************
*
*写函数,写一个长度为bytesize,到eeprom
*先把1k的eeprom读取放入sram,然后修改要写的位置,
*这个函数是还可以再优化的
******************************************************************************/
uint16_t EERPOM_Writeup4byte(uint32_t adr, uint8_t *pData, uint32_t length)
{
uint8_t buf[512];
uint8_t *pbuf;
uint32_t e_adr;
uint32_t e_sec;
uint32_t e_offset;
uint32_t a;
uint32_t err = EEPROM_ERR_SUCCESS;
#ifdef IAR
if (adr & 0x03)
{
err = EEPROM_ERR_INVALID_PARAM;
return (err);
}
#endif
if ((adr + length) > 1024)
{
err = EEPROM_ADR_OverFlow;
return (err);
}
e_adr = adr + EEPROM_START_ADR;
e_sec = e_adr & EEPROM_SECTOR_MASK;
e_offset = e_adr & 0x1ff;
while (length > 0)
{
//如果起始地址不等于0,或者长度小于512 都进入这个循环
if (e_offset || (length < 512))
{
pbuf = buf;
a = 512 - e_offset;
a = (length > a ? a : length);
memcpy(buf, (uint8_t *)e_sec, 512);
memcpy(&buf[e_offset], pData, a);
pData += a;
length -= a;
e_offset = 0;
}
else
{ //如果起始地址等于0且长度大于512
pbuf = pData;
pData += 512;
length -= 512;
}
err = Flash_EraseSector(e_sec);
err = Flash_Program(e_sec, (uint8_t *)pbuf, 512); //然后写入flash
e_sec += 0x200;
}
return err;
}
@@ -0,0 +1,33 @@
/******************************************************************************
*
* @brief eeprom Çý¶¯Í·Îļþ.
*
******************************************************************************/
#ifndef EEPROM_H_
#define EEPROM_H_
/******************************************************************************
* Includes
******************************************************************************/
#include "common.h"
#define EERPOM_SIZE 1024 // in bytes
#define EEPROM_START_ADR 0x00401000
#define EEPROM_ERR_SUCCESS 0x01
#define EEPROM_ADR_OverFlow 0x02
#define EEPROM_ERR_INVALID_PARAM 0x04
#define EEPROM_BLANK 0xffffffff
#define EEPROM_SECTOR_MASK 0x00401200
#define EEPROM_ARRAY_ADR_MASK 0x1ff
uint16_t Adress_Js(uint32_t adr);
uint16_t EEPROM_Erase(uint32_t adr);
uint32_t EEPROM_Read(uint32_t adr);
uint8_t EEPROM_ReadByte(uint32_t adr);
uint16_t EEPROM_Write(uint32_t adr, uint32_t Data);
uint16_t EEPROM_WriteByte(uint32_t adr, uint8_t Data);
uint16_t EERPOM_Writeup4byte(uint32_t adr, uint8_t *pData,uint32_t length);
#endif
@@ -0,0 +1,852 @@
/*****************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file etm.c
* @brief etm定时器函数库
* @author Navota
* @date 2018-3-1
***************************************************************************/
#include "common.h"
#include "etm.h"
/*!
* @brief 存放回调入口
*
*/
ETM_CallbackPtr ETM_Callback[3] = {(ETM_CallbackPtr)NULL};
/******************************************************************************
* 定义ETM的接口函数
*******************************************************************************/
/*******************************************************************************//*!
*
* @brief 设置ETM模块时钟资源及分频系数.
*
* @param[in] pETM 指向三个ETM定时器其中一个的基址.
* @param[in] ClockSource ETM 选择的时钟源 禁用(ETM_CLOCK_NOCLOCK)、系统时钟(ETM_CLOCK_SYSTEMCLOCK)、固定频率时钟/2ETM_CLOCK_FIXEDFREQCLOCK)、外接时钟(ETM_CLOCK_EXTERNALCLOCK.
* @param[in] ClockPrescale 分频系数.
*
* @return none.
*
*********************************************************************************/
void ETM_ClockSet(ETM_Type *pETM, uint8_t u8ClockSource, uint8_t u8ClockPrescale)
{
uint8_t u8Temp;
u8Temp = (pETM->SC & 0xE0);//pETM指向的SC寄存器低5位清0,即未选择时钟,时钟输入采取1分频
u8Temp |= (ETM_SC_CLKS(u8ClockSource & 0x3) | ETM_SC_PS(u8ClockPrescale & 0x7));
pETM->SC = u8Temp;//配置该ETM的状态与控制寄存器ETMx_SC
}
/*********************************************************************************//*!
*
* @brief ETM中PWM的初始化函数
*
* @param[in] pETM 指向三个ETM定时器其中一个的基址.
* @param[in] PWMModeSelect 居中对齐CPWM(10)、边沿对齐EPWM(01)以及级联模式PWM(11.
* @param[in] PWMEdgeSelect 高真脉冲(01)、低真脉冲(10).
*
* @return none.
*
*********************************************************************************/
void ETM_PWMInit(ETM_Type *pETM, uint8_t u8PWMModeSelect, uint8_t u8PWMEdgeSelect)
{
uint8_t channels, i;
ASSERT((ETM0== pETM) || (ETM1== pETM) || (ETM2== pETM));//断言来检测ETM通道是否正确
/* 选用ETM时钟 */
if (ETM0 == pETM)
{
channels = 2;
SIM->SCGC |= SIM_SCGC_ETM0_MASK; //ETM0共有两个通道
}
else if(ETM1 == pETM)
{
channels = 2;
SIM->SCGC |= SIM_SCGC_ETM1_MASK; //ETM1共有两个通道
}
else
{
channels = 6;
SIM->SCGC |= SIM_SCGC_ETM2_MASK; //ETM2共有六个通道
}
pETM->SC = 0x0; //关闭计数器
pETM->MOD = ETM_MOD_INIT;
if(ETM_PWMMODE_CENTERALLIGNED == u8PWMModeSelect) //打开CPWM
{
pETM->SC |= ETM_SC_CPWMS_MASK;
}
else if(ETM_PWMMODE_COMBINE == u8PWMModeSelect)
{
ASSERT(ETM2 == pETM);
pETM->MODE |= ETM_MODE_WPDIS_MASK | ETM_MODE_ETMEN_MASK;
pETM->COMBINE = ETM_COMBINE_COMBINE0_MASK | ETM_COMBINE_COMP0_MASK | ETM_COMBINE_SYNCEN0_MASK | ETM_COMBINE_DTEN0_MASK |
ETM_COMBINE_COMBINE1_MASK | ETM_COMBINE_COMP1_MASK | ETM_COMBINE_SYNCEN1_MASK | ETM_COMBINE_DTEN1_MASK |
ETM_COMBINE_COMBINE2_MASK | ETM_COMBINE_COMP2_MASK | ETM_COMBINE_SYNCEN2_MASK | ETM_COMBINE_DTEN2_MASK
; // 打开通道级联模式
pETM->SC &= ~ETM_SC_CPWMS_MASK;
}
if(ETM_PWM_HIGHTRUEPULSE == u8PWMEdgeSelect)
{
/* 配置通道寄存器,设置通道状态及通道计数值 */
for(i=0; i<channels; i++)
{
pETM->CONTROLS[i].CnSC = ETM_CnSC_MSB_MASK | ETM_CnSC_ELSB_MASK;
pETM->CONTROLS[i].CnV = ETM_C0V_INIT + i*100;
}
}
else if(ETM_PWM_LOWTRUEPULSE == u8PWMEdgeSelect)
{
for(i=0; i<channels; i++)
{
pETM->CONTROLS[i].CnSC = ETM_CnSC_MSB_MASK | ETM_CnSC_ELSA_MASK;
pETM->CONTROLS[i].CnV = ETM_C0V_INIT + i*100 ;
}
}
}
/*********************************************************************************//*!
*
* @brief 禁用ETM的通道功能,用于GPIO或其他功能
*
* @param[in] pETM 指向三个ETM定时器其中一个的基址.
* @param[in] u8ETM_Channel 通道号.
*
* @return none.
*
*********************************************************************************/
void ETM_disblechannel(ETM_Type *pETM, uint8_t u8ETM_Channel)
{
uint8_t i;
i= u8ETM_Channel;
pETM->CONTROLS[i].CnSC &= ~ (ETM_CnSC_ELSB_MASK| ETM_CnSC_ELSA_MASK);
}
/*********************************************************************************//*!
*
* @brief 输入捕捉初始化函数.
*
* @param[in] pETM 指向三个ETM定时器其中一个的基址.
* @param[in] Channel 配置通道号.
* @param[in] CaptureMode 选择捕捉方式:上升沿, 下降沿或跳变沿.
*
* @return none.
*
*********************************************************************************/
void ETM_InputCaptureInit(ETM_Type *pETM, uint8_t u8ETM_Channel, uint8_t u8CaptureMode)
{
ASSERT(((ETM0 == pETM) && (u8ETM_Channel < 2)) ||
((ETM1 == pETM) && (u8ETM_Channel < 2)) ||
((ETM2 == pETM) && (u8ETM_Channel < 6))
);
/* 选用ETM时钟 */
if ((ETM0 == pETM) && (u8ETM_Channel < 2))
{
SIM->SCGC |= SIM_SCGC_ETM0_MASK;
NVIC_EnableIRQ(ETM0_IRQn);
}
else if((ETM1 == pETM) && (u8ETM_Channel < 2))
{
SIM->SCGC |= SIM_SCGC_ETM1_MASK;
NVIC_EnableIRQ(ETM1_IRQn);
}
else
{
SIM->SCGC |= SIM_SCGC_ETM2_MASK;
NVIC_EnableIRQ(ETM2_IRQn);
}
pETM->SC = 0x0; //关闭计数器
pETM->MOD = 0xFFFF;
if(ETM_INPUTCAPTURE_RISINGEDGE == u8CaptureMode) //开启中断,捕获上升沿
{
pETM->CONTROLS[u8ETM_Channel].CnSC = ETM_CnSC_CHIE_MASK | ETM_CnSC_ELSA_MASK;
}
else if(ETM_INPUTCAPTURE_FALLINGEDGE == u8CaptureMode) //捕获下降沿
{
pETM->CONTROLS[u8ETM_Channel].CnSC = ETM_CnSC_CHIE_MASK | ETM_CnSC_ELSB_MASK;
}
else if(ETM_INPUTCAPTURE_BOTHEDGE == u8CaptureMode) //捕获跳变沿
{
pETM->CONTROLS[u8ETM_Channel].CnSC = ETM_CnSC_CHIE_MASK | ETM_CnSC_ELSA_MASK | ETM_CnSC_ELSB_MASK;
}
}
/*********************************************************************************//*!
*
* @brief 对ETM配置双边捕获模式来测量一个脉冲的宽度或周期(ETM2).
*
* @param[in] pETM ETM2.
* @param[in] ChannelPair 频道配对数的配置为: 0, 2, 4.
* @param[in] CaptureMode 选择单周期捕捉(4),和连续捕捉方式(5).
* @param[in] Channel_N_Edge 频道N边沿检测:无(0),上升沿(1)下降沿(2)双沿(3).
* @param[in] Channel_Np1_Edge 频道N+1边沿检测.
*
* @return none.
*
*********************************************************************************/
void ETM_DualEdgeCaptureInit(ETM_Type *pETM, uint8_t u8ChannelPair, uint8_t u8CaptureMode,
uint8_t u8Channel_N_Edge, uint8_t u8Channel_Np1_Edge)
{
ASSERT((ETM2 == pETM) && (u8ChannelPair < 6) && !(u8ChannelPair & 1) );
SIM->SCGC |= SIM_SCGC_ETM2_MASK;
if((0 == u8ChannelPair) || (2== u8ChannelPair))
{
}
pETM->SC = 0x0; /* 关闭计数器 */
pETM->MOD = 0xFFFF;
pETM->MODE |= ETM_MODE_ETMEN_MASK; /* ETMEN = 1 */
pETM->COMBINE |= ((ETM_COMBINE_DECAPEN0_MASK) << (u8ChannelPair * 4));
pETM->CONTROLS[u8ChannelPair].CnSC &= ~ETM_CnSC_CHF_MASK; /* CH(n)F 和 CH(n+1)F 位必须要先清除 */
pETM->CONTROLS[u8ChannelPair + 1].CnSC &= ~ETM_CnSC_CHF_MASK;
if(ETM_INPUTCAPTURE_DUALEDGE_ONESHOT == u8CaptureMode) /* 单次模式 */
{
pETM->CONTROLS[u8ChannelPair].CnSC &= ~ETM_CnSC_MSA_MASK;
pETM->CONTROLS[u8ChannelPair+1].CnSC &= ~ETM_CnSC_MSA_MASK;
}
else if(ETM_INPUTCAPTURE_DUALEDGE_CONTINUOUS == u8CaptureMode) /* 连续模式 */
{
pETM->CONTROLS[u8ChannelPair].CnSC |= ETM_CnSC_MSA_MASK;
pETM->CONTROLS[u8ChannelPair+1].CnSC |= ETM_CnSC_MSA_MASK;
}
pETM->CONTROLS[u8ChannelPair].CnSC |= (u8Channel_N_Edge << 2); /* 选择检测边沿 */
pETM->CONTROLS[u8ChannelPair + 1].CnSC |= (u8Channel_Np1_Edge << 2);
pETM->COMBINE |= (ETM_COMBINE_DECAP0_MASK << (u8ChannelPair * 4));
}
/*********************************************************************************//*!
*
* @brief 输出对比初始化.
*
* @param[in] pETM 指向三个ETM定时器其中一个的基址.
* @param[in] Channel 配置通道即通道号.
* @param[in] CompareMode 选择模式:翻转(01)、置位(11)、清0(10).
*
* @return none.
*
*********************************************************************************/
void ETM_OutputCompareInit(ETM_Type *pETM, uint8_t u8ETM_Channel, uint8_t u8CompareMode)
{
ASSERT(((ETM0 == pETM) && (u8ETM_Channel < 2)) ||
((ETM1 == pETM) && (u8ETM_Channel < 2)) ||
((ETM2 == pETM) && (u8ETM_Channel < 6))
);
/* 选用ETM模块时钟 */
if(ETM0 == pETM)
{
SIM->SCGC |= SIM_SCGC_ETM0_MASK;
}
else if(ETM1 == pETM)
{
SIM->SCGC |= SIM_SCGC_ETM1_MASK;
}
else
{
SIM->SCGC |= SIM_SCGC_ETM2_MASK;
}
pETM->SC = 0x0; //关闭计数器
pETM->MOD = ETM_MOD_INIT;
pETM->CONTROLS[u8ETM_Channel].CnSC = (ETM_CnSC_MSA_MASK | (u8CompareMode << 2));
pETM->CONTROLS[u8ETM_Channel].CnV = ETM_C0V_INIT;
}
/*********************************************************************************//*!
*
* @brief 实现软件同步触发(ETM2.
*
* @param[in] pETM ETM2.
*
* @return none.
*
*********************************************************************************/
void ETM_SoftwareSync(ETM_Type *pETM)
{
ASSERT(ETM2 == pETM);
pETM->SYNCONF |= ETM_SYNCONF_SYNCMODE_MASK;
pETM->SYNC |= ETM_SYNC_SWSYNC_MASK;
}
/*********************************************************************************//*!
*
* @brief ETM中配置ETMx_SYNC 寄存器来选择硬件触发(ETM2).
*
* @param[in] pETM ETM2.
* @param[in] u8TriggerN 选择硬件触发资源.
*
* @return none.
*
*********************************************************************************/
void ETM_HardwareSync(ETM_Type *pETM, uint8_t u8TriggerN)
{
ASSERT(ETM2 == pETM);
pETM->SYNCONF |= ETM_SYNCONF_SYNCMODE_MASK;
switch(u8TriggerN)
{
case ETM_SYNC_TRIGGER_TRIGGER2:
pETM->SYNC |= ETM_SYNC_TRIG2_MASK;
break;
case ETM_SYNC_TRIGGER_TRIGGER1:
pETM->SYNC |= ETM_SYNC_TRIG1_MASK;
break; /* 需要先配置ETM0CH0 */
case ETM_SYNC_TRIGGER_TRIGGER0:
pETM->SYNC |= ETM_SYNC_TRIG0_MASK;
break; /* 需要先配置ACMP0 */
default:
break;
}
}
/*********************************************************************************//*!
*
* @brief 通过配置ETM保证硬件同步,产生触发(可有多个触发)(ETM2).
*
* @param[in] pETM ETM2.
* @param[in] u8TriggerMask 硬件触发资源标志号.联合TRIG0~TREG2.(x000xxxx~x111xxxx)
*
* @return none.
*
*********************************************************************************/
void ETM_HardwareSyncCombine(ETM_Type *pETM, uint8_t u8TriggerMask)
{
ASSERT(ETM2 == pETM);
pETM->SYNCONF |= ETM_SYNCONF_SYNCMODE_MASK;
pETM->SYNC &= 0x8F;
pETM->SYNC |= (u8TriggerMask & 0x70);
}
/*********************************************************************************//*!
*
* @brief 硬件触发2产生ETM2的PWM同步触发(ETM2)
*
* @param[in] pETM ETM2.
*
* @return none.
*
*********************************************************************************/
void ETM_GenerateTrig2(ETM_Type *pETM)
{
ASSERT(ETM2 == pETM);
if(pETM->SYNC & ETM_SYNC_TRIG2_MASK)
{
#if defined(CPU_NV32)
SIM->SOPT |= SIM_SOPT_ETMSYNC_MASK;
#endif
}
}
/*********************************************************************************//*!
*
* @brief ETM死区时间设置(ETM2.
*
* @param[in] pETM ETM2.
* @param[in] PrescalerValue 总线时钟分频值, 0 to 3.
* @param[in] DeadETMeValue 时钟数值插入, 0 to 63.
*
* @return none.
*
*********************************************************************************/
void ETM_PWMDeadETMeSet(ETM_Type *pETM, uint8_t u8PrescalerValue, uint8_t u8DeadETMeValue)
{
ASSERT(ETM2 == pETM);
pETM->COMBINE |= 0x101010; /* 使能死区时间插入 */
if(!(pETM->MODE & ETM_MODE_WPDIS_MASK)) /* 判断是否使能写保护 */
{
pETM->MODE |= ETM_MODE_WPDIS_MASK; /* 禁止写保护 */
pETM->DEADETME = (ETM_DEADETME_DTVAL(u8DeadETMeValue & 0x3F) | ETM_DEADETME_DTPS(u8PrescalerValue & 0x3));
pETM->MODE &= ~ETM_MODE_WPDIS_MASK; /* 使能写保护 */
}
else
{
/* 若无写保护 */
pETM->DEADETME = (ETM_DEADETME_DTVAL(u8DeadETMeValue & 0x3F) | ETM_DEADETME_DTPS(u8PrescalerValue & 0x3));
}
pETM->SYNC |= ETM_SYNC_SWSYNC_MASK; /* 设置软件同步 */
}
/*********************************************************************************//*!
*
* @brief 设置输出屏蔽(ETM2.
*
* @param[in] pETM ETM2.
* @param[in] Channel 需要屏蔽的通道号.
*
* @return none.
*
*********************************************************************************/
void ETM_OutputMaskSet(ETM_Type *pETM, uint8_t u8ETM_Channel)
{
ASSERT((ETM2 == pETM) && (u8ETM_Channel < 6));
pETM->OUTMASK |= (1 << u8ETM_Channel);
if(pETM->SYNC & ETM_SYNC_SYNCHOM_MASK) /* 通过PWM同步更新 */
{
pETM->SYNCONF |= ETM_SYNCONF_SYNCMODE_MASK;
if(pETM->SYNCONF & ETM_SYNCONF_SWOM_MASK) /* 软件触发激活 */
{
pETM->SYNC |= ETM_SYNC_SWSYNC_MASK;
}
else if(pETM->SYNCONF & ETM_SYNCONF_HWOM_MASK) /* 硬件触发激活 */
{
pETM->SYNC |= ETM_SYNC_TRIG2_MASK;
#if defined(CPU_NV32)
SIM->SOPT |= SIM_SOPT_ETMSYNC_MASK; /* 使能硬件同步 */
#endif
}
else
{
}
}
else /* 若无软件同步, 在系统时钟的上升沿对其更新 */
{
}
}
/*********************************************************************************//*!
*
* @brief 配置软件输出控制SWOCTRL寄存器的同步是否由软件触发(ETM2).
*
* @param[in] pETM ETM2.
* @param[in] Channel 软件触发PWM波的通道选择.
* @param[in] ChannelValue 0或1,0不触发;1触发.
*
* @return none.
*
*********************************************************************************/
void ETM_SWOutputControlSet(ETM_Type *pETM, uint8_t u8ETM_Channel, uint8_t u8ChannelValue)
{
ASSERT((ETM2 == pETM) && (u8ETM_Channel < 6));
if(ETM_SWOCTRL_HIGH == u8ChannelValue)
{
pETM->SWOCTRL |= (0x0101 << u8ETM_Channel);
}
else if(ETM_SWOCTRL_LOW == u8ChannelValue)
{
pETM->SWOCTRL |= (1 << u8ETM_Channel);
pETM->SWOCTRL &= ~(0x100 << u8ETM_Channel);
}
if(pETM->SYNCONF & ETM_SYNCONF_SWOC_MASK)
{
pETM->SYNCONF |= ETM_SYNCONF_SYNCMODE_MASK;
if(pETM->SYNCONF & ETM_SYNCONF_SWSOC_MASK)
{
pETM->SYNC |= ETM_SYNC_SWSYNC_MASK;
}
else if(pETM->SYNCONF & ETM_SYNCONF_HWSOC_MASK)
{
pETM->SYNC |= ETM_SYNC_TRIG2_MASK;
#if defined(CPU_NV32)
SIM->SOPT |= SIM_SOPT_ETMSYNC_MASK;
#endif
}
}
else
{
}
}
/*********************************************************************************//*!
*
* @brief 设置通道输出极性(ETM2).
*
* @param[in] pETM ETM2.
* @param[in] Channel PWM波的通道选择.
* @param[in] ActiveValue 极性的选择,0为高电平,1为低电平.
*
* @return none.
*
*********************************************************************************/
void ETM_PolaritySet(ETM_Type *pETM, uint8_t u8ETM_Channel, uint8_t u8ActiveValue)
{
ASSERT((ETM2 == pETM) && (u8ETM_Channel < 6));
if(ETM_POLARITY_HIGHACTIVE == u8ActiveValue)
{
pETM->POL &= ~(1 << u8ETM_Channel);
}
else if(ETM_POLARITY_LOWACTIVE == u8ActiveValue)
{
pETM->POL |= (1 << u8ETM_Channel);
}
}
/*********************************************************************************//*!
*
* @brief 设置ETM模块在debug模式下的行为(ETM2).
*
* @param[in] pETM ETM2.
* @param[in] u8DebugMode debug 的模式从00-11之间选择.
*
* @return none.
*
*********************************************************************************/
void ETM_SetDebugModeBehavior(ETM_Type *pETM, uint8_t u8DebugMode)
{
ASSERT((ETM2 == pETM));
pETM->CONF &= ~ETM_CONF_BDMMODE_MASK;
pETM->CONF |= ETM_CONF_BDMMODE(u8DebugMode);
}
/*********************************************************************************//*!
*
* @brief ETM中TOF频率大小的设置(ETM2).
*
* @param[in] pETM ETM2.
* @param[in] u8TOFNUM TOF频率数,大小0和31之间.
*
* @return none.
*
*********************************************************************************/
void ETM_SetTOFFrequency(ETM_Type *pETM, uint8_t u8TOFNUM)
{
ASSERT((ETM2 == pETM));
pETM->CONF &= ~ETM_CONF_NUMTOF_MASK;
pETM->CONF |= ETM_CONF_NUMTOF(u8TOFNUM);
}
/*********************************************************************************//*!
*
* @brief 交换通道CHn)和通道CHn+1)的输出结果(ETM2).
*
* @param[in] pETM ETM2.
* @param[in] ChannelPair 要被交换的通道数号,即n可为0,1,2.
*
* @return none.
*
*********************************************************************************/
void ETM_InvertChannel(ETM_Type *pETM, uint8_t u8ChannelPair)
{
ASSERT((ETM2 == pETM) && u8ChannelPair <= 2);
pETM->INVCTRL |= 1<<u8ChannelPair;
if(pETM->SYNCONF & ETM_SYNCONF_INVC_MASK)
{
pETM->SYNCONF |= ETM_SYNCONF_SYNCMODE_MASK;
if(pETM->SYNCONF & ETM_SYNCONF_SWINVC_MASK)
{
pETM->SYNC |= ETM_SYNC_SWSYNC_MASK;
}
else if(pETM->SYNCONF & ETM_SYNCONF_HWINVC_MASK)
{
pETM->SYNC |= ETM_SYNC_TRIG2_MASK;
#if defined(CPU_NV32)
SIM->SOPT |= SIM_SOPT_ETMSYNC_MASK;
#endif
}
}
else
{
}
}
/*****************************************************************************//*!
*
* @brief ETM模块初始化函数.
*
* @param[in] pETM 指向三个ETM定时器其中一个的基址.
* @param[in] pConfig 配置ETM模块的结构体.
*
* @return none.
*
*****************************************************************************/
void ETM_Init(ETM_Type *pETM, ETM_ConfigType *pConfig)
{
ASSERT((ETM0 == pETM) || (ETM1 == pETM) || (ETM2 == pETM));
if(ETM0 == pETM)
{
SIM->SCGC |= SIM_SCGC_ETM0_MASK;
}
else if(ETM1 == pETM)
{
SIM->SCGC |= SIM_SCGC_ETM1_MASK;
}
else
{
SIM->SCGC |= SIM_SCGC_ETM2_MASK;
}
/*关闭计数器*/
pETM->SC = 0;
pETM->MODE = pConfig->mode;
pETM->MOD = pConfig->modulo;
pETM->CNT = pConfig->cnt;
if( pETM->MODE & ETM_MODE_ETMEN_MASK )
{
/* 当 ETMEN = 1时, 下列寄存器可以写入 */
pETM->COMBINE = pConfig->combine;
pETM->CNTIN = pConfig->cntin;
pETM->SYNC = pConfig->sync;
pETM->OUTINIT = pConfig->outinit;
pETM->OUTMASK = pConfig->outmask;
pETM->DEADETME = pConfig->deadETMe;
pETM->EXTTRIG = pConfig->exttrig;
pETM->POL = pConfig->pol;
pETM->FMS = pConfig->fms;
pETM->FILTER = pConfig->filter;
pETM->FLTCTRL = pConfig->fltctrl;
pETM->FLTPOL = pConfig->fltpol;
pETM->CONF = pConfig->conf;
pETM->SYNCONF = pConfig->synconf;
pETM->SWOCTRL = pConfig->swoctrl;
pETM->PWMLOAD = pConfig->pwmload;
}
/* 写入状态控制寄存器来使能时钟*/
pETM->SC = pConfig->sc;
}
/*****************************************************************************//*!
*
* @brief 复位ETM模块.
*
* @param[in] pETM 指向三个ETM定时器其中一个的基址.
*
* @return none.
*
*****************************************************************************/
void ETM_DeInit(ETM_Type *pETM)
{
ASSERT((ETM0 == pETM) || (ETM1 == pETM) || (ETM2 == pETM));
pETM->SC = 0;
pETM->MOD = 0;
pETM->CNT = 0;
if(ETM2 == pETM)
{
pETM->MODE = 0x4;
pETM->COMBINE = 0;
pETM->CNTIN = 0;
pETM->SYNC = 0;
pETM->OUTINIT = 0;
pETM->OUTMASK = 0;
pETM->DEADETME = 0;
pETM->EXTTRIG = 0;
pETM->POL = 0;
pETM->FMS = 0;
pETM->FILTER = 0;
pETM->FLTCTRL = 0;
pETM->FLTPOL = 0;
pETM->CONF = 0;
pETM->SYNCONF = 0;
pETM->SWOCTRL = 0;
pETM->PWMLOAD = 0;
}
/* 禁止ETM模块的时钟 */
if (ETM0 == pETM)
{
SIM->SCGC &= ~SIM_SCGC_ETM0_MASK;
NVIC_DisableIRQ(ETM0_IRQn);
}
else if(ETM1 == pETM)
{
SIM->SCGC &= ~SIM_SCGC_ETM1_MASK;
NVIC_DisableIRQ(ETM1_IRQn);
}
else if (ETM2 == pETM)
{
SIM->SCGC &= ~SIM_SCGC_ETM2_MASK;
NVIC_DisableIRQ(ETM2_IRQn);
}
}
/*****************************************************************************//*!
*
* @brief 配置ETM通道, 包括通道状态及控制寄存器CnSC和通道计数值寄存器CnV.
*
* @param[in] pETM 指向三个ETM定时器其中一个的基址.
* @param[in] ETM_Channel ETM的通道号.
* @param[in] pTETMCH_Params 配置ETM通道参数的结构体.
*
* @return none.
*
*****************************************************************************/
void ETM_ChannelInit(ETM_Type *pETM, uint8_t u8ETM_Channel, ETM_ChParamsType *pTETMCH_Params)
{
ASSERT((ETM0 == pETM) || (ETM1 == pETM) || (ETM2 == pETM)); //断言检测通道的正确性
if (ETM0 == pETM)
{
ASSERT(u8ETM_Channel < 2);
SIM->SCGC |= SIM_SCGC_ETM0_MASK;
}
else if(ETM1 == pETM)
{
ASSERT(u8ETM_Channel < 2);
SIM->SCGC |= SIM_SCGC_ETM1_MASK;
}
else
{
ASSERT(u8ETM_Channel < 6);
SIM->SCGC |= SIM_SCGC_ETM2_MASK;
}
pETM->CONTROLS[u8ETM_Channel].CnSC = pTETMCH_Params->u8CnSC;
pETM->CONTROLS[u8ETM_Channel].CnV = pTETMCH_Params->u16CnV;
return;
}
/*****************************************************************************//*!
*
* @brief 配置级联模式及占空比(ETM2).
*
* @param[in] pETM ETM2.
* @param[in] ETM_Channel 奇通道数:1、3、5.
* @param[in] dutyCycle 设置占空比,若DutyCycle为10,那么占空比就为10%.
*
* @return none.
*
*****************************************************************************/
void ETM_SetDutyCycleCombine(ETM_Type *pETM, uint8_t u8ETM_Channel, uint8_t u8DutyCycle)
{
uint16_t cnv = pETM->CONTROLS[u8ETM_Channel-1].CnV;
uint16_t modulo = pETM->MOD;
ASSERT((1 == u8ETM_Channel) || (3 == u8ETM_Channel) || (5 == u8ETM_Channel));
cnv += (u8DutyCycle * (modulo+1)) / 100;
if(cnv > modulo)
{
cnv = modulo - 1;
}
pETM->CONTROLS[u8ETM_Channel].CnV = cnv ;
pETM->PWMLOAD |= ETM_PWMLOAD_LDOK_MASK | (1<<u8ETM_Channel);
}
/*****************************************************************************//*!
*
* @brief 配置寄存器 ETMx_SYNCONF部分位置位,其中里面包含了软件输出的控制是否由硬件触发HW或是否有软件出发SW(ETM2)
*
* @param[in] pETM ETM2.
* @param[in] u32ConfigValue 用来配置SYNCONF寄存器.
*
* @return none.
*
*****************************************************************************/
void ETM_SyncConfigActivate(ETM_Type *pETM, uint32_t u32ConfigValue)
{
ASSERT((ETM2 == pETM));
pETM->SYNCONF |= u32ConfigValue;
}
/*****************************************************************************//*!
*
* @brief 配置寄存器 ETMx_SYNCONF部分位清除,其中里面包含了软件输出的控制是否由硬件触发HW或是否有软件出发SW(ETM2)
*
* @param[in] pETM ETM2.
* @param[in] u32ConfigValue 用来配置SYNCONF寄存器.
*
* @return none.
*
*****************************************************************************/
void ETM_SyncConfigDeactivate(ETM_Type *pETM, uint32_t u32ConfigValue)
{
ASSERT((ETM2 == pETM));
pETM->SYNCONF &= ~u32ConfigValue;
}
/*****************************************************************************//*!
*
* @brief 设置回调函数入口.
*
* @param[in] pETM 指向三个ETM定时器其中一个的基址.
* @param[in] pfnCallback 回调函数地址.
*
* @return none.
*
*****************************************************************************/
void ETM_SetCallback(ETM_Type *pETM, ETM_CallbackPtr pfnCallback)
{
ETM_Callback[((uint32_t)pETM - (uint32_t)ETM0_BASE)>>12] = pfnCallback;
}
/*****************************************************************************//*!
*
* @brief ETM0通道中断服务函数.
*
* @param none
*
* @return none
*
*****************************************************************************/
void ETM0_Isr(void)
{
if(ETM_Callback[0])
{
ETM_Callback[0]();
}
}
/*****************************************************************************//*!
*
* @brief ETM1通道中断服务函数.
*
* @param none
*
* @return none
*
*****************************************************************************/
void ETM1_Isr(void)
{
if(ETM_Callback[1])
{
ETM_Callback[1]();
}
}
/*****************************************************************************//*!
*
* @brief ETM2通道中断服务函数.
*
* @param none
*
* @return none
*
*****************************************************************************/
void ETM2_Isr(void)
{
if(ETM_Callback[2])
{
ETM_Callback[2]();
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,376 @@
/**************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file gpio.c
* @brief 通用输入输出模块(GPIO)函数库
* @author Navota
* @date 2018-3-1
**************************************************************************/
#include "gpio.h"
//GPIOA | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
// Px | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | C7 | C6 | C5 | C4 | C3 | C2 | C1 | C0 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0 |
//GPIOB | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
// Px | H7 | H6 | -- | -- | -- | H2 | H1 | H0 | -- | -- | -- | -- | G3 | G2 | G1 | C0 | F7 | F6 | F5 | F4 | F3 | F2 | F1 | F0 | E7 | E6 | E5 | E4 | E3 | E2 | E1 | E0 |
/*****************************************************************************/ /*!
* @brief 复位GPIO模块.
*
* @param[in] pGPIO GPIOA/GPIOB.
*
* @return none
*
*****************************************************************************/
void GPIO_DeInit(GPIO_Type *pGPIO)
{
/* Sanity check */
#if defined(CPU_NV32)
ASSERT((pGPIO == GPIOA) || (pGPIO == GPIOB));
#endif
pGPIO->PCOR = 0x00000000; /* 端口清零输出寄存器 */
pGPIO->PDDR = 0x00000000; /* 端口数据方向寄存器 */
//pGPIO->PDIR = 0x00000000; /* 端口数据输入寄存器 */
pGPIO->PDOR = 0x00000000; /* 端口数据输出寄存器 */
pGPIO->PIDR = 0xFFFFFFFF; /* 端口输入禁用寄存器 */
pGPIO->PSOR = 0x00000000; /* 端口置位输出寄存器 */
pGPIO->PTOR = 0x00000000; /* 端口切换输出寄存器 */
}
/*****************************************************************************/ /*!
* @brief 初始化GPIO引脚属性
*
* @param[in] pGPIO GPIOA/GPIOB.
* @param[in] u32PinMask 32位引脚掩码(GPIO_PTA0_MASK, GPIO_PTA1_MASK...)
* @param[in] sGpioType 引脚属性(输入GPIO_PinInput、输出GPIO_PinOutput、输出高电流驱动GPIO_PinOutput_HighCurrent、输入并开启上拉GPIO_PinInput_InternalPullup
*
* @return none
*
* @ 注:
* . 如果引脚配置为输入,禁用高电流驱动
* . 如果引脚配置为输出,禁用内部上拉,内部上拉仅为输入模式使用
* 仅PTH1/0, PTE1/0, PTD1/0, PTB5/4 支持高电流驱动.
*****************************************************************************/
void GPIO_Init(GPIO_Type *pGPIO, uint32_t u32PinMask, GPIO_PinConfigType sGpioType)
{
ASSERT((pGPIO == GPIOA) || (pGPIO == GPIOB));
/* 配置GPIO为输入或者输出 */
if ((sGpioType == GPIO_PinOutput) || (sGpioType == GPIO_PinOutput_HighCurrent))
{
pGPIO->PDDR |= u32PinMask; /* 引脚配置为通用输出*/
pGPIO->PIDR |= u32PinMask; /* 置位端口输入禁用寄存器*/
}
else if ((sGpioType == GPIO_PinInput) || (sGpioType == GPIO_PinInput_InternalPullup))
{
pGPIO->PDDR &= ~u32PinMask; /* 引脚配置为通用输入 */
pGPIO->PIDR &= ~u32PinMask; /* 清零端口输入禁用寄存器 */
}
/* 设置GPIO端口输入上拉 */
switch ((uint32_t)pGPIO)
{
case GPIOA_BASE:
(sGpioType == GPIO_PinInput_InternalPullup) ? (PORT->PUEL |= u32PinMask) : (PORT->PUEL &= ~u32PinMask);
break;
case GPIOB_BASE:
(sGpioType == GPIO_PinInput_InternalPullup) ? (PORT->PUEH |= u32PinMask) : (PORT->PUEH &= ~u32PinMask);
break;
default:
break;
}
/* 设置GPIO端口为高电流驱动输出 */
if (pGPIO == GPIOA)
{
if (u32PinMask & GPIO_PTB4_MASK)
{
PORT->HDRVE |= PORT_HDRVE_PTB4_MASK;
}
if (u32PinMask & GPIO_PTB5_MASK)
{
PORT->HDRVE |= PORT_HDRVE_PTB5_MASK;
}
if (u32PinMask & GPIO_PTD0_MASK)
{
PORT->HDRVE |= PORT_HDRVE_PTD0_MASK;
}
if (u32PinMask & GPIO_PTD1_MASK)
{
PORT->HDRVE |= PORT_HDRVE_PTD1_MASK;
}
}
if (pGPIO == GPIOB)
{
if (u32PinMask & GPIO_PTE0_MASK)
{
PORT->HDRVE |= PORT_HDRVE_PTE0_MASK;
}
if (u32PinMask & GPIO_PTE1_MASK)
{
PORT->HDRVE |= PORT_HDRVE_PTE1_MASK;
}
if (u32PinMask & GPIO_PTH0_MASK)
{
PORT->HDRVE |= PORT_HDRVE_PTH0_MASK;
}
if (u32PinMask & GPIO_PTH1_MASK)
{
PORT->HDRVE |= PORT_HDRVE_PTH1_MASK;
}
}
}
/*****************************************************************************/ /*!
* @brief 切换GPIO端口数据输出
*
* @param[in] pGPIO GPIOA/GPIOB.
* @param[in] u32PinMask 32位引脚掩码(GPIO_PTA0_MASK, GPIO_PTA1_MASK...)
*
* @return none
*
*****************************************************************************/
void GPIO_Toggle(GPIO_Type *pGPIO, uint32_t u32PinMask)
{
ASSERT((pGPIO == GPIOA) || (pGPIO == GPIOB));
pGPIO->PTOR = u32PinMask; /* 32位引脚掩码确定要切换输出的引脚 */
}
/*****************************************************************************/ /*!
* @brief 读取端口输入数据寄存器
*
* @param[in] pGPIO GPIOA/GPIOB.
*
* @return GPIOx->PDIR端口输入寄存器32位数值
*
*****************************************************************************/
uint32_t GPIO_Read(GPIO_Type *pGPIO)
{
ASSERT((pGPIO == GPIOA) || (pGPIO == GPIOB));
return (pGPIO->PDIR); /* 读端口数据输入寄存器 */
}
/*****************************************************************************/ /*!
* @brief 读取某个引脚的电平
*
* @param[in] pGPIO 指向GPIO模块 GPIOA/GPIOB.
* @param[in] GPIO_Pin GPIO引脚名 (GPIO_PTA0PIO_PTA1...)
*
* @return 端口数据寄存器某一位的值
*
*****************************************************************************/
uint8_t GPIO_BitRead(GPIO_PinType GPIO_Pin)
{
uint8_t data = 0;
ASSERT(GPIO_Pin < GPIO_PIN_MAX);
if (GPIO_Pin < GPIO_PTE0)
{
if (((1 << GPIO_Pin) & GPIOA->PDIR) > 0) /*判断要读取的位,对应的数值是1还是0*/
data = 0x1; /* 如果是1返回1,是0则返回0 */
else
data = 0x0;
}
else if (GPIO_Pin < GPIO_PIN_MAX)
{
GPIO_Pin = (GPIO_PinType)(GPIO_Pin - 32);
if (((1 << GPIO_Pin) & GPIOB->PDIR) > 0) /*判断要读取的位,对应的数值是1还是0*/
data = 0x1; /* 如果是1返回1,是0则返回0 */
else
data = 0x0;
}
return data;
}
/*****************************************************************************/ /*!
* @brief 写数据到端口数据输出寄存器
*
* @param[in] pGPIO GPIOA/GPIOB.
* @param[in] u32Value 写入到端口数据输出寄存器GPIOx->PDOR的值
*
* @return none
*
*****************************************************************************/
void GPIO_Write(GPIO_Type *pGPIO, uint32_t u32Value)
{
ASSERT((pGPIO == GPIOA) || (pGPIO == GPIOB));
pGPIO->PDOR = u32Value; /* 写数据到端口数据输出寄存器 */
}
/*****************************************************************************/ /*!
* @brief 初始化GPIO引脚属性
*
* @param[in] GPIO_Pin GPIO引脚名 (GPIO_PTA0、PIO_PTA1...)
* @param[in] GPIO_PinConfig 引脚属性(输入GPIO_PinInput、输出GPIO_PinOutput、输出高电流驱动GPIO_PinOutput_HighCurrent、输入并开启上拉GPIO_PinInput_InternalPullup
*
* @return none
*
*****************************************************************************/
void GPIO_PinInit(GPIO_PinType GPIO_Pin, GPIO_PinConfigType GPIO_PinConfig)
{
/* Sanity check */
ASSERT(GPIO_Pin < GPIO_PIN_MAX);
if (GPIO_Pin < GPIO_PTE0)
{
switch (GPIO_PinConfig)
{
case GPIO_PinOutput:
GPIOA->PDDR |= (1 << GPIO_Pin); /* 引脚配置为通用输出 */
GPIOA->PIDR |= (1 << GPIO_Pin); /* 端口输入禁用寄存器置一*/
PORT->PUEL &= ~(1 << GPIO_Pin); /* 禁用内部上拉 */
break;
case GPIO_PinInput:
GPIOA->PDDR &= ~(1 << GPIO_Pin); /* 引脚配置为通用输入 */
GPIOA->PIDR &= ~(1 << GPIO_Pin); /* 端口输入禁用寄存器清零 */
PORT->PUEL &= ~(1 << GPIO_Pin); /* 禁用内部上拉*/
break;
case GPIO_PinInput_InternalPullup:
GPIOA->PDDR &= ~(1 << GPIO_Pin); /* 引脚配置为通用输入 */
GPIOA->PIDR &= ~(1 << GPIO_Pin); /* 端口输入禁用寄存器清零 */
PORT->PUEL |= (1 << GPIO_Pin); /* 使能内部上拉 */
break;
case GPIO_PinOutput_HighCurrent:
GPIOA->PDDR |= (1 << GPIO_Pin); /* 引脚配置为通用输出 */
GPIOA->PIDR |= (1 << GPIO_Pin); /* 端口输入禁用寄存器置一 */
PORT->PUEL &= ~(1 << GPIO_Pin); /* 禁用内部上拉*/
break;
}
}
else if (GPIO_Pin < GPIO_PIN_MAX)
{
GPIO_Pin = (GPIO_PinType)(GPIO_Pin - 32);
switch (GPIO_PinConfig)
{
case GPIO_PinOutput:
GPIOB->PDDR |= (1 << GPIO_Pin); /* 引脚配置为通用输出 */
GPIOB->PIDR |= (1 << GPIO_Pin); /* 端口输入禁用寄存器置一 */
PORT->PUEH &= ~(1 << GPIO_Pin); /* 禁用内部上拉*/
break;
case GPIO_PinInput:
GPIOB->PDDR &= ~(1 << GPIO_Pin); /* 引脚配置为通用输入 */
GPIOB->PIDR &= ~(1 << GPIO_Pin); /* 端口输入禁用寄存器清零 */
PORT->PUEH &= ~(1 << GPIO_Pin); /* 禁用内部上拉*/
break;
case GPIO_PinInput_InternalPullup:
GPIOB->PDDR &= ~(1 << GPIO_Pin); /* 引脚配置为通用输入 */
GPIOB->PIDR &= ~(1 << GPIO_Pin); /* 端口输入禁用寄存器清零 */
PORT->PUEH |= (1 << GPIO_Pin); /* 使能内部上拉*/
break;
case GPIO_PinOutput_HighCurrent:
GPIOA->PDDR |= (1 << GPIO_Pin); /* 引脚配置为通用输出 */
GPIOA->PIDR |= (1 << GPIO_Pin); /* 端口输入禁用寄存器置一 */
PORT->PUEL &= ~(1 << GPIO_Pin); /* 禁用内部上拉*/
break;
}
}
/* 配置GPIO输出高电流驱动 */
if (GPIO_PinConfig == GPIO_PinOutput_HighCurrent)
{
switch (GPIO_Pin)
{
case GPIO_PTB4:
PORT->HDRVE |= PORT_HDRVE_PTB4_MASK;
break;
case GPIO_PTB5:
PORT->HDRVE |= PORT_HDRVE_PTB5_MASK;
break;
case GPIO_PTD0:
PORT->HDRVE |= PORT_HDRVE_PTD0_MASK;
break;
case GPIO_PTD1:
PORT->HDRVE |= PORT_HDRVE_PTD1_MASK;
break;
case GPIO_PTE0:
PORT->HDRVE |= PORT_HDRVE_PTE0_MASK;
break;
case GPIO_PTE1:
PORT->HDRVE |= PORT_HDRVE_PTE1_MASK;
break;
case GPIO_PTH0:
PORT->HDRVE |= PORT_HDRVE_PTH0_MASK;
break;
case GPIO_PTH1:
PORT->HDRVE |= PORT_HDRVE_PTH1_MASK;
break;
default:
break;
}
}
}
/*****************************************************************************/ /*!
* @brief 切换GPIO端口数据切换输出
*
* @param[in] GPIO_Pin GPIO引脚名 (GPIO_PTA0PIO_PTA1...)
*
* @return none
*
*****************************************************************************/
void GPIO_PinToggle(GPIO_PinType GPIO_Pin)
{
ASSERT(GPIO_Pin <= GPIO_PIN_MAX);
if (GPIO_Pin < GPIO_PTE0)
{
GPIOA->PTOR = (1 << GPIO_Pin);
}
else if (GPIO_Pin < GPIO_PIN_MAX)
{
GPIO_Pin = (GPIO_PinType)(GPIO_Pin - GPIO_PTE0);
GPIOB->PTOR = (1 << GPIO_Pin);
}
}
/*****************************************************************************/ /*!
* @brief GPIO端口数据输出置1
*
* @param[in] GPIO_Pin GPIO引脚名 (GPIO_PTA0PIO_PTA1...)
*
* @return none
*
*****************************************************************************/
void GPIO_PinSet(GPIO_PinType GPIO_Pin)
{
ASSERT(GPIO_Pin <= GPIO_PIN_MAX);
if (GPIO_Pin < GPIO_PTE0)
{
GPIOA->PSOR = (1 << GPIO_Pin);
}
else if (GPIO_Pin < GPIO_PIN_MAX)
{
GPIO_Pin = (GPIO_PinType)(GPIO_Pin - GPIO_PTE0);
GPIOB->PSOR = (1 << GPIO_Pin);
}
}
/*****************************************************************************/ /*!
* @brief GPIO端口数据输出清零
*
* @param[in] GPIO_Pin GPIO引脚名 (GPIO_PTA0PIO_PTA1...)
*
* @return none
*
*****************************************************************************/
void GPIO_PinClear(GPIO_PinType GPIO_Pin)
{
ASSERT(GPIO_Pin <= GPIO_PIN_MAX);
if (GPIO_Pin < GPIO_PTE0)
{
GPIOA->PCOR = (1 << GPIO_Pin);
}
else if (GPIO_Pin < GPIO_PIN_MAX)
{
GPIO_Pin = (GPIO_PinType)(GPIO_Pin - GPIO_PTE0);
GPIOB->PCOR = (1 << GPIO_Pin);
}
}
@@ -0,0 +1,583 @@
#ifndef _GPIO_H_
#define _GPIO_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
#include "stdint.h"
#include "core_cm0plus.h"
#include "bos.h"
/******************************************************************************
*宏定义,用于生位操作存储加载无符号字段提取(UBFX)硬件编码地址
*
*******************************************************************************/
#define GPIO_ALIAS_OFF 0x000F0000L
#define BOS_BIT_EXTRACT(ADDR,bit,width) (*(volatile uint32_t *)(((uint32_t) (((uint32_t)&ADDR)-GPIO_ALIAS_OFF)) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit & 0x1F)<<23) | ((width-1) & 0xF)<<19))
/******************************************************************************
*
* GPIO位带操作宏定义
*
******************************************************************************/
#define PTA0_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,0) //PTA0端口数据输出为高
#define PTA0_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,0) //PTA0端口数据输出为低
#define PTA0_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,0) //PTA0端口输出切换
#define PTA1_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,1)
#define PTA1_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,1)
#define PTA1_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,1)
#define PTA2_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,2)
#define PTA2_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,2)
#define PTA2_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,2)
#define PTA3_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,3)
#define PTA3_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,3)
#define PTA3_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,3)
#define PTA4_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,4)
#define PTA4_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,4)
#define PTA4_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,4)
#define PTA5_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,5)
#define PTA5_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,5)
#define PTA5_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,5)
#define PTA6_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,6)
#define PTA6_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,6)
#define PTA6_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,6)
#define PTA7_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,7)
#define PTA7_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,7)
#define PTA7_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,7)
#define PTB0_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,8) //PTB0端口数据输出为高
#define PTB0_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,8) //PTB0端口数据输出为低
#define PTB0_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,8) //PTB0端口数据输出切换
#define PTB1_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,9)
#define PTB1_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,9)
#define PTB1_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,9)
#define PTB2_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,10)
#define PTB2_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,10)
#define PTB2_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,10)
#define PTB3_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,11)
#define PTB3_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,11)
#define PTB3_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,11)
#define PTB4_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,12)
#define PTB4_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,12)
#define PTB4_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,12)
#define PTB5_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,13)
#define PTB5_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,13)
#define PTB5_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,13)
#define PTB6_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,14)
#define PTB6_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,14)
#define PTB6_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,14)
#define PTB7_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,15)
#define PTB7_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,15)
#define PTB7_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,15)
#define PTC0_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,16) //PTC0端口数据输出为高
#define PTC0_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,16) //PTC0端口数据输出为低
#define PTC0_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,16) //PTC0端口数据输出切换
#define PTC1_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,17)
#define PTC1_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,17)
#define PTC1_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,17)
#define PTC2_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,18)
#define PTC2_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,18)
#define PTC2_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,18)
#define PTC3_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,19)
#define PTC3_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,19)
#define PTC3_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,19)
#define PTC4_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,20)
#define PTC4_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,20)
#define PTC4_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,20)
#define PTC5_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,21)
#define PTC5_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,21)
#define PTC5_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,21)
#define PTC6_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,22)
#define PTC6_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,22)
#define PTC6_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,22)
#define PTC7_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,23)
#define PTC7_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,23)
#define PTC7_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,23)
#define PTD0_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,24) //PTD0端口数据输出为高
#define PTD0_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,24) //PTD0端口数据输出为低
#define PTD0_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,24) //PTD0端口数据输出切换
#define PTD1_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,25)
#define PTD1_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,25)
#define PTD1_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,25)
#define PTD2_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,26)
#define PTD2_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,26)
#define PTD2_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,26)
#define PTD3_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,27)
#define PTD3_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,27)
#define PTD3_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,27)
#define PTD4_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,28)
#define PTD4_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,28)
#define PTD4_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,28)
#define PTD5_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,29)
#define PTD5_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,29)
#define PTD5_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,29)
#define PTD6_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,30)
#define PTD6_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,30)
#define PTD6_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,30)
#define PTD7_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,31)
#define PTD7_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,31)
#define PTD7_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,31)
#define PTE0_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,0)
#define PTE0_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,0)
#define PTE0_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,0)
#define PTE1_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,1) //PTE0端口数据输出为高
#define PTE1_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,1) //PTE0端口数据输出为低
#define PTE1_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,1) //PTE0端口数据输出切换
#define PTE2_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,2)
#define PTE2_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,2)
#define PTE2_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,2)
#define PTE3_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,3)
#define PTE3_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,3)
#define PTE3_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,3)
#define PTE4_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,4)
#define PTE4_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,4)
#define PTE4_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,4)
#define PTE5_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,5)
#define PTE5_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,5)
#define PTE5_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,5)
#define PTE6_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,6)
#define PTE6_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,6)
#define PTE6_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,6)
#define PTE7_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,7)
#define PTE7_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,7)
#define PTE7_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,7)
#define PTF0_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,8) //PTF0端口数据输出为高
#define PTF0_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,8) //PTF0端口数据输出为低
#define PTF0_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,8) //PTF0端口数据输出切换
#define PTF1_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,9)
#define PTF1_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,9)
#define PTF1_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,9)
#define PTF2_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,10)
#define PTF2_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,10)
#define PTF2_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,10)
#define PTF3_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,11)
#define PTF3_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,11)
#define PTF3_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,11)
#define PTF4_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,12)
#define PTF4_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,12)
#define PTF4_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,12)
#define PTF5_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,13)
#define PTF5_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,13)
#define PTF5_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,13)
#define PTF6_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,14)
#define PTF6_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,14)
#define PTF6_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,14)
#define PTF7_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,15)
#define PTF7_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,15)
#define PTF7_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,15)
#define PTG0_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,16) //PTG0端口数据输出为高
#define PTG0_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,16) //PTG0端口数据输出为低
#define PTG0_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,16) //PTG0端口数据输出切换
#define PTG1_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,17)
#define PTG1_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,17)
#define PTG1_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,17)
#define PTG2_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,18)
#define PTG2_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,18)
#define PTG2_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,18)
#define PTG3_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,19)
#define PTG3_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,19)
#define PTG3_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,19)
#define PTG4_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,20)
#define PTG4_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,20)
#define PTG4_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,20)
#define PTG5_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,21)
#define PTG5_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,21)
#define PTG5_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,21)
#define PTG6_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,22)
#define PTG6_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,22)
#define PTG6_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,22)
#define PTG7_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,23)
#define PTG7_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,23)
#define PTG7_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,23)
#define PTH0_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,24) //PTH0端口数据输出为高
#define PTH0_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,24) //PTH0端口数据输出为低
#define PTH0_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,24) //PTH0端口数据输出切换
#define PTH1_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,25)
#define PTH1_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,25)
#define PTH1_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,25)
#define PTH2_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,26)
#define PTH2_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,26)
#define PTH2_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,26)
#define PTH3_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,27)
#define PTH3_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,27)
#define PTH3_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,27)
#define PTH4_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,28)
#define PTH4_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,28)
#define PTH4_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,28)
#define PTH5_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,29)
#define PTH5_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,29)
#define PTH5_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,29)
#define PTH6_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,30)
#define PTH6_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,30)
#define PTH6_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,30)
#define PTH7_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,31)
#define PTH7_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,31)
#define PTH7_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,31)
#define PTA0_IN BOS_BIT_EXTRACT(GPIOA->PDIR,0,1) //读取PA0端口输入数据
#define PTA1_IN BOS_BIT_EXTRACT(GPIOA->PDIR,1,1)
#define PTA2_IN BOS_BIT_EXTRACT(GPIOA->PDIR,2,1)
#define PTA3_IN BOS_BIT_EXTRACT(GPIOA->PDIR,3,1)
#define PTA4_IN BOS_BIT_EXTRACT(GPIOA->PDIR,4,1)
#define PTA5_IN BOS_BIT_EXTRACT(GPIOA->PDIR,5,1)
#define PTA6_IN BOS_BIT_EXTRACT(GPIOA->PDIR,6,1)
#define PTA7_IN BOS_BIT_EXTRACT(GPIOA->PDIR,7,1)
#define PTB0_IN BOS_BIT_EXTRACT(GPIOA->PDIR,8,1) //读取PB0端口输入数据
#define PTB1_IN BOS_BIT_EXTRACT(GPIOA->PDIR,9,1)
#define PTB2_IN BOS_BIT_EXTRACT(GPIOA->PDIR,10,1)
#define PTB3_IN BOS_BIT_EXTRACT(GPIOA->PDIR,11,1)
#define PTB4_IN BOS_BIT_EXTRACT(GPIOA->PDIR,12,1)
#define PTB5_IN BOS_BIT_EXTRACT(GPIOA->PDIR,13,1)
#define PTB6_IN BOS_BIT_EXTRACT(GPIOA->PDIR,14,1)
#define PTB7_IN BOS_BIT_EXTRACT(GPIOA->PDIR,15,1)
#define PTC0_IN BOS_BIT_EXTRACT(GPIOA->PDIR,16,1) //读取PC0端口输入数据
#define PTC1_IN BOS_BIT_EXTRACT(GPIOA->PDIR,17,1)
#define PTC2_IN BOS_BIT_EXTRACT(GPIOA->PDIR,18,1)
#define PTC3_IN BOS_BIT_EXTRACT(GPIOA->PDIR,19,1)
#define PTC4_IN BOS_BIT_EXTRACT(GPIOA->PDIR,20,1)
#define PTC5_IN BOS_BIT_EXTRACT(GPIOA->PDIR,21,1)
#define PTC6_IN BOS_BIT_EXTRACT(GPIOA->PDIR,22,1)
#define PTC7_IN BOS_BIT_EXTRACT(GPIOA->PDIR,23,1)
#define PTD0_IN BOS_BIT_EXTRACT(GPIOA->PDIR,24,1) //读取PD0端口输入数据
#define PTD1_IN BOS_BIT_EXTRACT(GPIOA->PDIR,25,1)
#define PTD2_IN BOS_BIT_EXTRACT(GPIOA->PDIR,26,1)
#define PTD3_IN BOS_BIT_EXTRACT(GPIOA->PDIR,27,1)
#define PTD4_IN BOS_BIT_EXTRACT(GPIOA->PDIR,28,1)
#define PTD5_IN BOS_BIT_EXTRACT(GPIOA->PDIR,29,1)
#define PTD6_IN BOS_BIT_EXTRACT(GPIOA->PDIR,30,1)
#define PTD7_IN BOS_BIT_EXTRACT(GPIOA->PDIR,31,1)
#define PTE0_IN BOS_BIT_EXTRACT(GPIOB->PDIR,0,1) //读取PE0端口输入数据
#define PTE1_IN BOS_BIT_EXTRACT(GPIOB->PDIR,1,1)
#define PTE2_IN BOS_BIT_EXTRACT(GPIOB->PDIR,2,1)
#define PTE3_IN BOS_BIT_EXTRACT(GPIOB->PDIR,3,1)
#define PTE4_IN BOS_BIT_EXTRACT(GPIOB->PDIR,4,1)
#define PTE5_IN BOS_BIT_EXTRACT(GPIOB->PDIR,5,1)
#define PTE6_IN BOS_BIT_EXTRACT(GPIOB->PDIR,6,1)
#define PTE7_IN BOS_BIT_EXTRACT(GPIOB->PDIR,7,1)
#define PTF0_IN BOS_BIT_EXTRACT(GPIOB->PDIR,8,1) //读取PF0端口输入数据
#define PTF1_IN BOS_BIT_EXTRACT(GPIOB->PDIR,9,1)
#define PTF2_IN BOS_BIT_EXTRACT(GPIOB->PDIR,10,1)
#define PTF3_IN BOS_BIT_EXTRACT(GPIOB->PDIR,11,1)
#define PTF4_IN BOS_BIT_EXTRACT(GPIOB->PDIR,12,1)
#define PTF5_IN BOS_BIT_EXTRACT(GPIOB->PDIR,13,1)
#define PTF6_IN BOS_BIT_EXTRACT(GPIOB->PDIR,14,1)
#define PTF7_IN BOS_BIT_EXTRACT(GPIOB->PDIR,15,1)
#define PTG0_IN BOS_BIT_EXTRACT(GPIOB->PDIR,16,1) //读取PG0端口输入数据 Modify
#define PTG1_IN BOS_BIT_EXTRACT(GPIOB->PDIR,17,1)
#define PTG2_IN BOS_BIT_EXTRACT(GPIOB->PDIR,18,1)
#define PTG3_IN BOS_BIT_EXTRACT(GPIOB->PDIR,19,1)
#define PTG4_IN BOS_BIT_EXTRACT(GPIOB->PDIR,20,1)
#define PTG5_IN BOS_BIT_EXTRACT(GPIOB->PDIR,21,1)
#define PTG6_IN BOS_BIT_EXTRACT(GPIOB->PDIR,22,1)
#define PTG7_IN BOS_BIT_EXTRACT(GPIOB->PDIR,23,1)
#define PTH0_IN BOS_BIT_EXTRACT(GPIOB->PDIR,24,1) //读取PH0端口输入数据
#define PTH1_IN BOS_BIT_EXTRACT(GPIOB->PDIR,25,1)
#define PTH2_IN BOS_BIT_EXTRACT(GPIOB->PDIR,26,1)
#define PTH3_IN BOS_BIT_EXTRACT(GPIOB->PDIR,27,1)
#define PTH4_IN BOS_BIT_EXTRACT(GPIOB->PDIR,28,1)
#define PTH5_IN BOS_BIT_EXTRACT(GPIOB->PDIR,29,1)
#define PTH6_IN BOS_BIT_EXTRACT(GPIOB->PDIR,30,1)
#define PTH7_IN BOS_BIT_EXTRACT(GPIOB->PDIR,31,1)
/******************************************************************************
*
* 定义GPIO引脚名
*
*******************************************************************************/
typedef enum
{
/* 用于GPIO */
GPIO_PTA0 = 0, /*!< GPIO Pin PTA0 */
GPIO_PTA1, /*!< GPIO Pin PTA1 */
GPIO_PTA2, /*!< GPIO Pin PTA2 */
GPIO_PTA3, /*!< GPIO Pin PTA3 */
GPIO_PTA4, /*!< GPIO Pin PTA4 */
GPIO_PTA5, /*!< GPIO Pin PTA5 */
GPIO_PTA6, /*!< GPIO Pin PTA6 */
GPIO_PTA7, /*!< GPIO Pin PTA7 */
GPIO_PTB0, /*!< GPIO Pin PTB0 */
GPIO_PTB1, /*!< GPIO Pin PTB1 */
GPIO_PTB2, /*!< GPIO Pin PTB2 */
GPIO_PTB3, /*!< GPIO Pin PTB3 */
GPIO_PTB4, /*!< GPIO Pin PTB4 */
GPIO_PTB5, /*!< GPIO Pin PTB5 */
GPIO_PTB6, /*!< GPIO Pin PTB6 */
GPIO_PTB7, /*!< GPIO Pin PTB7 */
GPIO_PTC0, /*!< GPIO Pin PTC0 */
GPIO_PTC1, /*!< GPIO Pin PTC1 */
GPIO_PTC2, /*!< GPIO Pin PTC2 */
GPIO_PTC3, /*!< GPIO Pin PTC3 */
GPIO_PTC4, /*!< GPIO Pin PTC4 */
GPIO_PTC5, /*!< GPIO Pin PTC5 */
GPIO_PTC6, /*!< GPIO Pin PTC6 */
GPIO_PTC7, /*!< GPIO Pin PTC7 */
GPIO_PTD0, /*!< GPIO Pin PTD0 */
GPIO_PTD1, /*!< GPIO Pin PTD1 */
GPIO_PTD2, /*!< GPIO Pin PTD2 */
GPIO_PTD3, /*!< GPIO Pin PTD3 */
GPIO_PTD4, /*!< GPIO Pin PTD4 */
GPIO_PTD5, /*!< GPIO Pin PTD5 */
GPIO_PTD6, /*!< GPIO Pin PTD6 */
GPIO_PTD7, /*!< GPIO Pin PTD7 */
/* in GPIOB register */
GPIO_PTE0, /*!< GPIO Pin PTE0 */
GPIO_PTE1, /*!< GPIO Pin PTE1 */
GPIO_PTE2, /*!< GPIO Pin PTE2 */
GPIO_PTE3, /*!< GPIO Pin PTE3 */
GPIO_PTE4, /*!< GPIO Pin PTE4 */
GPIO_PTE5, /*!< GPIO Pin PTE5 */
GPIO_PTE6, /*!< GPIO Pin PTE6 */
GPIO_PTE7, /*!< GPIO Pin PTE7 */
GPIO_PTF0, /*!< GPIO Pin PTF0 */
GPIO_PTF1, /*!< GPIO Pin PTF1 */
GPIO_PTF2, /*!< GPIO Pin PTF2 */
GPIO_PTF3, /*!< GPIO Pin PTF3 */
GPIO_PTF4, /*!< GPIO Pin PTF4 */
GPIO_PTF5, /*!< GPIO Pin PTF5 */
GPIO_PTF6, /*!< GPIO Pin PTF6 */
GPIO_PTF7, /*!< GPIO Pin PTF7 */
GPIO_PTG0, /*!< GPIO Pin PTG0 */
GPIO_PTG1, /*!< GPIO Pin PTG1 */
GPIO_PTG2, /*!< GPIO Pin PTG2 */
GPIO_PTG3, /*!< GPIO Pin PTG3 */
GPIO_PTG4, /*!< GPIO Pin PTG4 */
GPIO_PTG5, /*!< GPIO Pin PTG5 */
GPIO_PTG6, /*!< GPIO Pin PTG6 */
GPIO_PTG7, /*!< GPIO Pin PTG7 */
GPIO_PTH0, /*!< GPIO Pin PTH0 */
GPIO_PTH1, /*!< GPIO Pin PTH1 */
GPIO_PTH2, /*!< GPIO Pin PTH2 */
GPIO_PTH3, /*!< GPIO Pin PTH3 */
GPIO_PTH4, /*!< GPIO Pin PTH4 */
GPIO_PTH5, /*!< GPIO Pin PTH5 */
GPIO_PTH6, /*!< GPIO Pin PTH6 */
GPIO_PTH7, /*!< GPIO Pin PTH7 */
GPIO_PIN_MAX,
} GPIO_PinType;
/******************************************************************************
*
* 定义GPIO引脚掩码
*
*******************************************************************************/
typedef enum
{
/* in GPIOA register */
GPIO_PTA0_MASK = (1<<0), /*!< GPIO Pin PTA0 bit mask */
GPIO_PTA1_MASK = (1<<1), /*!< GPIO Pin PTA1 bit mask */
GPIO_PTA2_MASK = (1<<2), /*!< GPIO Pin PTA2 bit mask */
GPIO_PTA3_MASK = (1<<3), /*!< GPIO Pin PTA3 bit mask */
GPIO_PTA4_MASK = (1<<4), /*!< GPIO Pin PTA4 bit mask */
GPIO_PTA5_MASK = (1<<5), /*!< GPIO Pin PTA5 bit mask */
GPIO_PTA6_MASK = (1<<6), /*!< GPIO Pin PTA6 bit mask */
GPIO_PTA7_MASK = (1<<7), /*!< GPIO Pin PTA7 bit mask */
GPIO_PTB0_MASK = (1<<8), /*!< GPIO Pin PTB0 bit mask */
GPIO_PTB1_MASK = (1<<9), /*!< GPIO Pin PTB1 bit mask */
GPIO_PTB2_MASK = (1<<10), /*!< GPIO Pin PTB2 bit mask */
GPIO_PTB3_MASK = (1<<11), /*!< GPIO Pin PTB3 bit mask */
GPIO_PTB4_MASK = (1<<12), /*!< GPIO Pin PTB4 bit mask */
GPIO_PTB5_MASK = (1<<13), /*!< GPIO Pin PTB5 bit mask */
GPIO_PTB6_MASK = (1<<14), /*!< GPIO Pin PTB6 bit mask */
GPIO_PTB7_MASK = (1<<15), /*!< GPIO Pin PTB7 bit mask */
GPIO_PTC0_MASK = (1<<16), /*!< GPIO Pin PTC0 bit mask */
GPIO_PTC1_MASK = (1<<17), /*!< GPIO Pin PTC1 bit mask */
GPIO_PTC2_MASK = (1<<18), /*!< GPIO Pin PTC2 bit mask */
GPIO_PTC3_MASK = (1<<19), /*!< GPIO Pin PTC3 bit mask */
GPIO_PTC4_MASK = (1<<20), /*!< GPIO Pin PTC4 bit mask */
GPIO_PTC5_MASK = (1<<21), /*!< GPIO Pin PTC5 bit mask */
GPIO_PTC6_MASK = (1<<22), /*!< GPIO Pin PTC6 bit mask */
GPIO_PTC7_MASK = (1<<23), /*!< GPIO Pin PTC7 bit mask */
GPIO_PTD0_MASK = (1<<24), /*!< GPIO Pin PTD0 bit mask */
GPIO_PTD1_MASK = (1<<25), /*!< GPIO Pin PTD1 bit mask */
GPIO_PTD2_MASK = (1<<26), /*!< GPIO Pin PTD2 bit mask */
GPIO_PTD3_MASK = (1<<27), /*!< GPIO Pin PTD3 bit mask */
GPIO_PTD4_MASK = (1<<28), /*!< GPIO Pin PTD4 bit mask */
GPIO_PTD5_MASK = (1<<29), /*!< GPIO Pin PTD5 bit mask */
GPIO_PTD6_MASK = (1<<30), /*!< GPIO Pin PTD6 bit mask */
GPIO_PTD7_MASK = (int)(0x80000000), /*!< GPIO Pin PTD7 bit mask */
/* in GPIOB register */
GPIO_PTE0_MASK = (1<<0), /*!< GPIO Pin PTE0 bit mask */
GPIO_PTE1_MASK = (1<<1), /*!< GPIO Pin PTE1 bit mask */
GPIO_PTE2_MASK = (1<<2), /*!< GPIO Pin PTE2 bit mask */
GPIO_PTE3_MASK = (1<<3), /*!< GPIO Pin PTE3 bit mask */
GPIO_PTE4_MASK = (1<<4), /*!< GPIO Pin PTE4 bit mask */
GPIO_PTE5_MASK = (1<<5), /*!< GPIO Pin PTE5 bit mask */
GPIO_PTE6_MASK = (1<<6), /*!< GPIO Pin PTE6 bit mask */
GPIO_PTE7_MASK = (1<<7), /*!< GPIO Pin PTE7 bit mask */
GPIO_PTF0_MASK = (1<<8), /*!< GPIO Pin PTF0 bit mask */
GPIO_PTF1_MASK = (1<<9), /*!< GPIO Pin PTF1 bit mask */
GPIO_PTF2_MASK = (1<<10), /*!< GPIO Pin PTF2 bit mask */
GPIO_PTF3_MASK = (1<<11), /*!< GPIO Pin PTF3 bit mask */
GPIO_PTF4_MASK = (1<<12), /*!< GPIO Pin PTF4 bit mask */
GPIO_PTF5_MASK = (1<<13), /*!< GPIO Pin PTF5 bit mask */
GPIO_PTF6_MASK = (1<<14), /*!< GPIO Pin PTF6 bit mask */
GPIO_PTF7_MASK = (1<<15), /*!< GPIO Pin PTF7 bit mask */
GPIO_PTG0_MASK = (1<<16), /*!< GPIO Pin PTG0 bit mask */
GPIO_PTG1_MASK = (1<<17), /*!< GPIO Pin PTG1 bit mask */
GPIO_PTG2_MASK = (1<<18), /*!< GPIO Pin PTG2 bit mask */
GPIO_PTG3_MASK = (1<<19), /*!< GPIO Pin PTG3 bit mask */
GPIO_PTG4_MASK = (1<<20), /*!< GPIO Pin PTG4 bit mask */
GPIO_PTG5_MASK = (1<<21), /*!< GPIO Pin PTG5 bit mask */
GPIO_PTG6_MASK = (1<<22), /*!< GPIO Pin PTG6 bit mask */
GPIO_PTG7_MASK = (1<<23), /*!< GPIO Pin PTG7 bit mask */
GPIO_PTH0_MASK = (1<<24), /*!< GPIO Pin PTH0 bit mask */
GPIO_PTH1_MASK = (1<<25), /*!< GPIO Pin PTH1 bit mask */
GPIO_PTH2_MASK = (1<<26), /*!< GPIO Pin PTH2 bit mask */
GPIO_PTH3_MASK = (1<<27), /*!< GPIO Pin PTH3 bit mask */
GPIO_PTH4_MASK = (1<<28), /*!< GPIO Pin PTH4 bit mask */
GPIO_PTH5_MASK = (1<<29), /*!< GPIO Pin PTH5 bit mask */
GPIO_PTH6_MASK = (1<<30), /*!< GPIO Pin PTH6 bit mask */
GPIO_PTH7_MASK = (int)(0x80000000), /*!< GPIO Pin PTH7 bit mask */
} GPIO_PinMaskType;
/******************************************************************************
*
*定义GPIO引脚配置类型
*
*******************************************************************************/
/*
* . 如果引脚配置为输入,禁用高电流驱动
* . 如果引脚配置为输出,禁用内部上拉
* 仅PTH1/0, PTE1/0, PTD1/0, PTB5/4 支持高电流驱动.
*/
typedef enum
{
GPIO_PinOutput = 0, /*!< 设置引脚为输出 */
GPIO_PinInput, /*!< 设置引脚为输出*/
GPIO_PinInput_InternalPullup, /*!< 设置引脚为输入且内部上拉 */
GPIO_PinOutput_HighCurrent, /*!< 设置引脚为输出,高电流驱动*/
} GPIO_PinConfigType;
/*****************************************************************************//*!
* @brief 切换FGPIO端口数据输出
*
* @param[in] pGPIO FGPIOA/FGPIOB.
* @param[in] u32PinMask 32位引脚掩码 ( GPIO_PTA0_MASK, GPIO_PTA1_MASK...)
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void FGPIO_Toggle(FGPIO_Type *pFGPIO, uint32_t u32PinMask)
{
pFGPIO->PTOR = u32PinMask; /* 切换GPIO端口数据输出 */
}
/*****************************************************************************//*!
* @brief 读取FGPIO端口数据输入寄存器
*
* @param[in] pGPIO FGPIOA/FGPIOB.
*
* @return FGPIO端口数据输入寄存器32值
*
*****************************************************************************/
__STATIC_INLINE uint32_t FGPIO_Read(FGPIO_Type *pFGPIO)
{
return (pFGPIO->PDIR); /*读端口数据输入寄存器*/
}
/*****************************************************************************//*!
* @brief 写数据到FGPIO端口数据输出寄存
*
* @param[in] pGPIO FGPIOA/FGPIOB.
* @param[in] u32Value 写入的数值
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void FGPIO_Write(FGPIO_Type *pFGPIO, uint32_t u32Value)
{
pFGPIO->PDOR = u32Value; /*写数据到端口数据输出寄存器*/
}
void GPIO_DeInit(GPIO_Type *pGPIO);
void GPIO_Init(GPIO_Type *pGPIO, uint32_t u32PinMask, GPIO_PinConfigType sGpioType);
void GPIO_Toggle(GPIO_Type *pGPIO, uint32_t u32PinMask);
void GPIO_Write(GPIO_Type *pGPIO, uint32_t u32Value);
void GPIO_PinInit(GPIO_PinType GPIO_Pin, GPIO_PinConfigType GPIO_PinConfig);
void GPIO_PinToggle(GPIO_PinType GPIO_Pin);
void GPIO_PinSet(GPIO_PinType GPIO_Pin);
void GPIO_PinClear(GPIO_PinType GPIO_Pin);
uint32_t GPIO_Read(GPIO_Type *pGPIO);
uint8_t GPIO_BitRead(GPIO_PinType GPIO_Pin);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,601 @@
#ifndef _GPIO_H_
#define _GPIO_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
#include "stdint.h"
#include "core_cm0plus.h"
#include "bos.h"
/******************************************************************************
*宏定义,用于生位操作存储加载无符号字段提取(UBFX)硬件编码地址
*
*******************************************************************************/
#define GPIO_ALIAS_OFF 0x000F0000L
#define BOS_BIT_EXTRACT(ADDR,bit,width) (*(volatile uint32_t *)(((uint32_t) (((uint32_t)&ADDR)-GPIO_ALIAS_OFF)) \
| (BOS_OPCODE_BITFIELD <<26) \
| ((bit & 0x1F)<<23) | ((width-1) & 0xF)<<19))
/******************************************************************************
*
* GPIO位带操作宏定义
*
******************************************************************************/
#define PTA0_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,0) //PTA0端口数据输出为高
#define PTA0_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,0) //PTA0端口数据输出为低
#define PTA0_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,0) //PTA0端口输出切换
#define PTA1_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,1)
#define PTA1_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,1)
#define PTA1_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,1)
#define PTA2_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,2)
#define PTA2_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,2)
#define PTA2_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,2)
#define PTA3_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,3)
#define PTA3_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,3)
#define PTA3_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,3)
#define PTA4_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,4)
#define PTA4_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,4)
#define PTA4_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,4)
#define PTA5_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,5)
#define PTA5_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,5)
#define PTA5_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,5)
#define PTA6_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,6)
#define PTA6_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,6)
#define PTA6_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,6)
#define PTA7_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,7)
#define PTA7_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,7)
#define PTA7_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,7)
#define PTB0_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,8) //PTB0端口数据输出为高
#define PTB0_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,8) //PTB0端口数据输出为低
#define PTB0_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,8) //PTB0端口数据输出切换
#define PTB1_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,9)
#define PTB1_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,9)
#define PTB1_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,9)
#define PTB2_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,10)
#define PTB2_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,10)
#define PTB2_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,10)
#define PTB3_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,11)
#define PTB3_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,11)
#define PTB3_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,11)
#define PTB4_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,12)
#define PTB4_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,12)
#define PTB4_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,12)
#define PTB5_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,13)
#define PTB5_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,13)
#define PTB5_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,13)
#define PTB6_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,14)
#define PTB6_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,14)
#define PTB6_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,14)
#define PTB7_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,15)
#define PTB7_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,15)
#define PTB7_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,15)
#define PTC0_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,16) //PTC0端口数据输出为高
#define PTC0_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,16) //PTC0端口数据输出为低
#define PTC0_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,16) //PTC0端口数据输出切换
#define PTC1_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,17)
#define PTC1_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,17)
#define PTC1_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,17)
#define PTC2_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,18)
#define PTC2_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,18)
#define PTC2_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,18)
#define PTC3_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,19)
#define PTC3_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,19)
#define PTC3_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,19)
#define PTC4_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,20)
#define PTC4_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,20)
#define PTC4_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,20)
#define PTC5_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,21)
#define PTC5_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,21)
#define PTC5_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,21)
#define PTC6_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,22)
#define PTC6_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,22)
#define PTC6_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,22)
#define PTC7_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,23)
#define PTC7_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,23)
#define PTC7_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,23)
#define PTD0_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,24) //PTD0端口数据输出为高
#define PTD0_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,24) //PTD0端口数据输出为低
#define PTD0_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,24) //PTD0端口数据输出切换
#define PTD1_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,25)
#define PTD1_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,25)
#define PTD1_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,25)
#define PTD2_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,26)
#define PTD2_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,26)
#define PTD2_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,26)
#define PTD3_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,27)
#define PTD3_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,27)
#define PTD3_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,27)
#define PTD4_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,28)
#define PTD4_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,28)
#define PTD4_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,28)
#define PTD5_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,29)
#define PTD5_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,29)
#define PTD5_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,29)
#define PTD6_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,30)
#define PTD6_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,30)
#define PTD6_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,30)
#define PTD7_OUT_HIGH BOS_BIT_SET(&GPIOA->PDOR,31)
#define PTD7_OUT_LOW BOS_BIT_CLEAR(&GPIOA->PDOR,31)
#define PTD7_OUT_TOGGLE BOS_BIT_SET(&GPIOA->PTOR,31)
#define PTE0_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,0)
#define PTE0_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,0)
#define PTE0_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,0)
#define PTE1_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,1) //PTE0端口数据输出为高
#define PTE1_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,1) //PTE0端口数据输出为低
#define PTE1_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,1) //PTE0端口数据输出切换
#define PTE2_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,2)
#define PTE2_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,2)
#define PTE2_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,2)
#define PTE3_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,3)
#define PTE3_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,3)
#define PTE3_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,3)
#define PTE4_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,4)
#define PTE4_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,4)
#define PTE4_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,4)
#define PTE5_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,5)
#define PTE5_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,5)
#define PTE5_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,5)
#define PTE6_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,6)
#define PTE6_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,6)
#define PTE6_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,6)
#define PTE7_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,7)
#define PTE7_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,7)
#define PTE7_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,7)
#define PTF0_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,8) //PTF0端口数据输出为高
#define PTF0_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,8) //PTF0端口数据输出为低
#define PTF0_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,8) //PTF0端口数据输出切换
#define PTF1_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,9)
#define PTF1_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,9)
#define PTF1_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,9)
#define PTF2_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,10)
#define PTF2_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,10)
#define PTF2_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,10)
#define PTF3_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,11)
#define PTF3_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,11)
#define PTF3_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,11)
#define PTF4_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,12)
#define PTF4_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,12)
#define PTF4_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,12)
#define PTF5_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,13)
#define PTF5_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,13)
#define PTF5_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,13)
#define PTF6_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,14)
#define PTF6_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,14)
#define PTF6_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,14)
#define PTF7_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,15)
#define PTF7_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,15)
#define PTF7_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,15)
#define PTG0_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,16) //PTG0端口数据输出为高
#define PTG0_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,16) //PTG0端口数据输出为低
#define PTG0_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,16) //PTG0端口数据输出切换
#define PTG1_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,17)
#define PTG1_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,17)
#define PTG1_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,17)
#define PTG2_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,18)
#define PTG2_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,18)
#define PTG2_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,18)
#define PTG3_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,19)
#define PTG3_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,19)
#define PTG3_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,19)
#define PTG4_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,20)
#define PTG4_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,20)
#define PTG4_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,20)
#define PTG5_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,21)
#define PTG5_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,21)
#define PTG5_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,21)
#define PTG6_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,22)
#define PTG6_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,22)
#define PTG6_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,22)
#define PTG7_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,23)
#define PTG7_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,23)
#define PTG7_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,23)
#define PTH0_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,24) //PTH0端口数据输出为高
#define PTH0_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,24) //PTH0端口数据输出为低
#define PTH0_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,24) //PTH0端口数据输出切换
#define PTH1_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,25)
#define PTH1_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,25)
#define PTH1_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,25)
#define PTH2_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,26)
#define PTH2_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,26)
#define PTH2_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,26)
#define PTH3_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,27)
#define PTH3_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,27)
#define PTH3_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,27)
#define PTH4_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,28)
#define PTH4_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,28)
#define PTH4_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,28)
#define PTH5_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,29)
#define PTH5_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,29)
#define PTH5_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,29)
#define PTH6_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,30)
#define PTH6_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,30)
#define PTH6_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,30)
#define PTH7_OUT_HIGH BOS_BIT_SET(&GPIOB->PDOR,31)
#define PTH7_OUT_LOW BOS_BIT_CLEAR(&GPIOB->PDOR,31)
#define PTH7_OUT_TOGGLE BOS_BIT_SET(&GPIOB->PTOR,31)
#define PTA0_IN BOS_BIT_EXTRACT(GPIOA->PDIR,0,1) //读取PA0端口输入数据
#define PTA1_IN BOS_BIT_EXTRACT(GPIOA->PDIR,1,1)
#define PTA2_IN BOS_BIT_EXTRACT(GPIOA->PDIR,2,1)
#define PTA3_IN BOS_BIT_EXTRACT(GPIOA->PDIR,3,1)
#define PTA4_IN BOS_BIT_EXTRACT(GPIOA->PDIR,4,1)
#define PTA5_IN BOS_BIT_EXTRACT(GPIOA->PDIR,5,1)
#define PTA6_IN BOS_BIT_EXTRACT(GPIOA->PDIR,6,1)
#define PTA7_IN BOS_BIT_EXTRACT(GPIOA->PDIR,7,1)
#define PTB0_IN BOS_BIT_EXTRACT(GPIOA->PDIR,8,1) //读取PB0端口输入数据
#define PTB1_IN BOS_BIT_EXTRACT(GPIOA->PDIR,9,1)
#define PTB2_IN BOS_BIT_EXTRACT(GPIOA->PDIR,10,1)
#define PTB3_IN BOS_BIT_EXTRACT(GPIOA->PDIR,11,1)
#define PTB4_IN BOS_BIT_EXTRACT(GPIOA->PDIR,12,1)
#define PTB5_IN BOS_BIT_EXTRACT(GPIOA->PDIR,13,1)
#define PTB6_IN BOS_BIT_EXTRACT(GPIOA->PDIR,14,1)
#define PTB7_IN BOS_BIT_EXTRACT(GPIOA->PDIR,15,1)
#define PTC0_IN BOS_BIT_EXTRACT(GPIOA->PDIR,16,1) //读取PC0端口输入数据
#define PTC1_IN BOS_BIT_EXTRACT(GPIOA->PDIR,17,1)
#define PTC2_IN BOS_BIT_EXTRACT(GPIOA->PDIR,18,1)
#define PTC3_IN BOS_BIT_EXTRACT(GPIOA->PDIR,19,1)
#define PTC4_IN BOS_BIT_EXTRACT(GPIOA->PDIR,20,1)
#define PTC5_IN BOS_BIT_EXTRACT(GPIOA->PDIR,21,1)
#define PTC6_IN BOS_BIT_EXTRACT(GPIOA->PDIR,22,1)
#define PTC7_IN BOS_BIT_EXTRACT(GPIOA->PDIR,23,1)
#define PTD0_IN BOS_BIT_EXTRACT(GPIOA->PDIR,24,1) //读取PD0端口输入数据
#define PTD1_IN BOS_BIT_EXTRACT(GPIOA->PDIR,25,1)
#define PTD2_IN BOS_BIT_EXTRACT(GPIOA->PDIR,26,1)
#define PTD3_IN BOS_BIT_EXTRACT(GPIOA->PDIR,27,1)
#define PTD4_IN BOS_BIT_EXTRACT(GPIOA->PDIR,28,1)
#define PTD5_IN BOS_BIT_EXTRACT(GPIOA->PDIR,29,1)
#define PTD6_IN BOS_BIT_EXTRACT(GPIOA->PDIR,30,1)
#define PTD7_IN BOS_BIT_EXTRACT(GPIOA->PDIR,31,1)
#define PTE0_IN BOS_BIT_EXTRACT(GPIOB->PDIR,0,1) //读取PE0端口输入数据
#define PTE1_IN BOS_BIT_EXTRACT(GPIOB->PDIR,1,1)
#define PTE2_IN BOS_BIT_EXTRACT(GPIOB->PDIR,2,1)
#define PTE3_IN BOS_BIT_EXTRACT(GPIOB->PDIR,3,1)
#define PTE4_IN BOS_BIT_EXTRACT(GPIOB->PDIR,4,1)
#define PTE5_IN BOS_BIT_EXTRACT(GPIOB->PDIR,5,1)
#define PTE6_IN BOS_BIT_EXTRACT(GPIOB->PDIR,6,1)
#define PTE7_IN BOS_BIT_EXTRACT(GPIOB->PDIR,7,1)
#define PTF0_IN BOS_BIT_EXTRACT(GPIOB->PDIR,8,1) //读取PF0端口输入数据
#define PTF1_IN BOS_BIT_EXTRACT(GPIOB->PDIR,9,1)
#define PTF2_IN BOS_BIT_EXTRACT(GPIOB->PDIR,10,1)
#define PTF3_IN BOS_BIT_EXTRACT(GPIOB->PDIR,11,1)
#define PTF4_IN BOS_BIT_EXTRACT(GPIOB->PDIR,12,1)
#define PTF5_IN BOS_BIT_EXTRACT(GPIOB->PDIR,13,1)
#define PTF6_IN BOS_BIT_EXTRACT(GPIOB->PDIR,14,1)
#define PTF7_IN BOS_BIT_EXTRACT(GPIOB->PDIR,15,1)
#define PTG0_IN BOS_BIT_EXTRACT(GPIOB->PDIR,16,1) //读取PG0端口输入数据 Modify
#define PTG1_IN BOS_BIT_EXTRACT(GPIOB->PDIR,17,1)
#define PTG2_IN BOS_BIT_EXTRACT(GPIOB->PDIR,18,1)
#define PTG3_IN BOS_BIT_EXTRACT(GPIOB->PDIR,19,1)
#define PTG4_IN BOS_BIT_EXTRACT(GPIOB->PDIR,20,1)
#define PTG5_IN BOS_BIT_EXTRACT(GPIOB->PDIR,21,1)
#define PTG6_IN BOS_BIT_EXTRACT(GPIOB->PDIR,22,1)
#define PTG7_IN BOS_BIT_EXTRACT(GPIOB->PDIR,23,1)
#define PTH0_IN BOS_BIT_EXTRACT(GPIOB->PDIR,24,1) //读取PH0端口输入数据
#define PTH1_IN BOS_BIT_EXTRACT(GPIOB->PDIR,25,1)
#define PTH2_IN BOS_BIT_EXTRACT(GPIOB->PDIR,26,1)
#define PTH3_IN BOS_BIT_EXTRACT(GPIOB->PDIR,27,1)
#define PTH4_IN BOS_BIT_EXTRACT(GPIOB->PDIR,28,1)
#define PTH5_IN BOS_BIT_EXTRACT(GPIOB->PDIR,29,1)
#define PTH6_IN BOS_BIT_EXTRACT(GPIOB->PDIR,30,1)
#define PTH7_IN BOS_BIT_EXTRACT(GPIOB->PDIR,31,1)
/******************************************************************************
*
* 定义GPIO引脚名
*
*******************************************************************************/
typedef enum
{
/* 用于GPIO */
GPIO_PTA0 = 0, /*!< GPIO Pin PTA0 */
GPIO_PTA1, /*!< GPIO Pin PTA1 */
GPIO_PTA2, /*!< GPIO Pin PTA2 */
GPIO_PTA3, /*!< GPIO Pin PTA3 */
GPIO_PTA4, /*!< GPIO Pin PTA4 */
GPIO_PTA5, /*!< GPIO Pin PTA5 */
GPIO_PTA6, /*!< GPIO Pin PTA6 */
GPIO_PTA7, /*!< GPIO Pin PTA7 */
GPIO_PTB0, /*!< GPIO Pin PTB0 */
GPIO_PTB1, /*!< GPIO Pin PTB1 */
GPIO_PTB2, /*!< GPIO Pin PTB2 */
GPIO_PTB3, /*!< GPIO Pin PTB3 */
GPIO_PTB4, /*!< GPIO Pin PTB4 */
GPIO_PTB5, /*!< GPIO Pin PTB5 */
GPIO_PTB6, /*!< GPIO Pin PTB6 */
GPIO_PTB7, /*!< GPIO Pin PTB7 */
GPIO_PTC0, /*!< GPIO Pin PTC0 */
GPIO_PTC1, /*!< GPIO Pin PTC1 */
GPIO_PTC2, /*!< GPIO Pin PTC2 */
GPIO_PTC3, /*!< GPIO Pin PTC3 */
GPIO_PTC4, /*!< GPIO Pin PTC4 */
GPIO_PTC5, /*!< GPIO Pin PTC5 */
GPIO_PTC6, /*!< GPIO Pin PTC6 */
GPIO_PTC7, /*!< GPIO Pin PTC7 */
GPIO_PTD0, /*!< GPIO Pin PTD0 */
GPIO_PTD1, /*!< GPIO Pin PTD1 */
GPIO_PTD2, /*!< GPIO Pin PTD2 */
GPIO_PTD3, /*!< GPIO Pin PTD3 */
GPIO_PTD4, /*!< GPIO Pin PTD4 */
GPIO_PTD5, /*!< GPIO Pin PTD5 */
GPIO_PTD6, /*!< GPIO Pin PTD6 */
GPIO_PTD7, /*!< GPIO Pin PTD7 */
/* in GPIOB register */
GPIO_PTE0, /*!< GPIO Pin PTE0 */
GPIO_PTE1, /*!< GPIO Pin PTE1 */
GPIO_PTE2, /*!< GPIO Pin PTE2 */
GPIO_PTE3, /*!< GPIO Pin PTE3 */
GPIO_PTE4, /*!< GPIO Pin PTE4 */
GPIO_PTE5, /*!< GPIO Pin PTE5 */
GPIO_PTE6, /*!< GPIO Pin PTE6 */
GPIO_PTE7, /*!< GPIO Pin PTE7 */
GPIO_PTF0, /*!< GPIO Pin PTF0 */
GPIO_PTF1, /*!< GPIO Pin PTF1 */
GPIO_PTF2, /*!< GPIO Pin PTF2 */
GPIO_PTF3, /*!< GPIO Pin PTF3 */
GPIO_PTF4, /*!< GPIO Pin PTF4 */
GPIO_PTF5, /*!< GPIO Pin PTF5 */
GPIO_PTF6, /*!< GPIO Pin PTF6 */
GPIO_PTF7, /*!< GPIO Pin PTF7 */
GPIO_PTG0, /*!< GPIO Pin PTG0 */
GPIO_PTG1, /*!< GPIO Pin PTG1 */
GPIO_PTG2, /*!< GPIO Pin PTG2 */
GPIO_PTG3, /*!< GPIO Pin PTG3 */
GPIO_PTG4, /*!< GPIO Pin PTG4 */
GPIO_PTG5, /*!< GPIO Pin PTG5 */
GPIO_PTG6, /*!< GPIO Pin PTG6 */
GPIO_PTG7, /*!< GPIO Pin PTG7 */
GPIO_PTH0, /*!< GPIO Pin PTH0 */
GPIO_PTH1, /*!< GPIO Pin PTH1 */
GPIO_PTH2, /*!< GPIO Pin PTH2 */
GPIO_PTH3, /*!< GPIO Pin PTH3 */
GPIO_PTH4, /*!< GPIO Pin PTH4 */
GPIO_PTH5, /*!< GPIO Pin PTH5 */
GPIO_PTH6, /*!< GPIO Pin PTH6 */
GPIO_PTH7, /*!< GPIO Pin PTH7 */
/* the following pins are not in NV322 */
GPIO_PTI0, /*!< GPIO Pin PTI0 */
GPIO_PTI1, /*!< GPIO Pin PTI1 */
GPIO_PTI2, /*!< GPIO Pin PTI2 */
GPIO_PTI3, /*!< GPIO Pin PTI3 */
GPIO_PTI4, /*!< GPIO Pin PTI4 */
GPIO_PTI5, /*!< GPIO Pin PTI5 */
GPIO_PTI6, /*!< GPIO Pin PTI6 */
GPIO_PTI7, /*!< GPIO Pin PTI7 */
GPIO_PIN_MAX,
} GPIO_PinType;
/******************************************************************************
*
* 定义GPIO引脚掩码
*
*******************************************************************************/
typedef enum
{
/* in GPIOA register */
GPIO_PTA0_MASK = (1<<0), /*!< GPIO Pin PTA0 bit mask */
GPIO_PTA1_MASK = (1<<1), /*!< GPIO Pin PTA1 bit mask */
GPIO_PTA2_MASK = (1<<2), /*!< GPIO Pin PTA2 bit mask */
GPIO_PTA3_MASK = (1<<3), /*!< GPIO Pin PTA3 bit mask */
GPIO_PTA4_MASK = (1<<4), /*!< GPIO Pin PTA4 bit mask */
GPIO_PTA5_MASK = (1<<5), /*!< GPIO Pin PTA5 bit mask */
GPIO_PTA6_MASK = (1<<6), /*!< GPIO Pin PTA6 bit mask */
GPIO_PTA7_MASK = (1<<7), /*!< GPIO Pin PTA7 bit mask */
GPIO_PTB0_MASK = (1<<8), /*!< GPIO Pin PTB0 bit mask */
GPIO_PTB1_MASK = (1<<9), /*!< GPIO Pin PTB1 bit mask */
GPIO_PTB2_MASK = (1<<10), /*!< GPIO Pin PTB2 bit mask */
GPIO_PTB3_MASK = (1<<11), /*!< GPIO Pin PTB3 bit mask */
GPIO_PTB4_MASK = (1<<12), /*!< GPIO Pin PTB4 bit mask */
GPIO_PTB5_MASK = (1<<13), /*!< GPIO Pin PTB5 bit mask */
GPIO_PTB6_MASK = (1<<14), /*!< GPIO Pin PTB6 bit mask */
GPIO_PTB7_MASK = (1<<15), /*!< GPIO Pin PTB7 bit mask */
GPIO_PTC0_MASK = (1<<16), /*!< GPIO Pin PTC0 bit mask */
GPIO_PTC1_MASK = (1<<17), /*!< GPIO Pin PTC1 bit mask */
GPIO_PTC2_MASK = (1<<18), /*!< GPIO Pin PTC2 bit mask */
GPIO_PTC3_MASK = (1<<19), /*!< GPIO Pin PTC3 bit mask */
GPIO_PTC4_MASK = (1<<20), /*!< GPIO Pin PTC4 bit mask */
GPIO_PTC5_MASK = (1<<21), /*!< GPIO Pin PTC5 bit mask */
GPIO_PTC6_MASK = (1<<22), /*!< GPIO Pin PTC6 bit mask */
GPIO_PTC7_MASK = (1<<23), /*!< GPIO Pin PTC7 bit mask */
GPIO_PTD0_MASK = (1<<24), /*!< GPIO Pin PTD0 bit mask */
GPIO_PTD1_MASK = (1<<25), /*!< GPIO Pin PTD1 bit mask */
GPIO_PTD2_MASK = (1<<26), /*!< GPIO Pin PTD2 bit mask */
GPIO_PTD3_MASK = (1<<27), /*!< GPIO Pin PTD3 bit mask */
GPIO_PTD4_MASK = (1<<28), /*!< GPIO Pin PTD4 bit mask */
GPIO_PTD5_MASK = (1<<29), /*!< GPIO Pin PTD5 bit mask */
GPIO_PTD6_MASK = (1<<30), /*!< GPIO Pin PTD6 bit mask */
GPIO_PTD7_MASK = (int)(0x80000000), /*!< GPIO Pin PTD7 bit mask ** thanks to @homeyou */
/* in GPIOB register */
GPIO_PTE0_MASK = (1<<0), /*!< GPIO Pin PTE0 bit mask */
GPIO_PTE1_MASK = (1<<1), /*!< GPIO Pin PTE1 bit mask */
GPIO_PTE2_MASK = (1<<2), /*!< GPIO Pin PTE2 bit mask */
GPIO_PTE3_MASK = (1<<3), /*!< GPIO Pin PTE3 bit mask */
GPIO_PTE4_MASK = (1<<4), /*!< GPIO Pin PTE4 bit mask */
GPIO_PTE5_MASK = (1<<5), /*!< GPIO Pin PTE5 bit mask */
GPIO_PTE6_MASK = (1<<6), /*!< GPIO Pin PTE6 bit mask */
GPIO_PTE7_MASK = (1<<7), /*!< GPIO Pin PTE7 bit mask */
GPIO_PTF0_MASK = (1<<8), /*!< GPIO Pin PTF0 bit mask */
GPIO_PTF1_MASK = (1<<9), /*!< GPIO Pin PTF1 bit mask */
GPIO_PTF2_MASK = (1<<10), /*!< GPIO Pin PTF2 bit mask */
GPIO_PTF3_MASK = (1<<11), /*!< GPIO Pin PTF3 bit mask */
GPIO_PTF4_MASK = (1<<12), /*!< GPIO Pin PTF4 bit mask */
GPIO_PTF5_MASK = (1<<13), /*!< GPIO Pin PTF5 bit mask */
GPIO_PTF6_MASK = (1<<14), /*!< GPIO Pin PTF6 bit mask */
GPIO_PTF7_MASK = (1<<15), /*!< GPIO Pin PTF7 bit mask */
GPIO_PTG0_MASK = (1<<16), /*!< GPIO Pin PTG0 bit mask */
GPIO_PTG1_MASK = (1<<17), /*!< GPIO Pin PTG1 bit mask */
GPIO_PTG2_MASK = (1<<18), /*!< GPIO Pin PTG2 bit mask */
GPIO_PTG3_MASK = (1<<19), /*!< GPIO Pin PTG3 bit mask */
GPIO_PTG4_MASK = (1<<20), /*!< GPIO Pin PTG4 bit mask */
GPIO_PTG5_MASK = (1<<21), /*!< GPIO Pin PTG5 bit mask */
GPIO_PTG6_MASK = (1<<22), /*!< GPIO Pin PTG6 bit mask */
GPIO_PTG7_MASK = (1<<23), /*!< GPIO Pin PTG7 bit mask */
GPIO_PTH0_MASK = (1<<24), /*!< GPIO Pin PTH0 bit mask */
GPIO_PTH1_MASK = (1<<25), /*!< GPIO Pin PTH1 bit mask */
GPIO_PTH2_MASK = (1<<26), /*!< GPIO Pin PTH2 bit mask */
GPIO_PTH3_MASK = (1<<27), /*!< GPIO Pin PTH3 bit mask */
GPIO_PTH4_MASK = (1<<28), /*!< GPIO Pin PTH4 bit mask */
GPIO_PTH5_MASK = (1<<29), /*!< GPIO Pin PTH5 bit mask */
GPIO_PTH6_MASK = (1<<30), /*!< GPIO Pin PTH6 bit mask */
GPIO_PTH7_MASK = (int)(0x80000000), /*!< GPIO Pin PTH7 bit mask ** thanks to @homeyou */
/* in GPIOC register */
GPIO_PTI0_MASK = (1<<0), /*!< GPIO Pin PTI0 bit mask */
GPIO_PTI1_MASK = (1<<1), /*!< GPIO Pin PTI1 bit mask */
GPIO_PTI2_MASK = (1<<2), /*!< GPIO Pin PTI2 bit mask */
GPIO_PTI3_MASK = (1<<3), /*!< GPIO Pin PTI3 bit mask */
GPIO_PTI4_MASK = (1<<4), /*!< GPIO Pin PTI4 bit mask */
GPIO_PTI5_MASK = (1<<5), /*!< GPIO Pin PTI5 bit mask */
GPIO_PTI6_MASK = (1<<6), /*!< GPIO Pin PTI6 bit mask */
GPIO_PTI7_MASK = (1<<7), /*!< GPIO Pin PTI7 bit mask */
} GPIO_PinMaskType;
/******************************************************************************
*
*定义GPIO引脚配置类型
*
*******************************************************************************/
/*
* . 如果引脚配置为输入,禁用高电流驱动
* . 如果引脚配置为输出,禁用内部上拉
* 仅PTH1/0, PTE1/0, PTD1/0, PTB5/4 支持高电流驱动.
*/
typedef enum
{
GPIO_PinOutput = 0, /*!< 设置引脚为输出 */
GPIO_PinInput, /*!< 设置引脚为输出*/
GPIO_PinInput_InternalPullup, /*!< 设置引脚为输入且内部上拉 */
GPIO_PinOutput_HighCurrent, /*!< 设置引脚为输出,高电流驱动*/
} GPIO_PinConfigType;
/*****************************************************************************//*!
* @brief 切换FGPIO端口数据输出----通过32位掩码确定要切换输出的引脚
*
* @param[in] pGPIO 指向FGPIO模块, FGPIOA/FGPIOB.
* @param[in] u32PinMask 32位引脚掩码 ( GPIO_PTA0_MASK, GPIO_PTA1_MASK ............)
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void FGPIO_Toggle(FGPIO_Type *pFGPIO, uint32_t u32PinMask)
{
pFGPIO->PTOR = u32PinMask; /* 切换GPIO端口数据输出 */
}
/*****************************************************************************//*!
* @brief 读取FGPIO端口数据输入寄存器
*
* @param[in] pGPIO 指向FGPIO模块, FGPIOA/FGPIOB.
*
* @return FGPIO端口数据输入寄存器32值
*
*****************************************************************************/
__STATIC_INLINE uint32_t FGPIO_Read(FGPIO_Type *pFGPIO)
{
return (pFGPIO->PDIR); /*读端口数据输入寄存器*/
}
/*****************************************************************************//*!
* @brief 写数据到FGPIO端口数据输出寄存
*
* @param[in] pGPIO 指向FGPIO模块, FGPIOA/FGPIOB.
* @param[in] u32Value 写入的数值
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void FGPIO_Write(FGPIO_Type *pFGPIO, uint32_t u32Value)
{
pFGPIO->PDOR = u32Value; /*写数据到端口数据输出寄存器*/
}
void GPIO_DeInit(GPIO_Type *pGPIO);
void GPIO_Init(GPIO_Type *pGPIO, uint32_t u32PinMask, GPIO_PinConfigType sGpioType);
void GPIO_Toggle(GPIO_Type *pGPIO, uint32_t u32PinMask);
uint32_t GPIO_Read(GPIO_Type *pGPIO);
void GPIO_Write(GPIO_Type *pGPIO, uint32_t u32Value);
void GPIO_PinInit(GPIO_PinType GPIO_Pin, GPIO_PinConfigType GPIO_PinConfig);
void GPIO_PinToggle(GPIO_PinType GPIO_Pin);
void GPIO_PinSet(GPIO_PinType GPIO_Pin);
void GPIO_PinClear(GPIO_PinType GPIO_Pin);
uint8_t GPIO_BitRead(GPIO_PinType GPIO_Pin);
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,347 @@
/******************************************************************************
*
* @brief ICS 驱动头文件.
*
******************************************************************************/
#ifndef ICS_H_
#define ICS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
/****************************************************************************!
* @brief 时钟模式常量定义
*
***************************************************************************/
enum
{
ICS_CLK_MODE_FEI = 1, /*!< FEI 模式 */
ICS_CLK_MODE_FEE, /*!< FEE 模式 */
ICS_CLK_MODE_FEE_OSC, /*!< FEE 模式 OSC输出时钟源选择来自EXTAL引脚的外部时钟源 */
ICS_CLK_MODE_FBE, /*!< FBE 模式 */
ICS_CLK_MODE_FBE_OSC, /*!< FBE 模式 OSC输出时钟源选择来自EXTAL引脚的外部时钟源 */
ICS_CLK_MODE_FBI, /*!< FBI 模式 */
ICS_CLK_MODE_FBILP, /*!< FBILP 模式 */
ICS_CLK_MODE_FBELP, /*!< FBELP 模式 */
};
/*****************************************************************************//*!
*
* @brief 将时钟模式从当前模式切换到另一个时钟模式.
*
* 时钟模式宏观定义如下:
* FEI, FBI, FEE, FBE, FBILP, FBELP, FEE_OSC, FBE_OSC
* 注:FEE_OSC, FBE_OSC 不能用作当前时钟模式. 当前时钟模式和要切换到的时钟模式组合如下:
* < 当前时钟模式,要切换到的时钟模式>
* <FEI,FEE>, <FEI,FBI>, <FEI,FBE>, <FEI,FBE_OSC>, <FEI,FEE_OSC>, <FEE,FEI>,
* <FEE,FBI>, <FEE,FBE>, <FBI,FBE>, <FBI,FEE>, <FBI,FBILP>, <FBI,FEI>,
* <FBE,FBI>, <FBE,FEE>, <FBE,FEI>, <FBE,FBELP>, <FBELP,FBE>, <FBILP,FBI>.
*
* @param[in] CurMode 当前时钟模式
* @param[in] NewMode 要切换到的时钟模式
* @param[in] clkFreq 参考时钟频率
*
* @return none
* @warning FEE_OSC, FBE_OSC 不能用作当前时钟模式.
*
*****************************************************************************/
#define ICS_SwitchMode(CurMode, NewMode, clkFreq) CurMode##_to_##NewMode(clkFreq)
/******************************************************************************
* 定义 OSC 配置结构体
*
*******************************************************************************/
typedef struct
{
uint8_t bRange : 1; /*!< 1: 高频范围, 0: 低频范围 */
uint8_t bGain : 1; /*!< 1: 高增益, 0:低增益 */
uint8_t bEnable : 1; /*!< 1: 使能OSC, 0: 禁用OSC */
uint8_t bStopEnable : 1; /*!< 1: 停止模式下OSC使能, 0: 停止模式下OSC禁用 */
uint8_t bIsCryst : 1; /*!< 1: OSC输出选择振荡器时钟, 0: OSC输出选择来自extal引脚的外部时钟 */
uint8_t bWaitInit : 1; /*!< 1: 等待振荡器初始化完成, 0: 不等待 */
} OSC_ConfigType, *OSC_ConfigPtr;
/******************************************************************************
*
* ICS配置结构体
*
*******************************************************************************/
typedef struct
{
uint8_t u8ClkMode; /*!< 选择时钟模式*/
uint8_t bLPEnable; /*!< 低功耗模式下使能 */
uint32_t u32ClkFreq; /*!< 参考时钟频率 */
OSC_ConfigType oscConfig; /*!< OSC 配置 */
} ICS_ConfigType ;
/*****************************************************************************//*!
*
* @brief 使能中断.
*
* @param none
*
* @return none
*
* @see ICS_DisableInt
*****************************************************************************/
__STATIC_INLINE void ICS_EnableInt(void)
{
ICS->C4 |= (ICS_C4_LOLIE_MASK);
}
/*****************************************************************************//*!
*
* @brief 禁用中断
*
* @param none
*
* @return none
*
* @see ICS_EnableInt
*****************************************************************************/
__STATIC_INLINE void ICS_DisableInt(void)
{
ICS->C4 &= ~(ICS_C4_LOLIE_MASK);
}
/*****************************************************************************//*!
*
* @brief 使能时钟监控
*
* @param none
*
* @return none
*
* @see ICS_DisableClockMonitor
*****************************************************************************/
__STATIC_INLINE void ICS_EnableClockMonitor(void)
{
ICS->C4 |= (ICS_C4_CME_MASK);
}
/*****************************************************************************//*!
*
* @brief 禁用时钟监控
*
* @param none
*
* @return none
*
* @see ICS_EnableClockMonitor
*****************************************************************************/
__STATIC_INLINE void ICS_DisableClockMonitor(void)
{
ICS->C4 &= ~(ICS_C4_CME_MASK);
}
/*****************************************************************************//*!
*
* @brief 设置ICS输出时钟源分频
*
* @param[in] busDivide -- 分频值
*
* @return depends on commands
*****************************************************************************/
__STATIC_INLINE void ICS_SetBusDivider(uint8_t u8BusDivide)
{
ICS->C2 = (ICS->C2 & ~(ICS_C2_BDIV_MASK)) | ICS_C2_BDIV(u8BusDivide);
}
/*****************************************************************************//*!
*
* @brief 使能OSC
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void OSC_Enable(void)
{
OSC->CR |= (OSC_CR_OSCEN_MASK);
}
/*****************************************************************************//*!
*
* @brief 禁用OSC
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void OSC_Disable(void)
{
OSC->CR &= ~(OSC_CR_OSCEN_MASK);
}
/*****************************************************************************//*!
*
* @brief 设置OSC模块的频率范围为低频范围
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void OSC_SetLowRange(void)
{
OSC->CR &= ~(OSC_CR_RANGE_MASK);
}
/*!***************************************************************************//*!
+FUNCTION----------------------------------------------------------------
*
* @brief 设置OSC模块的频率范围为高频范围
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void OSC_SetHighRange(void)
{
OSC->CR |= (OSC_CR_RANGE_MASK);
}
/*****************************************************************************//*!
*
* @brief 设置OSC的工作模式为高增益模式
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void OSC_SetHighGain(void)
{
OSC->CR |= (OSC_CR_HGO_MASK);
}
/*****************************************************************************//*!
*
* @brief 设置OSC的工作模式为低功耗模式
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void OSC_SetLowGain(void)
{
OSC->CR &= ~(OSC_CR_HGO_MASK);
}
/*****************************************************************************//*!
*
* @brief 选择OSC模块的输出时钟源为振荡器时钟源
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void OSC_SelectCrystal(void)
{
OSC->CR |= (OSC_CR_OSCOS_MASK);
}
/*****************************************************************************//*!
*
* @brief OSC输出选择来自extal引脚的外部时钟
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void OSC_SelectClock(void)
{
OSC->CR &= ~(OSC_CR_OSCOS_MASK);
}
/*****************************************************************************//*!
*
* @brief 在停止模式下OSC模块使能
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void OSC_ActiveInStop(void)
{
OSC->CR |= (OSC_CR_OSCSTEN_MASK);
}
/*****************************************************************************//*!
*
* @brief 在停止模式下OSC模块禁用
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void OSC_InactiveInStop(void)
{
OSC->CR &= ~(OSC_CR_OSCSTEN_MASK);
}
/******************************************************************************/
void ICS_Init(ICS_ConfigType *pConfig);
void ICS_DeInit(void);
void ICS_SetClkDivider(uint32_t u32ClkFreqKHz);
void ICS_Trim(uint16 u16TrimValue);
void OSC_Init(OSC_ConfigType *pConfig);
void OSC_DeInit(void);
/************** 内联函数 ******************/
void ICS_DisableClockMonitor(void);
void ICS_DisableInt(void);
void ICS_EnableClockMonitor(void);
void ICS_EnableInt(void);
void ICS_SetBusDivider(uint8_t u8BusDivide);
void OSC_ActiveInStop(void);
void OSC_Enable(void);
void OSC_Disable(void);
void OSC_InactiveInStop(void);
void OSC_SelectClock(void);
void OSC_SelectCrystal(void);
void OSC_SetHighGain(void);
void OSC_SetHighRange(void);
void OSC_SetLowGain(void);
void OSC_SetLowRange(void);
/* do not touch the following functions */
void FEI_to_FEE(ICS_ConfigType *pConfig);
void FEI_to_FBI(ICS_ConfigType *pConfig);
void FEI_to_FBE(ICS_ConfigType *pConfig);
void FEE_to_FBI(ICS_ConfigType *pConfig);
void FEE_to_FEI(ICS_ConfigType *pConfig);
void FEE_to_FBE(ICS_ConfigType *pConfig);
void FBE_to_FEE(ICS_ConfigType *pConfig);
void FBE_to_FEI(ICS_ConfigType *pConfig);
void FBE_to_FBI(ICS_ConfigType *pConfig);
void FBE_to_FBELP(ICS_ConfigType *pConfig);
void FBI_to_FEI(ICS_ConfigType *pConfig);
void FBI_to_FBE(ICS_ConfigType *pConfig);
void FBI_to_FEE(ICS_ConfigType *pConfig);
void FBI_to_FBILP(ICS_ConfigType *pConfig);
void FBILP_to_FBI(ICS_ConfigType *pConfig);
void FBELP_to_FBE(ICS_ConfigType *pConfig);
void FEI_to_FBE_OSC(ICS_ConfigType *pConfig);
void FEI_to_FEE_OSC(ICS_ConfigType *pConfig);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,577 @@
/*********************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file i2c.c
* @brief i2c通讯接口函数库
* @author Navota
* @date 2017-1-1
************************************************************************/
#include "common.h"
#include "i2c.h"
/*!
* @brief 存放回调入口
*
*/
static I2C_CallbackType I2C_Callback[2] = {(I2C_CallbackType)NULL};
void I2C0_Isr( void );
/******************************************************************************
* 定义I2C的接口函数
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 初始化I2C模块.
*
* @param[in] pI2Cx I2C的基址.
* @param[in] pI2CConfig 配置I2C的结构体.
*
* @return none
*
*****************************************************************************/
void I2C_Init(I2C_Type *pI2Cx,I2C_ConfigPtr pI2CConfig)
{
uint8_t u8Temp;
#if defined(CPU_NV32)
SIM->SCGC |= SIM_SCGC_IIC_MASK;
#endif
I2C_SetBaudRate(pI2Cx,pI2CConfig->u16F);
I2C_SetSlaveAddress(pI2Cx,pI2CConfig->u16OwnA1);
pI2Cx->FLT = (uint8_t)pI2CConfig->u16Filt;
pI2Cx->RA = (uint8_t)pI2CConfig->u16RangeA & 0xfe;
I2C_SetSCLLowETMeout(pI2Cx,pI2CConfig->u16Slt);
/* 配置控制寄存器C2 */
u8Temp = 0;
if( pI2CConfig->sSetting.bGCAEn )
{
u8Temp |= I2C_C2_GCAEN_MASK;
}
if( pI2CConfig->sSetting.bAddressExt )
{
u8Temp |= I2C_C2_ADEXT_MASK;
}
if( pI2CConfig->sSetting.bRangeAddEn )
{
u8Temp |= I2C_C2_RMEN_MASK;
}
pI2Cx->C2 |= u8Temp;
/* 配置寄存器SMB */
u8Temp = 0;
if( pI2CConfig->sSetting.bFackEn )
{
u8Temp |= I2C_SMB_FACK_MASK;
}
if( pI2CConfig->sSetting.bSMB_AlertEn )
{
u8Temp |= I2C_SMB_ALERTEN_MASK;
}
if( pI2CConfig->sSetting.bSecondAddressEn )
{
u8Temp |= I2C_SMB_SIICAEN_MASK;
}
if( pI2CConfig->sSetting.bSHTF2IntEn )
{
u8Temp |= I2C_SMB_SHTF2IE_MASK;
}
pI2Cx->SMB = u8Temp;
/* 配置寄存器C1 */
u8Temp = 0;
if( pI2CConfig->sSetting.bIntEn )
{
u8Temp |= I2C_C1_IICIE_MASK;
if(pI2Cx == I2C0)
{
NVIC_EnableIRQ(I2C0_IRQn);
}
else
{
//
}
}
if( pI2CConfig->sSetting.bWakeUpEn )
{
u8Temp |= I2C_C1_WUEN_MASK;
}
if( pI2CConfig->sSetting.bI2CEn )
{
u8Temp |= I2C_C1_IICEN_MASK;
}
pI2Cx->C1 = u8Temp;
}
/*****************************************************************************//*!
*
* @brief 发送I2C起始信号(启动传输).
*
* @param[in] pI2Cx I2C的基址.
*
* @return 错误状态
*
*****************************************************************************/
uint8_t I2C_Start(I2C_Type *pI2Cx)
{
uint32_t u32ETMeout;
uint8_t u8ErrorStatus;
u32ETMeout = 0;
u8ErrorStatus = 0x00;
I2C_TxEnable(pI2Cx);//将 I2C 配置成 TX 发送模式
pI2Cx->C1 |= I2C_C1_MST_MASK;//将 I2C 配置成主机模式
//持续监测起始位有没有发送成功
while( (!I2C_IsBusy(pI2Cx)) && ( u32ETMeout < I2C_WAIT_STATUS_ETMEOUT))
{
u32ETMeout ++;
}
if( u32ETMeout == I2C_WAIT_STATUS_ETMEOUT )
{
u8ErrorStatus |= I2C_ERROR_START_NO_BUSY_FLAG;
}
return u8ErrorStatus;//返回错误标志,为0x10即起始信号没有发送成功
}
/*****************************************************************************//*!
*
* @brief 发送停止信号.
*
* @param[in] pI2Cx I2C的基址.
*
* @return 错误状态
*
*****************************************************************************/
uint8_t I2C_Stop(I2C_Type *pI2Cx)
{
uint32_t u32ETMeout;
uint8_t u8ErrorStatus;
u32ETMeout = 0;
u8ErrorStatus = 0x00;
pI2Cx->C1 &= ~I2C_C1_MST_MASK;
//持续监测 I2C 停止位是否发送成功
while( (I2C_IsBusy(pI2Cx) ) && ( u32ETMeout < I2C_WAIT_STATUS_ETMEOUT))
{
u32ETMeout ++;
}
if( u32ETMeout == I2C_WAIT_STATUS_ETMEOUT )
{
u8ErrorStatus |= I2C_ERROR_STOP_BUSY_FLAG;
}
return u8ErrorStatus;
}
/*****************************************************************************//*!
*
* @brief 发送重复起始位.
*
* @param[in] pI2Cx I2C的基址.
*
* @return 错误状态.
*
*****************************************************************************/
uint8_t I2C_RepeatStart(I2C_Type *pI2Cx)
{
uint32_t u32ETMeout;
uint8_t u8ErrorStatus;
u32ETMeout = 0;
u8ErrorStatus = 0x00;
pI2Cx->C1 |= I2C_C1_RSTA_MASK;
//持续监测起始位是否发送成功
while( (!I2C_IsBusy(I2C0) ) && ( u32ETMeout < I2C_WAIT_STATUS_ETMEOUT))
{
u32ETMeout ++;
}
if( u32ETMeout == I2C_WAIT_STATUS_ETMEOUT )
{
u8ErrorStatus |= I2C_ERROR_START_NO_BUSY_FLAG;
}
return u8ErrorStatus;
}
/*****************************************************************************//*!
*
* @brief 设置从机地址.
*
* @param[in] pI2Cx I2C的基址.
* @param[in] u16SlaveAddress 从机地址.
*
* @return none
*
*****************************************************************************/
void I2C_SetSlaveAddress(I2C_Type *pI2Cx,uint16_t u16SlaveAddress)
{
/* 写入8位地址 */
pI2Cx->A1 = (uint8_t)u16SlaveAddress;
/* 如果支持十位从机地址, 写入高三位地址 */
pI2Cx->C2 &= ~I2C_C2_AD_MASK;
pI2Cx->C2 |= (uint8_t)(u16SlaveAddress>>8)&0x03;
}
/*****************************************************************************//*!
*
* @brief 禁用I2C中断.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none.
*
*****************************************************************************/
void I2C_IntDisable(I2C_Type *pI2Cx)
{
pI2Cx->C1 &= ~I2C_C1_IICIE_MASK;
if(pI2Cx == I2C0)
{
NVIC_DisableIRQ(I2C0_IRQn);
}
else
{
}
}
/*****************************************************************************//*!
*
* @brief 使能I2C中断.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none.
*
*****************************************************************************/
void I2C_IntEnable(I2C_Type *pI2Cx)
{
pI2Cx->C1 |= I2C_C1_IICIE_MASK;
if(pI2Cx == I2C0)
{
NVIC_EnableIRQ(I2C0_IRQn);
}
else
{
}
}
/*****************************************************************************//*!
*
* @brief 设置SCL低超时周期.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none.
*
*****************************************************************************/
void I2C_SetSCLLowETMeout(I2C_Type *pI2Cx, uint16_t u16ETMeout)
{
pI2Cx->SLTL = (uint8_t)u16ETMeout;
pI2Cx->SLTH = (uint8_t)(u16ETMeout>>8);
}
/*****************************************************************************//*!
*
* @brief 复位I2C模块.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none
*
*****************************************************************************/
void I2C_Deinit(I2C_Type *pI2Cx)
{
pI2Cx->C1 &= ~I2C_C1_IICEN_MASK;
#if defined(CPU_NV32)
SIM->SCGC &= ~SIM_SCGC_IIC_MASK;
#endif
}
/*****************************************************************************//*!
*
* @brief 发送单字节数据.
*
* @param[in] pI2Cx I2C模块的基址.
* @param[in] u8WrBuff 要写的数据缓冲区.
*
* @return 错误状态
*
*****************************************************************************/
uint8_t I2C_WriteOneByte(I2C_Type *pI2Cx, uint8_t u8WrBuff)
{
uint32_t u32ETMeout;
uint8_t u8ErrorStatus;
u32ETMeout = 0;
u8ErrorStatus = 0x00;
while (((I2C_GetStatus(pI2Cx)&I2C_S_TCF_MASK) != I2C_S_TCF_MASK)
&& (u32ETMeout<I2C_WAIT_STATUS_ETMEOUT))
{
u32ETMeout ++;
}
if (u32ETMeout >= I2C_WAIT_STATUS_ETMEOUT)
{
u8ErrorStatus |= I2C_ERROR_NO_WAIT_TCF_FLAG;
return u8ErrorStatus;
}
I2C_TxEnable(pI2Cx); //将 I2C 配置成 TX 输出模式
I2C_WriteDataReg(pI2Cx,u8WrBuff); //写数据寄存器发送数据
u32ETMeout = 0;
while (((I2C_GetStatus(pI2Cx)&I2C_S_IICIF_MASK) != I2C_S_IICIF_MASK)
&& (u32ETMeout<I2C_WAIT_STATUS_ETMEOUT))
{
u32ETMeout ++;
}
if (u32ETMeout >= I2C_WAIT_STATUS_ETMEOUT)
{
u8ErrorStatus |= I2C_ERROR_NO_WAIT_IICIF_FLAG;
return u8ErrorStatus;
}
/* 清除中断标志位 */
I2C_ClearStatus(pI2Cx,I2C_S_IICIF_MASK);
if (I2C_GetStatus(pI2Cx) & I2C_S_RXAK_MASK)
{
u8ErrorStatus |= I2C_ERROR_NO_GET_ACK;
}
return u8ErrorStatus;
}
/*****************************************************************************//*!
*
* @brief 读取单字节数据.
*
* @param[in] pI2Cx I2C的基址.
* @param[out] pRdBuff 所要从从机读的地址.
* @param[out] u8Ack 发送 ack or nack.
*
* @return 错误状态
*
*****************************************************************************/
uint8_t I2C_ReadOneByte(I2C_Type *pI2Cx, uint8_t *pRdBuff, uint8_t u8Ack)
{
uint32_t u32ETMeout;
uint8_t u8ErrorStatus;
u32ETMeout = 0;
u8ErrorStatus = 0x00;
while (((I2C_GetStatus(pI2Cx)&I2C_S_TCF_MASK) != I2C_S_TCF_MASK)
&& (u32ETMeout<I2C_WAIT_STATUS_ETMEOUT))
{
u32ETMeout ++;
}
if (u32ETMeout >= I2C_WAIT_STATUS_ETMEOUT)
{
u8ErrorStatus |= I2C_ERROR_NO_WAIT_TCF_FLAG;
return u8ErrorStatus;
}
I2C_RxEnable(pI2Cx); //将 I2C 配置为输入模式
if( u8Ack )
{
/* 发送 nack */
I2C_SendNack(pI2Cx);
}
else
{
/* 发送 ack */
I2C_SendAck(pI2Cx);
}
*pRdBuff = I2C_ReadDataReg(pI2Cx); //将读到的数据存放到参数里头
u32ETMeout = 0;
//持续监测中断标志
while (((I2C_GetStatus(pI2Cx)&I2C_S_IICIF_MASK) != I2C_S_IICIF_MASK)
&& (u32ETMeout<I2C_WAIT_STATUS_ETMEOUT))
{
u32ETMeout ++;
}
if (u32ETMeout >= I2C_WAIT_STATUS_ETMEOUT)
{
u8ErrorStatus |= I2C_ERROR_NO_WAIT_IICIF_FLAG;
return u8ErrorStatus;
}
/*清除 IIC 中断标志位 */
I2C_ClearStatus(pI2Cx,I2C_S_IICIF_MASK);
return u8ErrorStatus;
}
/*****************************************************************************//*!
*
* @brief 发送数据到I2C,然后等待数据传送完成.
*
* @param[in] pI2Cx I2C的基址.
* @param[in] u16SlaveAddress 16位从机地址.
* @param[in] pWrBuff 需要发送数据的缓冲数组.
* @param[in] u32Length 发送字节的数目.
*
* @return 错误状态
*
*****************************************************************************/
uint8_t I2C_MasterSendWait(I2C_Type *pI2Cx,uint16_t u16SlaveAddress,uint8_t *pWrBuff,uint32_t u32Length)
{
uint32_t i;
uint8_t u8ErrorStatus;
/* 发送起始信号 */
u8ErrorStatus = I2C_Start(pI2Cx);
/* 给从机发送从机地址 */
u8ErrorStatus = I2C_WriteOneByte(pI2Cx,((uint8_t)u16SlaveAddress<<1) | I2C_WRITE);
/* 如果没有错误发生, 则继续发送字节*/
if( u8ErrorStatus == I2C_ERROR_NULL )
{
for(i=0;i<u32Length;i++)
{
u8ErrorStatus = I2C_WriteOneByte(pI2Cx,pWrBuff[i]);
if( u8ErrorStatus != I2C_ERROR_NULL )
{
return u8ErrorStatus;
}
}
}
/*发送 I2C 停止位 */
u8ErrorStatus = I2C_Stop(pI2Cx);
return u8ErrorStatus;
}
/*****************************************************************************//*!
*
* @brief 读取多个字节并等待完成.
*
* @param[in] pI2Cx I2C的基址.
* @param[in] u16SlaveAddress 从机地址.
* @param[in] pRdBuff 用于接收数据的缓冲区.
* @param[in] u32Length 接收数据的字节数.
*
* @return 错误状态
*
*****************************************************************************/
uint8_t I2C_MasterReadWait(I2C_Type *pI2Cx,uint16_t u16SlaveAddress,uint8_t *pRdBuff,uint32_t u32Length)
{
uint32_t i;
uint8_t u8ErrorStatus;
/* 发送起始信号到总线 */
u8ErrorStatus = I2C_Start(pI2Cx);
/* 给从机发送器件地址 */
u8ErrorStatus = I2C_WriteOneByte(pI2Cx,((uint8_t)u16SlaveAddress<<1) | I2C_READ);
/* 如果没有错误发生, 则继续接收字节*/
I2C_ReadOneByte(pI2Cx,&pRdBuff[0],I2C_SEND_ACK);
if( u8ErrorStatus == I2C_ERROR_NULL )
{
for(i=0;i<u32Length-1;i++)
{
u8ErrorStatus = I2C_ReadOneByte(pI2Cx,&pRdBuff[i],I2C_SEND_ACK);
if( u8ErrorStatus != I2C_ERROR_NULL )
{
return u8ErrorStatus;
}
}
u8ErrorStatus = I2C_ReadOneByte(pI2Cx,&pRdBuff[i],I2C_SEND_NACK);
}
/*发送停止信号 */
u8ErrorStatus = I2C_Stop(pI2Cx);
return u8ErrorStatus;
}
/*****************************************************************************//*!
*
* @brief 设置I2C模块的中断回调函数
*
* @param[in] pfnCallback 回调函数的地址
*
* @return none
*
*****************************************************************************/
void I2C1_SetCallBack( I2C_CallbackType pCallBack )
{
I2C_Callback[1] = pCallBack;
}
/*****************************************************************************//*!
*
* @brief 设置RTC模块的中断回调函数
*
* @param[in] pfnCallback 回调函数的地址
*
* @return none
*
*****************************************************************************/
void I2C0_SetCallBack( I2C_CallbackType pCallBack )
{
I2C_Callback[0] = pCallBack;
}
/*! @} */
/*****************************************************************************//*!
*
* @brief I2C0 中断服务函数.
*
* @param
*
* @return none
*
*****************************************************************************/
void I2C0_Isr( void )
{
if( I2C_Callback[0] )
{
I2C_Callback[0]();
}
}
/*****************************************************************************//*!
*
* @brief I2C1 中断服务函数.
*
* @param
*
* @return none
*
*****************************************************************************/
void I2C1_Isr( void )
{
if( I2C_Callback[1] )
{
I2C_Callback[1]();
}
}
@@ -0,0 +1,503 @@
/******************************************************************************
*
* @brief I2C 驱动头文件.
*
******************************************************************************/
#ifndef _I2C_H__
#define _I2C_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
/******************************************************************************
* 定义I2C的读和写
*
*//*!
* @{
*******************************************************************************/
#define I2C_READ 0x01 /*!< I2C 读 */
#define I2C_WRITE 0x0 /*!< I2C 写 */
/*! @} */
#define I2C_SEND_ACK 0 /*!< I2C 发送 ACK */
#define I2C_SEND_NACK 1 /*!< I2C 发送 NACK */
#define I2C_WAIT_STATUS_ETMEOUT 200000
/******************************************************************************
* 定义I2C错误状态
*
*//*!
* @{
*******************************************************************************/
#define I2C_ERROR_NULL 0x00 /*!< I2C 工作成功*/
#define I2C_ERROR_NO_WAIT_TCF_FLAG 0x01 /*!< I2C 等待传输完成超时*/
#define I2C_ERROR_NO_WAIT_IICIF_FLAG 0x02 /*!< I2C 等待中断超时 */
#define I2C_ERROR_NO_GET_ACK 0x04 /*!< I2C 没有得到 ACK */
#define I2C_ERROR_START_NO_BUSY_FLAG 0x10 /*!< I2C 没有成功发送起始信号 */
#define I2C_ERROR_STOP_BUSY_FLAG 0x20 /*!< I2C 没有成功发送停止信号 */
#define I2C_ERROR_BUS_BUSY 0x80 /*!< I2C 总线繁忙错误 */
/*! @} End of i2c_error_state_list */
/******************************************************************************
* 定义I2C总线状态
*
*//*!
* @{
*******************************************************************************/
#define I2C_BUS_NORMAL 0x00 /*!< I2C 总线正常 */
#define I2C_BUS_SLTF 0x01 /*!< I2C 总线偏移一个FLAG */
#define I2C_BUS_SHTF2 0x02 /*!< I2C 总线偏移两个FLAG */
/*! @} */
#define I2C_MODE_MASTER 1
#define I2C_MODE_SLAVE 0
#define I2C_ADDRESS_7BIT 0
#define I2C_ADDRESS_10BIT 1
#define I2C_ETMEOUT_BUS_CLOCK_DIV64 0
#define I2C_ETMEOUT_BUS_CLOCK 1
/******************************************************************************
*
*//*! @I2C控制参数结构体
* @{
*******************************************************************************/
/*!
* @I2C控制参数结构体.
*
*/
typedef struct
{
uint16_t bI2CEn :1; /*!< 使能I2C模块 */
uint16_t bIntEn :1; /*!< 使能I2C中断 */
uint16_t bWakeUpEn :1; /*!< I2C唤醒使能 */
uint16_t bGCAEn :1; /*!< I2C通用启动地址使能 */
uint16_t bAddressExt :1; /*!< I2C地址扩展选择 */
uint16_t bRangeAddEn :1; /*!< 使能范围地址匹配 */
uint16_t bFackEn :1; /*!< 使能快速ack */
uint16_t bSMB_AlertEn :1; /*!< SMB 报警响应地址使能 */
uint16_t bSecondAddressEn:1; /*!< 启用第二I2C地址 */
uint16_t bETMeoutCountClockSelect:1; /*!< 超时计数器时钟选择 */
uint16_t bSHTF2IntEn :1; /*!< SHTF2 中断使能 */
uint16_t Reserve :5;
}I2C_SettingType;
/*! @} */
/******************************************************************************
*
*//*! @I2C配置结构体
* @{
*******************************************************************************/
/*!
* @I2C配置结构体.
*
*/
typedef struct
{
I2C_SettingType sSetting;
uint16_t u16F; /*!< 设置I2C模块的波特率 */
uint16_t u16OwnA1; /*!< 从机地址 */
uint16_t u16OwnA2; /*!< SMBus使用的从机地址 */
uint16_t u16RangeA; /*!< 范围地址 */
uint16_t u16Filt; /*!< I2C输入干扰滤波器 */
uint16_t u16Slt; /*!< SCL低超时周期 */
}I2C_ConfigType, *I2C_ConfigPtr;
/*! @} */
/*!
* @brief I2C 回调类型.
*
*/
typedef void (*I2C_CallbackType)(void);
/*! @} */
/******************************************************************************
******************************************************************************/
/*!
* 内联函数
*/
/*****************************************************************************//*!
*
* @brief 配置I2C发送模式.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void I2C_TxEnable(I2C_Type *pI2Cx)
{
pI2Cx->C1 |= I2C_C1_TX_MASK;
}
/*****************************************************************************//*!
*
* @brief 配置I2C接收模式.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void I2C_RxEnable(I2C_Type *pI2Cx)
{
pI2Cx->C1 &= ~I2C_C1_TX_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置I2C波特率.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void I2C_SetBaudRate(I2C_Type *pI2Cx,uint32_t u32Bps)
{
pI2Cx->F = (uint8_t)u32Bps;
}
/*****************************************************************************//*!
*
* @brief 使能通用地址启动.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void I2C_GeneralCallEnable(I2C_Type *pI2Cx)
{
pI2Cx->C2 |= I2C_C2_GCAEN_MASK;
}
/*****************************************************************************//*!
*
* @brief SMBus 报警响应地址使能.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void I2C_SMBusAlertEnable(I2C_Type *pI2Cx)
{
pI2Cx->SMB|= I2C_SMB_ALERTEN_MASK;
}
/*****************************************************************************//*!
*
* @brief 范围地址匹配使能.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void I2C_RangeAddressEnable(I2C_Type *pI2Cx)
{
pI2Cx->C2 |= I2C_C2_RMEN_MASK;
}
/*****************************************************************************//*!
*
* @brief SHTF2 中断使能.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void I2C_SHTF2IntEnable(I2C_Type *pI2Cx)
{
pI2Cx->SMB |= I2C_SMB_SHTF2IE_MASK;
}
/*****************************************************************************//*!
*
* @brief 超时计数器时钟选择.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void I2C_ETMeoutCounterClockSelect(I2C_Type *pI2Cx, uint8_t u8Clock)
{
if( u8Clock )
{
pI2Cx->SMB |= I2C_SMB_TCKSEL_MASK;
}
else
{
pI2Cx->SMB &= ~I2C_SMB_TCKSEL_MASK;
}
}
/*****************************************************************************//*!
*
* @brief 获取I2C的状态.
*
* @param[in] pI2Cx I2C的基址.
*
* @return I2C的状态
*
*****************************************************************************/
__STATIC_INLINE uint8_t I2C_GetStatus(I2C_Type *pI2Cx)
{
return pI2Cx->S;
}
/*****************************************************************************//*!
*
* @brief 清除特定的状态.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void I2C_ClearStatus(I2C_Type *pI2Cx, uint8_t u8ClearFlag)
{
pI2Cx->S |= u8ClearFlag;
}
/*****************************************************************************//*!
*
* @brief 写数据到数据寄存器.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void I2C_WriteDataReg(I2C_Type *pI2Cx, uint8_t u8DataBuff)
{
pI2Cx->D = u8DataBuff;
}
/*****************************************************************************//*!
*
* @brief 从数据寄存器读取数据.
*
* @param[in] pI2Cx I2C的基址.
*
* @return I2C数据寄存器值
*
*****************************************************************************/
__STATIC_INLINE uint8_t I2C_ReadDataReg(I2C_Type *pI2Cx )
{
return pI2Cx->D;
}
/*****************************************************************************//*!
*
* @brief 检查I2C模式是否为发送.
*
* @param[in] pI2Cx I2C的基址.
*
* @return 是/否
*
*****************************************************************************/
__STATIC_INLINE uint8_t I2C_IsTxMode(I2C_Type *pI2Cx )
{
return(pI2Cx->C1 & I2C_C1_TX_MASK);
}
/*****************************************************************************//*!
*
* @brief 检查总线是否繁忙.
*
* @param[in] pI2Cx I2C的基址.
*
* @return 是/否
*
*****************************************************************************/
__STATIC_INLINE uint8_t I2C_IsBusy(I2C_Type *pI2Cx )
{
return (pI2Cx->S & I2C_S_BUSY_MASK);
}
/*****************************************************************************//*!
*
* @brief 确认信号是否被接收.
*
* @param[in] pI2Cx I2C的基址.
*
* @return 是/否
*
*****************************************************************************/
__STATIC_INLINE uint8_t I2C_IsReceivedAck(I2C_Type *pI2Cx )
{
return (pI2Cx->S & I2C_S_RXAK_MASK);
}
/*****************************************************************************//*!
*
* @brief 检查I2C是否为主机模式.
*
* @param[in] pI2Cx I2C的基址.
*
* @return 是/否.
*
*****************************************************************************/
__STATIC_INLINE uint8_t I2C_IsMasterMode(I2C_Type *pI2Cx )
{
return(pI2Cx->C1 & I2C_C1_MST_MASK);
}
/*****************************************************************************//*!
*
* @brief 检查有无低超时发生.
*
* @param[in] pI2Cx I2C的基址.
*
* @return 是/否.
*
*****************************************************************************/
__STATIC_INLINE uint8_t I2C_IsSMB_SLTF(I2C_Type *pI2Cx )
{
return (pI2Cx->SMB & I2C_SMB_SLTF_MASK);
}
/*****************************************************************************//*!
*
* @brief 检查有无高超时发生.
*
* @param[in] pI2Cx I2C的基址.
*
* @return 是/否.
*
*****************************************************************************/
__STATIC_INLINE uint8_t I2C_IsSMB_SHTF2(I2C_Type *pI2Cx )
{
return(pI2Cx->SMB & I2C_SMB_SHTF2_MASK);
}
/*****************************************************************************//*!
*
* @brief 清除SCL低超时标志.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void I2C_ClearSLTF(I2C_Type *pI2Cx )
{
pI2Cx->SMB |= I2C_SMB_SLTF_MASK;
}
/*****************************************************************************//*!
*
* @brief 清除高超时标志位2.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void I2C_ClearSHTF2(I2C_Type *pI2Cx )
{
pI2Cx->SMB |= I2C_SMB_SHTF2_MASK;
}
/*****************************************************************************//*!
*
* @brief 发送信号ACK.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void I2C_SendAck(I2C_Type *pI2Cx )
{
pI2Cx->C1 &= ~I2C_C1_TXAK_MASK;
}
/*****************************************************************************//*!
*
* @brief 发送信号NACK.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void I2C_SendNack(I2C_Type *pI2Cx )
{
pI2Cx->C1 |= I2C_C1_TXAK_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能第二I2C地址.
*
* @param[in] pI2Cx I2C的基址.
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void I2C_SecondAddressEnable(I2C_Type *pI2Cx)
{
pI2Cx->SMB |= I2C_SMB_SIICAEN_MASK;
}
/******************************************************************************
******************************************************************************/
void I2C_Init(I2C_Type *pI2Cx,I2C_ConfigPtr pI2CConfig);
uint8_t I2C_Start(I2C_Type *pI2Cx);
uint8_t I2C_Stop(I2C_Type *pI2Cx);
uint8_t I2C_RepeatStart(I2C_Type *pI2Cx);
uint8_t I2C_IsTxMode(I2C_Type *pI2Cx );
uint8_t I2C_IsBusy(I2C_Type *pI2Cx );
uint8_t I2C_IsReceivedAck(I2C_Type *pI2Cx );
uint8_t I2C_IsMasterMode(I2C_Type *pI2Cx );
void I2C_ClearSHTF2(I2C_Type *pI2Cx );
void I2C_ClearSLTF(I2C_Type *pI2Cx );
uint8_t I2C_IsSMB_SHTF2(I2C_Type *pI2Cx );
uint8_t I2C_IsSMB_SLTF(I2C_Type *pI2Cx );
void I2C_TxEnable(I2C_Type *pI2Cx);
void I2C_RxEnable(I2C_Type *pI2Cx);
void I2C_IntEnable(I2C_Type *pI2Cx);
void I2C_IntDisable(I2C_Type *pI2Cx);
void I2C_SetBaudRate(I2C_Type *pI2Cx,uint32_t u32Bps);
void I2C_SetSlaveAddress(I2C_Type *pI2Cx,uint16_t u16SlaveAddress);
void I2C_GeneralCallEnable(I2C_Type *pI2Cx);
void I2C_SMBusAlertEnable(I2C_Type *pI2Cx);
void I2C_RangeAddressEnable(I2C_Type *pI2Cx);
void I2C_SHTF2IntEnable(I2C_Type *pI2Cx);
void I2C_ETMeoutCounterClockSelect(I2C_Type *pI2Cx, uint8_t u8Clock);
void I2C_SetSCLLowETMeout(I2C_Type *pI2Cx, uint16_t u16ETMeout);
uint8_t I2C_GetStatus(I2C_Type *pI2Cx);
void I2C_ClearStatus(I2C_Type *pI2Cx, uint8_t u8ClearFlag);
void I2C_SendAck(I2C_Type *pI2Cx );
void I2C_SendNack(I2C_Type *pI2Cx );
void I2C_SecondAddressEnable(I2C_Type *pI2Cx);
void I2C_ClearStatus(I2C_Type *pI2Cx, uint8_t u8ClearFlag);
void I2C_WriteDataReg(I2C_Type *pI2Cx, uint8_t u8DataBuff);
uint8_t I2C_ReadDataReg(I2C_Type *pI2Cx );
void I2C_Deinit(I2C_Type *pI2Cx);
uint8_t I2C_WriteOneByte(I2C_Type *pI2Cx, uint8_t u8WrBuff);
uint8_t I2C_ReadOneByte(I2C_Type *pI2Cx, uint8_t *pRdBuff, uint8_t u8Ack);
uint8_t I2C_MasterSendWait(I2C_Type *pI2Cx,uint16_t u16SlaveAddress,uint8_t *pWrBuff,uint32_t u32Length);
uint8_t I2C_MasterReadWait(I2C_Type *pI2Cx,uint16_t u16SlaveAddress,uint8_t *pRdBuff,uint32_t u32Length);
void I2C0_SetCallBack( I2C_CallbackType pCallBack );
void I2C1_SetCallBack( I2C_CallbackType pCallBack );
/*! @} */
#ifdef __cplusplus
}
#endif
#endif //
@@ -0,0 +1,252 @@
/**************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file kbi.c
* @brief 键盘中断(KBI)函数库
* @author Navota
* @date 2017-1-1
****************************************************************************/
#include "common.h"
#include "kbi.h"
/****************************************************************************!
* @ 存放KBI回调函数接口
****************************************************************************/
KBI_CallbackType KBI_Callback[KBI_MAX_NO] = {(KBI_CallbackType)NULL};
/*****************************************************************************//*!
*
* @brief 初始化KBI模块.
*
* @param[in] pKBI 指向KBI模块.
* @param[in] pConfig 指向KBI配置结构体
*
* @return none.
*
* @see KBI_DeInit.
*
*****************************************************************************/
void KBI_Init(KBI_Type *pKBI, KBI_ConfigType *pConfig)
{
#if defined(CPU_NV32)
uint16_t i;
uint8_t sc = 0;
uint8_t u8Port;
uint8_t u8PinPos;
uint16_t u16PinMapping[KBI_MAX_NO][8] =
{
{
0, 1, 2, 3, 8, 9, 10, 11 /* KBI0中断输入引脚在GPIOA寄存器中的位置*/
},
{
24, 25, 26, 27, 28, 29, 30, 31 /*KBI1中断输入引脚在GPIOA寄存器中的位置*/
}
};
#elif defined(CPU_NV32M3)
uint16_t i;
uint8_t sc = 0;
uint8_t u8Port;
uint8_t u8PinPos;
uint16_t u16PinMapping[KBI_MAX_NO][8] =
{
{
0, 1, 2, 3, 8, 9, 10, 11 /* KBI0中断输入引脚在GPIOA寄存器中的位置*/
},
{
20, 21, 16, 17, 18, 19, 12, 13 /* KBI1中断输入引脚在GPIOA寄存器中的位置*/
}
};
#elif defined(CPU_NV32M4)
uint32_t i;
uint32_t sc = 0;
uint32_t u8Port;
uint32_t u8PinPos;
uint32_t u16PinMapping[KBI_MAX_NO][KBI_MAX_PINS_PER_PORT] =
{
{/* KBI0P0~KBI0P31 中断输入引脚在GPIOA寄存器中的位置 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
},
{/* KBI1P0~KBI1P31中断输入引脚在GPIOA寄存器中的位置 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
}
};
#endif
if(KBI0 == pKBI)
{
SIM->SCGC |= SIM_SCGC_KBI0_MASK; /* 使能KBI0模块的总线时钟 */
u8Port = 0;
}
else if (KBI1 == pKBI)
{
SIM->SCGC |= SIM_SCGC_KBI1_MASK; /* 使能KBI1模块的总线时钟 */
u8Port = 1;
}
/*设定KBI中断检测模式*/
sc = pConfig->sBits.bMode;
pKBI->SC = sc;
/* 配置KBI中断输入引脚 */
for (i = 0; i < KBI_MAX_PINS_PER_PORT; i++)
{
if(pConfig->sPin[i].bEn)
{
pKBI->PE |= (1<<i); /* 使能I/O引脚为KBI中断输入引脚*/
pKBI->ES = (pKBI->ES & ~(1<<i)) | (pConfig->sPin[i].bEdge << i);
u8PinPos = u16PinMapping[u8Port][i];
ASSERT(!(u8PinPos & 0x80));
#if defined(CPU_NV32)|| defined(CPU_NV32M3)
FGPIOA->PIDR &= ~(1<<u8PinPos); /* 使能GPIO输入*/
FGPIOA->PDDR &= ~(1<<u8PinPos); /* 引脚配置为通用输入 */
PORT->PUEL |= (1<<u8PinPos); /* 使能内部上拉*/
#elif defined(CPU_NV32M4)
if (u8Port == 0) /* KBI0 */
{
FGPIOA->PIDR &= ~(1<<u8PinPos); /* 使能GPIO输入*/
FGPIOA->PDDR &= ~(1<<u8PinPos); /* 引脚配置为通用输入 */
PORT->PUE0 |= (1<<u8PinPos); /* 使能内部上拉*/
}
else if (u8Port == 1) /* KBI1 */
{
FGPIOB->PIDR &= ~(1<<u8PinPos); /* 使能GPIO输入*/
FGPIOB->PDDR &= ~(1<<u8PinPos); /* 引脚配置为通用输入 */
PORT->PUE1 |= (1<<u8PinPos); /* 使能内部上拉*/
}
#endif
}
}
#if defined(CPU_NV32M4)
/*Reset KBI_SP register*/
sc = pConfig->sBits.bRstKbsp<<KBI_SC_RSTKBSP_SHIFT;
pKBI->SC |= sc;
/*Real KBI_SP register enable*/
sc = pConfig->sBits.bKbspEn<<KBI_SC_KBSPEN_SHIFT;
pKBI->SC |= sc;
#endif
/*清除中断标志位*/
pKBI->SC = sc;
/* 使能KBI中断 */
if(pConfig->sBits.bIntEn)
{
pKBI->SC |= KBI_SC_KBIE_MASK;
if(KBI0 == pKBI)
{
NVIC_EnableIRQ(KBI0_IRQn);
}
else
{
NVIC_EnableIRQ(KBI1_IRQn);
}
}
}
/*****************************************************************************//*!
*
* @brief 设置KBI回调函数,通过中断服务函数调用
*
* @param[in] pKBI 指向KBI模块.
* @param[in] pfnCallback 指向回调函数.
*
* @return none.
*
* @ Pass/ Fail criteria: none.
*
*****************************************************************************/
void KBI_SetCallback(KBI_Type *pKBI, KBI_CallbackType pfnCallback)
{
if(KBI0 == pKBI)
{
KBI_Callback[0] = pfnCallback;
}
else
{
KBI_Callback[1] = pfnCallback;
}
}
/*****************************************************************************//*!
*
* @brief 复位KBI模块.
*
* @param[in] pKBI 指向KBI模块.
*
* @return none.
*
* @see KBI_Init.
*
*****************************************************************************/
void KBI_DeInit(KBI_Type *pKBI)
{
if(KBI0 == pKBI)
{
NVIC_DisableIRQ(KBI0_IRQn);
}
else
{
NVIC_DisableIRQ(KBI1_IRQn);
}
pKBI->PE = 0;
pKBI->SC = 0;
pKBI->ES = 0;
if(KBI0 == pKBI)
{
SIM->SCGC &= ~SIM_SCGC_KBI0_MASK; /* 禁用KBI0模块总线时钟 */
}
else
{
SIM->SCGC &= ~SIM_SCGC_KBI1_MASK; /* 禁用KBI1模块总线时钟 */
}
}
/*****************************************************************************//*!
*
* @brief KBI0模块中断服务函数.
*
* @param none.
*
* @return none.
*
*****************************************************************************/
void KBI0_Isr(void)
{
KBI0->SC |= KBI_SC_KBACK_MASK; /*清除中断标志位 */
if(KBI_Callback[0])
{
KBI_Callback[0]();
}
}
/*****************************************************************************//*!
*
* @brief KBI1模块中断服务函数
*
* @param none.
*
* @return none.
*
*
*****************************************************************************/
void KBI1_Isr(void)
{
KBI1->SC |= KBI_SC_KBACK_MASK; /*清除中断标志位*/
if(KBI_Callback[1])
{
KBI_Callback[1]();
}
}
@@ -0,0 +1,372 @@
/******************************************************************************
*
* @brief KBI 驱动头文件.
*
******************************************************************************/
#ifndef _KBI_H_
#define _KBI_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
/********************************************************!
*
* @brief KBI模块中断输入信号检测模式选择
*
***********************************************************/
typedef enum
{
KBI_MODE_EDGE_ONLY = 0, /*!< 选择 边沿检测 */
KBI_MODE_EDGE_LEVEL /*!< 选择 边沿和电平检测*/
}KBI_ModeType;
typedef enum
{
KBI_FALLING_EDGE_LOW_LEVEL = 0, /*!< 选择 下降沿或低电平 */
KBI_RISING_EDGE_HIGH_LEVEL /*!< 选择 上升沿或高电平 */
}KBI_EdgeType;
/******************************************************************************
*
* 定义KBI模块个数和中断输入引脚个数
*
*******************************************************************************/
#define KBI_MAX_NO 2 /*!< KBI模块个数 */
#if defined(CPU_NV32)|| defined(CPU_NV32M3)
#define KBI_MAX_PINS_PER_PORT 8 /*!< KBI中断输入引脚个数 */
#elif defined(CPU_NV32M4)
#define KBI_MAX_PINS_PER_PORT 32 /*!< KBI中断输入引脚个数 */
#endif
/******************************************************************************
* KBI回调函数声明
******************************************************************************/
typedef void (*KBI_CallbackType)(void);
/******************************************************************************
*
* KBI引脚配置结构体
*
*******************************************************************************/
typedef struct
{
uint8_t bEdge : 1; /*!< 边沿/电平选择为*/
uint8_t bEn : 1; /*!< 引脚使能位*/
uint8_t bRsvd : 6; /*!< 保留 */
} KBI_PinConfigType;
/******************************************************************************
*
* KBI配置结构体
*
*******************************************************************************/
/*!
* @brief KBI状态和控制寄存器结构体.
*
*/
typedef struct
{
#if defined(CPU_NV32)|| defined(CPU_NV32M3)
struct
{
uint8_t bMode : 1; /*!< 选择KBI检测模式 */
uint8_t bIntEn : 1; /*!< 使能KBI中断位 */
uint8_t bRsvd : 6; /*!< 保留 */
} sBits;
#elif defined(CPU_NV32M4)
struct
{
uint32_t bMode : 1; /*!< 选择KBI检测模式 */
uint32_t bIntEn : 1; /*!< 使能KBI中断位 */
uint32_t bRsvd2 : 2; /*!< 保留 */
uint32_t bKbspEn : 1; /*!<Real KBI_SP register enable*/
uint32_t bRstKbsp: 1; /*!<Reset KBI_SP register*/
uint32_t bRsvd26 : 26; /*!< reserved */
} sBits;
#endif
KBI_PinConfigType sPin[KBI_MAX_PINS_PER_PORT];
} KBI_ConfigType, *KBI_ConfigTypePtr;
/*****************************************************************************//*!
*
* @brief 设置仅下降沿检测.
*
* @param[in] pKBI 指向KBI模块.
* @param[in] PinMasks KBI中断输入引脚号.
*
* @return none.
*
* @see KBI_DetectRisingEdge.
*
*****************************************************************************/
#if defined(CPU_NV32)|| defined(CPU_NV32M3)
__STATIC_INLINE void KBI_DetectFallingEdge(KBI_Type *pKBI, uint8_t PinMasks)
#elif defined(CPU_NV32M4)
__STATIC_INLINE void KBI_DetectFallingEdge(KBI_Type *pKBI, uint32_t PinMasks)
#endif
{
pKBI->SC &= ~KBI_SC_KBMOD_MASK;
pKBI->ES &= ~(PinMasks);
}
/*****************************************************************************//*!
*
* @brief 设置仅高电平检测
*
* @param[in] pKBI 指向KBI模块.
* @param[in] PinMasks KBI中断输入引脚号.
*
* @return none.
*
* @see KBI_DetectFallingEdge.
*
*****************************************************************************/
#if defined(CPU_NV32)|| defined(CPU_NV32M3)
__STATIC_INLINE void KBI_DetectRisingEdge(KBI_Type *pKBI, uint8_t PinMasks)
#elif defined(CPU_NV32M4)
__STATIC_INLINE void KBI_DetectRisingEdge(KBI_Type *pKBI, uint32_t PinMasks)
#endif
{
pKBI->SC &= ~KBI_SC_KBMOD_MASK;
pKBI->ES |= (PinMasks);
}
/*****************************************************************************//*!
*
* @brief 设置上升沿和高电平检测
*
* @param[in] pKBI 指向KBI模块.
* @param[in] PinMasks KBI中断输入引脚号.
*
* @return none.
*
* @see KBI_DetectFallingEdgeLowLevel.
*
*****************************************************************************/
#if defined(CPU_NV32)|| defined(CPU_NV32M3)
__STATIC_INLINE void KBI_DetectRisingEdgeHighLevel(KBI_Type *pKBI, uint8_t PinMasks)
#elif defined(CPU_NV32M4)
__STATIC_INLINE void KBI_DetectRisingEdgeHighLevel(KBI_Type *pKBI, uint32_t PinMasks)
#endif
{
pKBI->SC |= KBI_SC_KBMOD_MASK;
pKBI->ES |= (PinMasks);
}
/*****************************************************************************//*!
*
* @brief 设置下降沿和低电平检测
*
* @param[in] pKBI 指向KBI模块.
* @param[in] PinMasks KBI中断输入引脚号.
*
* @return none.
*
* @ Pass/ Fail criteria: none.
*
* @see KBI_DetectRisingEdgeHighLevel.
*
*****************************************************************************/
#if defined(CPU_NV32)|| defined(CPU_NV32M3)
__STATIC_INLINE void KBI_DetectFallingEdgeLowLevel(KBI_Type *pKBI, uint8_t PinMasks)
#elif defined(CPU_NV32M4)
__STATIC_INLINE void KBI_DetectFallingEdgeLowLevel(KBI_Type *pKBI, uint32_t PinMasks)
#endif
{
pKBI->SC |= KBI_SC_KBMOD_MASK;
pKBI->ES &= ~(PinMasks);
}
/*****************************************************************************//*!
*
* @brief 使能KBI中断输入引脚
*
* @param[in] pKBI 指向KBI模块..
* @param[in] PinMasks KBI中断输入引脚号.
*
* @return none.
*
* @see KBI_Disable.
*
*****************************************************************************/
#if defined(CPU_NV32)|| defined(CPU_NV32M3)
__STATIC_INLINE void KBI_Enable(KBI_Type *pKBI, uint8_t PinMasks)
#elif defined(CPU_NV32M4)
__STATIC_INLINE void KBI_Enable(KBI_Type *pKBI, uint32_t PinMasks)
#endif
{
pKBI->PE |= (PinMasks);
}
/*****************************************************************************//*!
*
* @brief 禁用KBI中断输入引脚.
*
* @param[in] pKBI 指向KBI模块..
* @param[in] PinMasks KBI中断输入引脚号.
*
* @return none.
*
* @see KBI_Enable.
*
*****************************************************************************/
#if defined(CPU_NV32)|| defined(CPU_NV32M3)
__STATIC_INLINE void KBI_Disable(KBI_Type *pKBI, uint8_t PinMasks)
#elif defined(CPU_NV32M4)
__STATIC_INLINE void KBI_Disable(KBI_Type *pKBI, uint32_t PinMasks)
#endif
{
pKBI->PE &= ~(PinMasks);
}
/*****************************************************************************//*!
*
* @brief 使能KBI中断
*
* @param[in] pKBI 指向KBI模块..
*
* @return none.
*
*
* @see KBI_DisableInt.
*
*****************************************************************************/
__STATIC_INLINE void KBI_EnableInt(KBI_Type *pKBI)
{
pKBI->SC |= KBI_SC_KBIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用KBI中断
*
* @param[in] pKBI 指向KBI模块.
*
* @return none.
*
*
* @see KBI_EnableInt.
*
*****************************************************************************/
__STATIC_INLINE void KBI_DisableInt(KBI_Type *pKBI)
{
pKBI->SC &= ~KBI_SC_KBIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 获取中断标志位
*
* @param[in] pKBI 指向KBI模块.
*
* @return uint8_t.
*
* @see KBI_ClrFlags.
*
*****************************************************************************/
#if defined(CPU_NV32)|| defined(CPU_NV32M3)
__STATIC_INLINE uint8_t KBI_GetFlags(KBI_Type *pKBI)
#elif defined(CPU_NV32M4)
__STATIC_INLINE uint32_t KBI_GetFlags(KBI_Type *pKBI)
#endif
{
return (pKBI->SC & KBI_SC_KBF_MASK);
}
/*****************************************************************************//*!
*
* @brief 清除中断标志位.
*
* @param[in] pKBI 指向KBI模块.
*
* @return none.
*
*
* @see KBI_GetFlags.
*
*****************************************************************************/
__STATIC_INLINE void KBI_ClrFlags(KBI_Type *pKBI)
{
pKBI->SC |= KBI_SC_KBACK_MASK;
}
#if defined(CPU_NV32M4)
/*****************************************************************************//*!
*
* @brief Real KBI_SP register enable.
*
* @param[in] pKBI pointer to KBI module
*
* @return none.
*
* @ Pass/ Fail criteria: none
*
* @see The real ETMe value of Keyboard source pin to be read.
*
*****************************************************************************/
__STATIC_INLINE void KBI_SPEnable(KBI_Type *pKBI)
{
pKBI->SC |= KBI_SC_KBSPEN_MASK;
}
/*****************************************************************************//*!
*
* @brief Get KBI source pin register fields.
*
* @param[in] pKBI pointer to KBI module.
*
* @return uint32_t.
*
* @ Pass/ Fail criteria: none.
*
* @see KBI_GetSP.
*
*****************************************************************************/
__STATIC_INLINE uint32_t KBI_GetSP(KBI_Type *pKBI)
{
return (pKBI->SP & KBI_SP_SP_MASK);
}
/*****************************************************************************//*!
*
* @brief Reset KBI_SP register.
*
* @param[in] pKBI pointer to KBI module
*
* @return none.
*
* @ Pass/ Fail criteria: none
*
* @see KBI_RstSP.
*
*****************************************************************************/
__STATIC_INLINE void KBI_RstSP(KBI_Type *pKBI)
{
pKBI->SC |= KBI_SC_RSTKBSP_MASK;
}
#endif
/******************************************************************************
* Global functions
******************************************************************************/
void KBI_Init(KBI_Type *pKBI, KBI_ConfigType *pConfig);
void KBI_SetCallback(KBI_Type *pKBI, KBI_CallbackType pfnCallback);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,317 @@
/*!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file flash.c
* @brief flash函数库
* @author Navota
* @date 2018-6-19
*/
#include "flash.h"
#define FLASH_ENABLE_STALLING_FLASH_CONTROLLER
/*****************************************************************************//*!
+FUNCTION----------------------------------------------------------------
* @function name: Flash_Init
*
* @brief 初始化FLASH
*
* @param
*
* @return none
*
*****************************************************************************/
uint16_t Flash_Init(void)
{
uint16_t err = FLASH_ERR_SUCCESS;
uint32_t clkDIV = BUS_CLK_HZ/1000000L - 1;
uint32_t Tpgs =(285 *(BUS_CLK_HZ/100))/1000000L; //update 2016.8.4 by 光脚板のGG
uint32_t Tprog =(675*(BUS_CLK_HZ/100))/1000000L; //by 光脚板のGG
EFMCR=(clkDIV<<24) + 0x00000001; //divide to 1M hz
EFMETM0=(Tpgs<<16) + 0x00001194; //0x00281194; //
EFMETM1=(Tprog<<16) + 0x000088B8; //
return(err);
}
/*****************************************************************************//*!
+FUNCTION----------------------------------------------------------------
* @function name: FlashProgram
*
* @brief flash加载编程:总的过程就是,给出字节长度,先写入满足两个字的个数,
* 再写入剩余满足一个字的个数,最后写入剩余的字节数。
*
* @param[in] wNVMTargetAddress 所要存放的FLASH首地址
* @param[in] *pData 所要存放的数据
* @param[in] sizeBytes 字节长度
*
* @return none
*
*****************************************************************************/
__ramfunc uint16_t Flash_Program(uint32_t wNVMTargetAddress, uint8_t *pData, uint16_t sizeBytes)
{
uint16_t err = FLASH_ERR_SUCCESS;
uint16_t w2LongWordCount = sizeBytes>>3;//处理一下,得到2个字的个数
uint8_t wLeftBytes = (sizeBytes & 0x07);//低位三个字节的个数
uint16_t wLeftLongWords = wLeftBytes>>2;//低位中满一个字个数
uint32_t wTargetAddress = wNVMTargetAddress;
uint32_t dwData0,dwData1;
uint32_t *pdwData = (uint32_t*)pData;//传参
int i;
//判断是否字对齐
if(wNVMTargetAddress & 0x03)
{
err = FLASH_ERR_INVALID_PARAM;
return (err);//返回无效的参数
}
//循环写入两个长字(即8个字节),共写入w2LongWordCount * 8个字节
for(i = 0; i < w2LongWordCount; i++)
{
dwData0 = *pdwData++;
dwData1 = *pdwData++;
err = Flash_Program2LongWords(wTargetAddress, dwData0, dwData1);//加载两个字的编程
if(err) //地址不为4个字节对齐,则直接跳转
{
goto EndP;
//break;
}
wTargetAddress += 8;//循环一次写入8个字节,即2个字,NV32的flash是字对齐的
}
// 一个字的编程,即4bytes
for(i = 0; i < wLeftLongWords; i++)
{
dwData0 = *pdwData++;
err = Flash_Program1LongWord(wTargetAddress, dwData0);
if(err)
{
goto EndP;
//break;
}
wTargetAddress += 4;
}
wLeftBytes = (wLeftBytes-(wLeftLongWords<<2)); //在两字和一字的编程都处理完后剩余的低两位字节数
if(!wLeftBytes){ //若无剩余字节数,返回成功
return (err);
}
#if defined(BIG_ENDIAN)
dwData0 = 0;
pData = (uint8_t*)pdwData;
for(i = wLeftBytes; i >0; i--)
{
dwData0 <<= 8;
dwData0 |= *pData++;
}
wLeftBytes = 4 - wLeftBytes;
for(i = wLeftBytes; i >0; i--)
{
dwData0 <<= 8;
dwData0 |= 0xFF;
}
#else
dwData0 = 0xFFFFFFFFL;
pData = (uint8_t*)pdwData+wLeftBytes-1;
for(i = wLeftBytes; i >0; i--)
{
dwData0 <<= 8;
dwData0 |= *pData--;
}
#endif
err = Flash_Program1LongWord(wTargetAddress, dwData0);
EndP:
return (err);
}
/*****************************************************************************//*!
* @function name: FlashProgram1LongWord
*
* @brief 加载一个字的大小,编程到FLASH中(也就是四个字节)
*
* @param[in] wNVMTargetAddress 所要存放的FLASH首地址
* @param[in] dwData 所要存放的数据
*
* @return none
*
*****************************************************************************/
__ramfunc uint16_t Flash_Program1LongWord(uint32_t wNVMTargetAddress, uint32_t dwData)
{
uint16_t err = FLASH_ERR_SUCCESS;
//判断是否为字对齐
if(wNVMTargetAddress & 0x03)
{
err = FLASH_ERR_INVALID_PARAM;
return (err);
}
// 清除错误标志
EFMCMD = FLASH_CMD_CLEAR;
//写入数据到对应的地址中
DisableInterrupts;
M32(wNVMTargetAddress) = dwData;
//加载编程命令
EFM_LaunchCMD(FLASH_CMD_PROGRAM);
EnableInterrupts;
return (err);//返回状态
}
/*****************************************************************************//*!
* @function name: FlashProgram2LongWords
*
* @brief 加载两个字的大小,编程到FLASH中(也就是八个字节)
*
* @param[in] wNVMTargetAddress 所要存放的FLASH首地址
* @param[in] dwData0 低4个字节
* @param[in] dwData1 高4个字节
*
* @return none
*
*****************************************************************************/
__ramfunc uint16_t Flash_Program2LongWords(uint32_t wNVMTargetAddress, uint32_t dwData0, uint32_t dwData1)
{
uint16_t err = FLASH_ERR_SUCCESS;
//判断是否为字对齐
if(wNVMTargetAddress & 0x03)
{
err = FLASH_ERR_INVALID_PARAM;
return (err);
}
// 清除错误标志
EFMCMD = FLASH_CMD_CLEAR;
DisableInterrupts;
M32(wNVMTargetAddress) = dwData0;//存放数据到以目标地址为起始的4个字节的空间中
EFM_LaunchCMD(FLASH_CMD_PROGRAM);//0x20000000,加载编程命令
EnableInterrupts;
wNVMTargetAddress = wNVMTargetAddress +4;//地址是字对齐的,地址向后移一个字
EFMCMD = FLASH_CMD_CLEAR;
DisableInterrupts;
M32(wNVMTargetAddress) = dwData1;//第二个数据放入处理后的地址的4个字节的空间中
EFM_LaunchCMD(FLASH_CMD_PROGRAM);//加载编程命令
EnableInterrupts;
return (err);//返回处理状态
}
/*****************************************************************************//*!
+FUNCTION----------------------------------------------------------------
* @function name: Flash_EraseSector
*
* @brief 擦除目标地址的一个扇区(512字节),.
*
* @param[in] wNVMTargetAddress 擦除扇区的首地址
*
* @return none
*
*****************************************************************************/
__ramfunc uint16_t Flash_EraseSector(uint32_t wNVMTargetAddress)
{
uint16_t err = FLASH_ERR_SUCCESS;
// 判断是否字对齐
if(wNVMTargetAddress & 0x03)
{
err = FLASH_ERR_INVALID_PARAM;
return (err);
}
// 清除错误标志
EFMCMD = FLASH_CMD_CLEAR;
DisableInterrupts;
M32(wNVMTargetAddress) = 0xffffffff;
EFM_LaunchCMD(FLASH_CMD_ERASE_SECTOR);//加载擦除命令
EnableInterrupts;
return (err);
}
__ramfunc uint16_t Flash_VerifyBackdoorKey()
{
uint16_t err = FLASH_ERR_SUCCESS;
// Clear error flags
EFMCMD = FLASH_CMD_CLEAR;
// Write index to specify the command code to be loaded
Custombkd = FLASH_FACTORY_KEY;
return (err);
}
/*****************************************************************************//*!
+FUNCTION----------------------------------------------------------------
* @function name: NVM_EraseAll
*
* @brief 整片擦除FLASH(慎用,注意0X40E这个地址,在调试阶段写入0XFE)
*
* @param
*
* @return none
*
*****************************************************************************/
__ramfunc uint16_t NVM_EraseAll(void)
{
uint16_t err = FLASH_ERR_SUCCESS;
EFMCMD = FLASH_CMD_CLEAR;
EFM_LaunchCMD(FLASH_CMD_ERASE_ALL);
// Clear error flags
return err;
}
/*****************************************************************************//*!
+FUNCTION----------------------------------------------------------------
* @function name: NVM_Unsecure
*
* @brief unsecure
*
* @param
*
* @return none
*
*****************************************************************************/
__ramfunc uint16_t NVM_Unsecure(void)
{
uint16_t err = FLASH_ERR_SUCCESS;
return err;
}
/*****************************************************************************//*!
+FUNCTION----------------------------------------------------------------
* @function name: EFM_LaunchCMD
*
* @brief 命令加载函数(注:此函数须放入SRAM中运行)
*
* @param
*
* @return none
*
*****************************************************************************/
#ifdef IAR
void __ramfunc EFM_LaunchCMD(uint32_t EFM_CMD)
#else
__ramfunc void EFM_LaunchCMD(uint32_t EFM_CMD)
#endif
{
DisableInterrupts;
if((EFMCMD&EFM_DONE_MASK)== EFM_STATUS_READY)
{
EFMCMD = EFM_CMD;
}
while(1)
{
if((EFMCMD&EFM_DONE_MASK) == EFM_STATUS_DONE) break;
}
EnableInterrupts;
}
@@ -0,0 +1,84 @@
/******************************************************************************
*
* @brief FLASH Çý¶¯Í·Îļþ.
*
******************************************************************************/
#ifndef FLASH_H_
#define FLASH_H_
#include "common.h"
#define ETMRH_FSTAT_MGSTAT0_MASK (1)
#define ETMRH_FSTAT_MGSTAT1_MASK (1<<1)
#define FLASH_SECTOR_SIZE 512 // in bytes
#define FLASH_ERR_BASE 0x3000
#define FLASH_ERR_SUCCESS 0
#define FLASH_ERR_INVALID_PARAM (FLASH_ERR_BASE+1)
#define EEPROM_ERR_SINGLE_BIT_FAULT (FLASH_ERR_BASE+2)
#define EEPROM_ERR_DOUBLE_BIT_FAULT (FLASH_ERR_BASE+4)
#define FLASH_ERR_ACCESS (FLASH_ERR_BASE+8)
#define FLASH_ERR_PROTECTION (FLASH_ERR_BASE+0x10)
#define FLASH_ERR_MGSTAT0 (FLASH_ERR_BASE+0x11)
#define FLASH_ERR_MGSTAT1 (FLASH_ERR_BASE+0x12)
#define FLASH_ERR_INIT_CCIF (FLASH_ERR_BASE+0x14)
#define FLASH_ERR_INIT_FDIV (FLASH_ERR_BASE+0x18)
/*********************************/
#define FLASH_CMD_PROGRAM 0x20000000
#define FLASH_CMD_CLEAR 0x00005000
#define FLASH_CMD_ERASE_ALL 0x41000000
#define FLASH_CMD_ERASE_SECTOR 0x40000000
#define FLASH_FACTORY_KEY 0x00cfbdbe
#define EFM_DONE_MASK 0x00006000
#define EFM_STATUS_DONE 0x00006000
#define EFM_STATUS_READY 0x00002000
#define FLASH_ACCERR_MASK 0x10
#define M8(adr) (*((volatile unsigned char *) (adr)))
#define M16(adr) (*((volatile unsigned short *) (adr)))
#define M32(adr) (*((volatile unsigned long *) (adr)))
#define __ramfunc __attribute__ ((long_call, section (".ramfunctions")))
/******************************************************************************
******************************************************************************/
typedef uint16_t (*TFlash_Fun1)(uint32_t wNVMTargetAddress, uint8_t *pbData, uint8_t bByteCount);
typedef uint16_t (*TFlash_Fun2)(uint32_t wNVMTargetAddress, uint32_t dwData0, uint32_t dwData1);
typedef uint16_t (*TFlash_Fun3)(uint32_t wNVMTargetAddress, uint32_t dwData);
/******************************************************************************
******************************************************************************/
__ramfunc uint16_t Flash_Program(uint32_t wNVMTargetAddress, uint8_t *pData, uint16_t sizeBytes);
__ramfunc uint16_t Flash_Program1LongWord(uint32_t wNVMTargetAddress, uint32_t dwData);
__ramfunc uint16_t Flash_Program2LongWords(uint32_t wNVMTargetAddress, uint32_t dwData0, uint32_t dwData1);
__ramfunc uint16_t Flash_EraseSector(uint32_t wNVMTargetAddress);
__ramfunc uint16_t Flash_VerifyBackdoorKey(void);
__ramfunc uint16_t NVM_EraseAll(void);
__ramfunc uint16_t NVM_Unsecure(void);
uint16_t Flash_Init(void);
#ifdef IAR
void __ramfunc EFM_LaunchCMD(uint32_t EFM_CMD);
#else
__ramfunc void EFM_LaunchCMD(uint32_t EFM_CMD);
#endif
void Flash_CopyInRAM(void);
void Flash_CopyRouinte2RAM(char *func, uint16_t sizeFunc);
/********************************************************************/
#endif /* FLASH_H_ */
@@ -0,0 +1,41 @@
/******************************************************************************
*
* Navota Microelectronics Inc. Navota Camels 32 Bit MCU
* (c) Copyright 2015-2016 Navota Microelectronics, Inc.
* ALL RIGHTS RESERVED.
*
******************************************************************************
*
* @file flash_cmd.c
*
* @brief application entry point which performs application specific tasks.
*
*******************************************************************************
*
* provide a demo for how to initialize the NV32, output messages via SCI,
* flash operations, etc.
* NOTE:
* printf call may occupy a lot of memory (around 1924 bytes), so please
* consider your code size before using printf.
******************************************************************************
*
* provide FLASH driver
*
******************************************************************************/
#include "flash.h"
void EFM_LaunchCMD(uint32_t EFM_CMD)
{
#define DisableInterrupts£»
if((EFMCMD&EFM_DONE_MASK)== EFM_STATUS_READY)
{
EFMCMD = EFM_CMD;
}
while(1)
{
if((EFMCMD&EFM_DONE_MASK) == EFM_STATUS_DONE) break;
}
#define EnableInterrupts;
__asm("nop");
}
@@ -0,0 +1,182 @@
/************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file pit.c
* @brief pit定时器函数库
* @author Navota
* @date 2018-3-1
************************************************************************/
#include "common.h"
#include "pit.h"
/*!
* @brief 存放回调入口
*
*/
PIT_CallbackType PIT_Callback[2] = {(PIT_CallbackType)NULL};
void PIT_Ch0Isr(void);
void PIT_Ch1Isr(void);
/******************************************************************************
* 定义PIT的接口函数
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 初始化PIT模块.
*
* @param[in] u8Channel_No 通道号
* @param[in] pConfig 配置模块的结构体指针
*
* @return none
*
*****************************************************************************/
void PIT_Init(uint8_t u8Channel_No, PIT_ConfigType *pConfig)
{
SIM->SCGC |= SIM_SCGC_PIT_MASK; /*!< 选通PIT模块门控时钟 */
if (pConfig->bFreeze)
{
PIT_SetDebugFreeze();
}
if (pConfig->bModuleDis == 0)
{
PIT_Enable(); /*!< 标准PIT定时器的时钟使能 */
}
PIT_SetLoadVal(u8Channel_No, pConfig->u32LoadValue); //加载对应通道的定时器起始值
if (pConfig->bInterruptEn)
{
if (u8Channel_No)
{
NVIC_EnableIRQ(PIT_CH1_IRQn); //开启对应通道IRQ中断
}
else
{
NVIC_EnableIRQ(PIT_CH0_IRQn);
}
PIT_ChannelEnableInt(u8Channel_No); //开启对应通道的中断请求
}
else
{
NVIC_DisableIRQ(PIT_CH0_IRQn); //禁止通道0的IRQ中断
}
if (pConfig->bChainMode)
{
PIT_ChannelEnableChain(u8Channel_No); //定时器链接到前一定时器
}
if (pConfig->bETMerEn)
{
PIT_ChannelEnable(u8Channel_No); //定时器通道使能
}
}
/*****************************************************************************//*!
*
* @brief 装载定时器起始值到加载值寄存器中.
*
* @param[in] u8Channel_No 通道号
* @param[in] u32loadvalue 所有加载的数值
*
* @return none
*
*****************************************************************************/
void PIT_SetLoadVal(uint8_t u8Channel, uint32_t u32loadvalue)
{
PIT->CHANNEL[u8Channel].LDVAL = u32loadvalue;
}
/*****************************************************************************//*!
*
* @brief 设置PIT模块回调函数.
*
* @param[in] u8Channel_No 通道号.
* @param[in] pfnCallback 指向回调函数.
*
* @return none
*
*****************************************************************************/
void PIT_SetCallback(uint8_t u8Channel_No, PIT_CallbackType pfnCallback)
{
PIT_Callback[u8Channel_No] = pfnCallback;
}
/*****************************************************************************//*!
*
* @brief 复位PIT模块
*
* @param none
*
* @return none
*
*****************************************************************************/
void PIT_DeInit(void)
{
NVIC_DisableIRQ(PIT_CH0_IRQn);
NVIC_DisableIRQ(PIT_CH1_IRQn);
PIT_SetLoadVal(0,0);
PIT_SetLoadVal(1,0);
PIT_ChannelDisable(0);
PIT_ChannelDisable(1);
PIT_ChannelDisableInt(0);
PIT_ChannelDisableInt(1);
PIT_ChannelDisableChain(0);
PIT_ChannelDisableChain(1);
PIT_ChannelClrFlags(0);
PIT_ChannelClrFlags(1);
PIT_SetDebugOn();
PIT_Disable();
SIM->SCGC &= ~SIM_SCGC_PIT_MASK;
}
/*****************************************************************************//*!
*
* @brief PIT0通道中断服务函数.
*
* @param none
*
* @return none
*
*****************************************************************************/
void PIT_Ch0Isr(void)
{
PIT_ChannelClrFlags(0); //清除中断标志位
if (PIT_Callback[0])
{
PIT_Callback[0]();
}
}
/*****************************************************************************//*!
*
* @brief PIT0通道中断服务函数.
*
* @param none
*
* @return none
*
*****************************************************************************/
void PIT_Ch1Isr(void)
{
PIT_ChannelClrFlags(1); //清除中断标志位
if (PIT_Callback[1])
{
PIT_Callback[1]();
}
}
@@ -0,0 +1,275 @@
/******************************************************************************
*
* @brief PIT 驱动头文件.
*
******************************************************************************/
#ifndef PIT_H_
#define PIT_H_
#include"common.h"
#ifdef __cplusplus
extern "C" {
#endif
/******************************************************************************
* PIT 通道号列表
*
*//*!
*******************************************************************************/
enum
{
PIT_CHANNEL0 = 0, /*!< PIT 通道 0 */
PIT_CHANNEL1 /*!< PIT 通道 1 */
};
/*! */
/*!
* @brief PIT 回调类型.
*
*/
typedef void (*PIT_CallbackType)(void);
/* PIT 配置结构体体
*/
/*!
* @brief PIT 配置参数.
*
*/
typedef struct
{
uint8_t bFreeze : 1; /*!< 1: 在调试模式时冻结, 0: 在调试模式时仍然运行 */
uint8_t bModuleDis : 1; /*!< 1: 禁用PIT模块, 0: 使能PIT模块 */
uint8_t bReserved0 : 1; /*!< 保留 */
uint8_t bReserved1 : 5; /*!< 保留 */
uint8_t bETMerEn : 1; /*!< 1: 使能PIT通道, 0: 禁止PIT通道 */
uint8_t bInterruptEn : 1; /*!< 1: 使能PIT通道中断, 0: 禁止PIT通道中断 */
uint8_t bChainMode : 1; /*!< 1: 使能链模式, 0: 禁止链模式 */
uint8_t bReserved2 : 5; /*!< 保留 */
uint8_t bFlag : 1; /*!< 1: PIT中断标志位置位,写1清0, 0: PIT中断标志位没有置位 */
uint8_t bReserved3 : 7; /*!< 保留 */
uint32_t u32LoadValue ; /*!< 32位通道加载模值 */
} PIT_ConfigType, *PIT_ConfigPtr;
/******************************************************************************
******************************************************************************/
/*!
* 内联函数
*/
/*****************************************************************************//*!
*
* @brief 使能PIT模块.
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void PIT_Enable(void)
{
PIT->MCR &= ~PIT_MCR_MDIS_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用PIT模块.
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void PIT_Disable(void)
{
PIT->MCR |= PIT_MCR_MDIS_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置PIT在调试模式下禁止运行.
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void PIT_SetDebugFreeze(void)
{
PIT->MCR |= PIT_MCR_FRZ_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置PIT在调试模式下继续运行.
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void PIT_SetDebugOn(void)
{
PIT->MCR &= ~PIT_MCR_FRZ_MASK;
}
/*****************************************************************************//*!
*
* @brief PIT定时器通道使能.
*
* @param[in] u8Channel 通道号.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void PIT_ChannelEnable(uint8_t u8Channel)
{
PIT->CHANNEL[u8Channel].TCTRL |= PIT_TCTRL_TEN_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用PIT定时器通道.
*
* @param[in] u8Channel 通道号.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void PIT_ChannelDisable(uint8_t u8Channel)
{
PIT->CHANNEL[u8Channel].TCTRL &= ~PIT_TCTRL_TEN_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能PIT定时器通道中断.
*
* @param[in] u8Channel 通道号.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void PIT_ChannelEnableInt(uint8_t u8Channel)
{
PIT->CHANNEL[u8Channel].TCTRL |= PIT_TCTRL_TIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用PIT定时器通道中断.
*
* @param[in] u8Channel 通道号.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void PIT_ChannelDisableInt(uint8_t u8Channel)
{
PIT->CHANNEL[u8Channel].TCTRL &= ~PIT_TCTRL_TIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能PIT定时器通道链模式.
*
* @param[in] u8Channel 通道号.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void PIT_ChannelEnableChain(uint8_t u8Channel)
{
PIT->CHANNEL[u8Channel].TCTRL |= PIT_TCTRL_CHN_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用PIT定时器通道链模式.
*
* @param[in] u8Channel 通道号.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void PIT_ChannelDisableChain(uint8_t u8Channel)
{
PIT->CHANNEL[u8Channel].TCTRL &= ~PIT_TCTRL_CHN_MASK;
}
/*****************************************************************************//*!
*
* @brief 获取PIT通道中断标志位.
*
* @param[in] u8Channel 通道号.
*
* @return PIT通道中断标志位.
*
*****************************************************************************/
__STATIC_INLINE uint8_t PIT_ChannelGetFlags(uint8_t u8Channel)
{
uint8_t bflag;
bflag = (PIT->CHANNEL[u8Channel].TFLG & PIT_TFLG_TIF_MASK);
return bflag;
}
/*****************************************************************************//*!
*
* @brief 清除PIT通道中断标志位.
*
* @param[in] u8Channel 通道号.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void PIT_ChannelClrFlags(uint8_t u8Channel)
{
PIT->CHANNEL[u8Channel].TFLG |= PIT_TFLG_TIF_MASK;
}
/******************************************************************************
******************************************************************************/
void PIT_Init(uint8_t u8Channel_No, PIT_ConfigType *pConfig);
void PIT_SetLoadVal(uint8_t u8Channel, uint32_t u32loadvalue);
void PIT_SetCallback(uint8_t u8Channel_No, PIT_CallbackType pfnCallback);
void PIT_DeInit(void);
#ifdef __cplusplus
}
#endif
#endif /* PIT_H_ */
@@ -0,0 +1,137 @@
/************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file rtc.c
* @brief rtc定时器函数库
* @author Navota
* @date 2018-3-1
***************************************************************************/
#include "common.h"
#include "rtc.h"
/*!
* @brief 存放中断回调入口
*
*/
RTC_CallbackType RTC_Callback[1] = {(RTC_CallbackType)NULL};
void RTC_Isr(void);
/******************************************************************************
* 定义RTC的接口函数
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 初始化RTC模块
*
* @param[in] pConfig 配置RTC模块的结构体
*
* @return none
*
*****************************************************************************/
void RTC_Init(RTC_ConfigType *pConfig)
{
uint16_t u16Clocksource, u16Prescler;
uint16_t u16ModVal;
u16Clocksource =0;
u16Prescler =0;
u16ModVal =0;
SIM->SCGC |= SIM_SCGC_RTC_MASK;
u16ModVal = pConfig->u16ModuloValue;
RTC_SetModulo(u16ModVal);
if (pConfig->bRTCOut)
{
RTC->SC= RTC_SC_RTCO_MASK;
}
if (pConfig->bInterruptEn)
{
NVIC_EnableIRQ(RTC_IRQn);
RTC_EnableInt();
}
else
{
NVIC_DisableIRQ(RTC_IRQn);
}
if (pConfig->bFlag)
{
RTC_ClrFlags();
}
u16Clocksource = pConfig->bClockSource;
u16Prescler = pConfig->bClockPresaler;
RTC_SetClock(u16Clocksource,u16Prescler );
}
/*****************************************************************************//*!
*
* @brief 设置RTC模块的中断回调函数
*
* @param[in] pfnCallback 回调函数的地址
*
* @return none
*
*****************************************************************************/
void RTC_SetCallback(RTC_CallbackType pfnCallback)
{
RTC_Callback[0] = pfnCallback;
}
/*****************************************************************************//*!
*
* @brief 复位RTC模块
*
* @param none
*
* @return none
*
*****************************************************************************/
void RTC_DeInit(void)
{
NVIC_DisableIRQ(RTC_IRQn);
RTC->MOD = 0;
while(RTC->MOD);
if(RTC_GetFlags())
{
RTC_ClrFlags();
}
RTC->SC = 0;
while(RTC->SC);
SIM->SCGC &= ~SIM_SCGC_RTC_MASK;
}
/*****************************************************************************//*!
*
* @brief RTC中断服务函数
*
* @param none
*
* @return none
*
*****************************************************************************/
void RTC_Isr(void)
{
RTC_ClrFlags(); //清除中断标志位
if (RTC_Callback[0])
{
RTC_Callback[0]();
}
}
@@ -0,0 +1,182 @@
/******************************************************************************
*
* @brief RTC 驱动头文件.
*
******************************************************************************/
#ifndef RTC_H_
#define RTC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
/******************************************************************************
* RTC控制位定义
*
*//*!
* @{
*******************************************************************************/
#define RTC_OUTPUT_ENABLE 1 /*!< 使能RTC输出引脚 */
#define RTC_INTERRUPT_ENABLE 1 /*!< 使能RTC中断 */
#define RTC_CLKSRC_EXTERNAL 0 /*!< 选择外部时钟作为RTC时钟源 */
#define RTC_CLKSRC_1KHZ 1 /*!< 选择LPO时钟作为RTC时钟源 */
#define RTC_CLKSRC_IREF 2 /*!< 选择内部参考时钟ICSIRCLK作为RTC时钟源 */
#define RTC_CLKSRC_BUS 3 /*!< 选择总线时钟作为RTC时钟源 */
#define RTC_CLK_PRESCALER_128 1 /*!< 根据RTCLKS位选择是1还是128分频 */
#define RTC_CLK_PRESCALER_256 2 /*!< 根据RTCLKS位选择是2还是256分频 */
#define RTC_CLK_PRESCALER_512 3 /*!< 根据RTCLKS位选择是4还是512分频 */
#define RTC_CLK_PRESCALER_1024 4 /*!< 根据RTCLKS位选择是8还是1024分频 */
#define RTC_CLK_PRESCALER_2048 5 /*!< 根据RTCLKS位选择是16还是2048分频 */
#define RTC_CLK_PRESCALER_100 6 /*!< 根据RTCLKS位选择是32还是100分频 */
#define RTC_CLK_PRESCALER_1000 7 /*!< 根据RTCLKS位选择是64还是1000分频 */
/*! @} */
/*!
* @brief RTC 回调类型.
*
*/
typedef void (*RTC_CallbackType)(void);
/* RTC 配置结构体体
*/
/*!
* @brief RTC 配置参数.
*
*/
typedef struct
{
uint16_t bReserved : 4; /*!< 保留 */
uint16_t bRTCOut : 1; /*!< 1: 使能RTC输出, 0: 禁止RTC输出 */
uint16_t bReserved1 : 1; /*!< 保留 */
uint16_t bInterruptEn : 1; /*!< 1: 使能RTC中断, 0: RTC 禁止RTC中断 */
uint16_t bFlag : 1; /*!< 1: RTC实时中断标志 */
uint16_t bClockPresaler : 3; /*!< 3: RTC分频系数选择 */
uint16_t bReserved2 : 3; /*!< 保留*/
uint16_t bClockSource : 2; /*!< 2:RTC时钟源选择 */
uint16_t u16ModuloValue ; /*!< 16位RTC模值 */
} RTC_ConfigType, *RTC_ConfigPtr;
/******************************************************************************
******************************************************************************/
/*!
* 内联函数
*/
/*****************************************************************************//*!
*
* @brief 使能RTC中断.
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void RTC_EnableInt(void)
{
RTC->SC |= RTC_SC_RTIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁止RTC中断.
*
* @param none
*
* @return non
*
*****************************************************************************/
__STATIC_INLINE void RTC_DisableInt(void)
{
RTC->SC &= ~RTC_SC_RTIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置16位RTC模值.
*
* @param[in] u16Mod_Value 16位模值
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void RTC_SetModulo(uint16_t u16Mod_Value)
{
RTC->MOD = u16Mod_Value;
}
/*****************************************************************************//*!
*
* @brief 设置RTC时钟以及分频系数.
*
* @param[in] u16Clock_Number 选择时钟源
* @param[in] u16Presalcer 分频系数
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void RTC_SetClock(uint16_t u16Clock_Number, uint16_t u16Presalcer)
{
uint32_t u32rtc_sc;
u32rtc_sc = RTC->SC;
u32rtc_sc &= ~(RTC_SC_RTCLKS_MASK | RTC_SC_RTCPS_MASK);
u32rtc_sc |= RTC_SC_RTCLKS(u16Clock_Number) | RTC_SC_RTCPS(u16Presalcer);
RTC->SC = u32rtc_sc;
}
/*****************************************************************************//*!
*
* @brief 获取RTC中断标志位.
*
* @param none
*
* @return RTC中断标志位.
*
*****************************************************************************/
__STATIC_INLINE uint8_t RTC_GetFlags(void)
{
uint8_t bflag;
bflag = RTC->SC & RTC_SC_RTIF_MASK;
return bflag;
}
/*****************************************************************************//*!
*
* @brief 清除RTC中断标志位.
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void RTC_ClrFlags(void)
{
RTC->SC |= RTC_SC_RTIF_MASK;
}
/******************************************************************************
******************************************************************************/
void RTC_Init(RTC_ConfigType *pConfig);
void RTC_SetCallback(RTC_CallbackType pfnCallback);
void RTC_DeInit(void);
#ifdef __cplusplus
}
#endif
#endif /* RTC_H_ */
@@ -0,0 +1,164 @@
/*************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file sim.c
* @brief 系统集成模块(SIM)函数库
* @author Navota
* @date 2018-3-1
*************************************************************************/
#include "common.h"
#include "sim.h"
#if defined(CPU_NV32)
/*****************************************************************************//*!
*
* @ 初始化SIM寄存器.
*
* @ 输入 pConfig 指向SIM配置结构体.
*
* @ 无返回
*
* @ 参看 SIM_ConfigType
*
*****************************************************************************/
void SIM_Init(SIM_ConfigType *pConfig)
{
uint32_t u32Sopt;
uint32_t u32PinSel;
uint32_t u32Scgc;
uint32_t u32BusDiv;
/*
* 初始化SIM寄存器
*/
u32Sopt = 0x0010000E; /*使能SWD、RESET、NMI引脚 */
u32PinSel = 0;
u32Scgc = 0x00003000; /* 使能SWD、FLASH模块的总线时钟 */
u32BusDiv = 0;
u32BusDiv = pConfig->sBits.bBusDiv; /*总线时钟分频值*/
if(pConfig->sBits.bDisableNMI) /*禁用NMI引脚*/
{
u32Sopt &= ~SIM_SOPT_NMIE_MASK;
}
if(pConfig->sBits.bDisableRESET) /*禁用RSTPE引脚*/
{
u32Sopt &= ~SIM_SOPT_RSTPE_MASK;
}
if(pConfig->sBits.bDisableSWD) /*禁用SWDE引脚*/
{
u32Sopt &= ~SIM_SOPT_SWDE_MASK;
}
if(pConfig->sBits.bEnableCLKOUT) /*使能总线时钟*/
{
u32Sopt |= SIM_SOPT_CLKOE_MASK;
}
if(pConfig->sBits.bETMSYNC) /*ETM2同步选择*/
{
u32Sopt |= SIM_SOPT_ETMSYNC_MASK; /*生成ETM2模块的PWM同步触发*/
}
if(pConfig->sBits.bRXDCE) /*UAT0_RX捕捉选择*/
{
u32Sopt |= SIM_SOPT_RXDCE_MASK; /*UAT0_RX输入信号接到UART0模块和ETM0通道1*/
}
if(pConfig->sBits.bTXDME) /*URAT0_TX捕捉选择*/
{
u32Sopt |= SIM_SOPT_TXDME_MASK; /*URAT0_TX输出映射到引出线前由ETM0通道调制*/
}
if(pConfig->sBits.bACIC) /*模拟比较器至输入捕获使能*/
{
u32Sopt |= SIM_SOPT_ACIC_MASK; /* ACMP0输出连接到ETM1输出通道0*/
}
if(pConfig->sBits.bRTCC)
{
u32Sopt |= SIM_SOPT_RTCC_MASK; /*RTC溢出连接到ETM1输入通道*/
}
if(pConfig->sBits.bRXDFE) /*URT0 RxD滤波器选择*/
{
u32Sopt |= SIM_SOPT_RXDFE_MASK; /*RXD0输入信号由ACMP0滤波,然后注入UART0*/
}
u32Sopt |= ((pConfig->u8BusRef & 0x07) << 16); /*总线时钟128分频*/
u32Sopt |= ((pConfig->u8Delay) << 24); /*设置从ETM2初始化/匹配到触发ADC转换的延时时间*/
u32Sopt |= ((pConfig->sBits.u8ADHWT & 0x03) << 8); /*选择ETM2匹配作为ADC转换的硬件触发源*/
u32PinSel = pConfig->u32PinSel;
u32Scgc = pConfig->u32SCGC;
/*写数据到SIM模块寄存器 */
SIM->SOPT = u32Sopt;
SIM->PINSEL = u32PinSel;
SIM->SCGC = u32Scgc;
SIM->BUSDIV = u32BusDiv;
}
#endif
/****************************************************************************//*!
*
* @ 设置SIM时钟选通控制寄存器,使能或者禁用外设门控时钟
*
* @ 输入 u32PeripheralMask 外设时钟掩码
* @ 输入 u8GateOn 1:开启, 0:关闭.
*
* @ 无返回
*
*****************************************************************************/
void SIM_SetClockGating(uint32_t u32PeripheralMask, uint8_t u8GateOn)
{
uint32_t u32Scgc;
u32Scgc = SIM->SCGC;
if(u8GateOn)
{
u32Scgc |= u32PeripheralMask;
}
else
{
u32Scgc &= ~u32PeripheralMask;
}
SIM->SCGC = u32Scgc;
}
/*****************************************************************************//*!
*
* @ 读取相应的状态标志位.
*
* @ 输入 u32StatusMask 指示要被读取的状态
*
* @ 返回状态.
*
*****************************************************************************/
uint32_t SIM_GetStatus(uint32_t u32StatusMask)
{
uint32_t u32Status;
u32Status = SIM->SRSID & u32StatusMask; //读取状态标志位
return (u32Status);
}
/*****************************************************************************//*!
*
* @ 读相应的ID寄存器.
*
* @ 输入 u8ID ID的类型.
*
* @ 返回 ID
*
* 参看 IDType
*
*****************************************************************************/
uint8_t SIM_ReadID(IDType sID)
{
uint32_t u32ID;
uint8_t u8IDOffset[4] =
{
28, 24, 20,16
};
u32ID = (SIM->SRSID >> u8IDOffset[sID]) & 0x0F; //读取ID
return (u32ID);
}
@@ -0,0 +1,472 @@
/******************************************************************************
*
* @brief SIM 驱动头文件.
*
******************************************************************************/
#ifndef SIM_H_
#define SIM_H_
typedef enum {
ID_TYPE_FAMID, /*!< NV32F100x系列 ID */
ID_TYPE_SUBFAMID, /*!< NV32F100x子系列 ID */
ID_TYPE_REVID, /*!< 器件版本 ID */
ID_TYPE_PINID /*!< 器件引脚 ID */
} IDType;
#if defined(CPU_NV32)
typedef struct{
struct{
uint32_t bEnableCLKOUT : 1; /*!< 1: 使能 , 0: 禁用 */
uint32_t bTXDME : 1; /*!< 1: 使能 TXDME, 0: 禁用 */
uint32_t bETMSYNC : 1; /*!< 1: 使能 ETM SYNC, 0: 未触发任何同步 */
uint32_t bRXDFE : 1; /*!< 1: 使能 RXD 滤波, 0: 无滤波 */
uint32_t bRXDCE : 1; /*!< 1: 使能 RXD 捕捉, 0: 无捕捉 */
uint32_t bACIC : 1; /*!< 1: ACMP0的输出通道连接到ETM1的输入通道0, 0: 无连接 */
uint32_t bRTCC : 1; /*!< 1: RTC溢出连接到ETM1输入通道1, 0: 无连接 */
uint32_t u8ADHWT : 2; /*!< 选择ADC转换硬件触发源 */
uint32_t bDisableSWD : 1; /*!< 1: 禁用SWD, 0: 使能 */
uint32_t bDisableRESET : 1; /*!< 1: 禁用复位引脚, 0: 使能 */
uint32_t bDisableNMI : 1; /*!< 1: 禁用NMI中断输入引脚, 0:使能 */
uint32_t bBusDiv : 1; /*!< 总线分频系数 */
} sBits;
uint8_t u8Delay; /*!< ETM触发ADC转换延时值 */
uint8_t u8BusRef; /*!< 总线参考 */
uint32_t u32PinSel; /*!< 引脚选择寄存器的值*/
uint32_t u32SCGC; /*!< 时钟选通寄存器的值 */
} SIM_ConfigType, *SIM_ConfigPtr; /*!< SIM模块配置结构体类型 */
#endif
#if defined(CPU_NV32)
/*****************************************************************************//*!
*
* @brief 设置ETM2触发ADC转换的延时时间
*
* @param[in] u8Delay 延时时间模数值,参考时钟采用总线时钟分频
*
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void SIM_DelayETM2Trig2ADC(uint8_t u8Delay)
{
SIM->SOPT = (SIM->SOPT & ~(SIM_SOPT_DELAY_MASK)) | SIM_SOPT_DELAY(u8Delay);
}
/*****************************************************************************//*!
*
* @brief 使能总线时钟在PH2上
*
* @param none
*
* @return none
*
* @ 参看 SIM_DisableClockOutput
*****************************************************************************/
__STATIC_INLINE void SIM_EnableClockOutput(void)
{
SIM->SOPT |= (SIM_SOPT_CLKOE_MASK);
}
/*****************************************************************************//*!
*
* @brief 禁用总线时钟输出在PH2上
*
* @param none
*
* @return none
*
* @参看 SIM_EnableClockOutput
*****************************************************************************/
__STATIC_INLINE void SIM_DisableClockOutput(void)
{
SIM->SOPT &= ~(SIM_SOPT_CLKOE_MASK);
}
/*****************************************************************************//*!
*
* @brief 设置总线时钟输出分频.
*
* @param[in] u8Divide 分频系数 (3-bits)
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_SetClockOutputDivide(uint8_t u8Divide)
{
SIM->SOPT = (SIM->SOPT & ~(SIM_SOPT_BUSREF_MASK)) | SIM_SOPT_BUSREF(u8Divide & 0x07);
}
/*****************************************************************************//*!
*
* @brief UART0_RX输入信号连接到UART0模块和ETM0通道1
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_EnableUART0RXDConnectETMOCH1(void)
{
SIM->SOPT |= (SIM_SOPT_RXDCE_MASK);
}
/*****************************************************************************//*!
*
* @brief UART0_TX输出在映射到引出线前由ETM0通道0调制
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_EnableUART0Modulation(void)
{
SIM->SOPT |= (SIM_SOPT_TXDME_MASK);
}
/*****************************************************************************//*!
*
* @brief UART0_TX输出直接连接到引出线上
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_DisableUART0Modulation(void)
{
SIM->SOPT &= ~(SIM_SOPT_TXDME_MASK);
}
/*****************************************************************************//*!
*
* @brief 生成ETM2模块的PWM同步触发
*
* @param none
*
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void SIM_GenerateSoftwareTrig2ETM2(void)
{
SIM->SOPT |= (SIM_SOPT_ETMSYNC_MASK);
}
/*****************************************************************************//*!
*
* @brief ETM2_CH3通道映射到PD1上
*
* @param none
*
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void SIM_RemapETM2CH3Pin(void)
{
SIM->PINSEL |= SIM_PINSEL_ETM2PS3_MASK;
}
/*****************************************************************************//*!
*
* @brief ETM2_CH2通道映射到PD0上
*
* @param none
*
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void SIM_RemapETM2CH2Pin(void)
{
SIM->PINSEL |= SIM_PINSEL_ETM2PS2_MASK;
}
/*****************************************************************************//*!
*
* @brief ETM0_CH1通道映射到PB3上
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_RemapETM0CH1Pin(void)
{
SIM->PINSEL |= SIM_PINSEL_ETM0PS1_MASK;
}
/*****************************************************************************//*!
*
* @brief ETM0_CH0通道映射到PB2上
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_RemapETM0CH0Pin(void)
{
SIM->PINSEL |= SIM_PINSEL_ETM0PS0_MASK;
}
/*****************************************************************************//*!
*
* @brief UART0_RX和UART0_TX映射到PA2和PA3上
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_RemapUART0Pin(void)
{
SIM->PINSEL |= SIM_PINSEL_UART0PS_MASK;
}
/*****************************************************************************//*!
*
* @brief SPI0_SCK SPI0_MOSI SPI0_MISO和SPI0_PCS映射到PE0、PE1、PE2、PE3上
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_RemapSPI0Pin(void)
{
SIM->PINSEL |= SIM_PINSEL_SPI0PS_MASK;
}
/*****************************************************************************//*!
*
* @brief I2C0_SCL和I2C_SDA分别映射到PB7、PB6上
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_RemapI2CPin(void)
{
SIM->PINSEL |= SIM_PINSEL_IICPS_MASK;
}
/*****************************************************************************//*!
*
* @brief RXD0输入信号由ACPM0滤波,然后注入UART0
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_EnableUART0Filter(void)
{
SIM->SOPT |= (SIM_SOPT_RXDFE_MASK);
}
/******************************************************************************!
*
* @brief RXD0输入信号直接连接到UARTO模块
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_DisableUART0Filter(void)
{
SIM->SOPT &= ~(SIM_SOPT_RXDFE_MASK);
}
/*****************************************************************************//*!
*
* @brief 选择RTC溢出作为ADC硬件触发源
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_TriggerADCByRTC(void)
{
SIM->SOPT &= ~(SIM_SOPT_ADHWT_MASK);
}
/*****************************************************************************//*!
*
* @brief 选择PIT溢出作为ADC硬件触发源
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_TriggerADCByPIT(void)
{
SIM->SOPT = (SIM->SOPT & ~(SIM_SOPT_ADHWT_MASK)) | SIM_SOPT_ADHWT(1);
}
/*****************************************************************************//*!
*
* @brief 设置ETM2初始化作为ADC硬件触发源.ETM2初始化后经过一段时间延时触发ADC转换
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_TriggerADCByETM2Init(void)
{
SIM->SOPT = (SIM->SOPT & ~(SIM_SOPT_ADHWT_MASK)) | SIM_SOPT_ADHWT(2);
}
/*****************************************************************************//*!
*
* @brief 设置ETM2匹配作为ADC硬件触发源,ETM2匹配后经过一段时间的延时触发ADC转换
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_TriggerADCByETM2Match(void)
{
SIM->SOPT = (SIM->SOPT & ~(SIM_SOPT_ADHWT_MASK)) | SIM_SOPT_ADHWT(3);
}
/*****************************************************************************//*!
*
* @brief RTC溢出连接到ETM1输入通道1
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_EnableRTCCapture(void)
{
SIM->SOPT |= (SIM_SOPT_RTCC_MASK);
}
/*****************************************************************************//*!
*
* @brief RTC溢出未连接到ETM1输入通道1
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_DisableRTCCapture(void)
{
SIM->SOPT &= ~(SIM_SOPT_RTCC_MASK);
}
/*****************************************************************************//*!
*
* @brief ACMP0输出连接到ETM1输入通道0
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_EnableACMP0InputCapture(void)
{
SIM->SOPT |= (SIM_SOPT_ACIC_MASK);
}
/*****************************************************************************//*!
*
* @brief ACMP0输出未连接到ETM1输入通道0
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_DisableACMP0InputCapture(void)
{
SIM->SOPT &= ~(SIM_SOPT_ACIC_MASK);
}
/*****************************************************************************//*!
*
* @brief RTC0映射到PC5上
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_RemapRTCPin(void)
{
SIM->PINSEL |= SIM_PINSEL_RTCPS_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置总线时钟频率
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_SetBusDivide(uint8_t u8Divide)
{
SIM->BUSDIV = u8Divide;
}
/*****************************************************************************//*!
*
* @brief ETM2_CH1通道映射到PH1上
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_RemapETM2CH1Pin(void)
{
SIM->PINSEL |= SIM_PINSEL_ETM2PS1_MASK;
}
/*****************************************************************************//*!
*
* @brief ETM2_CH0通道映射到PH0上
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_RemapETM2CH0Pin(void)
{
SIM->PINSEL |= SIM_PINSEL_ETM2PS0_MASK;
}
/*****************************************************************************//*!
*
* @brief ETM1_CH1通道映射到PE7上
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_RemapETM1CH1Pin(void)
{
SIM->PINSEL |= SIM_PINSEL_ETM1PS1_MASK;
}
/*****************************************************************************//*!
*
* @brief ETM1_CH0映射到PH2上
*
* @param none
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SIM_RemapETM1CH0Pin(void)
{
SIM->PINSEL |= SIM_PINSEL_ETM1PS0_MASK;
}
#endif
/****************************************************************************/
void SIM_Init(SIM_ConfigType *pConfig);
void SIM_SetClockGating(uint32_t u32PeripheralMask, uint8_t u8GateOn);
uint32_t SIM_GetStatus(uint32_t u32StatusMask);
uint8_t SIM_ReadID(IDType sID);
#endif
@@ -0,0 +1,297 @@
/**************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file spi.c
* @brief 串行外设接口模块(SPI)函数库
* @author Navota
* @date 2017-1-1
****************************************************************************/
#include "common.h"
#include "spi.h"
/****************************************************************************!
* @ 存放SPI回调函数接口
****************************************************************************/
SPI_CallbackType SPI_Callback[MAX_SPI_NO] = {(SPI_CallbackType)NULL};
/*****************************************************************************//*!
*
* @brief 初始化SPI模块
*
* @param[in] pSPI 指向SPI模块.
* @param[in] pConfig 指向SPI配置参数.
*
* @return none.
*
*****************************************************************************/
void SPI_Init(SPI_Type *pSPI, SPI_ConfigType *pConfig)
{
#if defined(CPU_NV32M3)
/* sanity check */
ASSERT((pSPI == SPI0));
SIM->SCGC |= SIM_SCGC_SPI0_MASK;
#else
/* sanity check */
ASSERT((pSPI == SPI0) || (pSPI == SPI1));
/*使能SPI模块总线时钟*/
if( pSPI == SPI0)
{
SIM->SCGC |= SIM_SCGC_SPI0_MASK;
}
else
{
SIM->SCGC |= SIM_SCGC_SPI1_MASK;
}
#endif
/*配置SPI控制寄存器 */
if( pConfig->sSettings.bIntEn) //使能SPI中断
{
SPI_IntEnable(pSPI);
#if defined(CPU_NV32M3)
NVIC_EnableIRQ(SPI0_IRQn);
#else
if( pSPI == SPI0 )
{
NVIC_EnableIRQ(SPI0_IRQn);
}
else
{
NVIC_EnableIRQ(SPI1_IRQn);
}
#endif
}
if( pConfig->sSettings.bTxIntEn) //使能SPI发送中断
{
SPI_TxIntEnable(pSPI);
#if defined(CPU_NV32M3)
NVIC_EnableIRQ(SPI0_IRQn);
#else
if( pSPI == SPI0 )
{
NVIC_EnableIRQ(SPI0_IRQn);
}
else
{
NVIC_EnableIRQ(SPI1_IRQn);
}
#endif
}
if( pConfig->sSettings.bMasterMode) //主/从机选择
{
SPI_SetMasterMode(pSPI); //SPI设置为主机模式
}
else
{
SPI_SetSlaveMode(pSPI); //SPI设置为从机模式
}
if( pConfig->sSettings.bClkPolarityLow) //时钟极性配置
{
SPI_SetClockPol(pSPI,1);
}
if( pConfig->sSettings.bClkPhase1) //时钟相位配置
{
SPI_SetClockPhase(pSPI,1);
}
if( pConfig->sSettings.bShiftLSBFirst) //设置SPI串行数据传输开始位
{
SPI_SetLSBFirst(pSPI); // SPI串行数据传输从最低位开始(LSB)
}
if( pConfig->sSettings.bMatchIntEn)
{
SPI_MatchIntEnable(pSPI); //使能SPI匹配中断
}
if( pConfig->sSettings.bModeFaultEn)
{
SPI_ModfEnable(pSPI); //使能主机模式模式错误功能.
}
if( pConfig->sSettings.bMasterAutoDriveSS)
{
/*设置SSOE和MODFEN位,从机模式中SS引脚为从机输出,自动驱动从机SS引脚使能*/
SPI_SSOutputEnable(pSPI);
SPI_ModfEnable(pSPI);
}
if( pConfig->sSettings.bPinAsOuput)
{
SPI_BidirPinEnable(pSPI); //使能双向引脚配置.
}
if( pConfig->sSettings.bBidirectionModeEn)
{
SPI_BidirOutEnable(pSPI); //使能双向模式输出.
}
if( pConfig->sSettings.bStopInWaitMode)
{
SPI_ClockStopEnable(pSPI); //SPI时钟在等待模式下关闭
}
if(pConfig->sSettings.bMasterMode) //设置波特率
{
SPI_SetBaudRate(pSPI,pConfig->u32BusClkHz,pConfig->u32BitRate);
}
/*使能SPI模块*/
if( pConfig->sSettings.bModuleEn)
{
SPI_Enable(pSPI);
}
}
/*****************************************************************************//*!
*
* @brief 设置SPI波特率.
*
* @param[in] pSPI 指向SPI模块
* @param[in] u32BusClock 总线时钟.
* @param[in] u32Bps SPI波特率.
*
* @return none.
*
*****************************************************************************/
void SPI_SetBaudRate(SPI_Type *pSPI,uint32_t u32BusClock,uint32_t u32Bps)
{
uint32_t u32BitRateDivisor;
uint8_t u8Sppr;
uint8_t u8Spr;
uint8_t u8ReadFlag;
u32BitRateDivisor = u32BusClock/u32Bps; /* 计算波特率因子 */
u8ReadFlag = 0;
/* 计算最适合的 SPPR 和 SPR */
for (u8Spr = 0; u8Spr <= 8; u8Spr++)
{
for(u8Sppr = 0; u8Sppr <= 7; u8Sppr++)
{
if((u32BitRateDivisor>>(u8Spr+1))<=(u8Sppr+1))
{
u8ReadFlag = 1;
break;
}
}
if(u8ReadFlag)
{
break;
}
}
if(u8Sppr >=8)
{
u8Sppr = 7;
}
if(u8Spr >8)
{
u8Spr = 8;
}
/* 设置波特率 */
pSPI->BR = SPI_BR_SPPR(u8Sppr) | SPI_BR_SPR(u8Spr);
}
/*****************************************************************************//*!
*
* @brief 读/写数据寄存器.
*
* @param[in] pSPI 指向SPI模块.
* @param[in] pWrBuff -- 发送(写)数组指针
* @param[in] uiLength -- 读/写数据长度.
* @param[out] pRdBuff -- 接收(读)数组指针.
*
* @return if <0, means error, 0: success.
*
*****************************************************************************/
ResultType SPI_TransferWait(SPI_Type *pSPI, SPI_WidthType* pRdBuff, SPI_WidthType *pWrBuff,uint32 uiLength)
{
ResultType err = SPI_ERR_SUCCESS;
uint32_t i;
if(!uiLength)
{
return (err);
}
for(i = 0; i < uiLength; i++)
{
while(!SPI_IsSPTEF(pSPI));
SPI_WriteDataReg(pSPI,pWrBuff[i]);
while(!SPI_IsSPRF(pSPI));
pRdBuff[i] = SPI_ReadDataReg(pSPI);
}
return (err);
}
/*****************************************************************************//*!
*
* @brief 复位SPI模块
*
* @param[in] pSPI 指向SPI模块
*
* @return none.
*
*****************************************************************************/
void SPI_DeInit(SPI_Type *pSPI)
{
int16 i;
pSPI->C1 = SPI_C1_DEFAULT;
pSPI->C2 = SPI_C2_DEFAULT;
pSPI->BR = SPI_BR_DEFAULT;
pSPI->M = SPI_M_DEFAULT;
for(i = 0; i<100; i++); /*延时一段时间,等待SPI退出中断 */
}
/*****************************************************************************//*!
*
* @brief 设置SPI回调函数,在中断服务函数中调用
*
* @param[in] pSPI 指向SPI模块
* @param[in] pfnCallback 回调函数.
*
* @return none.
*
*****************************************************************************/
void SPI_SetCallback(SPI_Type *pSPI,SPI_CallbackType pfnCallback)
{
uint32_t u32Port = ((uint32_t)pSPI-(uint32_t)SPI0)>>12;
ASSERT(u32Port <2);
SPI_Callback[u32Port] = pfnCallback;
}
/*****************************************************************************//*!
*
* @brief SPI0 中断服务函数.
*
* @param none.
* @return none.
*
*****************************************************************************/
void SPI0_Isr(void)
{
if( SPI_Callback[0] )
{
SPI_Callback[0]();
}
}
#ifndef CPU_NV32M3
/*****************************************************************************//*!
*
* @brief SPI1 中断服务函数
*
* @param none.
* @return none.
*
*****************************************************************************/
void SPI1_Isr(void)
{
if( SPI_Callback[1] )
{
SPI_Callback[1]();
}
}
#endif
@@ -0,0 +1,567 @@
/******************************************************************************
*
* @brief SPI 驱动头文件.
*
******************************************************************************/
#ifndef SPI_H_
#define SPI_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
/******************************************************************************
* 定义SPI模块个数
******************************************************************************/
#define MAX_SPI_NO 2
/******************************************************************************
*
* 定义SPI寄存复位值
*
*******************************************************************************/
#define SPI_C1_DEFAULT 0x04 /*!< SPI 控制寄存器1 */
#define SPI_C2_DEFAULT 0x00 /*!< SPI 控制寄存器2 */
#define SPI_BR_DEFAULT 0x00 /*!< SPI 波特率寄存器 */
#define SPI_S_DEFAULT 0x20 /*!< SPI 状态寄存器 */
#define SPI_M_DEFAULT 0x00 /*!< SPI 匹配寄存器 */
/******************************************************************************
*
* 定义SPI传输状态
*
*******************************************************************************/
#define SPI_ERR_SUCCESS 0 /*!< 成功 */
#define SPI_ERR_CODE_BASE ((uint32)SPI0 - 0x40000000L) /*!< SPI基地址错误 */
#define SPI_ERR_TXBUF_NOT_EMPTY (SPI_ERR_CODE_BASE+1) /*!< 失败由于发送缓冲区空时,标志位没有置位*/
#define SPI_ERR_RXBUF_NOT_FULL (SPI_ERR_CODE_BASE+2) /*!< 失败由于接收缓冲区满时,标志位没有置位 */
/******************************************************************************
* 数据类型别名定义
******************************************************************************/
typedef uint8_t SPI_WidthType; /* SPI 发送数据宽度类型 */
typedef uint32_t ResultType; /* SPI 收发返回状态数据类型 */
/******************************************************************************
*
* SPI回调函数声明
*
*******************************************************************************/
typedef void (*SPI_CallbackType)(void);
/******************************************************************************
*
* SPI 结构体类型
*
*******************************************************************************/
typedef struct
{
uint32_t bIntEn : 1; /*!< 1: 使能中断, 0: 禁用中断*/
uint32_t bModuleEn : 1; /*!< 1: 使能SPI模块, 0: 禁用SPI模块 */
uint32_t bTxIntEn : 1; /*!< 1: 使能发送中断, 0: 禁用发送中断 */
uint32_t bMasterMode : 1; /*!< 1: 主机模式, 0: 从机模式 */
uint32_t bClkPolarityLow : 1; /*!< 设置时钟极性 */
uint32_t bClkPhase1 : 1; /*!< 设置时钟相位 */
uint32_t bMasterAutoDriveSS : 1; /*!< 从机选择输出使能 */
uint32_t bShiftLSBFirst : 1; /*!< 1: LSB, 0: MSB */
uint32_t bMatchIntEn : 1; /*!< 1: 使能匹配中断, 0: 禁用匹配中断 */
uint32_t bModeFaultEn : 1; /*!< 使能主机模式错误功能 */
uint32_t bBidirectionModeEn : 1; /*!< 双向模式输出控制 */
uint32_t bPinAsOuput : 1; /*!< SPI引脚控制 */
uint32_t bStopInWaitMode : 1; /*!< 配置SPI时钟在等待模式下的工作状态 */
uint32_t bRsvd : 19;
} SPI_SettingType;
/******************************************************************************
*
* SPI配置结构体类型
*
*******************************************************************************/
typedef struct
{
SPI_SettingType sSettings; /*!< SPI 结构体 */
uint32_t u32BitRate; /*!< 设置波特率 */
uint32_t u32BusClkHz; /*!< 输入总线时钟 */
} SPI_ConfigType; /*!< SPI配置结构体 */
/*****************************************************************************//*!
*
* @brief SPI串行数据传输从最低位开始(LSB)
*
* @param[in] pSPI 指向SPI模块
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void SPI_SetLSBFirst(SPI_Type *pSPI)
{
pSPI->C1 |= SPI_C1_LSBFE_MASK;
}
/*****************************************************************************//*!
*
* @brief SPI串行数据传输从最高位开始(MSB)
*
* @param[in] pSPI 指向SPI模块
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void SPI_SetMSBFirst(SPI_Type *pSPI)
{
pSPI->C1 &= ~SPI_C1_LSBFE_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置SPI时钟极性.
*
* @param[in] pSPI 指向SPI模块 .
* @param[in] u8PolLow 设置时钟极性. 1-SCK时钟有效状态为高(无效状态为低)
* 0-SCK时钟有效状态为低(无效状态为高)
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_SetClockPol(SPI_Type *pSPI,uint8_t u8PolLow)
{
if( u8PolLow )
{
pSPI->C1 |= SPI_C1_CPOL_MASK;
}
else
{
pSPI->C1 &= ~SPI_C1_CPOL_MASK;
}
}
/*****************************************************************************//*!
*
* @brief 设置SPI时钟相位.
*
* @param[in] pSPI 指向SPI模块
* @param[in] u8Phase 设置时钟相位, 1 - 数据在SCK下降沿输出,在上升沿采样.
* 0 - 数据在SCK上升沿采样,在下降沿输出
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_SetClockPhase(SPI_Type *pSPI,uint8_t u8Phase)
{
if( u8Phase )
{
pSPI->C1 |= SPI_C1_CPHA_MASK;
}
else
{
pSPI->C1 &= ~SPI_C1_CPHA_MASK;
}
}
/*****************************************************************************//*!
*
* @brief 使能SPI模块.
*
* @param[in] pSPI 指向SPI模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_Enable(SPI_Type *pSPI)
{
pSPI->C1 |= SPI_C1_SPE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用SPI模块
*
* @param[in] pSPI 指向SPI模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_Disable(SPI_Type *pSPI)
{
pSPI->C1 &= ~SPI_C1_SPE_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能SPI中断.
*
* @param[in] pSPI 指向SPI模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_IntEnable(SPI_Type *pSPI)
{
pSPI->C1 |= SPI_C1_SPIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用SPI中断.
*
* @param[in] pSPI 指向SPI模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_IntDisable(SPI_Type *pSPI)
{
pSPI->C1 &= ~SPI_C1_SPIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置SPI为主机模式.
*
* @param[in] pSPI 指向SPI模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_SetMasterMode(SPI_Type *pSPI)
{
pSPI->C1 |= SPI_C1_MSTR_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置SPI为从机模式.
*
* @param[in] pSPI 指向SPI模块 .
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_SetSlaveMode(SPI_Type *pSPI)
{
pSPI->C1 &= ~SPI_C1_MSTR_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能SPI发送中断.
*
* @param[in] pSPI 指向SPI模块 .
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void SPI_TxIntEnable(SPI_Type *pSPI)
{
pSPI->C1 |= SPI_C1_SPTIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用SPI发送中断.
*
* @param[in] pSPI 指向SPI模块 .
*
* @return none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void SPI_TxIntDisable(SPI_Type *pSPI)
{
pSPI->C1 &= ~SPI_C1_SPTIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能从机选择输出.
*
* @param[in] pSPI 指向SPI模块 .
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_SSOutputEnable(SPI_Type *pSPI )
{
pSPI->C1 |= SPI_C1_SSOE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用从机选择输出.
*
* @param[in] pSPI 指向SPI模块 .
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_SSOutputDisable(SPI_Type *pSPI )
{
pSPI->C1 &= ~SPI_C1_SSOE_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能SPI匹配中断.
*
* @param[in] pSPI 指向SPI模块 .
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_MatchIntEnable(SPI_Type *pSPI )
{
pSPI->C2 |= SPI_C2_SPMIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用SPI匹配中断.
*
* @param[in] pSPI 指向SPI模块
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void SPI_MatchIntDisable(SPI_Type *pSPI )
{
pSPI->C2 &= ~SPI_C2_SPMIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用主机模式错误功能
*
* @param[in] pSPI 指向SPI模块 .
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void SPI_ModfDisable(SPI_Type *pSPI )
{
pSPI->C2 &= ~SPI_C2_MODFEN_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能主机模式模式错误功能.
*
* @param[in] pSPI 指向SPI模块
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void SPI_ModfEnable(SPI_Type *pSPI )
{
pSPI->C2 |= SPI_C2_MODFEN_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能双向模式输出.
*
* @param[in] pSPI 指向SPI模块 .
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void SPI_BidirOutEnable(SPI_Type *pSPI )
{
pSPI->C2 |= SPI_C2_BIDIROE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用双向模式输出
*
* @param[in] pSPI 指向SPI模块
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void SPI_BidirOutDisable(SPI_Type *pSPI )
{
pSPI->C2 &= ~SPI_C2_BIDIROE_MASK;
}
/*****************************************************************************//*!
*
* @brief SPI时钟在等待模式下一直运行
*
* @param[in] pSPI 指向SPI模块 .
*
* @return none.
*
*****************************************************************************/
__STATIC_INLINE void SPI_ClockStopDisable(SPI_Type *pSPI )
{
pSPI->C2 &= ~SPI_C2_SPISWAI_MASK;
}
/*****************************************************************************//*!
*
* @brief SPI时钟在等待模式下关闭
*
* @param[in] pSPI 指向SPI模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_ClockStopEnable(SPI_Type *pSPI )
{
pSPI->C2 |= SPI_C2_SPISWAI_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能双向引脚配置.
*
* @param[in] pSPI 指向SPI模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_BidirPinEnable(SPI_Type *pSPI)
{
pSPI->C2 |= SPI_C2_SPC0_MASK;
}
/*****************************************************************************//*!
*
* @brief SPI使用独立的引脚用作数据的输入输出.
*
* @param[in] pSPI 指向SPI模块
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_BidirPinDisable(SPI_Type *pSPI)
{
pSPI->C2 &= ~SPI_C2_SPC0_MASK;
}
/*****************************************************************************//*!
*
* @brief 读取接收数据缓冲区满标准位.
*
* @param[in] pSPI 指向SPI模块 .
*
* @return TRUE or FALSE.
*
*****************************************************************************/
__STATIC_INLINE uint8_t SPI_IsSPRF(SPI_Type *pSPI )
{
return(pSPI->S & SPI_S_SPRF_MASK);
}
/*****************************************************************************//*!
*
* @brief 读取SPI匹配标志位
*
* @param[in] pSPI 指向SPI模块 .
*
* @return TRUE or FALSE.
*
*****************************************************************************/
__STATIC_INLINE uint8_t SPI_IsSPMF(SPI_Type *pSPI )
{
return(pSPI->S & SPI_S_SPMF_MASK);
}
/*****************************************************************************//*!
*
* @brief 读取SPI发送数据缓冲区空标志位.
*
* @param[in] pSPI 指向SPI模块 .
*
* @return TRUE or FALSE.
*
*****************************************************************************/
__STATIC_INLINE uint8_t SPI_IsSPTEF(SPI_Type *pSPI )
{
return(pSPI->S & SPI_S_SPTEF_MASK);
}
/*****************************************************************************//*!
*
* @brief 读取主机模式错误标志位
*
* @param[in] pSPI 指向SPI模块
*
* @return TRUE or FALSE.
*
*****************************************************************************/
__STATIC_INLINE uint8_t SPI_IsMODF(SPI_Type *pSPI )
{
return(pSPI->S & SPI_S_MODF_MASK);
}
/*****************************************************************************//*!
*
* @brief 读取SPI数据寄存器.
*
* @param[in] pSPI 指向SPI模块
*
* @return 数据寄存器的值
*
*****************************************************************************/
__STATIC_INLINE uint8_t SPI_ReadDataReg(SPI_Type *pSPI )
{
return pSPI->D;
}
/*****************************************************************************//*!
*
* @brief 写数据到SPI数据寄存器.
*
* @param[in] pSPI 指向SPI模块
* @param[in] u8WrBuff 写到SPI数据寄存器的数据缓冲区
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_WriteDataReg(SPI_Type *pSPI, uint8_t u8WrBuff )
{
pSPI->D = u8WrBuff;
}
/*****************************************************************************//*!
*
* @brief 写数据到SPI匹配寄存器.
*
* @param[in] pSPI 指向SPI模块
* @param[in] u8WrBuff 写到SPI匹配寄存器的数据缓冲区
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void SPI_WriteMatchValue(SPI_Type *pSPI, uint8_t u8WrBuff )
{
pSPI->M = u8WrBuff;
}
/******************************************************************************/
void SPI_Enable(SPI_Type *pSPI);
void SPI_Disable(SPI_Type *pSPI);
void SPI_SetLSBFirst(SPI_Type *pSPI);
void SPI_SetMSBFirst(SPI_Type *pSPI);
void SPI_IntEnable(SPI_Type *pSPI);
void SPI_IntDisable(SPI_Type *pSPI);
void SPI_SetMasterMode(SPI_Type *pSPI);
void SPI_SetSlaveMode(SPI_Type *pSPI);
void SPI_TxIntEnable(SPI_Type *pSPI);
void SPI_TxIntDisable(SPI_Type *pSPI);
void SPI_SSOutputEnable(SPI_Type *pSPI );
void SPI_SSOutputDisable(SPI_Type *pSPI );
void SPI_MatchIntEnable(SPI_Type *pSPI );
void SPI_MatchIntDisable(SPI_Type *pSPI );
void SPI_ModfDisable(SPI_Type *pSPI );
void SPI_ModfEnable(SPI_Type *pSPI );
void SPI_BidirOutEnable(SPI_Type *pSPI );
void SPI_BidirOutDisable(SPI_Type *pSPI );
void SPI_ClockStopDisable(SPI_Type *pSPI );
void SPI_ClockStopEnable(SPI_Type *pSPI );
void SPI_BidirPinEnable(SPI_Type *pSPI );
void SPI_BidirPinDisable(SPI_Type *pSPI );
void SPI_SetClockPol(SPI_Type *pSPI,uint8_t u8PolLow);
void SPI_SetClockPhase(SPI_Type *pSPI,uint8_t u8Phase);
void SPI_SetBaudRate(SPI_Type *pSPI,uint32_t u32BusClock,uint32_t u32Bps );
uint8_t SPI_IsSPRF(SPI_Type *pSPI );
uint8_t SPI_IsSPMF(SPI_Type *pSPI );
uint8_t SPI_IsSPTEF(SPI_Type *pSPI );
uint8_t SPI_IsMODF(SPI_Type *pSPI );
uint8_t SPI_ReadDataReg(SPI_Type *pSPI );
void SPI_WriteDataReg(SPI_Type *pSPI, uint8_t u8WrBuff );
void SPI_WriteMatchValue(SPI_Type *pSPI, uint8_t u8WrBuff );
void SPI_Init(SPI_Type *pSPI, SPI_ConfigType *pConfig);
void SPI_DeInit(SPI_Type *pSPI);
ResultType SPI_TransferWait(SPI_Type *pSPI, SPI_WidthType* pRdBuff, SPI_WidthType *pWrBuff,uint32 uiLength);
void SPI_SetCallback(SPI_Type *pSPI,SPI_CallbackType pfnCallback);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,437 @@
/*************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file uart.c
* @brief uart通讯接口函数库
* @author Navota
* @date 2017-1-1
*************************************************************************/
#include "uart.h"
/*!
* @brief 存放回调入口
*
*/
UART_CallbackType UART_Callback = NULL;
/******************************************************************************
* 定义UART的接口函数
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 初始化UART,关中断,无硬件流控制.
*
* @param[in] pUART 指向三个UART其中一个的基址
* @param[in] pConfig 配置UART的结构体
*
* @return none
*
*****************************************************************************/
void UART_Init(UART_Type *pUART, UART_ConfigType *pConfig)
{
uint16_t u16Sbr;
uint8_t u8Temp;
uint32_t u32SysClk = pConfig->u32SysClkHz;//定义系统时钟
uint32_t u32Baud = pConfig->u32Baudrate;//定义波特率
/* 合法性检查 */
ASSERT((pUART == UART0) || (pUART == UART1) || (pUART == UART2));
/* 设置时钟选通控制用来选择相应的 UART 口 */
if (pUART == UART0)
{
SIM->SCGC |= SIM_SCGC_UART0_MASK;//使能相应功能位, 选通对应 UART
}
#if defined(CPU_NV32)
else if (pUART == UART1)
{
SIM->SCGC |= SIM_SCGC_UART1_MASK;
}
else
{
SIM->SCGC |= SIM_SCGC_UART2_MASK;
}
#endif
/*确保在我们进行配置时, 禁止发送和接收*/
pUART->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK );
/* 配置 UART 为 8 位模式, 无奇偶校验位 */
pUART->C1 = 0;
/* 波特率计算 */
u16Sbr = (((u32SysClk)>>4) + (u32Baud>>1))/u32Baud;
/*把当前数据存放在串口波特率寄存器中, 且SBR位清0,即波特率发生器被禁止*/
u8Temp = pUART->BDH & ~(UART_BDH_SBR_MASK);
pUART->BDH = u8Temp | UART_BDH_SBR(u16Sbr >> 8);
pUART->BDL = (uint8_t)(u16Sbr & UART_BDL_SBR_MASK);
/*使能 UART 接收和发送 */
pUART->C2 |= (UART_C2_TE_MASK | UART_C2_RE_MASK );
}
/*****************************************************************************//*!
*
* @brief 接收一个字符.
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return 接收到的字符
*
*****************************************************************************/
uint8_t UART_GetChar(UART_Type *pUART)
{
/* 合法性检测 */
ASSERT((pUART == UART0) || (pUART == UART1) || (pUART == UART2));
/* 等待直到一个字符被接收 */
while (!(pUART->S1 & UART_S1_RDRF_MASK));
/* 返回接收到的8位数据 */
return pUART->D;
}
/*****************************************************************************//*!
*
* @brief 发送一个字符.
*
* @param[in] pUART 指向三个UART其中一个的基址
* @param[in] u8Char 要发送的字符
*
* @return none
*
*****************************************************************************/
void UART_PutChar(UART_Type *pUART, uint8_t u8Char)
{
/* 一直等待, 直到缓冲区为空 */
while (!(pUART->S1 & UART_S1_TDRE_MASK));
/* 发送字符到数据寄存器 */
pUART->D = (uint8_t)u8Char;
}
/*****************************************************************************//*!
*
* @brief 波特率设置.
*
* @param[in] pUART 指向三个UART其中一个的基址
* @param[in] pConfig 波特率相关配置结构体
*
* @return none
*
*****************************************************************************/
void UART_SetBaudrate(UART_Type *pUART, UART_ConfigBaudrateType *pConfig)
{
uint8_t u8Temp;
uint16_t u16Sbr;
uint32_t u32SysClk = pConfig->u32SysClkHz;
uint32_t u32baud = pConfig->u32Baudrate;
/* 合法性检测 */
ASSERT((pUART == UART0) || (pUART == UART1) || (pUART == UART2));
/*计算波特率,四舍五入提高精度 */
u16Sbr = (((u32SysClk)>>4) + (u32baud>>1))/u32baud;
u8Temp = pUART->BDH & ~(UART_BDH_SBR_MASK);
pUART->BDH = u8Temp | UART_BDH_SBR(u16Sbr >> 8);
pUART->BDL = (uint8_t)(u16Sbr & UART_BDL_SBR_MASK);
pUART->C2 |= (UART_C2_TE_MASK | UART_C2_RE_MASK );
}
/*****************************************************************************//*!
*
* @brief 使能UART中断.
*
* @param[in] pUART 指向三个UART其中一个的基址
* @param[in] InterruptType 中断的类型
*
* @return none
*
*****************************************************************************/
void UART_EnableInterrupt(UART_Type *pUART, UART_InterruptType InterruptType)
{
/* 通道合法性检查 */
ASSERT((pUART == UART0) || (pUART == UART1) || (pUART == UART2));
if (InterruptType == UART_TxBuffEmptyInt) //发送中断使能
{
pUART->C2 |= UART_C2_TIE_MASK;
}
else if (InterruptType == UART_TxCompleteInt) //传输完成中断使能
{
pUART->C2 |= UART_C2_TCIE_MASK;
}
else if (InterruptType == UART_RxBuffFullInt) //接收器中断使能
{
pUART->C2 |= UART_C2_RIE_MASK;
}
else if (InterruptType == UART_IdleLineInt) //空闲线中断使能
{
pUART->C2 |= UART_C2_ILIE_MASK;
}
else if (InterruptType == UART_RxOverrunInt) //过载中断使能
{
pUART->C3 |= UART_C3_ORIE_MASK;
}
else if (InterruptType == UART_NoiseErrorInt) //噪声错误中断使能
{
pUART->C3 |= UART_C3_NEIE_MASK;
}
else if (InterruptType == UART_FramingErrorInt) //帧错误中断使能
{
pUART->C3 |= UART_C3_FEIE_MASK;
}
else if (InterruptType == UART_ParityErrorInt) //奇偶校验中断使能
{
pUART->C3 |= UART_C3_FEIE_MASK;
}
else
{
//其他暂不支持类型的中断
}
}
/*****************************************************************************//*!
*
* @brief 禁用UART中断.
*
* @param[in] 指向三个UART其中一个的基址
* @param[in] 中断的类型
*
* @return none
*
*****************************************************************************/
void UART_DisableInterrupt(UART_Type *pUART, UART_InterruptType InterruptType)
{
/* 通道合法性检查 */
ASSERT((pUART == UART0) || (pUART == UART1) || (pUART == UART2));
if (InterruptType == UART_TxBuffEmptyInt) //发送中断禁用
{
pUART->C2 &= (~UART_C2_TIE_MASK);
}
else if (InterruptType == UART_TxCompleteInt) //传输完成中断禁用
{
pUART->C2 &= (~UART_C2_TCIE_MASK);
}
else if (InterruptType == UART_RxBuffFullInt) //接收器中断禁用
{
pUART->C2 &= (~UART_C2_RIE_MASK);
}
else if (InterruptType == UART_IdleLineInt) //空闲线中断禁用
{
pUART->C2 &= (~UART_C2_ILIE_MASK);
}
else if (InterruptType == UART_RxOverrunInt) //过载中断禁用
{
pUART->C3 &= (~UART_C3_ORIE_MASK);
}
else if (InterruptType == UART_NoiseErrorInt) //噪声错误中断禁用
{
pUART->C3 &= (~UART_C3_NEIE_MASK);
}
else if (InterruptType == UART_FramingErrorInt) //帧错误中断禁用
{
pUART->C3 &= (~UART_C3_FEIE_MASK);
}
else if (InterruptType == UART_ParityErrorInt) //奇偶校验中断禁用
{
pUART->C3 &= (~UART_C3_FEIE_MASK);
}
else
{
//其他暂不支持类型的中断
}
}
/*****************************************************************************//*!
*
* @brief 从两个状态寄存器获取UART状态
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return 16位的状态
*
*****************************************************************************/
uint16_t UART_GetFlags(UART_Type *pUART)
{
uint16_t u16StatusFlags = 0;//先清空标志位
u16StatusFlags = pUART->S2; //将状态寄存器 2 的值赋给标志参数
u16StatusFlags = (u16StatusFlags<<8)| pUART->S1; //两个状态寄存器拼接赋给标志参数
return u16StatusFlags;//返回标志参数的值
}
/*****************************************************************************//*!
*
* @brief 检查特定的位是否置位.
*
* @param[in] pUART 指向三个UART其中一个的基址
* @param[in] FlagType 位的类型
*
* @return
* 1, 标志置位
* 0, 标志清零
*
*****************************************************************************/
uint8_t UART_CheckFlag(UART_Type *pUART, UART_FlagType FlagType)
{
uint16_t u16StatusFlags = 0;
u16StatusFlags = UART_GetFlags(pUART);
return (u16StatusFlags & (1<<FlagType));
}
/*****************************************************************************//*!
*
* @brief 用查询模式发送字符串.
*
* @param[in] pUART 指向三个UART其中一个的基址
* @param[in] pSendBuff 字符串首地址
* @param[in] u32Length 字符串的长度
*
* @return none
*
*****************************************************************************/
void UART_SendWait(UART_Type *pUART, uint8_t *pSendBuff, uint32_t u32Length)
{
uint8_t u8TxChar;
uint32_t i;
for (i = 0; i < u32Length; i++)
{
u8TxChar = pSendBuff[i];
while (!UART_IsTxBuffEmpty(pUART))
{
#if defined(ENABLE_WDOG)
WDOG_Feed();
#endif
}
UART_WriteDataReg(pUART, u8TxChar);
}
}
/*****************************************************************************//*!
*
* @brief 用查询模式接收字符串.
*
* @param[in] pUART 指向三个UART其中一个的基址
* @param[in] pReceiveBuff 定义接收字符串的首地址
* @param[in] u32Length 所要接收字符串的长度
*
* @return none
*
*****************************************************************************/
void UART_ReceiveWait(UART_Type *pUART, uint8_t *pReceiveBuff, uint32_t u32Length)
{
uint8_t u8RxChar;
uint32_t i;
for (i = 0; i < u32Length; i++)
{
while (!UART_IsRxBuffFull(pUART))
{
#if defined(ENABLE_WDOG)
WDOG_Feed();
#endif
}
u8RxChar = UART_ReadDataReg(pUART);
pReceiveBuff[i] = u8RxChar;
}
}
/*****************************************************************************//*!
*
* @brief 等待发送完成.
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
void UART_WaitTxComplete(UART_Type *pUART)
{
while (!UART_IsTxComplete(pUART));//一直等待直到发送完成
}
/*****************************************************************************//*!
*
* @brief 设置UART模块的中断回调函数.
*
* @param[in] pfnCallback 回调函数的地址
*
* @return none
*
*****************************************************************************/
void UART_SetCallback(UART_CallbackType pfnCallback)
{
UART_Callback = pfnCallback;
}
/*! @} */
/*****************************************************************************//*!
*
* @brief uart0 中断服务函数.
*
* @param none
*
* @return none
*
*****************************************************************************/
void UART0_Isr(void)
{
UART_Callback(UART0);
}
#if defined(CPU_NV32)
/*****************************************************************************//*!
*
* @brief uart0 中断服务函数.
*
* @param none
*
* @return none
*
*****************************************************************************/
void UART1_Isr(void)
{
UART_Callback(UART1);
}
/*****************************************************************************//*!
*
* @brief uart0 中断服务函数.
*
* @param none
*
* @return none
*
*****************************************************************************/
void UART2_Isr(void)
{
UART_Callback(UART2);
}
#endif
@@ -0,0 +1,461 @@
/******************************************************************************
*
* @brief UART 驱动头文件.
*
******************************************************************************/
#ifndef _UART_H_
#define _UART_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
#include "wdog.h"
#define MAX_UART_NO 3
/*!
* @brief UART 设置类型.
*
*/
typedef struct
{
uint32_t bEnable : 1; /*!< 1: 使能, 0: 禁用 */
uint32_t resvd : 31; /*!< 1: 保留位域 */
} UART_SettingType;
/*! @} */
/*!
* @brief UART 配置结构体.
*
*/
typedef struct
{
UART_SettingType sSettings; /*!< UART 设置 */
uint32_t u32SysClkHz; /*!< 系统时钟 */
uint32_t u32Baudrate; /*!< UART 波特率 */
} UART_ConfigType;
/*! @} */
/*!
* @brief UART 波特率配置结构体.
*
*/
typedef struct
{
uint32_t u32SysClkHz; /*!< 系统时钟 */
uint32_t u32Baudrate; /*!< UART 波特率 */
} UART_ConfigBaudrateType;
/*! @} */
/******************************************************************************
*define uart配置模式列表
*
*//*! @uart配置模式列表
* @{
******************************************************************************/
typedef enum
{
UART_Mode8Bit, /*!< 8位模式 */
UART_Mode9Bit, /*!< 9位模式 */
UART_ModeEnableLoopback, /*!< 使能环回模式 */
UART_ModeDisableLoopback, /*!< 禁用环回模式*/
UART_ModeEnableSingleWire, /*!< 使能UART单线模式 */
UART_ModeDisableSingleWire, /*!< 禁用UART单线模式 */
} UART_ModeType;
/*! @} */
/******************************************************************************
*define uart中断类型
*
*//*! @uart中断类型列表
* @{
******************************************************************************/
typedef enum
{
UART_TxBuffEmptyInt, /*!< 发送中断 */
UART_TxCompleteInt, /*!< 传输完成中断 */
UART_RxBuffFullInt, /*!< 接收器中断 */
UART_IdleLineInt, /*!< 空闲线中断 */
UART_RxOverrunInt, /*!< 过载中断 */
UART_NoiseErrorInt, /*!< 噪声错误中断 */
UART_FramingErrorInt, /*!< /帧错误中断 */
UART_ParityErrorInt, /*!< 奇偶校验中断 */
} UART_InterruptType;
/*! @} */
/******************************************************************************
*define uart标志类型定义
*
*//*! @uart标志类型定义列表
* @{
******************************************************************************/
typedef enum
{
UART_FlagPF = 0, /*!< 奇数 */
UART_FlagFE, /*!< 帧错误标志 */
UART_FlagNF, /*!< 噪声标志 */
UART_FlagOR, /*!< 接收过载 */
UART_FlagIDLE, /*!< 空闲线标志 */
UART_FlagRDRF, /*!< 接收数据满标志 */
UART_FlagTC, /*!< 发送完成标志 */
UART_FlagTDRE, /*!< 发送寄存器空标志 */
UART_FlagRAF, /*!< 有效接收器标志 */
UART_FlagLBKDE, /*!< LIN间隔检测使能 */
UART_FlagBRK13, /*!< 间隔字符长度 */
UART_FlagRWUID, /*!< 接收唤醒空闲检测 */
UART_FlagRXINV, /*!< 接收数据反转 */
UART_FlagRev1, /*!< 保留 */
UART_FlagRXEDGIF, /*!< RXD引脚的有效边沿中断标志 */
UART_FlagLBKDIF, /*!< LIN终止检测中断标志 */
} UART_FlagType;
/*! @} */
/*!
* @brief UART 回调类型.
*
*/
typedef void (*UART_CallbackType)(UART_Type *pUART);
/******************************************************************************
******************************************************************************/
/*!
* 内联函数
*/
/******************************************************************************
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 读取接收数据
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return 接收到的字符
*
*****************************************************************************/
__STATIC_INLINE uint8_t UART_ReadDataReg(UART_Type *pUART)
{
return pUART->D;
}
/*****************************************************************************//*!
*
* @brief 写发送字符
*
* @param[in] pUART 指向三个UART其中一个的基址
* @param[in] u8Char 需要发送的字符
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_WriteDataReg(UART_Type *pUART, uint8_t u8Char)
{
pUART->D = (uint8_t)u8Char;
}
/*****************************************************************************//*!
*
* @brief 检测接收数据寄存器是否满
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return 0, 没有字符接收; 非0, 有字符接收到
*
*****************************************************************************/
__STATIC_INLINE uint8_t UART_CharPresent(UART_Type *pUART)
{
return (pUART->S1 & UART_S1_RDRF_MASK);
}
/*****************************************************************************//*!
*
* @brief 使能发送器
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_EnableTx(UART_Type *pUART)
{
pUART->C2 |= UART_C2_TE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用发送器
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_DisableTx(UART_Type *pUART)
{
pUART->C2 &= (~UART_C2_TE_MASK);
}
/*****************************************************************************//*!
*
* @brief 使能接收器
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_EnableRx(UART_Type *pUART)
{
pUART->C2 |= UART_C2_RE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用接收器
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_DisableRx(UART_Type *pUART)
{
pUART->C2 &= (~UART_C2_RE_MASK);
}
/*****************************************************************************//*!
*
* @brief 使能循环模式
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_EnableLoopback(UART_Type *pUART)
{
pUART->C1 |= UART_C1_LOOPS_MASK;
pUART->C1 &= (~UART_C1_RSRC_MASK);
}
/*****************************************************************************//*!
*
* @brief 使能单线模式
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_EnableSingleWire(UART_Type *pUART)
{
pUART->C1 |= UART_C1_LOOPS_MASK;
pUART->C1 |= UART_C1_RSRC_MASK;
}
/*****************************************************************************//*!
*
* @brief 设置8位模式
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_Set8BitMode(UART_Type *pUART)
{
pUART->C1 &= (~UART_C1_M_MASK);
}
/*****************************************************************************//*!
*
* @brief 设置9位模式
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_Set9BitMode(UART_Type *pUART)
{
pUART->C1 |= UART_C1_M_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能发送空中断
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_EnableTxBuffEmptyInt(UART_Type *pUART)
{
pUART->C2 |= UART_C2_TIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能发送完成中断
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_EnableTxCompleteInt(UART_Type *pUART)
{
pUART->C2 |= UART_C2_TCIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 使能接收满中断
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_EnableRxBuffFullInt(UART_Type *pUART)
{
pUART->C2 |= UART_C2_RIE_MASK;
}
/*****************************************************************************//*!
*
* @brief 禁用发送空中断
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_DisableTxBuffEmptyInt(UART_Type *pUART)
{
pUART->C2 &= (~UART_C2_TIE_MASK);
}
/*****************************************************************************//*!
*
* @brief 禁用传输完成中断
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_DisableTxCompleteInt(UART_Type *pUART)
{
pUART->C2 &= (~UART_C2_TCIE_MASK);
}
/*****************************************************************************//*!
*
* @brief 禁用接收满中断
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_DisableRxBuffFullInt(UART_Type *pUART)
{
pUART->C2 &= (~UART_C2_RIE_MASK);
}
/*****************************************************************************//*!
*
* @brief 发送间隔字符
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void UART_PutBreak(UART_Type *pUART)
{
pUART->C2 |= UART_C2_SBK_MASK;
pUART->C2 &= (~UART_C2_SBK_MASK);
}
/*****************************************************************************//*!
*
* @brief 检测发送完成标志.
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return
* 1, 发送标志置位
* 0, 发送标志清除
*
*****************************************************************************/
__STATIC_INLINE uint8_t UART_IsTxComplete(UART_Type *pUART)
{
return (pUART->S1 & UART_S1_TC_MASK);
}
/*****************************************************************************//*!
*
* @brief 检测发送寄存器是否空
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return
* 1, 发送寄存器空
* 0, 发送寄存器不为空
*
*****************************************************************************/
__STATIC_INLINE uint8_t UART_IsTxBuffEmpty(UART_Type *pUART)
{
return (pUART->S1 & UART_S1_TDRE_MASK);
}
/*****************************************************************************//*!
*
* @brief 检测接收数据寄存器是否满
*
* @param[in] pUART 指向三个UART其中一个的基址
*
* @return
* 1, 接收数据寄存器满
* 0, 接收数据寄存器不为满
*
*****************************************************************************/
__STATIC_INLINE uint8_t UART_IsRxBuffFull(UART_Type *pUART)
{
return (pUART->S1 & UART_S1_RDRF_MASK);
}
/*! @} */
/******************************************************************************
******************************************************************************/
void UART_Init(UART_Type *pUART, UART_ConfigType *pConfig);
uint8_t UART_GetChar(UART_Type *pUART);
void UART_PutChar(UART_Type *pUART, uint8_t u8Char);
void UART_SetBaudrate(UART_Type *pUART, UART_ConfigBaudrateType *pConfig);
void UART_EnableInterrupt(UART_Type *pUART, UART_InterruptType InterruptType);
void UART_DisableInterrupt(UART_Type *pUART, UART_InterruptType InterruptType);
uint16_t UART_GetFlags(UART_Type *pUART);
uint8_t UART_CheckFlag(UART_Type *pUART, UART_FlagType FlagType);
void UART_SendWait(UART_Type *pUART, uint8_t *pSendBuff, uint32_t u32Length);
void UART_ReceiveWait(UART_Type *pUART, uint8_t *pReceiveBuff, uint32_t u32Length);
void UART_WaitTxComplete(UART_Type *pUART);
void UART_SetCallback(UART_CallbackType pfnCallback);
void UART0_Isr(void);
void UART1_Isr(void);
void UART2_Isr(void);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _UART_H_ */
@@ -0,0 +1,265 @@
/****************************************************************************!
* 技术讨论:QQ群 123763203
* 官网 www.navota.com
*
* @file wdg.c
* @brief wdg定时器函数库
* @author Navota
* @date 2018-3-1
*******************************************************************************/
#include "common.h"
#include "wdog.h"
/******************************************************************************
*******************************************************************************/
/*****************************************************************************//*!
*
* @brief 禁用看门狗定时器
*
* @param none
*
* @return none
*
*****************************************************************************/
void WDOG_Disable(void)
{
uint8_t u8Cs1 = WDOG->CS1;
uint8_t u8Cs2 = WDOG->CS2;
uint16_t u16TOVAL = WDOG->TOVAL;
uint16_t u16WIN = WDOG->WIN;
u8Cs1 &= ~WDOG_CS1_EN_MASK;
/* 首先要解锁unlock看门狗,才可以往寄存器写数据 */
WDOG_Unlock();
WDOG->CS2 = u8Cs2;
WDOG->TOVAL = u16TOVAL;
WDOG->WIN = u16WIN;
WDOG->CS1 = u8Cs1;
}
/*****************************************************************************//*!
*
* @brief 禁用看门狗但允许其重新配置.
*
*
* @param none
*
* @return none
*
*****************************************************************************/
void WDOG_DisableWDOGEnableUpdate(void)
{
uint8_t u8Cs1 = WDOG->CS1;
uint8_t u8Cs2 = WDOG->CS2;
uint16_t u16TOVAL = WDOG->TOVAL;
uint16_t u16WIN = WDOG->WIN;
u8Cs1 &= ~WDOG_CS1_EN_MASK;
u8Cs1 |= WDOG_CS1_UPDATE_MASK;
WDOG_Unlock(); //Modify
WDOG->CS2 = u8Cs2;
WDOG->TOVAL = u16TOVAL;
WDOG->WIN = u16WIN;
WDOG->CS1 = u8Cs1;
}
/*****************************************************************************//*!
*
* @brief 使能看门狗定时器.
*
* @param none
*
* @return none
*
*****************************************************************************/
void WDOG_Enable(void)
{
uint8_t u8Cs1 = WDOG->CS1;
u8Cs1 |= WDOG_CS1_EN_MASK;
/* 首先要解锁unlock看门狗,才可以往寄存器写数据 */
WDOG_Unlock();
WDOG->CS1 = u8Cs1;
}
/*****************************************************************************//*!
*
* @brief 初始化看门狗.
*
* @param[in] pConfig 配置看门狗的结构体.
*
* @return none
*
* @warning make sure that WDOG is not initialized after reset or WDOG update is enabled
* after reset by calling WDOG_EnableUpdate / WDOG_DisableWDOGEnableUpdate.
*
* @see WDOG_EnableUpdate, WDOG_DisableWDOGEnableUpdate
*
*************************************************************************/
void WDOG_Init(WDOG_ConfigPtr pConfig)
{
uint8_t u8Cs1;
uint8_t u8Cs2;
uint16_t u16Toval;
uint16_t u16Win;
u8Cs1 = 0x80; /* CS1寄存器的默认值 */
u8Cs2 = 0;
u16Toval = pConfig->u16ETMeOut;
u16Win = pConfig->u16WinETMe;
if(pConfig->sBits.bDisable)
{
u8Cs1 &= ~WDOG_CS1_EN_MASK;
}
if(pConfig->sBits.bIntEnable)
{
u8Cs1 |= WDOG_CS1_INT_MASK;
}
if(pConfig->sBits.bStopEnable)
{
u8Cs1 |= WDOG_CS1_STOP_MASK;
}
if(pConfig->sBits.bDbgEnable)
{
u8Cs1 |= WDOG_CS1_DBG_MASK;
}
if(pConfig->sBits.bWaitEnable)
{
u8Cs1 |= WDOG_CS1_WAIT_MASK;
}
if(pConfig->sBits.bUpdateEnable)
{
u8Cs1 |= WDOG_CS1_UPDATE_MASK;
}
if(pConfig->sBits.bWinEnable)
{
u8Cs2 |= WDOG_CS2_WIN_MASK;
}
if(pConfig->sBits.bPrescaler)
{
u8Cs2 |= WDOG_CS2_PRES_MASK;
}
u8Cs2 |= (pConfig->sBits.bClkSrc & 0x03);
/* 首先要解锁unlock看门狗,才可以往寄存器写数据 */
WDOG_Unlock();
WDOG->CS2 = u8Cs2;
WDOG->TOVAL8B.TOVALL = u16Toval;
WDOG->TOVAL8B.TOVALH = u16Toval >> 8;
WDOG->WIN8B.WINL = u16Win;
WDOG->WIN8B.WINH = u16Win >> 8;
WDOG->CS1 = u8Cs1;
}
/*****************************************************************************//*!
*
* @brief 复位看门狗.
*
* @param none
*
* @return none
*
*****************************************************************************/
void WDOG_DeInit(void)
{
WDOG_Unlock();
WDOG->CS2 = WDOG_CS2_DEFAULT_VALUE;
WDOG->TOVAL = WDOG_TOVAL_DEFAULT_VALUE;
WDOG->WIN = WDOG_WIN_DEFAULT_VALUE;
WDOG->CS1 = WDOG_CS1_DEFAULT_VALUE;
}
/*****************************************************************************//*!
*
* @brief 喂狗-刷新看门狗.
*
* @param none
*
* @return none
*
*****************************************************************************/
void WDOG_Feed(void)
{
//在喂狗期间,总中断需要关闭
DisableInterrupts;
WDOG->CNT = 0x02A6;//喂狗的两条指令,必须跟随在128个总线时钟周期内执行
WDOG->CNT = 0x80B4;
EnableInterrupts;
}
/*****************************************************************************//*!
*
* @brief 使能更新看门狗.
*
* @param none
*
* @return none
*
*****************************************************************************/
void WDOG_EnableUpdate(void)
{
uint8_t u8Cs1 = WDOG->CS1;
uint8_t u8Cs2 = WDOG->CS2;
uint16_t u16TOVAL = WDOG->TOVAL;
uint16_t u16WIN = WDOG->WIN;
u8Cs1 |= WDOG_CS1_UPDATE_MASK;
/* 首先要解锁unlock看门狗,才可以往寄存器写数据 */
WDOG_Unlock();
WDOG->CS2 = u8Cs2;
WDOG->TOVAL = u16TOVAL;
WDOG->WIN = u16WIN;
WDOG->CS1 = u8Cs1;
}
/*****************************************************************************//*!
*
* @brief 禁用更新看门狗.
*
* @param none
*
* @return none
*
*****************************************************************************/
void WDOG_DisableUpdate(void)
{
uint8_t u8Cs1 = WDOG->CS1;
uint8_t u8Cs2 = WDOG->CS2;
uint16_t u16TOVAL = WDOG->TOVAL;
uint16_t u16WIN = WDOG->WIN;
u8Cs1 &= ~WDOG_CS1_UPDATE_MASK;
/* 首先要解锁unlock看门狗,才可以往寄存器写数据 */
WDOG_Unlock();
WDOG->CS2 = u8Cs2;
WDOG->TOVAL = u16TOVAL;
WDOG->WIN = u16WIN;
WDOG->CS1 = u8Cs1;
}
/********************************************************************/
/*! @} */
@@ -0,0 +1,153 @@
/******************************************************************************
*
* @brief WDG 驱动头文件.
*
******************************************************************************/
#ifndef __WDOG_H__
#define __WDOG_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
#include "sim.h"
/*****************************************************************************/
/******************************************************************************
* 定义WDG时钟源
*
*//*! @WDG时钟源
* @{
*******************************************************************************/
#define WDOG_CLK_BUS 0 /*!< 总线时钟 */
#define WDOG_CLK_INTERNAL_32KHZ 2 /*!< 内部 32 kHz (ICSIRCLK) */
#define WDOG_CLK_INTERNAL_1KHZ 1 /*!< 内部 LPO 1 KHz */
#define WDOG_CLK_EXTERNAL 3 /*!< 外部时钟 */
/*! @} */
/* 看门狗时钟源选择 */
#define WDOG_CLK (WDOG_CLK_INTERNAL_1KHZ)
/* 看门狗寄存器默认值设置 */
#define WDOG_CS1_DEFAULT_VALUE 0x80
#define WDOG_CS2_DEFAULT_VALUE 0x01
#define WDOG_TOVAL_DEFAULT_VALUE 0x0400
#define WDOG_WIN_DEFAULT_VALUE 0x0000
/*!
* @brief 看门狗解锁.
*/
#define WDOG_Unlock() DisableInterrupts; WDOG->CNT = 0x20C5; WDOG->CNT = 0x28D9; EnableInterrupts //Modify
/*! @} */
/******************************************************************************
* define 看门狗配置结构体
*
*//*! @看门狗配置结构体
* @{
*******************************************************************************/
typedef struct {
struct {
uint16_t bIntEnable : 1; /*!< 看门狗中断使能 */
uint16_t bDisable : 1; /*!< 禁用看门狗 */
uint16_t bWaitEnable : 1; /*!< 使能看门狗等待模式 */
uint16_t bStopEnable : 1; /*!< 使能看门狗停止模式 */
uint16_t bDbgEnable : 1; /*!< 使能看门狗调试模式 */
uint16_t bWinEnable : 1; /*!< 使能看门狗窗口模式 */
uint16_t bUpdateEnable : 1; /*!< 使能允许看门狗更新 */
uint16_t bClkSrc : 2; /*!< 看门狗时钟源选择 */
uint16_t bPrescaler : 1; /*!< 预分频系数 */
}sBits; /*!< 位域结构体 */
uint16_t u16ETMeOut; /*!< 看门狗超时值 */
uint16_t u16WinETMe; /*!< 看门狗窗口值 */
} WDOG_ConfigType, *WDOG_ConfigPtr; /*!< 看门狗配置结构体类型 */
/*! @} */
/******************************************************************************
******************************************************************************/
/*!
* 内联函数
*/
/*****************************************************************************//*!
*
* @brief 设置看门狗超时值.
*
* @param[in] u16ETMeOut 超时值.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void WDOG_SetETMeOut(uint16_t u16ETMeOut)
{
WDOG->CNT = 0x20C5;
WDOG->CNT = 0x28D9;
WDOG->TOVAL8B.TOVALL = u16ETMeOut;
WDOG->TOVAL8B.TOVALH = u16ETMeOut >> 8;
}
/*****************************************************************************//*!
*
* @brief 设置看门狗窗口.
*
* @param[in] u16WinETMe 看门狗窗口值.
*
* @return none
*
*****************************************************************************/
__STATIC_INLINE void WDOG_SetWindow(uint16_t u16WinETMe)
{
WDOG->CNT = 0x20C5;
WDOG->CNT = 0x28D9;
WDOG->WIN8B.WINL = u16WinETMe;
WDOG->WIN8B.WINH = u16WinETMe >> 8;
}
/*****************************************************************************//*!
*
* @brief 检查看门狗是否复位.
*
* @param none.
*
* @return TRUE 当看门狗复位发生, FALSE 无.
*
*****************************************************************************/
__STATIC_INLINE uint8_t WDOG_IsReset(void)
{
if(SIM_GetStatus(SIM_SRSID_WDOG_MASK))
{
return (TRUE);
}
return (FALSE);
}
/*! @} */
void WDOG_Init(WDOG_ConfigPtr pConfig);
void WDOG_DeInit(void);
void WDOG_Disable(void);
void WDOG_DisableWDOGEnableUpdate(void);
void WDOG_Enable(void);
void WDOG_Feed(void);
void WDOG_SetETMeOut(uint16_t u16ETMeOut);
void WDOG_SetWindow(uint16_t u16WinETMe);
void WDOG_EnableUpdate(void);
void WDOG_DisableUpdate(void);
uint8_t WDOG_IsReset(void);
#ifdef __cplusplus
}
#endif
/********************************************************************/
#endif /* __WDOG_H__ */