First librpitx commit after separate from rpitx project
This commit is contained in:
parent
21b5194862
commit
a62f65621a
30 changed files with 4889 additions and 0 deletions
675
LICENCE.txt
Normal file
675
LICENCE.txt
Normal file
|
@ -0,0 +1,675 @@
|
||||||
|
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>.
|
||||||
|
|
15
app/Makefile
Normal file
15
app/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
all: testrpitx
|
||||||
|
|
||||||
|
CFLAGS = -Wall -g -O3 -Wno-unused-variable
|
||||||
|
LDFLAGS = -lm -lrt -lpthread -lliquid
|
||||||
|
CCP = g++
|
||||||
|
CC = gcc
|
||||||
|
|
||||||
|
|
||||||
|
testrpitx: testrpitx.cpp ../src/librpitx.h ../src/librpitx.a
|
||||||
|
|
||||||
|
$(CCP) $(CFLAGS) -o testrpitx testrpitx.cpp ../src/librpitx.a $(LDFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
|
||||||
|
rm -f testrpitx
|
402
app/testrpitx.cpp
Normal file
402
app/testrpitx.cpp
Normal file
|
@ -0,0 +1,402 @@
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "../src/librpitx.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "stdio.h"
|
||||||
|
#include <cstring>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
bool running=true;
|
||||||
|
void SimpleTest(uint64_t Freq)
|
||||||
|
{
|
||||||
|
generalgpio genpio;
|
||||||
|
fprintf(stderr,"GPIOPULL =%x\n",genpio.gpioreg[GPPUDCLK0]);
|
||||||
|
#define PULL_OFF 0
|
||||||
|
#define PULL_DOWN 1
|
||||||
|
#define PULL_UP 2
|
||||||
|
genpio.gpioreg[GPPUD]=PULL_DOWN;
|
||||||
|
usleep(100);
|
||||||
|
genpio.gpioreg[GPPUDCLK0]=(1<<4); //GPIO CLK is GPIO 4
|
||||||
|
usleep(100);
|
||||||
|
//genpio.gpioreg[GPPUDCLK0]=(0); //GPIO CLK is GPIO 4
|
||||||
|
|
||||||
|
clkgpio clk;
|
||||||
|
clk.print_clock_tree();
|
||||||
|
//clk.SetPllNumber(clk_plld,2);
|
||||||
|
clk.SetAdvancedPllMode(true);
|
||||||
|
clk.SetCenterFrequency(Freq,100000);
|
||||||
|
int Deviation=0;
|
||||||
|
clk.SetFrequency(000);
|
||||||
|
clk.enableclk(4);
|
||||||
|
while(running)
|
||||||
|
{
|
||||||
|
sleep(5);
|
||||||
|
//Deviation+=1;
|
||||||
|
clk.SetFrequency(Deviation);
|
||||||
|
}
|
||||||
|
/*for(int i=0;i<100000;i+=1)
|
||||||
|
{
|
||||||
|
clk.SetFrequency(i);
|
||||||
|
usleep(1000);
|
||||||
|
}*/
|
||||||
|
clk.disableclk(4);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleTestDMA(uint64_t Freq)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
int SR=200000;
|
||||||
|
int FifoSize=4096;
|
||||||
|
//ngfmdmasync ngfmtest(1244200000,SR,14,FifoSize);
|
||||||
|
ngfmdmasync ngfmtest(Freq,SR,14,FifoSize);
|
||||||
|
for(int i=0;running;)
|
||||||
|
{
|
||||||
|
//usleep(10);
|
||||||
|
usleep(FifoSize*1000000.0*3.0/(4.0*SR));
|
||||||
|
int Available=ngfmtest.GetBufferAvailable();
|
||||||
|
if(Available>FifoSize/2)
|
||||||
|
{
|
||||||
|
int Index=ngfmtest.GetUserMemIndex();
|
||||||
|
//printf("GetIndex=%d\n",Index);
|
||||||
|
for(int j=0;j<Available;j++)
|
||||||
|
{
|
||||||
|
//ngfmtest.SetFrequencySample(Index,((i%10000)>5000)?1000:0);
|
||||||
|
ngfmtest.SetFrequencySample(Index+j,(i%SR));
|
||||||
|
i++;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
fprintf(stderr,"End\n");
|
||||||
|
|
||||||
|
ngfmtest.stop();
|
||||||
|
|
||||||
|
}
|
||||||
|
using std::complex;
|
||||||
|
void SimpleTestLiquid()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
int SR=200000;
|
||||||
|
int FifoSize=4096;
|
||||||
|
ngfmdmasync ngfmtest(144200000,SR,14,FifoSize);
|
||||||
|
dsp mydsp(SR);
|
||||||
|
nco_crcf q = nco_crcf_create(LIQUID_NCO);
|
||||||
|
nco_crcf_set_phase(q, 0.0f);
|
||||||
|
nco_crcf_set_frequency(q, -0.2f);
|
||||||
|
|
||||||
|
//ngfmtest.print_clock_tree();
|
||||||
|
for(int i=0;(i<SR)&&running;)
|
||||||
|
{
|
||||||
|
//usleep(10);
|
||||||
|
usleep(FifoSize*1000000.0*3.0/(4.0*SR));
|
||||||
|
int Available=ngfmtest.GetBufferAvailable();
|
||||||
|
if(Available>FifoSize/2)
|
||||||
|
{
|
||||||
|
int Index=ngfmtest.GetUserMemIndex();
|
||||||
|
//printf("GetIndex=%d\n",Index);
|
||||||
|
for(int j=0;j<Available;j++)
|
||||||
|
{
|
||||||
|
//ngfmtest.SetFrequencySample(Index,((i%10000)>5000)?1000:0);
|
||||||
|
//ngfmtest.SetFrequencySample(Index+j,(i%SR));
|
||||||
|
nco_crcf_adjust_frequency(q,1e-5);
|
||||||
|
liquid_float_complex x;
|
||||||
|
nco_crcf_step(q);
|
||||||
|
nco_crcf_cexpf(q, &x);
|
||||||
|
mydsp.pushsample(x);
|
||||||
|
if(mydsp.frequency>SR) mydsp.frequency=SR;
|
||||||
|
if(mydsp.frequency<-SR) mydsp.frequency=-SR;
|
||||||
|
ngfmtest.SetFrequencySample(Index+j,mydsp.frequency);
|
||||||
|
//fprintf(stderr,"freq=%f Amp=%f\n",mydsp.frequency,mydsp.amplitude);
|
||||||
|
//fprintf(stderr,"freq=%f\n",nco_crcf_get_frequency(q)*SR);
|
||||||
|
i++;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
fprintf(stderr,"End\n");
|
||||||
|
|
||||||
|
ngfmtest.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleTestFileIQ(uint64_t Freq)
|
||||||
|
{
|
||||||
|
FILE *iqfile=NULL;
|
||||||
|
iqfile=fopen("../ssbtest.iq","rb");
|
||||||
|
if (iqfile==NULL) printf("input file issue\n");
|
||||||
|
|
||||||
|
|
||||||
|
bool stereo=true;
|
||||||
|
int SR=48000;
|
||||||
|
int FifoSize=512;
|
||||||
|
//iqdmasync iqtest(1245000000,SR,14,FifoSize);
|
||||||
|
//iqdmasync iqtest(50100000,SR,14,FifoSize);
|
||||||
|
iqdmasync iqtest(Freq,SR,14,FifoSize);
|
||||||
|
//iqdmasync iqtest(14100000,SR,14,FifoSize);
|
||||||
|
short IQBuffer[128*2];
|
||||||
|
|
||||||
|
while(running)
|
||||||
|
{
|
||||||
|
//usleep(FifoSize*1000000.0*1.0/(8.0*SR));
|
||||||
|
usleep(100);
|
||||||
|
int Available=iqtest.GetBufferAvailable();
|
||||||
|
if(Available>256)
|
||||||
|
{
|
||||||
|
int Index=iqtest.GetUserMemIndex();
|
||||||
|
int nbread=fread(IQBuffer,sizeof(short),128*2,iqfile);
|
||||||
|
if(nbread>0)
|
||||||
|
{
|
||||||
|
//printf("NbRead=%d\n",nbread);
|
||||||
|
for(int i=0;i<nbread/2;i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
liquid_float_complex x=complex<float>(IQBuffer[i*2]/32768.0,IQBuffer[i*2+1]/32768.0);
|
||||||
|
iqtest.SetIQSample(Index+i,x);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("End of file\n");
|
||||||
|
fseek ( iqfile , 0 , SEEK_SET );
|
||||||
|
//break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iqtest.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SimpleTestbpsk(uint64_t Freq)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
clkgpio clk;
|
||||||
|
clk.print_clock_tree();
|
||||||
|
int SR=100000;
|
||||||
|
int FifoSize=1024;
|
||||||
|
int NumberofPhase=2;
|
||||||
|
phasedmasync biphase(Freq,SR,NumberofPhase,14,FifoSize);
|
||||||
|
int lastphase=0;
|
||||||
|
while(running)
|
||||||
|
{
|
||||||
|
//usleep(FifoSize*1000000.0*1.0/(8.0*SR));
|
||||||
|
usleep(10);
|
||||||
|
int Available=biphase.GetBufferAvailable();
|
||||||
|
if(Available>256)
|
||||||
|
{
|
||||||
|
int Index=biphase.GetUserMemIndex();
|
||||||
|
|
||||||
|
|
||||||
|
for(int i=0;i<Available;i++)
|
||||||
|
{
|
||||||
|
int phase=(rand()%NumberofPhase);
|
||||||
|
biphase.SetPhase(Index+i,phase);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
for(int i=0;i<Available/2;i++)
|
||||||
|
{
|
||||||
|
int phase=2*(rand()%NumberofPhase/2);
|
||||||
|
biphase.SetPhase(Index+i*2,(phase+lastphase)/2);
|
||||||
|
biphase.SetPhase(Index+i*2+1,phase);
|
||||||
|
lastphase=phase;
|
||||||
|
}*/
|
||||||
|
/*for(int i=0;i<Available;i++)
|
||||||
|
{
|
||||||
|
lastphase=(lastphase+1)%NumberofPhase;
|
||||||
|
biphase.SetPhase(Index+i,lastphase);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
biphase.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SimpleTestSerial()
|
||||||
|
{
|
||||||
|
|
||||||
|
bool stereo=true;
|
||||||
|
int SR=10000;
|
||||||
|
int FifoSize=1024;
|
||||||
|
bool dualoutput=true;
|
||||||
|
serialdmasync testserial(SR,14,FifoSize,dualoutput);
|
||||||
|
|
||||||
|
while(running)
|
||||||
|
{
|
||||||
|
|
||||||
|
usleep(10);
|
||||||
|
int Available=testserial.GetBufferAvailable();
|
||||||
|
if(Available>256)
|
||||||
|
{
|
||||||
|
int Index=testserial.GetUserMemIndex();
|
||||||
|
|
||||||
|
|
||||||
|
for(int i=0;i<Available;i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
testserial.SetSample(Index+i,i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testserial.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleTestAm(uint64_t Freq)
|
||||||
|
{
|
||||||
|
FILE *audiofile=NULL;
|
||||||
|
audiofile=fopen("../ssbaudio48.wav","rb");
|
||||||
|
if (audiofile==NULL) printf("input file issue\n");
|
||||||
|
|
||||||
|
|
||||||
|
bool Stereo=true;
|
||||||
|
int SR=48000;
|
||||||
|
int FifoSize=512;
|
||||||
|
amdmasync amtest(Freq,SR,14,FifoSize);
|
||||||
|
|
||||||
|
short AudioBuffer[128*2];
|
||||||
|
|
||||||
|
while(running)
|
||||||
|
{
|
||||||
|
//usleep(FifoSize*1000000.0*1.0/(8.0*SR));
|
||||||
|
usleep(100);
|
||||||
|
int Available=amtest.GetBufferAvailable();
|
||||||
|
if(Available>256)
|
||||||
|
{
|
||||||
|
int Index=amtest.GetUserMemIndex();
|
||||||
|
int nbread=fread(AudioBuffer,sizeof(short),128*2,audiofile);
|
||||||
|
if(nbread>0)
|
||||||
|
{
|
||||||
|
|
||||||
|
for(int i=0;i<nbread/2;i++)
|
||||||
|
{
|
||||||
|
if(!Stereo)
|
||||||
|
{
|
||||||
|
float x=((AudioBuffer[i*2]/32768.0)+(AudioBuffer[i*2+1]/32768.0))/4.0;
|
||||||
|
amtest.SetAmSample(Index+i,x);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float x=((AudioBuffer[i]/32768.0)/2.0)*8.0;
|
||||||
|
amtest.SetAmSample(Index+i,x);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("End of file\n");
|
||||||
|
fseek ( audiofile , 0 , SEEK_SET );
|
||||||
|
//break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
amtest.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleTestOOK(uint64_t Freq)
|
||||||
|
{
|
||||||
|
|
||||||
|
int SR=1000;
|
||||||
|
int FifoSize=512;
|
||||||
|
amdmasync amtest(Freq,SR,14,FifoSize);
|
||||||
|
|
||||||
|
|
||||||
|
int count=0;
|
||||||
|
int Every=SR/100;
|
||||||
|
float x=0.0;
|
||||||
|
while(running)
|
||||||
|
{
|
||||||
|
//usleep(FifoSize*1000000.0*1.0/(8.0*SR));
|
||||||
|
usleep(100);
|
||||||
|
int Available=amtest.GetBufferAvailable();
|
||||||
|
if(Available>256)
|
||||||
|
{
|
||||||
|
int Index=amtest.GetUserMemIndex();
|
||||||
|
for(int i=0;i<Available;i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//if((count/Every)%4>2) x=0; else x=1;
|
||||||
|
//x+=(1.0/(float)SR*10.0);
|
||||||
|
x+=0.0001;
|
||||||
|
if(x>1.0) x=0;
|
||||||
|
|
||||||
|
amtest.SetAmSample(Index+i,x);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
amtest.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleTestBurstFsk(uint64_t Freq)
|
||||||
|
{
|
||||||
|
|
||||||
|
//int SR=40625;
|
||||||
|
int SR=40625;
|
||||||
|
int Deviation=26370;
|
||||||
|
int FiFoSize=4000;
|
||||||
|
fskburst fsktest(Freq,SR,Deviation,14,FiFoSize);
|
||||||
|
|
||||||
|
unsigned char TabSymbol[FiFoSize];
|
||||||
|
int BurstSize=100;
|
||||||
|
|
||||||
|
while(running)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0;i<FiFoSize;i++)
|
||||||
|
{
|
||||||
|
TabSymbol[i]=(i/10)%2;
|
||||||
|
}
|
||||||
|
fsktest.SetSymbols(TabSymbol,FiFoSize);
|
||||||
|
sleep(1);
|
||||||
|
fsktest.SetSymbols(TabSymbol,FiFoSize/2);
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
fsktest.stop();
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
terminate(int num)
|
||||||
|
{
|
||||||
|
running=false;
|
||||||
|
fprintf(stderr,"Caught signal - Terminating\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
|
||||||
|
uint64_t Freq=144200000;
|
||||||
|
if(argc>1)
|
||||||
|
Freq=atol(argv[1]);
|
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
struct sigaction sa;
|
||||||
|
|
||||||
|
std::memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sa_handler = terminate;
|
||||||
|
sigaction(i, &sa, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
//SimpleTest(Freq);
|
||||||
|
//SimpleTestbpsk(Freq);
|
||||||
|
//SimpleTestFileIQ(Freq);
|
||||||
|
SimpleTestDMA(Freq);
|
||||||
|
//SimpleTestAm(Freq);
|
||||||
|
//SimpleTestOOK(Freq);
|
||||||
|
//SimpleTestBurstFsk(Freq);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
21
src/Makefile
Normal file
21
src/Makefile
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
all: librpitx
|
||||||
|
|
||||||
|
CFLAGS = -Wall -O3 -Wno-unused-variable
|
||||||
|
LDFLAGS = -lm -lrt -lpthread -lliquid
|
||||||
|
CCP = g++
|
||||||
|
CC = gcc
|
||||||
|
|
||||||
|
librpitx: librpitx.h gpio.h gpio.cpp dma.h dma.cpp mailbox.c raspberry_pi_revision.c fmdmasync.h fmdmasync.cpp ngfmdmasync.h ngfmdmasync.cpp dsp.h dsp.cpp iqdmasync.h iqdmasync.cpp serialdmasync.h serialdmasync.cpp phasedmasync.h phasedmasync.cpp fskburst.h fskburst.cpp
|
||||||
|
$(CC) $(CFLAGS) -c -o mailbox.o mailbox.c
|
||||||
|
$(CC) $(CFLAGS) -c -o raspberry_pi_revision.o raspberry_pi_revision.c
|
||||||
|
$(CCP) $(CFLAGS) -c dsp.cpp iqdmasync.cpp ngfmdmasync.cpp fmdmasync.cpp dma.cpp gpio.cpp serialdmasync.cpp phasedmasync.cpp amdmasync.h amdmasync.cpp fskburst.cpp
|
||||||
|
$(AR) rc librpitx.a dsp.o iqdmasync.o ngfmdmasync.o fmdmasync.o dma.o gpio.o mailbox.o raspberry_pi_revision.o serialdmasync.o phasedmasync.o amdmasync.o fskburst.o
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
|
||||||
|
rm -f *.o *.a
|
||||||
|
|
||||||
|
#install: all
|
||||||
|
|
139
src/amdmasync.cpp
Normal file
139
src/amdmasync.cpp
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 Evariste COURJAUD F5OEO
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "amdmasync.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
|
||||||
|
amdmasync::amdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize):bufferdma(Channel,FifoSize,3,2)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
tunefreq=TuneFrequency;
|
||||||
|
clkgpio::SetAdvancedPllMode(true);
|
||||||
|
clkgpio::SetCenterFrequency(TuneFrequency,SampleRate);
|
||||||
|
clkgpio::SetFrequency(0);
|
||||||
|
clkgpio::enableclk(4); // GPIO 4 CLK by default
|
||||||
|
syncwithpwm=false;
|
||||||
|
|
||||||
|
if(syncwithpwm)
|
||||||
|
{
|
||||||
|
pwmgpio::SetPllNumber(clk_plld,1);
|
||||||
|
pwmgpio::SetFrequency(SampleRate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pcmgpio::SetPllNumber(clk_plld,1);
|
||||||
|
pcmgpio::SetFrequency(SampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
padgpio pad;
|
||||||
|
Originfsel=pad.gpioreg[PADS_GPIO_0];
|
||||||
|
|
||||||
|
SetDmaAlgo();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
amdmasync::~amdmasync()
|
||||||
|
{
|
||||||
|
clkgpio::disableclk(4);
|
||||||
|
padgpio pad;
|
||||||
|
pad.gpioreg[PADS_GPIO_0]=Originfsel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void amdmasync::SetDmaAlgo()
|
||||||
|
{
|
||||||
|
dma_cb_t *cbp = cbarray;
|
||||||
|
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//@0
|
||||||
|
//Set Amplitude by writing to PADS
|
||||||
|
cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
|
||||||
|
cbp->dst = 0x7E000000+(PADS_GPIO_0<<2)+PADS_GPIO;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
//@1
|
||||||
|
//Set Amplitude to FSEL for amplitude=0
|
||||||
|
cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample+1]);
|
||||||
|
cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
|
||||||
|
// Delay
|
||||||
|
if(syncwithpwm)
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
|
||||||
|
else
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);
|
||||||
|
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
|
||||||
|
if(syncwithpwm)
|
||||||
|
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
|
||||||
|
else
|
||||||
|
cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cbp--;
|
||||||
|
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
|
||||||
|
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void amdmasync::SetAmSample(uint32_t Index,float Amplitude) //-1;1
|
||||||
|
{
|
||||||
|
Index=Index%buffersize;
|
||||||
|
|
||||||
|
int IntAmplitude=round(abs(Amplitude)*8.0)-1;
|
||||||
|
|
||||||
|
int IntAmplitudePAD=IntAmplitude;
|
||||||
|
if(IntAmplitudePAD>7) IntAmplitudePAD=7;
|
||||||
|
if(IntAmplitudePAD<0) IntAmplitudePAD=0;
|
||||||
|
|
||||||
|
//fprintf(stderr,"Amplitude=%f PAD %d\n",Amplitude,IntAmplitudePAD);
|
||||||
|
sampletab[Index*registerbysample]=(0x5A<<24) + (IntAmplitudePAD&0x7) + (1<<4) + (0<<3); // Amplitude PAD
|
||||||
|
|
||||||
|
//sampletab[Index*registerbysample+2]=(Originfsel & ~(7 << 12)) | (4 << 12); //Alternate is CLK
|
||||||
|
if(IntAmplitude==-1)
|
||||||
|
{
|
||||||
|
sampletab[Index*registerbysample+1]=(Originfsel & ~(7 << 12)) | (0 << 12); //Pin is in -> Amplitude 0
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sampletab[Index*registerbysample+1]=(Originfsel & ~(7 << 12)) | (4 << 12); //Alternate is CLK
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PushSample(Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
22
src/amdmasync.h
Normal file
22
src/amdmasync.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef DEF_AMDMASYNC
|
||||||
|
#define DEF_AMDMASYNC
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "dma.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
|
||||||
|
class amdmasync:public bufferdma,public clkgpio,public pwmgpio,public pcmgpio
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
uint64_t tunefreq;
|
||||||
|
bool syncwithpwm;
|
||||||
|
uint32_t Originfsel;
|
||||||
|
public:
|
||||||
|
amdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize);
|
||||||
|
~amdmasync();
|
||||||
|
void SetDmaAlgo();
|
||||||
|
|
||||||
|
void SetAmSample(uint32_t Index,float Amplitude);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
BIN
src/amdmasync.h.gch
Normal file
BIN
src/amdmasync.h.gch
Normal file
Binary file not shown.
271
src/dma.cpp
Normal file
271
src/dma.cpp
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 Evariste COURJAUD F5OEO
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "dma.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "mailbox.h"
|
||||||
|
#include "raspberry_pi_revision.h"
|
||||||
|
}
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define BUS_TO_PHYS(x) ((x)&~0xC0000000)
|
||||||
|
|
||||||
|
dma::dma(int Channel,uint32_t CBSize,uint32_t UserMemSize) // Fixme! Need to check to be 256 Aligned for UserMem
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Channel %d CBSize %d UsermemSize %d\n",Channel,CBSize,UserMemSize);
|
||||||
|
|
||||||
|
channel=Channel;
|
||||||
|
mbox.handle = mbox_open();
|
||||||
|
if (mbox.handle < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Failed to open mailbox\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
cbsize=CBSize;
|
||||||
|
usermemsize=UserMemSize;
|
||||||
|
|
||||||
|
GetRpiInfo(); // Fill mem_flag and dram_phys_base
|
||||||
|
uint32_t MemoryRequired=CBSize*sizeof(dma_cb_t)+UserMemSize*sizeof(uint32_t);
|
||||||
|
int NumPages=(MemoryRequired/PAGE_SIZE)+1;
|
||||||
|
fprintf(stderr,"%d Size NUM PAGES %d PAGE_SIZE %d\n",MemoryRequired,NumPages,PAGE_SIZE);
|
||||||
|
mbox.mem_ref = mem_alloc(mbox.handle, NumPages* PAGE_SIZE, PAGE_SIZE, mem_flag);
|
||||||
|
/* TODO: How do we know that succeeded? */
|
||||||
|
//fprintf(stderr,"mem_ref %x\n", mbox.mem_ref);
|
||||||
|
mbox.bus_addr = mem_lock(mbox.handle, mbox.mem_ref);
|
||||||
|
//fprintf(stderr,"bus_addr = %x\n", mbox.bus_addr);
|
||||||
|
mbox.virt_addr = (uint8_t *)mapmem(BUS_TO_PHYS(mbox.bus_addr), NumPages* PAGE_SIZE);
|
||||||
|
//fprintf(stderr,"virt_addr %p\n", mbox.virt_addr);
|
||||||
|
virtbase = (uint8_t *)((uint32_t *)mbox.virt_addr);
|
||||||
|
//fprintf(stderr,"virtbase %p\n", virtbase);
|
||||||
|
cbarray = (dma_cb_t *)virtbase; // We place DMA Control Blocks (CB) at beginning of virtual memory
|
||||||
|
//fprintf(stderr,"cbarray %p\n", cbarray);
|
||||||
|
usermem= (unsigned int *)(virtbase+CBSize*sizeof(dma_cb_t)); // user memory is placed after
|
||||||
|
//fprintf(stderr,"usermem %p\n", usermem);
|
||||||
|
|
||||||
|
dma_reg.gpioreg[DMA_CS+channel*0x40] = BCM2708_DMA_RESET|DMA_CS_INT; // Remove int flag
|
||||||
|
usleep(100);
|
||||||
|
dma_reg.gpioreg[DMA_CONBLK_AD+channel*0x40]=mem_virt_to_phys((void*)cbarray ); // reset to beginning
|
||||||
|
}
|
||||||
|
|
||||||
|
void dma::GetRpiInfo()
|
||||||
|
{
|
||||||
|
RASPBERRY_PI_INFO_T info;
|
||||||
|
if (getRaspberryPiInformation(&info) > 0)
|
||||||
|
{
|
||||||
|
if(info.peripheralBase==RPI_BROADCOM_2835_PERIPHERAL_BASE)
|
||||||
|
{
|
||||||
|
|
||||||
|
dram_phys_base = 0x40000000;
|
||||||
|
mem_flag = MEM_FLAG_L1_NONALLOCATING|MEM_FLAG_HINT_PERMALOCK|MEM_FLAG_NO_INIT;//0x0c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((info.peripheralBase==RPI_BROADCOM_2836_PERIPHERAL_BASE)||(info.peripheralBase==RPI_BROADCOM_2837_PERIPHERAL_BASE))
|
||||||
|
{
|
||||||
|
|
||||||
|
dram_phys_base = 0xc0000000;
|
||||||
|
mem_flag = MEM_FLAG_L1_NONALLOCATING/*MEM_FLAG_DIRECT*/|MEM_FLAG_HINT_PERMALOCK|MEM_FLAG_NO_INIT;//0x04;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Unknown Raspberry architecture\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dma::~dma()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
unmapmem(mbox.virt_addr, NumPages * PAGE_SIZE);
|
||||||
|
*/
|
||||||
|
mem_unlock(mbox.handle, mbox.mem_ref);
|
||||||
|
|
||||||
|
mem_free(mbox.handle, mbox.mem_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dma::mem_virt_to_phys(volatile void *virt)
|
||||||
|
{
|
||||||
|
//MBOX METHOD
|
||||||
|
uint32_t offset = (uint8_t *)virt - mbox.virt_addr;
|
||||||
|
return mbox.bus_addr + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dma::mem_phys_to_virt(volatile uint32_t phys)
|
||||||
|
{
|
||||||
|
//MBOX METHOD
|
||||||
|
uint32_t offset=phys-mbox.bus_addr;
|
||||||
|
uint32_t result=(uint32_t)((uint8_t *)mbox.virt_addr+offset);
|
||||||
|
//printf("MemtoVirt:Offset=%lx phys=%lx -> %lx\n",offset,phys,result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dma::start()
|
||||||
|
{
|
||||||
|
dma_reg.gpioreg[DMA_CS+channel*0x40] = BCM2708_DMA_RESET;
|
||||||
|
usleep(100);
|
||||||
|
dma_reg.gpioreg[DMA_CONBLK_AD+channel*0x40]=mem_virt_to_phys((void*)cbarray ); // reset to beginning
|
||||||
|
dma_reg.gpioreg[DMA_DEBUG+channel*0x40] = 7; // clear debug error flags
|
||||||
|
usleep(100);
|
||||||
|
dma_reg.gpioreg[DMA_CS+channel*0x40] = DMA_CS_PRIORITY(15) | DMA_CS_PANIC_PRIORITY(15) | DMA_CS_DISDEBUG |DMA_CS_ACTIVE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dma::stop()
|
||||||
|
{
|
||||||
|
dma_reg.gpioreg[DMA_CS+channel*0x40] = BCM2708_DMA_RESET;
|
||||||
|
usleep(1000);
|
||||||
|
dma_reg.gpioreg[DMA_CS+channel*0x40] = BCM2708_DMA_INT | BCM2708_DMA_END;
|
||||||
|
usleep(100);
|
||||||
|
dma_reg.gpioreg[DMA_CONBLK_AD+channel*0x40]=mem_virt_to_phys((void *)cbarray );
|
||||||
|
usleep(100);
|
||||||
|
dma_reg.gpioreg[DMA_DEBUG+channel*0x40] = 7; // clear debug error flags
|
||||||
|
usleep(100);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dma::getcbposition()
|
||||||
|
{
|
||||||
|
volatile uint32_t dmacb=(uint32_t)(dma_reg.gpioreg[DMA_CONBLK_AD+channel*0x40]);
|
||||||
|
//fprintf(stderr,"cb=%x\n",dmacb);
|
||||||
|
if(dmacb>0)
|
||||||
|
return mem_phys_to_virt(dmacb)-(uint32_t)virtbase;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
// dma_reg.gpioreg[DMA_CONBLK_AD+channel*0x40]-mem_virt_to_phys((void *)cbarray );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dma::isrunning()
|
||||||
|
{
|
||||||
|
return ((dma_reg.gpioreg[DMA_CS+channel*0x40]&DMA_CS_ACTIVE)>0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dma::isunderflow()
|
||||||
|
{
|
||||||
|
//if((dma_reg.gpioreg[DMA_CS+channel*0x40]&DMA_CS_INT)>0) fprintf(stderr,"Status:%x\n",dma_reg.gpioreg[DMA_CS+channel*0x40]);
|
||||||
|
return ((dma_reg.gpioreg[DMA_CS+channel*0x40]&DMA_CS_INT)>0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//**************************************** BUFFER DMA ********************************************************
|
||||||
|
bufferdma::bufferdma(int Channel,uint32_t tbuffersize,uint32_t tcbbysample,uint32_t tregisterbysample):dma(Channel,tbuffersize*tcbbysample,tbuffersize*tregisterbysample)
|
||||||
|
{
|
||||||
|
buffersize=tbuffersize;
|
||||||
|
cbbysample=tcbbysample;
|
||||||
|
registerbysample=tregisterbysample;
|
||||||
|
fprintf(stderr,"BufferSize %d , cb %d user %d\n",buffersize,buffersize*cbbysample,buffersize*registerbysample);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
current_sample=0;
|
||||||
|
last_sample=0;
|
||||||
|
sample_available=buffersize;
|
||||||
|
|
||||||
|
sampletab=usermem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bufferdma::SetDmaAlgo()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int bufferdma::GetBufferAvailable()
|
||||||
|
{
|
||||||
|
int diffsample=0;
|
||||||
|
if(Started)
|
||||||
|
{
|
||||||
|
int CurrenCbPos=getcbposition();
|
||||||
|
if(CurrenCbPos!=-1)
|
||||||
|
{
|
||||||
|
current_sample=CurrenCbPos/(sizeof(dma_cb_t)*cbbysample);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr,"DMA WEIRD STATE\n");
|
||||||
|
current_sample=0;
|
||||||
|
}
|
||||||
|
//fprintf(stderr,"CurrentCB=%d\n",current_sample);
|
||||||
|
diffsample=current_sample-last_sample;
|
||||||
|
if(diffsample<0) diffsample+=buffersize;
|
||||||
|
|
||||||
|
//fprintf(stderr,"cur %d last %d diff%d\n",current_sample,last_sample,diffsample);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//last_sample=buffersize-1;
|
||||||
|
diffsample=buffersize;
|
||||||
|
current_sample=0;
|
||||||
|
//fprintf(stderr,"Warning DMA stopped \n");
|
||||||
|
//fprintf(stderr,"S:cur %d last %d diff%d\n",current_sample,last_sample,diffsample);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if(isunderflow())
|
||||||
|
{
|
||||||
|
fprintf(stderr,"cur %d last %d \n",current_sample,last_sample);
|
||||||
|
fprintf(stderr,"Underflow\n");
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return diffsample;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int bufferdma::GetUserMemIndex()
|
||||||
|
{
|
||||||
|
|
||||||
|
int IndexAvailable=-1;
|
||||||
|
//fprintf(stderr,"Avail=%d\n",GetBufferAvailable());
|
||||||
|
if(GetBufferAvailable())
|
||||||
|
{
|
||||||
|
IndexAvailable=last_sample+1;
|
||||||
|
if(IndexAvailable>=(int)buffersize) IndexAvailable=0;
|
||||||
|
}
|
||||||
|
return IndexAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bufferdma::PushSample(int Index)
|
||||||
|
{
|
||||||
|
if(Index<0) return -1; // No buffer available
|
||||||
|
|
||||||
|
/*
|
||||||
|
dma_cb_t *cbp;
|
||||||
|
cbp=&cbarray[last_sample*cbbysample+cbbysample-1];
|
||||||
|
cbp->info=cbp->info&(~BCM2708_DMA_SET_INT);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
last_sample=Index;
|
||||||
|
/*
|
||||||
|
cbp=&cbarray[Index*cbbysample+cbbysample-1];
|
||||||
|
cbp->info=cbp->info|(BCM2708_DMA_SET_INT);
|
||||||
|
*/
|
||||||
|
if(Started==false)
|
||||||
|
{
|
||||||
|
if(last_sample>buffersize/4)
|
||||||
|
{
|
||||||
|
start(); // 1/4 Fill buffer before starting DMA
|
||||||
|
Started=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
121
src/dma.h
Normal file
121
src/dma.h
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
#ifndef DEF_DMA
|
||||||
|
#define DEF_DMA
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
|
||||||
|
// ---- Memory allocating defines
|
||||||
|
// https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
|
||||||
|
#define MEM_FLAG_DISCARDABLE (1 << 0) /* can be resized to 0 at any time. Use for cached data */
|
||||||
|
#define MEM_FLAG_NORMAL (0 << 2) /* normal allocating alias. Don't use from ARM */
|
||||||
|
#define MEM_FLAG_DIRECT (1 << 2) /* 0xC alias uncached */
|
||||||
|
#define MEM_FLAG_COHERENT (2 << 2) /* 0x8 alias. Non-allocating in L2 but coherent */
|
||||||
|
#define MEM_FLAG_L1_NONALLOCATING (MEM_FLAG_DIRECT | MEM_FLAG_COHERENT) /* Allocating in L2 */
|
||||||
|
#define MEM_FLAG_ZERO ( 1 << 4) /* initialise buffer to all zeros */
|
||||||
|
#define MEM_FLAG_NO_INIT ( 1 << 5) /* don't initialise (default is initialise to all ones */
|
||||||
|
#define MEM_FLAG_HINT_PERMALOCK (1 << 6) /* Likely to be locked for long periods of time. */
|
||||||
|
|
||||||
|
#define BCM2708_DMA_SRC_IGNOR (1<<11)
|
||||||
|
#define BCM2708_DMA_SRC_INC (1<<8)
|
||||||
|
#define BCM2708_DMA_DST_IGNOR (1<<7)
|
||||||
|
#define BCM2708_DMA_NO_WIDE_BURSTS (1<<26)
|
||||||
|
#define BCM2708_DMA_WAIT_RESP (1<<3)
|
||||||
|
|
||||||
|
|
||||||
|
#define BCM2708_DMA_D_DREQ (1<<6)
|
||||||
|
#define BCM2708_DMA_PER_MAP(x) ((x)<<16)
|
||||||
|
#define BCM2708_DMA_END (1<<1)
|
||||||
|
#define BCM2708_DMA_RESET (1<<31)
|
||||||
|
#define BCM2708_DMA_INT (1<<2)
|
||||||
|
|
||||||
|
#define DMA_CS (0x00/4)
|
||||||
|
#define DMA_CONBLK_AD (0x04/4)
|
||||||
|
#define DMA_DEBUG (0x20/4)
|
||||||
|
|
||||||
|
//Page 61
|
||||||
|
#define DREQ_PCM_TX 2
|
||||||
|
#define DREQ_PCM_RX 3
|
||||||
|
#define DREQ_SMI 4
|
||||||
|
#define DREQ_PWM 5
|
||||||
|
#define DREQ_SPI_TX 6
|
||||||
|
#define DREQ_SPI_RX 7
|
||||||
|
#define DREQ_SPI_SLAVE_TX 8
|
||||||
|
#define DREQ_SPI_SLAVE_RX 9
|
||||||
|
|
||||||
|
|
||||||
|
class dma
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
struct {
|
||||||
|
int handle; /* From mbox_open() */
|
||||||
|
unsigned mem_ref; /* From mem_alloc() */
|
||||||
|
unsigned bus_addr; /* From mem_lock() */
|
||||||
|
uint8_t *virt_addr; /* From mapmem() */
|
||||||
|
} mbox;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t info, src, dst, length,
|
||||||
|
stride, next, pad[2];
|
||||||
|
} dma_cb_t; //8*4=32 bytes
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t *virtaddr;
|
||||||
|
uint32_t physaddr;
|
||||||
|
} page_map_t;
|
||||||
|
|
||||||
|
page_map_t *page_map;
|
||||||
|
|
||||||
|
uint8_t *virtbase;
|
||||||
|
int NumPages=0;
|
||||||
|
int channel; //DMA Channel
|
||||||
|
dmagpio dma_reg;
|
||||||
|
|
||||||
|
uint32_t mem_flag; //Cache or not depending on Rpi1 or 2/3
|
||||||
|
uint32_t dram_phys_base;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
dma_cb_t *cbarray;
|
||||||
|
uint32_t cbsize;
|
||||||
|
uint32_t *usermem;
|
||||||
|
uint32_t usermemsize;
|
||||||
|
bool Started=false;
|
||||||
|
|
||||||
|
dma(int Channel,uint32_t CBSize,uint32_t UserMemSize);
|
||||||
|
~dma();
|
||||||
|
uint32_t mem_virt_to_phys(volatile void *virt);
|
||||||
|
uint32_t mem_phys_to_virt(volatile uint32_t phys);
|
||||||
|
void GetRpiInfo();
|
||||||
|
int start();
|
||||||
|
int stop();
|
||||||
|
int getcbposition();
|
||||||
|
bool isrunning();
|
||||||
|
bool isunderflow();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PHYSICAL_BUS 0x7E000000
|
||||||
|
|
||||||
|
class bufferdma:public dma
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t current_sample;
|
||||||
|
uint32_t last_sample;
|
||||||
|
uint32_t sample_available;
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint32_t buffersize;
|
||||||
|
uint32_t cbbysample;
|
||||||
|
uint32_t registerbysample;
|
||||||
|
uint32_t *sampletab;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bufferdma(int Channel,uint32_t tbuffersize,uint32_t tcbbysample,uint32_t tregisterbysample);
|
||||||
|
void SetDmaAlgo();
|
||||||
|
int GetBufferAvailable();
|
||||||
|
int GetUserMemIndex();
|
||||||
|
int PushSample(int Index);
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
86
src/dsp.cpp
Normal file
86
src/dsp.cpp
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 Evariste COURJAUD F5OEO
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "dsp.h"
|
||||||
|
|
||||||
|
dsp::dsp()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
dsp::dsp(uint32_t srate):samplerate(srate)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define ln(x) (log(x)/log(2.718281828459045235f))
|
||||||
|
|
||||||
|
// Again some functions taken gracefully from F4GKR : https://github.com/f4gkr/RadiantBee
|
||||||
|
|
||||||
|
//Normalize to [-180,180):
|
||||||
|
inline double dsp::constrainAngle(double x){
|
||||||
|
x = fmod(x + M_PI,2*M_PI);
|
||||||
|
if (x < 0)
|
||||||
|
x += 2*M_PI;
|
||||||
|
return x - M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to [-360,360]
|
||||||
|
inline double dsp::angleConv(double angle){
|
||||||
|
return fmod(constrainAngle(angle),2*M_PI);
|
||||||
|
}
|
||||||
|
inline double dsp::angleDiff(double a,double b){
|
||||||
|
double dif = fmod(b - a + M_PI,2*M_PI);
|
||||||
|
if (dif < 0)
|
||||||
|
dif += 2*M_PI;
|
||||||
|
return dif - M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double dsp::unwrap(double previousAngle,double newAngle){
|
||||||
|
return previousAngle - angleDiff(newAngle,angleConv(previousAngle));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int dsp::arctan2(int y, int x) // Should be replaced with fast_atan2 from rtl_fm
|
||||||
|
{
|
||||||
|
int abs_y = abs(y);
|
||||||
|
int angle;
|
||||||
|
if((x==0)&&(y==0)) return 0;
|
||||||
|
if(x >= 0){
|
||||||
|
angle = 45 - 45 * (x - abs_y) / ((x + abs_y)==0?1:(x + abs_y));
|
||||||
|
} else {
|
||||||
|
angle = 135 - 45 * (x + abs_y) / ((abs_y - x)==0?1:(abs_y - x));
|
||||||
|
}
|
||||||
|
return (y < 0) ? -angle : angle; // negate if in quad III or IV
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsp::pushsample(liquid_float_complex sample)
|
||||||
|
{
|
||||||
|
|
||||||
|
amplitude=norm(sample);
|
||||||
|
|
||||||
|
double phase=atan2(sample.imag(),sample.real());
|
||||||
|
//fprintf(stderr,"phase %f\n",phase);
|
||||||
|
phase=unwrap(prev_phase,phase);
|
||||||
|
|
||||||
|
double dp= phase-prev_phase;
|
||||||
|
|
||||||
|
frequency = (dp*(double)samplerate)/(2.0*M_PI);
|
||||||
|
prev_phase = phase;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
31
src/dsp.h
Normal file
31
src/dsp.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef DEF_DSP
|
||||||
|
#define DEF_DSP
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <math.h>
|
||||||
|
#include <complex>
|
||||||
|
#include <liquid/liquid.h>
|
||||||
|
class dsp
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
double prev_phase = 0;
|
||||||
|
|
||||||
|
double constrainAngle(double x);
|
||||||
|
double angleConv(double angle);
|
||||||
|
double angleDiff(double a,double b);
|
||||||
|
double unwrap(double previousAngle,double newAngle);
|
||||||
|
int arctan2(int y, int x);
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint32_t samplerate;
|
||||||
|
//double phase;
|
||||||
|
double amplitude;
|
||||||
|
double frequency;
|
||||||
|
|
||||||
|
dsp();
|
||||||
|
dsp(uint32_t samplerate);
|
||||||
|
void pushsample(liquid_float_complex sample);
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
77
src/fmdmasync.cpp
Normal file
77
src/fmdmasync.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 Evariste COURJAUD F5OEO
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "fmdmasync.h"
|
||||||
|
#include "gpio.h" //for definition of registers
|
||||||
|
|
||||||
|
fmdmasync::fmdmasync(int Channel,uint32_t FifoSize):dma(Channel,FifoSize*2,FifoSize)
|
||||||
|
{
|
||||||
|
SetDmaAlgo();
|
||||||
|
FillMemory(12,1472);
|
||||||
|
}
|
||||||
|
|
||||||
|
fmdmasync::~fmdmasync()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void fmdmasync::SetDmaAlgo()
|
||||||
|
{
|
||||||
|
dma_cb_t *cbp = cbarray;
|
||||||
|
for (uint32_t samplecnt = 0; samplecnt < cbsize/2; samplecnt++) { //cbsize/2 because we have 2 CB by sample
|
||||||
|
|
||||||
|
|
||||||
|
// Write a frequency sample
|
||||||
|
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[samplecnt]);
|
||||||
|
cbp->dst = 0x7E000000 + (GPCLK_DIV<<2) + CLK_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
|
||||||
|
// Delay
|
||||||
|
|
||||||
|
cbp->info = /*BCM2708_DMA_SRC_IGNOR | */BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
|
||||||
|
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
|
||||||
|
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
cbp--;
|
||||||
|
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
|
||||||
|
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fmdmasync::FillMemory(uint32_t FreqDivider,uint32_t FreqFractionnal)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (uint32_t samplecnt = 0; samplecnt < usermemsize; samplecnt++)
|
||||||
|
{
|
||||||
|
usermem[samplecnt]=0x5A000000 | ((FreqDivider)<<12) | FreqFractionnal;
|
||||||
|
FreqFractionnal=(FreqFractionnal+1)%4096;
|
||||||
|
if (FreqFractionnal==0) FreqDivider++;
|
||||||
|
}
|
||||||
|
}
|
16
src/fmdmasync.h
Normal file
16
src/fmdmasync.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef DEF_FMDMASYNC
|
||||||
|
#define DEF_FMDMASYNC
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "dma.h"
|
||||||
|
|
||||||
|
class fmdmasync:public dma
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
fmdmasync(int Channel,uint32_t FifoSize);
|
||||||
|
~fmdmasync();
|
||||||
|
void SetDmaAlgo();
|
||||||
|
void FillMemory(uint32_t FreqDivider,uint32_t FreqFractionnal);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
130
src/fskburst.cpp
Normal file
130
src/fskburst.cpp
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 Evariste COURJAUD F5OEO
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "fskburst.h"
|
||||||
|
|
||||||
|
|
||||||
|
fskburst::fskburst(uint64_t TuneFrequency,uint32_t SymbolRate,uint32_t Deviation,int Channel,uint32_t FifoSize):bufferdma(Channel,FifoSize+2,2,1),freqdeviation(Deviation)
|
||||||
|
{
|
||||||
|
|
||||||
|
clkgpio::SetAdvancedPllMode(true);
|
||||||
|
clkgpio::SetCenterFrequency(TuneFrequency,SymbolRate); // Write Mult Int and Frac : FixMe carrier is already there
|
||||||
|
clkgpio::SetFrequency(0);
|
||||||
|
//clkgpio::enableclk(4); // GPIO 4 CLK by default
|
||||||
|
syncwithpwm=false;
|
||||||
|
|
||||||
|
if(syncwithpwm)
|
||||||
|
{
|
||||||
|
pwmgpio::SetPllNumber(clk_plld,1);
|
||||||
|
pwmgpio::SetFrequency(SymbolRate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pcmgpio::SetPllNumber(clk_plld,1);
|
||||||
|
pcmgpio::SetFrequency(SymbolRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SetDmaAlgo();
|
||||||
|
|
||||||
|
padgpio pad;
|
||||||
|
Originfsel=pad.gpioreg[PADS_GPIO_0];
|
||||||
|
}
|
||||||
|
|
||||||
|
fskburst::~fskburst()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void fskburst::SetDmaAlgo()
|
||||||
|
{
|
||||||
|
sampletab[buffersize*registerbysample-2]=(Originfsel & ~(7 << 12)) | (4 << 12); //Enable Clk
|
||||||
|
sampletab[buffersize*registerbysample-1]=(Originfsel & ~(7 << 12)) | (0 << 12); //Disable Clk
|
||||||
|
|
||||||
|
dma_cb_t *cbp = cbarray;
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[buffersize*registerbysample-2]);
|
||||||
|
cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1); // Stop DMA
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
for (uint32_t samplecnt = 0; samplecnt < buffersize-2; samplecnt++)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// Write a frequency sample
|
||||||
|
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
|
||||||
|
cbp->dst = 0x7E000000 + (PLLA_FRAC<<2) + CLK_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
|
||||||
|
// Delay
|
||||||
|
if(syncwithpwm)
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
|
||||||
|
else
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);
|
||||||
|
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
|
||||||
|
if(syncwithpwm)
|
||||||
|
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
|
||||||
|
else
|
||||||
|
cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
}
|
||||||
|
lastcbp=cbp;
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[(buffersize*registerbysample-1)]);
|
||||||
|
cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = 0; // Stop DMA
|
||||||
|
|
||||||
|
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
|
||||||
|
}
|
||||||
|
void fskburst::SetSymbols(unsigned char *Symbols,uint32_t Size)
|
||||||
|
{
|
||||||
|
if(Size>buffersize-2) {fprintf(stderr,"Buffer overflow\n");return;}
|
||||||
|
|
||||||
|
dma_cb_t *cbp=cbarray+1+1;
|
||||||
|
for(unsigned int i=0;i<Size;i++)
|
||||||
|
{
|
||||||
|
sampletab[i]=(0x5A<<24)|GetMasterFrac((Symbols[i]==0)?-freqdeviation:freqdeviation);
|
||||||
|
|
||||||
|
cbp = &cbarray[i*cbbysample+1+1];
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
}
|
||||||
|
cbp->next = mem_virt_to_phys(lastcbp);
|
||||||
|
|
||||||
|
|
||||||
|
dma::start();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
23
src/fskburst.h
Normal file
23
src/fskburst.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef DEF_FSKBURST
|
||||||
|
#define DEF_FSKBURST
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "dma.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
|
||||||
|
class fskburst:public bufferdma,public clkgpio,public pwmgpio,public pcmgpio
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
uint32_t freqdeviation;
|
||||||
|
uint32_t Originfsel;
|
||||||
|
bool syncwithpwm;
|
||||||
|
dma_cb_t *lastcbp;
|
||||||
|
public:
|
||||||
|
fskburst(uint64_t TuneFrequency,uint32_t SymbolRate,uint32_t Deviation,int Channel,uint32_t FifoSize);
|
||||||
|
~fskburst();
|
||||||
|
void SetDmaAlgo();
|
||||||
|
|
||||||
|
void SetSymbols(unsigned char *Symbols,uint32_t Size);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
687
src/gpio.cpp
Normal file
687
src/gpio.cpp
Normal file
|
@ -0,0 +1,687 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 Evariste COURJAUD F5OEO
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "mailbox.h"
|
||||||
|
}
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "raspberry_pi_revision.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
gpio::gpio(uint32_t base, uint32_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
gpioreg=( uint32_t *)mapmem(base,len);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t gpio::GetPeripheralBase()
|
||||||
|
{
|
||||||
|
RASPBERRY_PI_INFO_T info;
|
||||||
|
uint32_t BCM2708_PERI_BASE=0;
|
||||||
|
if (getRaspberryPiInformation(&info) > 0)
|
||||||
|
{
|
||||||
|
if(info.peripheralBase==RPI_BROADCOM_2835_PERIPHERAL_BASE)
|
||||||
|
{
|
||||||
|
BCM2708_PERI_BASE = info.peripheralBase ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((info.peripheralBase==RPI_BROADCOM_2836_PERIPHERAL_BASE)||(info.peripheralBase==RPI_BROADCOM_2837_PERIPHERAL_BASE))
|
||||||
|
{
|
||||||
|
BCM2708_PERI_BASE = info.peripheralBase ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BCM2708_PERI_BASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//******************** DMA Registers ***************************************
|
||||||
|
|
||||||
|
dmagpio::dmagpio():gpio(GetPeripheralBase()+DMA_BASE,DMA_LEN)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************** CLK Registers *****************************************
|
||||||
|
clkgpio::clkgpio():gpio(GetPeripheralBase()+CLK_BASE,CLK_LEN)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
clkgpio::~clkgpio()
|
||||||
|
{
|
||||||
|
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(0 << 4) ; //4 is START CLK
|
||||||
|
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
int clkgpio::SetPllNumber(int PllNo,int MashType)
|
||||||
|
{
|
||||||
|
//print_clock_tree();
|
||||||
|
if(PllNo<8)
|
||||||
|
pllnumber=PllNo;
|
||||||
|
else
|
||||||
|
pllnumber=clk_pllc;
|
||||||
|
|
||||||
|
if(MashType<4)
|
||||||
|
Mash=MashType;
|
||||||
|
else
|
||||||
|
Mash=0;
|
||||||
|
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber/*|(1 << 5)*/ ; //5 is Reset CLK
|
||||||
|
usleep(100);
|
||||||
|
Pllfrequency=GetPllFrequency(pllnumber);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t clkgpio::GetPllFrequency(int PllNo)
|
||||||
|
{
|
||||||
|
uint64_t Freq=0;
|
||||||
|
switch(PllNo)
|
||||||
|
{
|
||||||
|
case clk_osc:Freq=XOSC_FREQUENCY;break;
|
||||||
|
case clk_plla:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLA_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLA_FRAC]/(1<<20);break;
|
||||||
|
//case clk_pllb:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLB_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLB_FRAC]/(1<<20);break;
|
||||||
|
case clk_pllc:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLC_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLC_FRAC]/(1<<20);break;
|
||||||
|
case clk_plld:Freq=(XOSC_FREQUENCY*((uint64_t)gpioreg[PLLD_CTRL]&0x3ff) +(XOSC_FREQUENCY*(uint64_t)gpioreg[PLLD_FRAC])/(1<<20))/(gpioreg[PLLD_PER]>>1);break;
|
||||||
|
case clk_hdmi:Freq=XOSC_FREQUENCY*((uint64_t)gpioreg[PLLH_CTRL]&0x3ff) +XOSC_FREQUENCY*(uint64_t)gpioreg[PLLH_FRAC]/(1<<20);break;
|
||||||
|
}
|
||||||
|
fprintf(stderr,"Freq = %lld\n",Freq);
|
||||||
|
|
||||||
|
return Freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int clkgpio::SetClkDivFrac(uint32_t Div,uint32_t Frac)
|
||||||
|
{
|
||||||
|
|
||||||
|
gpioreg[GPCLK_DIV] = 0x5A000000 | ((Div)<<12) | Frac;
|
||||||
|
usleep(100);
|
||||||
|
fprintf(stderr,"Clk Number %d div %d frac %d\n",pllnumber,Div,Frac);
|
||||||
|
//gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber |(1<<4) ; //4 is START CLK
|
||||||
|
// usleep(10);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int clkgpio::SetMasterMultFrac(uint32_t Mult,uint32_t Frac)
|
||||||
|
{
|
||||||
|
|
||||||
|
fprintf(stderr,"Master Mult %d Frac %d\n",Mult,Frac);
|
||||||
|
gpioreg[PLLA_CTRL] = (0x5a<<24) | (0x21<<12) | Mult;
|
||||||
|
usleep(100);
|
||||||
|
gpioreg[PLLA_FRAC]= 0x5A000000 | Frac ;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int clkgpio::SetFrequency(int Frequency)
|
||||||
|
{
|
||||||
|
if(ModulateFromMasterPLL)
|
||||||
|
{
|
||||||
|
double FloatMult=((double)(CentralFrequency+Frequency)*PllFixDivider)/(double)(XOSC_FREQUENCY);
|
||||||
|
uint32_t freqctl = FloatMult*((double)(1<<20)) ;
|
||||||
|
int IntMultiply= freqctl>>20; // Need to be calculated to have a center frequency
|
||||||
|
freqctl&=0xFFFFF; // Fractionnal is 20bits
|
||||||
|
uint32_t FracMultiply=freqctl&0xFFFFF;
|
||||||
|
//gpioreg[PLLA_FRAC]= 0x5A000000 | FracMultiply ; // Only Frac is Sent
|
||||||
|
SetMasterMultFrac(IntMultiply,FracMultiply);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double Freqresult=(double)Pllfrequency/(double)(CentralFrequency+Frequency);
|
||||||
|
uint32_t FreqDivider=(uint32_t)Freqresult;
|
||||||
|
uint32_t FreqFractionnal=(uint32_t) (4096*(Freqresult-(double)FreqDivider));
|
||||||
|
if((FreqDivider>4096)||(FreqDivider<2)) fprintf(stderr,"Frequency out of range\n");
|
||||||
|
printf("DIV/FRAC %u/%u \n",FreqDivider,FreqFractionnal);
|
||||||
|
|
||||||
|
SetClkDivFrac(FreqDivider,FreqFractionnal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t clkgpio::GetMasterFrac(int Frequency)
|
||||||
|
{
|
||||||
|
if(ModulateFromMasterPLL)
|
||||||
|
{
|
||||||
|
double FloatMult=((double)(CentralFrequency+Frequency)*PllFixDivider)/(double)(XOSC_FREQUENCY);
|
||||||
|
uint32_t freqctl = FloatMult*((double)(1<<20)) ;
|
||||||
|
int IntMultiply= freqctl>>20; // Need to be calculated to have a center frequency
|
||||||
|
freqctl&=0xFFFFF; // Fractionnal is 20bits
|
||||||
|
uint32_t FracMultiply=freqctl&0xFFFFF;
|
||||||
|
return FracMultiply;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0; //Not in Master CLk mode
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int clkgpio::ComputeBestLO(uint64_t Frequency,int Bandwidth)
|
||||||
|
{
|
||||||
|
// Algorithm adapted from https://github.com/SaucySoliton/PiFmRds/blob/master/src/pi_fm_rds.c
|
||||||
|
// Choose an integer divider for GPCLK0
|
||||||
|
//
|
||||||
|
// There may be improvements possible to this algorithm.
|
||||||
|
double xtal_freq_recip=1.0/19.2e6; // todo PPM correction
|
||||||
|
int best_divider=0;
|
||||||
|
|
||||||
|
|
||||||
|
int solution_count=0;
|
||||||
|
//printf("carrier:%3.2f ",carrier_freq/1e6);
|
||||||
|
int divider,min_int_multiplier,max_int_multiplier, fom, int_multiplier, best_fom=0;
|
||||||
|
double frac_multiplier;
|
||||||
|
best_divider=0;
|
||||||
|
for( divider=1;divider<4096;divider++)
|
||||||
|
{
|
||||||
|
if( Frequency*divider < 600e6 ) continue; // widest accepted frequency range
|
||||||
|
if( Frequency*divider > 1500e6 ) break;
|
||||||
|
|
||||||
|
max_int_multiplier=((int)((double)(Frequency+Bandwidth)*divider*xtal_freq_recip));
|
||||||
|
min_int_multiplier=((int)((double)(Frequency-Bandwidth)*divider*xtal_freq_recip));
|
||||||
|
if( min_int_multiplier!=max_int_multiplier ) continue; // don't cross integer boundary
|
||||||
|
|
||||||
|
solution_count++; // if we make it here the solution is acceptable,
|
||||||
|
fom=0; // but we want a good solution
|
||||||
|
|
||||||
|
if( Frequency*divider > 900e6 ) fom++; // prefer freqs closer to 1000
|
||||||
|
if( Frequency*divider < 1100e6 ) fom++;
|
||||||
|
if( Frequency*divider > 800e6 ) fom++; // accepted frequency range
|
||||||
|
if( Frequency*divider < 1200e6 ) fom++;
|
||||||
|
|
||||||
|
|
||||||
|
frac_multiplier=((double)(Frequency)*divider*xtal_freq_recip);
|
||||||
|
int_multiplier = (int) frac_multiplier;
|
||||||
|
frac_multiplier = frac_multiplier - int_multiplier;
|
||||||
|
if((int_multiplier%2)==0) fom++;
|
||||||
|
if( (frac_multiplier>0.4) && (frac_multiplier<0.6) ) fom+=2; // prefer mulipliers away from integer boundaries
|
||||||
|
|
||||||
|
|
||||||
|
//if( divider%2 == 1 ) fom+=2; // prefer odd dividers
|
||||||
|
// Even and odd dividers could have different harmonic content,
|
||||||
|
// but the latest measurements have shown no significant difference.
|
||||||
|
|
||||||
|
|
||||||
|
//printf(" multiplier:%f divider:%d VCO: %4.1fMHz\n",carrier_freq*divider*xtal_freq_recip,divider,(double)carrier_freq*divider/1e6);
|
||||||
|
if( fom > best_fom )
|
||||||
|
{
|
||||||
|
best_fom=fom;
|
||||||
|
best_divider=divider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(solution_count>0)
|
||||||
|
{
|
||||||
|
PllFixDivider=best_divider;
|
||||||
|
fprintf(stderr," multiplier:%f divider:%d VCO: %4.1fMHz\n",Frequency*best_divider*xtal_freq_recip,best_divider,(double)Frequency*best_divider/1e6);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Central frequency not available !!!!!!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int clkgpio::SetCenterFrequency(uint64_t Frequency,int Bandwidth)
|
||||||
|
{
|
||||||
|
CentralFrequency=Frequency;
|
||||||
|
if(ModulateFromMasterPLL)
|
||||||
|
{
|
||||||
|
//Choose best PLLDiv and Div
|
||||||
|
ComputeBestLO(Frequency,Bandwidth); //FixeDivider update
|
||||||
|
|
||||||
|
SetFrequency(0);
|
||||||
|
usleep(1000);
|
||||||
|
if((gpioreg[CM_LOCK]&CM_LOCK_FLOCKA)>0)
|
||||||
|
fprintf(stderr,"Master PLLA Locked\n");
|
||||||
|
else
|
||||||
|
fprintf(stderr,"Warning ! Master PLLA NOT Locked !!!!\n");
|
||||||
|
SetClkDivFrac(PllFixDivider,0); // NO MASH !!!!
|
||||||
|
usleep(100);
|
||||||
|
|
||||||
|
usleep(100);
|
||||||
|
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
|
||||||
|
usleep(100);
|
||||||
|
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GetPllFrequency(pllnumber);// Be sure to get the master PLL frequency
|
||||||
|
gpioreg[GPCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clkgpio::SetPhase(bool inversed)
|
||||||
|
{
|
||||||
|
uint32_t StateBefore=clkgpio::gpioreg[GPCLK_CNTL];
|
||||||
|
clkgpio::gpioreg[GPCLK_CNTL]= (0x5A<<24) | StateBefore | ((inversed?1:0)<<8) | 1<<5;
|
||||||
|
clkgpio::gpioreg[GPCLK_CNTL]= (0x5A<<24) | StateBefore | ((inversed?1:0)<<8) | 0<<5;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clkgpio::SetAdvancedPllMode(bool Advanced)
|
||||||
|
{
|
||||||
|
ModulateFromMasterPLL=Advanced;
|
||||||
|
if(ModulateFromMasterPLL)
|
||||||
|
{
|
||||||
|
SetPllNumber(clk_plla,0); // Use PPL_A , Do not USE MASH which generates spurious
|
||||||
|
gpioreg[0x104/4]=0x5A00020A; // Enable Plla_PER
|
||||||
|
usleep(100);
|
||||||
|
|
||||||
|
uint32_t ana[4];
|
||||||
|
for(int i=3;i>=0;i--)
|
||||||
|
{
|
||||||
|
ana[i]=gpioreg[(0x1010/4)+i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//ana[1]&=~(1<<14); // No use prediv means Frequency
|
||||||
|
ana[1]|=(1<<14); // use prediv means Frequency*2
|
||||||
|
for(int i=3;i>=0;i--)
|
||||||
|
{
|
||||||
|
gpioreg[(0x1010/4)+i]=(0x5A<<24)|ana[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
usleep(100);
|
||||||
|
gpioreg[PLLA_PER]=0x5A000002; // Div ?
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clkgpio::print_clock_tree(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
printf("PLLC_DIG0=%08x\n",gpioreg[(0x1020/4)]);
|
||||||
|
printf("PLLC_DIG1=%08x\n",gpioreg[(0x1024/4)]);
|
||||||
|
printf("PLLC_DIG2=%08x\n",gpioreg[(0x1028/4)]);
|
||||||
|
printf("PLLC_DIG3=%08x\n",gpioreg[(0x102c/4)]);
|
||||||
|
printf("PLLC_ANA0=%08x\n",gpioreg[(0x1030/4)]);
|
||||||
|
printf("PLLC_ANA1=%08x\n",gpioreg[(0x1034/4)]);
|
||||||
|
printf("PLLC_ANA2=%08x\n",gpioreg[(0x1038/4)]);
|
||||||
|
printf("PLLC_ANA3=%08x\n",gpioreg[(0x103c/4)]);
|
||||||
|
printf("PLLC_DIG0R=%08x\n",gpioreg[(0x1820/4)]);
|
||||||
|
printf("PLLC_DIG1R=%08x\n",gpioreg[(0x1824/4)]);
|
||||||
|
printf("PLLC_DIG2R=%08x\n",gpioreg[(0x1828/4)]);
|
||||||
|
printf("PLLC_DIG3R=%08x\n",gpioreg[(0x182c/4)]);
|
||||||
|
|
||||||
|
printf("PLLA_ANA0=%08x\n",gpioreg[(0x1010/4)]);
|
||||||
|
printf("PLLA_ANA1=%08x prediv=%d\n",gpioreg[(0x1014/4)],(gpioreg[(0x1014/4)]>>14)&1);
|
||||||
|
printf("PLLA_ANA2=%08x\n",gpioreg[(0x1018/4)]);
|
||||||
|
printf("PLLA_ANA3=%08x\n",gpioreg[(0x101c/4)]);
|
||||||
|
|
||||||
|
printf("GNRIC CTL=%08x DIV=%8x ",gpioreg[ 0],gpioreg[ 1]);
|
||||||
|
printf("VPU CTL=%08x DIV=%8x\n",gpioreg[ 2],gpioreg[ 3]);
|
||||||
|
printf("SYS CTL=%08x DIV=%8x ",gpioreg[ 4],gpioreg[ 5]);
|
||||||
|
printf("PERIA CTL=%08x DIV=%8x\n",gpioreg[ 6],gpioreg[ 7]);
|
||||||
|
printf("PERII CTL=%08x DIV=%8x ",gpioreg[ 8],gpioreg[ 9]);
|
||||||
|
printf("H264 CTL=%08x DIV=%8x\n",gpioreg[10],gpioreg[11]);
|
||||||
|
printf("ISP CTL=%08x DIV=%8x ",gpioreg[12],gpioreg[13]);
|
||||||
|
printf("V3D CTL=%08x DIV=%8x\n",gpioreg[14],gpioreg[15]);
|
||||||
|
|
||||||
|
printf("CAM0 CTL=%08x DIV=%8x ",gpioreg[16],gpioreg[17]);
|
||||||
|
printf("CAM1 CTL=%08x DIV=%8x\n",gpioreg[18],gpioreg[19]);
|
||||||
|
printf("CCP2 CTL=%08x DIV=%8x ",gpioreg[20],gpioreg[21]);
|
||||||
|
printf("DSI0E CTL=%08x DIV=%8x\n",gpioreg[22],gpioreg[23]);
|
||||||
|
printf("DSI0P CTL=%08x DIV=%8x ",gpioreg[24],gpioreg[25]);
|
||||||
|
printf("DPI CTL=%08x DIV=%8x\n",gpioreg[26],gpioreg[27]);
|
||||||
|
printf("GP0 CTL=%08x DIV=%8x ",gpioreg[0x70/4],gpioreg[0x74/4]);
|
||||||
|
printf("GP1 CTL=%08x DIV=%8x\n",gpioreg[30],gpioreg[31]);
|
||||||
|
|
||||||
|
printf("GP2 CTL=%08x DIV=%8x ",gpioreg[32],gpioreg[33]);
|
||||||
|
printf("HSM CTL=%08x DIV=%8x\n",gpioreg[34],gpioreg[35]);
|
||||||
|
printf("OTP CTL=%08x DIV=%8x ",gpioreg[36],gpioreg[37]);
|
||||||
|
printf("PCM CTL=%08x DIV=%8x\n",gpioreg[38],gpioreg[39]);
|
||||||
|
printf("PWM CTL=%08x DIV=%8x ",gpioreg[40],gpioreg[41]);
|
||||||
|
printf("SLIM CTL=%08x DIV=%8x\n",gpioreg[42],gpioreg[43]);
|
||||||
|
printf("SMI CTL=%08x DIV=%8x ",gpioreg[44],gpioreg[45]);
|
||||||
|
printf("SMPS CTL=%08x DIV=%8x\n",gpioreg[46],gpioreg[47]);
|
||||||
|
|
||||||
|
printf("TCNT CTL=%08x DIV=%8x ",gpioreg[48],gpioreg[49]);
|
||||||
|
printf("TEC CTL=%08x DIV=%8x\n",gpioreg[50],gpioreg[51]);
|
||||||
|
printf("TD0 CTL=%08x DIV=%8x ",gpioreg[52],gpioreg[53]);
|
||||||
|
printf("TD1 CTL=%08x DIV=%8x\n",gpioreg[54],gpioreg[55]);
|
||||||
|
|
||||||
|
printf("TSENS CTL=%08x DIV=%8x ",gpioreg[56],gpioreg[57]);
|
||||||
|
printf("TIMER CTL=%08x DIV=%8x\n",gpioreg[58],gpioreg[59]);
|
||||||
|
printf("UART CTL=%08x DIV=%8x ",gpioreg[60],gpioreg[61]);
|
||||||
|
printf("VEC CTL=%08x DIV=%8x\n",gpioreg[62],gpioreg[63]);
|
||||||
|
|
||||||
|
|
||||||
|
printf("PULSE CTL=%08x DIV=%8x ",gpioreg[100],gpioreg[101]);
|
||||||
|
printf("PLLT CTL=%08x DIV=????????\n",gpioreg[76]);
|
||||||
|
|
||||||
|
printf("DSI1E CTL=%08x DIV=%8x ",gpioreg[86],gpioreg[87]);
|
||||||
|
printf("DSI1P CTL=%08x DIV=%8x\n",gpioreg[88],gpioreg[89]);
|
||||||
|
printf("AVE0 CTL=%08x DIV=%8x\n",gpioreg[90],gpioreg[91]);
|
||||||
|
|
||||||
|
printf("CMPLLA=%08x ",gpioreg[0x104/4]);
|
||||||
|
printf("CMPLLC=%08x \n",gpioreg[0x108/4]);
|
||||||
|
printf("CMPLLD=%08x ",gpioreg[0x10C/4]);
|
||||||
|
printf("CMPLLH=%08x \n",gpioreg[0x110/4]);
|
||||||
|
|
||||||
|
printf("EMMC CTL=%08x DIV=%8x\n",gpioreg[112],gpioreg[113]);
|
||||||
|
printf("EMMC CTL=%08x DIV=%8x\n",gpioreg[112],gpioreg[113]);
|
||||||
|
printf("EMMC CTL=%08x DIV=%8x\n",gpioreg[112],gpioreg[113]);
|
||||||
|
|
||||||
|
|
||||||
|
// Sometimes calculated frequencies are off by a factor of 2
|
||||||
|
// ANA1 bit 14 may indicate that a /2 prescaler is active
|
||||||
|
printf("PLLA PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLA_CTRL]>>16) ,gpioreg[PLLA_CTRL]&0x3ff, gpioreg[PLLA_FRAC] );
|
||||||
|
printf(" %f MHz\n",19.2* ((float)(gpioreg[PLLA_CTRL]&0x3ff) + ((float)gpioreg[PLLA_FRAC])/((float)(1<<20))) );
|
||||||
|
printf("DSI0=%d CORE=%d PER=%d CCP2=%d\n\n",gpioreg[PLLA_DSI0],gpioreg[PLLA_CORE],gpioreg[PLLA_PER],gpioreg[PLLA_CCP2]);
|
||||||
|
|
||||||
|
|
||||||
|
printf("PLLB PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLB_CTRL]>>16) ,gpioreg[PLLB_CTRL]&0x3ff, gpioreg[PLLB_FRAC] );
|
||||||
|
printf(" %f MHz\n",19.2* ((float)(gpioreg[PLLB_CTRL]&0x3ff) + ((float)gpioreg[PLLB_FRAC])/((float)(1<<20))) );
|
||||||
|
printf("ARM=%d SP0=%d SP1=%d SP2=%d\n\n",gpioreg[PLLB_ARM],gpioreg[PLLB_SP0],gpioreg[PLLB_SP1],gpioreg[PLLB_SP2]);
|
||||||
|
|
||||||
|
printf("PLLC PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLC_CTRL]>>16) ,gpioreg[PLLC_CTRL]&0x3ff, gpioreg[PLLC_FRAC] );
|
||||||
|
printf(" %f MHz\n",19.2* ((float)(gpioreg[PLLC_CTRL]&0x3ff) + ((float)gpioreg[PLLC_FRAC])/((float)(1<<20))) );
|
||||||
|
printf("CORE2=%d CORE1=%d PER=%d CORE0=%d\n\n",gpioreg[PLLC_CORE2],gpioreg[PLLC_CORE1],gpioreg[PLLC_PER],gpioreg[PLLC_CORE0]);
|
||||||
|
|
||||||
|
printf("PLLD %x PDIV=%d NDIV=%d FRAC=%d ",gpioreg[PLLD_CTRL],(gpioreg[PLLD_CTRL]>>16) ,gpioreg[PLLD_CTRL]&0x3ff, gpioreg[PLLD_FRAC] );
|
||||||
|
printf(" %f MHz\n",19.2* ((float)(gpioreg[PLLD_CTRL]&0x3ff) + ((float)gpioreg[PLLD_FRAC])/((float)(1<<20))) );
|
||||||
|
printf("DSI0=%d CORE=%d PER=%d DSI1=%d\n\n",gpioreg[PLLD_DSI0],gpioreg[PLLD_CORE],gpioreg[PLLD_PER],gpioreg[PLLD_DSI1]);
|
||||||
|
|
||||||
|
printf("PLLH PDIV=%d NDIV=%d FRAC=%d ",(gpioreg[PLLH_CTRL]>>16) ,gpioreg[PLLH_CTRL]&0x3ff, gpioreg[PLLH_FRAC] );
|
||||||
|
printf(" %f MHz\n",19.2* ((float)(gpioreg[PLLH_CTRL]&0x3ff) + ((float)gpioreg[PLLH_FRAC])/((float)(1<<20))) );
|
||||||
|
printf("AUX=%d RCAL=%d PIX=%d STS=%d\n\n",gpioreg[PLLH_AUX],gpioreg[PLLH_RCAL],gpioreg[PLLH_PIX],gpioreg[PLLH_STS]);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void clkgpio::enableclk(int gpio)
|
||||||
|
{
|
||||||
|
switch(gpio)
|
||||||
|
{
|
||||||
|
case 4: gengpio.setmode(gpio,fsel_alt0);break;
|
||||||
|
case 20:gengpio.setmode(gpio,fsel_alt5);break;
|
||||||
|
case 32:gengpio.setmode(gpio,fsel_alt0);break;
|
||||||
|
case 34:gengpio.setmode(gpio,fsel_alt0);break;
|
||||||
|
default: fprintf(stderr,"gpio %d has no clk - available(4,20,32,34)\n",gpio);break;
|
||||||
|
}
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clkgpio::disableclk(int gpio)
|
||||||
|
{
|
||||||
|
gengpio.setmode(gpio,fsel_input);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************************** GENERAL GPIO *****************************************************
|
||||||
|
|
||||||
|
generalgpio::generalgpio():gpio(GetPeripheralBase()+GENERAL_BASE,GENERAL_LEN)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
generalgpio::~generalgpio()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int generalgpio::setmode(uint32_t gpio, uint32_t mode)
|
||||||
|
{
|
||||||
|
int reg, shift;
|
||||||
|
|
||||||
|
reg = gpio/10;
|
||||||
|
shift = (gpio%10) * 3;
|
||||||
|
|
||||||
|
gpioreg[reg] = (gpioreg[reg] & ~(7<<shift)) | (mode<<shift);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ********************************** PWM GPIO **********************************
|
||||||
|
|
||||||
|
pwmgpio::pwmgpio():gpio(GetPeripheralBase()+PWM_BASE,PWM_LEN)
|
||||||
|
{
|
||||||
|
|
||||||
|
gpioreg[PWM_CTL] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pwmgpio::~pwmgpio()
|
||||||
|
{
|
||||||
|
|
||||||
|
gpioreg[PWM_CTL] = 0;
|
||||||
|
gpioreg[PWM_DMAC] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pwmgpio::enablepwm(int gpio,int PwmNumber)
|
||||||
|
{
|
||||||
|
if(PwmNumber==0)
|
||||||
|
{
|
||||||
|
switch(gpio)
|
||||||
|
{
|
||||||
|
case 12:gengpio.setmode(gpio,fsel_alt0);break;
|
||||||
|
case 18:gengpio.setmode(gpio,fsel_alt5);break;
|
||||||
|
case 40:gengpio.setmode(gpio,fsel_alt0);break;
|
||||||
|
|
||||||
|
default: fprintf(stderr,"gpio %d has no pwm - available(12,18,40)\n",gpio);break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(PwmNumber==1)
|
||||||
|
{
|
||||||
|
switch(gpio)
|
||||||
|
{
|
||||||
|
case 13:gengpio.setmode(gpio,fsel_alt0);break;
|
||||||
|
case 19:gengpio.setmode(gpio,fsel_alt5);break;
|
||||||
|
case 41:gengpio.setmode(gpio,fsel_alt0);break;
|
||||||
|
case 45:gengpio.setmode(gpio,fsel_alt0);break;
|
||||||
|
default: fprintf(stderr,"gpio %d has no pwm - available(13,19,41,45)\n",gpio);break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pwmgpio::disablepwm(int gpio)
|
||||||
|
{
|
||||||
|
gengpio.setmode(gpio,fsel_input);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int pwmgpio::SetPllNumber(int PllNo,int MashType)
|
||||||
|
{
|
||||||
|
if(PllNo<8)
|
||||||
|
pllnumber=PllNo;
|
||||||
|
else
|
||||||
|
pllnumber=clk_pllc;
|
||||||
|
if(MashType<4)
|
||||||
|
Mash=MashType;
|
||||||
|
else
|
||||||
|
Mash=0;
|
||||||
|
clk.gpioreg[PWMCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(0 << 4) ; //4 is STOP CLK
|
||||||
|
usleep(100);
|
||||||
|
Pllfrequency=GetPllFrequency(pllnumber);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pwmgpio::GetPllFrequency(int PllNo)
|
||||||
|
{
|
||||||
|
return clk.GetPllFrequency(PllNo);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int pwmgpio::SetFrequency(uint64_t Frequency)
|
||||||
|
{
|
||||||
|
Prediv=32; // Fixe for now , need investigation if not 32 !!!! FixMe !
|
||||||
|
double Freqresult=(double)Pllfrequency/(double)(Frequency*Prediv);
|
||||||
|
uint32_t FreqDivider=(uint32_t)Freqresult;
|
||||||
|
uint32_t FreqFractionnal=(uint32_t) (4096*(Freqresult-(double)FreqDivider));
|
||||||
|
if((FreqDivider>4096)||(FreqDivider<2)) fprintf(stderr,"Frequency out of range\n");
|
||||||
|
fprintf(stderr,"PWM clk=%d / %d\n",FreqDivider,FreqFractionnal);
|
||||||
|
clk.gpioreg[PWMCLK_DIV] = 0x5A000000 | ((FreqDivider)<<12) | FreqFractionnal;
|
||||||
|
|
||||||
|
usleep(100);
|
||||||
|
clk.gpioreg[PWMCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is STAR CLK
|
||||||
|
usleep(100);
|
||||||
|
|
||||||
|
|
||||||
|
SetPrediv(Prediv); //SetMode should be called before
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void pwmgpio::SetMode(int Mode)
|
||||||
|
{
|
||||||
|
if((Mode>=pwm1pin)&&(Mode<=pwm1pinrepeat))
|
||||||
|
ModePwm=Mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pwmgpio::SetPrediv(int predivisor) //Mode should be only for SYNC or a Data serializer : Todo
|
||||||
|
{
|
||||||
|
Prediv=predivisor;
|
||||||
|
if(Prediv>32)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"PWM Prediv is max 32\n");
|
||||||
|
Prediv=2;
|
||||||
|
}
|
||||||
|
fprintf(stderr,"PWM Prediv %d\n",Prediv);
|
||||||
|
gpioreg[PWM_RNG1] = Prediv;// 250 -> 8KHZ
|
||||||
|
usleep(100);
|
||||||
|
gpioreg[PWM_RNG2] = Prediv;// 32 Mandatory for Serial Mode without gap
|
||||||
|
|
||||||
|
//gpioreg[PWM_FIFO]=0xAAAAAAAA;
|
||||||
|
|
||||||
|
gpioreg[PWM_DMAC] = PWMDMAC_ENAB | PWMDMAC_THRSHLD;
|
||||||
|
usleep(100);
|
||||||
|
gpioreg[PWM_CTL] = PWMCTL_CLRF;
|
||||||
|
usleep(100);
|
||||||
|
|
||||||
|
//gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_MSEN1;
|
||||||
|
switch(ModePwm)
|
||||||
|
{
|
||||||
|
case pwm1pin:gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_MSEN1;break; // All serial go to 1 pin
|
||||||
|
case pwm2pin:gpioreg[PWM_CTL] = PWMCTL_USEF2|PWMCTL_PWEN2|PWMCTL_MODE2|PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1;break;// Alternate bit to pin 1 and 2
|
||||||
|
case pwm1pinrepeat:gpioreg[PWM_CTL] = PWMCTL_USEF1| PWMCTL_MODE1| PWMCTL_PWEN1|PWMCTL_RPTL1;break; // All serial go to 1 pin, repeat if empty : RF mode with PWM
|
||||||
|
}
|
||||||
|
usleep(100);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ********************************** PCM GPIO (I2S) **********************************
|
||||||
|
|
||||||
|
pcmgpio::pcmgpio():gpio(GetPeripheralBase()+PCM_BASE,PCM_LEN)
|
||||||
|
{
|
||||||
|
gpioreg[PCM_CS_A] = 1; // Disable Rx+Tx, Enable PCM block
|
||||||
|
}
|
||||||
|
|
||||||
|
pcmgpio::~pcmgpio()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int pcmgpio::SetPllNumber(int PllNo,int MashType)
|
||||||
|
{
|
||||||
|
if(PllNo<8)
|
||||||
|
pllnumber=PllNo;
|
||||||
|
else
|
||||||
|
pllnumber=clk_pllc;
|
||||||
|
if(MashType<4)
|
||||||
|
Mash=MashType;
|
||||||
|
else
|
||||||
|
Mash=0;
|
||||||
|
clk.gpioreg[PCMCLK_CNTL]= 0x5A000000 | (Mash << 9) | pllnumber|(1 << 4) ; //4 is START CLK
|
||||||
|
Pllfrequency=GetPllFrequency(pllnumber);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pcmgpio::GetPllFrequency(int PllNo)
|
||||||
|
{
|
||||||
|
return clk.GetPllFrequency(PllNo);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int pcmgpio::ComputePrediv(uint64_t Frequency)
|
||||||
|
{
|
||||||
|
int prediv=5;
|
||||||
|
for(prediv=10;prediv<1000;prediv++)
|
||||||
|
{
|
||||||
|
double Freqresult=(double)Pllfrequency/(double)(Frequency*prediv);
|
||||||
|
if((Freqresult<4096.0)&&(Freqresult>2.0))
|
||||||
|
{
|
||||||
|
fprintf(stderr,"PCM prediv = %d\n",prediv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prediv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pcmgpio::SetFrequency(uint64_t Frequency)
|
||||||
|
{
|
||||||
|
Prediv=ComputePrediv(Frequency);
|
||||||
|
double Freqresult=(double)Pllfrequency/(double)(Frequency*Prediv);
|
||||||
|
uint32_t FreqDivider=(uint32_t)Freqresult;
|
||||||
|
uint32_t FreqFractionnal=(uint32_t) (4096*(Freqresult-(double)FreqDivider));
|
||||||
|
fprintf(stderr,"PCM clk=%d / %d\n",FreqDivider,FreqFractionnal);
|
||||||
|
if((FreqDivider>4096)||(FreqDivider<2)) fprintf(stderr,"PCM Frequency out of range\n");
|
||||||
|
clk.gpioreg[PCMCLK_DIV] = 0x5A000000 | ((FreqDivider)<<12) | FreqFractionnal;
|
||||||
|
SetPrediv(Prediv);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int pcmgpio::SetPrediv(int predivisor) //Carefull we use a 10 fixe divisor for now : frequency is thus f/10 as a samplerate
|
||||||
|
{
|
||||||
|
if(predivisor>1000)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"PCM prediv should be <1000");
|
||||||
|
predivisor=1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpioreg[PCM_TXC_A] = 0<<31 | 1<<30 | 0<<20 | 0<<16; // 1 channel, 8 bits
|
||||||
|
usleep(100);
|
||||||
|
|
||||||
|
//printf("Nb PCM STEP (<1000):%d\n",NbStepPCM);
|
||||||
|
gpioreg[PCM_MODE_A] = (predivisor-1)<<10; // SHOULD NOT EXCEED 1000 !!!
|
||||||
|
usleep(100);
|
||||||
|
gpioreg[PCM_CS_A] |= 1<<4 | 1<<3; // Clear FIFOs
|
||||||
|
usleep(100);
|
||||||
|
gpioreg[PCM_DREQ_A] = 64<<24 | 64<<8 ; //TX Fifo PCM=64 DMA Req when one slot is free?
|
||||||
|
usleep(100);
|
||||||
|
gpioreg[PCM_CS_A] |= 1<<9; // Enable DMA
|
||||||
|
usleep(100);
|
||||||
|
gpioreg[PCM_CS_A] |= 1<<2; //START TX PCM
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ********************************** PADGPIO (Amplitude) **********************************
|
||||||
|
|
||||||
|
padgpio::padgpio():gpio(GetPeripheralBase()+PADS_GPIO,PADS_GPIO_LEN)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
padgpio::~padgpio()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
284
src/gpio.h
Normal file
284
src/gpio.h
Normal file
|
@ -0,0 +1,284 @@
|
||||||
|
#ifndef DEF_GPIO
|
||||||
|
#define DEF_GPIO
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class gpio
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
volatile uint32_t *gpioreg;
|
||||||
|
gpio(uint32_t base, uint32_t len);
|
||||||
|
|
||||||
|
uint32_t GetPeripheralBase();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define DMA_BASE (0x00007000 )
|
||||||
|
#define DMA_LEN 0xF00
|
||||||
|
|
||||||
|
#define BCM2708_DMA_SRC_IGNOR (1<<11)
|
||||||
|
#define BCM2708_DMA_SRC_INC (1<<8)
|
||||||
|
#define BCM2708_DMA_DST_IGNOR (1<<7)
|
||||||
|
#define BCM2708_DMA_NO_WIDE_BURSTS (1<<26)
|
||||||
|
#define BCM2708_DMA_WAIT_RESP (1<<3)
|
||||||
|
#define BCM2708_DMA_SET_INT (1<<0)
|
||||||
|
|
||||||
|
#define BCM2708_DMA_D_DREQ (1<<6)
|
||||||
|
#define BCM2708_DMA_PER_MAP(x) ((x)<<16)
|
||||||
|
#define BCM2708_DMA_END (1<<1)
|
||||||
|
#define BCM2708_DMA_RESET (1<<31)
|
||||||
|
#define BCM2708_DMA_ABORT (1<<30)
|
||||||
|
#define BCM2708_DMA_INT (1<<2)
|
||||||
|
|
||||||
|
#define DMA_CS (0x00/4)
|
||||||
|
#define DMA_CONBLK_AD (0x04/4)
|
||||||
|
#define DMA_DEBUG (0x20/4)
|
||||||
|
|
||||||
|
#define DMA_CS_RESET (1<<31)
|
||||||
|
#define DMA_CS_ABORT (1<<30)
|
||||||
|
#define DMA_CS_DISDEBUG (1<<28)
|
||||||
|
#define DMA_CS_INT (1<<2)
|
||||||
|
#define DMA_CS_END (1<<1)
|
||||||
|
#define DMA_CS_ACTIVE (1<<0)
|
||||||
|
#define DMA_CS_PRIORITY(x) ((x)&0xf << 16)
|
||||||
|
#define DMA_CS_PANIC_PRIORITY(x) ((x)&0xf << 20)
|
||||||
|
|
||||||
|
class dmagpio:public gpio
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
dmagpio();
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//************************************ GENERAL GPIO ***************************************
|
||||||
|
|
||||||
|
#define GENERAL_BASE (0x00200000)
|
||||||
|
#define GENERAL_LEN 0xB4
|
||||||
|
|
||||||
|
#define GPFSEL0 (0x00/4)
|
||||||
|
#define GPFSEL1 (0x04/4)
|
||||||
|
#define GPFSEL2 (0x08/4)
|
||||||
|
#define GPPUD (0x94/4)
|
||||||
|
#define GPPUDCLK0 (0x9C/4)
|
||||||
|
|
||||||
|
enum {fsel_input,fsel_output,fsel_alt5,fsel_alt4,fsel_alt0,fsel_alt1,fsel_alt2,fsel_alt3};
|
||||||
|
|
||||||
|
class generalgpio:public gpio
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
generalgpio();
|
||||||
|
int setmode(uint32_t gpio, uint32_t mode);
|
||||||
|
~generalgpio();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add for PLL frequency CTRL wihout divider
|
||||||
|
// https://github.com/raspberrypi/linux/blob/rpi-4.9.y/drivers/clk/bcm/clk-bcm2835.c
|
||||||
|
// See interesting patch for jitter https://github.com/raspberrypi/linux/commit/76527b4e6a5dbe55e0b2d8ab533c2388b36c86be
|
||||||
|
|
||||||
|
#define CLK_BASE (0x00101000)
|
||||||
|
#define CLK_LEN 0x1300
|
||||||
|
|
||||||
|
#define CORECLK_CNTL (0x08/4)
|
||||||
|
#define CORECLK_DIV (0x0c/4)
|
||||||
|
#define GPCLK_CNTL (0x70/4)
|
||||||
|
#define GPCLK_DIV (0x74/4)
|
||||||
|
#define EMMCCLK_CNTL (0x1C0/4)
|
||||||
|
#define EMMCCLK_DIV (0x1C4/4)
|
||||||
|
|
||||||
|
#define CM_LOCK (0x114/4)
|
||||||
|
# define CM_LOCK_FLOCKH (1<<12)
|
||||||
|
# define CM_LOCK_FLOCKD (1<<11)
|
||||||
|
# define CM_LOCK_FLOCKC (1<<10)
|
||||||
|
# define CM_LOCK_FLOCKB (1<<9)
|
||||||
|
# define CM_LOCK_FLOCKA (1<<8)
|
||||||
|
|
||||||
|
#define PLLA_CTRL (0x1100/4)
|
||||||
|
#define PLLA_FRAC (0x1200/4)
|
||||||
|
#define PLLA_DSI0 (0x1300/4)
|
||||||
|
#define PLLA_CORE (0x1400/4)
|
||||||
|
#define PLLA_PER (0x1500/4)
|
||||||
|
#define PLLA_CCP2 (0x1600/4)
|
||||||
|
|
||||||
|
#define PLLB_CTRL (0x11e0/4)
|
||||||
|
#define PLLB_FRAC (0x12e0/4)
|
||||||
|
#define PLLB_ARM (0x13e0/4)
|
||||||
|
#define PLLB_SP0 (0x14e0/4)
|
||||||
|
#define PLLB_SP1 (0x15e0/4)
|
||||||
|
#define PLLB_SP2 (0x16e0/4)
|
||||||
|
|
||||||
|
#define PLLC_CTRL (0x1120/4)
|
||||||
|
#define PLLC_FRAC (0x1220/4)
|
||||||
|
#define PLLC_CORE2 (0x1320/4)
|
||||||
|
#define PLLC_CORE1 (0x1420/4)
|
||||||
|
#define PLLC_PER (0x1520/4)
|
||||||
|
#define PLLC_CORE0 (0x1620/4)
|
||||||
|
|
||||||
|
#define PLLD_CTRL (0x1140/4)
|
||||||
|
#define PLLD_FRAC (0x1240/4)
|
||||||
|
#define PLLD_DSI0 (0x1340/4)
|
||||||
|
#define PLLD_CORE (0x1440/4)
|
||||||
|
#define PLLD_PER (0x1540/4)
|
||||||
|
#define PLLD_DSI1 (0x1640/4)
|
||||||
|
|
||||||
|
#define PLLH_CTRL (0x1160/4)
|
||||||
|
#define PLLH_FRAC (0x1260/4)
|
||||||
|
#define PLLH_AUX (0x1360/4)
|
||||||
|
#define PLLH_RCAL (0x1460/4)
|
||||||
|
#define PLLH_PIX (0x1560/4)
|
||||||
|
#define PLLH_STS (0x1660/4)
|
||||||
|
|
||||||
|
#define XOSC_CTRL (0x1190/4)
|
||||||
|
#define XOSC_FREQUENCY 19200000
|
||||||
|
|
||||||
|
enum {clk_gnd,clk_osc,clk_debug0,clk_debug1,clk_plla,clk_pllc,clk_plld,clk_hdmi};
|
||||||
|
|
||||||
|
class clkgpio:public gpio
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
int pllnumber;
|
||||||
|
int Mash;
|
||||||
|
uint64_t Pllfrequency;
|
||||||
|
bool ModulateFromMasterPLL=false;
|
||||||
|
uint64_t CentralFrequency=0;
|
||||||
|
generalgpio gengpio;
|
||||||
|
public:
|
||||||
|
int PllFixDivider=8; //Fix divider from the master clock in advanced mode
|
||||||
|
|
||||||
|
clkgpio();
|
||||||
|
~clkgpio();
|
||||||
|
int SetPllNumber(int PllNo,int MashType);
|
||||||
|
uint64_t GetPllFrequency(int PllNo);
|
||||||
|
void print_clock_tree(void);
|
||||||
|
int SetFrequency(int Frequency);
|
||||||
|
int SetClkDivFrac(uint32_t Div,uint32_t Frac);
|
||||||
|
void SetPhase(bool inversed);
|
||||||
|
void SetAdvancedPllMode(bool Advanced);
|
||||||
|
int SetCenterFrequency(uint64_t Frequency,int Bandwidth);
|
||||||
|
int ComputeBestLO(uint64_t Frequency,int Bandwidth);
|
||||||
|
int SetMasterMultFrac(uint32_t Mult,uint32_t Frac);
|
||||||
|
uint32_t GetMasterFrac(int Frequency);
|
||||||
|
void enableclk(int gpio);
|
||||||
|
void disableclk(int gpio);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//************************************ PWM GPIO ***************************************
|
||||||
|
|
||||||
|
#define PWM_BASE (0x0020C000)
|
||||||
|
#define PWM_LEN 0x28
|
||||||
|
|
||||||
|
#define PWM_CTL (0x00/4)
|
||||||
|
#define PWM_DMAC (0x08/4)
|
||||||
|
#define PWM_RNG1 (0x10/4)
|
||||||
|
#define PWM_RNG2 (0x20/4)
|
||||||
|
#define PWM_FIFO (0x18/4)
|
||||||
|
|
||||||
|
#define PWMCLK_CNTL (40) // Clk register
|
||||||
|
#define PWMCLK_DIV (41) // Clk register
|
||||||
|
|
||||||
|
|
||||||
|
#define PWMCTL_MSEN2 (1<<15)
|
||||||
|
#define PWMCTL_USEF2 (1<<13)
|
||||||
|
#define PWMCTL_RPTL2 (1<<10)
|
||||||
|
#define PWMCTL_MODE2 (1<<9)
|
||||||
|
#define PWMCTL_PWEN2 (1<<8)
|
||||||
|
|
||||||
|
#define PWMCTL_MSEN1 (1<<7)
|
||||||
|
#define PWMCTL_CLRF (1<<6)
|
||||||
|
#define PWMCTL_USEF1 (1<<5)
|
||||||
|
#define PWMCTL_POLA1 (1<<4)
|
||||||
|
#define PWMCTL_RPTL1 (1<<2)
|
||||||
|
#define PWMCTL_MODE1 (1<<1)
|
||||||
|
#define PWMCTL_PWEN1 (1<<0)
|
||||||
|
#define PWMDMAC_ENAB (1<<31)
|
||||||
|
#define PWMDMAC_THRSHLD ((15<<8)|(15<<0))
|
||||||
|
enum pwmmode{pwm1pin,pwm2pin,pwm1pinrepeat};
|
||||||
|
|
||||||
|
class pwmgpio:public gpio
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
clkgpio clk;
|
||||||
|
int pllnumber;
|
||||||
|
int Mash;
|
||||||
|
int Prediv; //Range of PWM
|
||||||
|
uint64_t Pllfrequency;
|
||||||
|
bool ModulateFromMasterPLL=false;
|
||||||
|
int ModePwm=pwm1pin;
|
||||||
|
generalgpio gengpio;
|
||||||
|
public:
|
||||||
|
pwmgpio();
|
||||||
|
~pwmgpio();
|
||||||
|
int SetPllNumber(int PllNo,int MashType);
|
||||||
|
uint64_t GetPllFrequency(int PllNo);
|
||||||
|
int SetFrequency(uint64_t Frequency);
|
||||||
|
int SetPrediv(int predivisor);
|
||||||
|
void SetMode(int Mode);
|
||||||
|
void enablepwm(int gpio,int PwmNumber);
|
||||||
|
void disablepwm(int gpio);
|
||||||
|
};
|
||||||
|
|
||||||
|
//******************************* PCM GPIO (I2S) ***********************************
|
||||||
|
#define PCM_BASE (0x00203000)
|
||||||
|
#define PCM_LEN 0x24
|
||||||
|
|
||||||
|
#define PCM_CS_A (0x00/4)
|
||||||
|
#define PCM_FIFO_A (0x04/4)
|
||||||
|
#define PCM_MODE_A (0x08/4)
|
||||||
|
#define PCM_RXC_A (0x0c/4)
|
||||||
|
#define PCM_TXC_A (0x10/4)
|
||||||
|
#define PCM_DREQ_A (0x14/4)
|
||||||
|
#define PCM_INTEN_A (0x18/4)
|
||||||
|
#define PCM_INT_STC_A (0x1c/4)
|
||||||
|
#define PCM_GRAY (0x20/4)
|
||||||
|
|
||||||
|
#define PCMCLK_CNTL (38) // Clk register
|
||||||
|
#define PCMCLK_DIV (39) // Clk register
|
||||||
|
|
||||||
|
class pcmgpio:public gpio
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
clkgpio clk;
|
||||||
|
int pllnumber;
|
||||||
|
int Mash;
|
||||||
|
int Prediv; //Range of PCM
|
||||||
|
|
||||||
|
uint64_t Pllfrequency;
|
||||||
|
int SetPrediv(int predivisor);
|
||||||
|
|
||||||
|
public:
|
||||||
|
pcmgpio();
|
||||||
|
~pcmgpio();
|
||||||
|
int SetPllNumber(int PllNo,int MashType);
|
||||||
|
uint64_t GetPllFrequency(int PllNo);
|
||||||
|
int SetFrequency(uint64_t Frequency);
|
||||||
|
int ComputePrediv(uint64_t Frequency);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//******************************* PAD GPIO (Amplitude) ***********************************
|
||||||
|
#define PADS_GPIO (0x00100000)
|
||||||
|
#define PADS_GPIO_LEN (0x40/4)
|
||||||
|
|
||||||
|
#define PADS_GPIO_0 (0x2C/4)
|
||||||
|
#define PADS_GPIO_1 (0x30/4)
|
||||||
|
#define PADS_GPIO_2 (0x34/4)
|
||||||
|
|
||||||
|
class padgpio:public gpio
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
padgpio();
|
||||||
|
~padgpio();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
165
src/iqdmasync.cpp
Normal file
165
src/iqdmasync.cpp
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 Evariste COURJAUD F5OEO
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "iqdmasync.h"
|
||||||
|
|
||||||
|
|
||||||
|
iqdmasync::iqdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize):bufferdma(Channel,FifoSize,4,3)
|
||||||
|
{
|
||||||
|
// Usermem :
|
||||||
|
// FRAC frequency
|
||||||
|
// PAD Amplitude
|
||||||
|
// FSEL for amplitude 0
|
||||||
|
|
||||||
|
tunefreq=TuneFrequency;
|
||||||
|
clkgpio::SetAdvancedPllMode(true);
|
||||||
|
clkgpio::SetCenterFrequency(TuneFrequency,SampleRate); // Write Mult Int and Frac : FixMe carrier is already there
|
||||||
|
clkgpio::SetFrequency(0);
|
||||||
|
clkgpio::enableclk(4);
|
||||||
|
syncwithpwm=false;
|
||||||
|
|
||||||
|
if(syncwithpwm)
|
||||||
|
{
|
||||||
|
pwmgpio::SetPllNumber(clk_plld,1);
|
||||||
|
pwmgpio::SetFrequency(SampleRate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pcmgpio::SetPllNumber(clk_plld,1);
|
||||||
|
pcmgpio::SetFrequency(SampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
mydsp.samplerate=SampleRate;
|
||||||
|
|
||||||
|
padgpio pad;
|
||||||
|
Originfsel=pad.gpioreg[PADS_GPIO_0];
|
||||||
|
|
||||||
|
SetDmaAlgo();
|
||||||
|
|
||||||
|
|
||||||
|
// Note : Spurious are at +/-(19.2MHZ/2^20)*Div*N : (N=1,2,3...) So we need to have a big div to spurious away BUT
|
||||||
|
// Spurious are ALSO at +/-(19.2MHZ/2^20)*(2^20-Div)*N
|
||||||
|
// Max spurious avoid is to be in the center ! Theory shoud be that spurious are set away at 19.2/2= 9.6Mhz ! But need to get account of div of PLLClock
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
iqdmasync::~iqdmasync()
|
||||||
|
{
|
||||||
|
padgpio pad;
|
||||||
|
pad.gpioreg[PADS_GPIO_0]=Originfsel;
|
||||||
|
clkgpio::disableclk(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iqdmasync::SetPhase(bool inversed)
|
||||||
|
{
|
||||||
|
clkgpio::SetPhase(inversed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iqdmasync::SetDmaAlgo()
|
||||||
|
{
|
||||||
|
dma_cb_t *cbp = cbarray;
|
||||||
|
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
|
||||||
|
{
|
||||||
|
|
||||||
|
//@0
|
||||||
|
//Set Amplitude by writing to PADS
|
||||||
|
cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample+1]);
|
||||||
|
cbp->dst = 0x7E000000+(PADS_GPIO_0<<2)+PADS_GPIO;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
//@1
|
||||||
|
//Set Amplitude to FSEL for amplitude=0
|
||||||
|
cbp->info = 0;//BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample+2]);
|
||||||
|
cbp->dst = 0x7E000000 + (GPFSEL0<<2)+GENERAL_BASE;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
//@2 Write a frequency sample
|
||||||
|
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
|
||||||
|
cbp->dst = 0x7E000000 + (PLLA_FRAC<<2) + CLK_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
|
||||||
|
//@3 Delay
|
||||||
|
if(syncwithpwm)
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
|
||||||
|
else
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);
|
||||||
|
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
|
||||||
|
if(syncwithpwm)
|
||||||
|
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
|
||||||
|
else
|
||||||
|
cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cbp--;
|
||||||
|
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
|
||||||
|
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void iqdmasync::SetIQSample(uint32_t Index,liquid_float_complex sample)
|
||||||
|
{
|
||||||
|
Index=Index%buffersize;
|
||||||
|
mydsp.pushsample(sample);
|
||||||
|
/*if(mydsp.frequency>2250) mydsp.frequency=2250;
|
||||||
|
if(mydsp.frequency<1000) mydsp.frequency=1000;*/
|
||||||
|
sampletab[Index*registerbysample]=(0x5A<<24)|GetMasterFrac(mydsp.frequency); //Frequency
|
||||||
|
int IntAmplitude=(int)(mydsp.amplitude*1e4*8.0)-1;
|
||||||
|
|
||||||
|
int IntAmplitudePAD=0;
|
||||||
|
if(IntAmplitude>7) IntAmplitudePAD=7;
|
||||||
|
if(IntAmplitude<0) IntAmplitudePAD=0;
|
||||||
|
sampletab[Index*registerbysample+1]=(0x5A<<24) + (IntAmplitudePAD&0x7) + (1<<4) + (0<<3); // Amplitude PAD
|
||||||
|
|
||||||
|
//sampletab[Index*registerbysample+2]=(Originfsel & ~(7 << 12)) | (4 << 12); //Alternate is CLK
|
||||||
|
if(IntAmplitude==-1)
|
||||||
|
{
|
||||||
|
sampletab[Index*registerbysample+2]=(Originfsel & ~(7 << 12)) | (0 << 12); //Pin is in -> Amplitude 0
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sampletab[Index*registerbysample+2]=(Originfsel & ~(7 << 12)) | (4 << 12); //Alternate is CLK
|
||||||
|
}
|
||||||
|
|
||||||
|
//fprintf(stderr,"amp%f %d\n",mydsp.amplitude,IntAmplitudePAD);
|
||||||
|
PushSample(Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
27
src/iqdmasync.h
Normal file
27
src/iqdmasync.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef DEF_IQDMASYNC
|
||||||
|
#define DEF_IQDMASYNC
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "dma.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "dsp.h"
|
||||||
|
#include <liquid/liquid.h>
|
||||||
|
|
||||||
|
|
||||||
|
class iqdmasync:public bufferdma,public clkgpio,public pwmgpio,public pcmgpio
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
uint64_t tunefreq;
|
||||||
|
bool syncwithpwm;
|
||||||
|
dsp mydsp;
|
||||||
|
uint32_t Originfsel; //Save the original FSEL GPIO
|
||||||
|
public:
|
||||||
|
iqdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize);
|
||||||
|
~iqdmasync();
|
||||||
|
void SetDmaAlgo();
|
||||||
|
|
||||||
|
void SetPhase(bool inversed);
|
||||||
|
void SetIQSample(uint32_t Index,liquid_float_complex sample);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
27
src/librpitx.h
Normal file
27
src/librpitx.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 Evariste COURJAUD F5OEO
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dma.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "fmdmasync.h"
|
||||||
|
#include "ngfmdmasync.h"
|
||||||
|
#include "iqdmasync.h"
|
||||||
|
#include "serialdmasync.h"
|
||||||
|
#include "phasedmasync.h"
|
||||||
|
#include "amdmasync.h"
|
||||||
|
#include "fskburst.h"
|
||||||
|
#include "dsp.h"
|
280
src/mailbox.c
Normal file
280
src/mailbox.c
Normal file
|
@ -0,0 +1,280 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2012, Broadcom Europe Ltd.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the copyright holder nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "mailbox.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void *mapmem(unsigned base, unsigned size)
|
||||||
|
{
|
||||||
|
int mem_fd;
|
||||||
|
unsigned offset = base % PAGE_SIZE;
|
||||||
|
base = base - offset;
|
||||||
|
/* open /dev/mem */
|
||||||
|
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
|
||||||
|
printf("can't open /dev/mem\nThis program should be run as root. Try prefixing command with: sudo\n");
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
void *mem = mmap(
|
||||||
|
0,
|
||||||
|
size,
|
||||||
|
PROT_READ|PROT_WRITE,
|
||||||
|
MAP_SHARED/*|MAP_FIXED*/,
|
||||||
|
mem_fd,
|
||||||
|
base);
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("base=0x%x, mem=%p\n", base, mem);
|
||||||
|
#endif
|
||||||
|
if (mem == MAP_FAILED) {
|
||||||
|
printf("mmap error %d\n", (int)mem);
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
close(mem_fd);
|
||||||
|
return (char *)mem + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *unmapmem(void *addr, unsigned size)
|
||||||
|
{
|
||||||
|
int s = munmap(addr, size);
|
||||||
|
if (s != 0) {
|
||||||
|
printf("munmap error %d\n", s);
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* use ioctl to send mbox property message
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int mbox_property(int file_desc, void *buf)
|
||||||
|
{
|
||||||
|
int ret_val = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf);
|
||||||
|
|
||||||
|
if (ret_val < 0) {
|
||||||
|
printf("ioctl_set_msg failed:%d\n", ret_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
unsigned *p = buf; int i; unsigned size = *(unsigned *)buf;
|
||||||
|
for (i=0; i<size/4; i++)
|
||||||
|
printf("%04x: 0x%08x\n", i*sizeof *p, p[i]);
|
||||||
|
#endif
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
unsigned p[32];
|
||||||
|
//printf("Requesting %d bytes\n", size);
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x3000c; // (the tag id)
|
||||||
|
p[i++] = 12; // (size of the buffer)
|
||||||
|
p[i++] = 12; // (size of the data)
|
||||||
|
p[i++] = size; // (num bytes? or pages?)
|
||||||
|
p[i++] = align; // (alignment)
|
||||||
|
p[i++] = flags; // (MEM_FLAG_L1_NONALLOCATING)
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i*sizeof *p; // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned mem_free(int file_desc, unsigned handle)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
unsigned p[32];
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x3000f; // (the tag id)
|
||||||
|
p[i++] = 4; // (size of the buffer)
|
||||||
|
p[i++] = 4; // (size of the data)
|
||||||
|
p[i++] = handle;
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i*sizeof *p; // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned mem_lock(int file_desc, unsigned handle)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
unsigned p[32];
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x3000d; // (the tag id)
|
||||||
|
p[i++] = 4; // (size of the buffer)
|
||||||
|
p[i++] = 4; // (size of the data)
|
||||||
|
p[i++] = handle;
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i*sizeof *p; // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned mem_unlock(int file_desc, unsigned handle)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
unsigned p[32];
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x3000e; // (the tag id)
|
||||||
|
p[i++] = 4; // (size of the buffer)
|
||||||
|
p[i++] = 4; // (size of the data)
|
||||||
|
p[i++] = handle;
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i*sizeof *p; // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
unsigned p[32];
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x30010; // (the tag id)
|
||||||
|
p[i++] = 28; // (size of the buffer)
|
||||||
|
p[i++] = 28; // (size of the data)
|
||||||
|
p[i++] = code;
|
||||||
|
p[i++] = r0;
|
||||||
|
p[i++] = r1;
|
||||||
|
p[i++] = r2;
|
||||||
|
p[i++] = r3;
|
||||||
|
p[i++] = r4;
|
||||||
|
p[i++] = r5;
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i*sizeof *p; // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned qpu_enable(int file_desc, unsigned enable)
|
||||||
|
{
|
||||||
|
int i=0;
|
||||||
|
unsigned p[32];
|
||||||
|
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
|
||||||
|
p[i++] = 0x30012; // (the tag id)
|
||||||
|
p[i++] = 4; // (size of the buffer)
|
||||||
|
p[i++] = 4; // (size of the data)
|
||||||
|
p[i++] = enable;
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i*sizeof *p; // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout) {
|
||||||
|
int i=0;
|
||||||
|
unsigned p[32];
|
||||||
|
|
||||||
|
p[i++] = 0; // size
|
||||||
|
p[i++] = 0x00000000; // process request
|
||||||
|
p[i++] = 0x30011; // (the tag id)
|
||||||
|
p[i++] = 16; // (size of the buffer)
|
||||||
|
p[i++] = 16; // (size of the data)
|
||||||
|
p[i++] = num_qpus;
|
||||||
|
p[i++] = control;
|
||||||
|
p[i++] = noflush;
|
||||||
|
p[i++] = timeout; // ms
|
||||||
|
|
||||||
|
p[i++] = 0x00000000; // end tag
|
||||||
|
p[0] = i*sizeof *p; // actual size
|
||||||
|
|
||||||
|
mbox_property(file_desc, p);
|
||||||
|
return p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
int mbox_open() {
|
||||||
|
int file_desc;
|
||||||
|
|
||||||
|
// Open a char device file used for communicating with kernel mbox driver.
|
||||||
|
file_desc = open(VCIO_DEVICE_FILE_NAME, 0);
|
||||||
|
if(file_desc >= 0) {
|
||||||
|
printf("Using mbox device " VCIO_DEVICE_FILE_NAME ".\n");
|
||||||
|
return file_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to create one
|
||||||
|
unlink(LOCAL_DEVICE_FILE_NAME);
|
||||||
|
if(mknod(LOCAL_DEVICE_FILE_NAME, S_IFCHR|0600, makedev(MAJOR_NUM_A, 0)) >= 0 &&
|
||||||
|
(file_desc = open(LOCAL_DEVICE_FILE_NAME, 0)) >= 0) {
|
||||||
|
printf("Using local mbox device file with major %d.\n", MAJOR_NUM_A);
|
||||||
|
return file_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink(LOCAL_DEVICE_FILE_NAME);
|
||||||
|
if(mknod(LOCAL_DEVICE_FILE_NAME, S_IFCHR|0600, makedev(MAJOR_NUM_B, 0)) >= 0 &&
|
||||||
|
(file_desc = open(LOCAL_DEVICE_FILE_NAME, 0)) >= 0) {
|
||||||
|
printf("Using local mbox device file with major %d.\n", MAJOR_NUM_B);
|
||||||
|
return file_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return file_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mbox_close(int file_desc) {
|
||||||
|
close(file_desc);
|
||||||
|
}
|
56
src/mailbox.h
Normal file
56
src/mailbox.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2012, Broadcom Europe Ltd.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the copyright holder nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEF_MAILBOX
|
||||||
|
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
// Newer kernels (>= 4.1) use major 249, older ones major 100.
|
||||||
|
#define MAJOR_NUM_A 249
|
||||||
|
#define MAJOR_NUM_B 100
|
||||||
|
#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM_B, 0, char *)
|
||||||
|
|
||||||
|
#define LOCAL_DEVICE_FILE_NAME "/dev/rpidatv-mb"
|
||||||
|
#define VCIO_DEVICE_FILE_NAME "/dev/vcio"
|
||||||
|
|
||||||
|
#define PAGE_SIZE (4*1024)
|
||||||
|
|
||||||
|
|
||||||
|
int mbox_open();
|
||||||
|
void mbox_close(int file_desc);
|
||||||
|
|
||||||
|
unsigned get_version(int file_desc);
|
||||||
|
unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags);
|
||||||
|
unsigned mem_free(int file_desc, unsigned handle);
|
||||||
|
unsigned mem_lock(int file_desc, unsigned handle);
|
||||||
|
unsigned mem_unlock(int file_desc, unsigned handle);
|
||||||
|
void *mapmem(unsigned base, unsigned size);
|
||||||
|
void *unmapmem(void *addr, unsigned size);
|
||||||
|
|
||||||
|
unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5);
|
||||||
|
unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout);
|
||||||
|
unsigned qpu_enable(int file_desc, unsigned enable);
|
||||||
|
#endif
|
117
src/ngfmdmasync.cpp
Normal file
117
src/ngfmdmasync.cpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 Evariste COURJAUD F5OEO
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "ngfmdmasync.h"
|
||||||
|
|
||||||
|
|
||||||
|
ngfmdmasync::ngfmdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize):bufferdma(Channel,FifoSize,2,1)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
tunefreq=TuneFrequency;
|
||||||
|
clkgpio::SetAdvancedPllMode(true);
|
||||||
|
clkgpio::SetCenterFrequency(TuneFrequency,SampleRate); // Write Mult Int and Frac : FixMe carrier is already there
|
||||||
|
clkgpio::SetFrequency(0);
|
||||||
|
clkgpio::enableclk(4); // GPIO 4 CLK by default
|
||||||
|
syncwithpwm=false;
|
||||||
|
|
||||||
|
if(syncwithpwm)
|
||||||
|
{
|
||||||
|
pwmgpio::SetPllNumber(clk_plld,1);
|
||||||
|
pwmgpio::SetFrequency(SampleRate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pcmgpio::SetPllNumber(clk_plld,1);
|
||||||
|
pcmgpio::SetFrequency(SampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SetDmaAlgo();
|
||||||
|
|
||||||
|
|
||||||
|
// Note : Spurious are at +/-(19.2MHZ/2^20)*Div*N : (N=1,2,3...) So we need to have a big div to spurious away BUT
|
||||||
|
// Spurious are ALSO at +/-(19.2MHZ/2^20)*(2^20-Div)*N
|
||||||
|
// Max spurious avoid is to be in the center ! Theory shoud be that spurious are set away at 19.2/2= 9.6Mhz ! But need to get account of div of PLLClock
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngfmdmasync::~ngfmdmasync()
|
||||||
|
{
|
||||||
|
clkgpio::disableclk(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ngfmdmasync::SetPhase(bool inversed)
|
||||||
|
{
|
||||||
|
clkgpio::SetPhase(inversed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ngfmdmasync::SetDmaAlgo()
|
||||||
|
{
|
||||||
|
dma_cb_t *cbp = cbarray;
|
||||||
|
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// Write a frequency sample
|
||||||
|
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
|
||||||
|
cbp->dst = 0x7E000000 + (PLLA_FRAC<<2) + CLK_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
|
||||||
|
// Delay
|
||||||
|
if(syncwithpwm)
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
|
||||||
|
else
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);
|
||||||
|
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
|
||||||
|
if(syncwithpwm)
|
||||||
|
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
|
||||||
|
else
|
||||||
|
cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cbp--;
|
||||||
|
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
|
||||||
|
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ngfmdmasync::SetFrequencySample(uint32_t Index,int Frequency)
|
||||||
|
{
|
||||||
|
Index=Index%buffersize;
|
||||||
|
sampletab[Index]=(0x5A<<24)|GetMasterFrac(Frequency);
|
||||||
|
//fprintf(stderr,"Frac=%d\n",GetMasterFrac(Frequency));
|
||||||
|
PushSample(Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
22
src/ngfmdmasync.h
Normal file
22
src/ngfmdmasync.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef DEF_NGFMDMASYNC
|
||||||
|
#define DEF_NGFMDMASYNC
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "dma.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
|
||||||
|
class ngfmdmasync:public bufferdma,public clkgpio,public pwmgpio,public pcmgpio
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
uint64_t tunefreq;
|
||||||
|
bool syncwithpwm;
|
||||||
|
public:
|
||||||
|
ngfmdmasync(uint64_t TuneFrequency,uint32_t SampleRate,int Channel,uint32_t FifoSize);
|
||||||
|
~ngfmdmasync();
|
||||||
|
void SetDmaAlgo();
|
||||||
|
|
||||||
|
void SetPhase(bool inversed);
|
||||||
|
void SetFrequencySample(uint32_t Index,int Frequency);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
133
src/phasedmasync.cpp
Normal file
133
src/phasedmasync.cpp
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 Evariste COURJAUD F5OEO
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "phasedmasync.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
phasedmasync::phasedmasync(uint64_t TuneFrequency,uint32_t SampleRate,int NumberOfPhase,int Channel,uint32_t FifoSize):bufferdma(Channel,FifoSize,2,1) // Number of phase between 2 and 16
|
||||||
|
{
|
||||||
|
|
||||||
|
SetMode(pwm1pinrepeat);
|
||||||
|
pwmgpio::SetPllNumber(clk_plla,0);
|
||||||
|
|
||||||
|
tunefreq=TuneFrequency*NumberOfPhase;
|
||||||
|
|
||||||
|
if((NumberOfPhase==2)||(NumberOfPhase==4)||(NumberOfPhase==8)||(NumberOfPhase==16)||(NumberOfPhase==32))
|
||||||
|
NumbPhase=NumberOfPhase;
|
||||||
|
else
|
||||||
|
fprintf(stderr,"PWM critical error: %d is not a legal number of phase\n",NumberOfPhase);
|
||||||
|
clkgpio::SetAdvancedPllMode(true);
|
||||||
|
|
||||||
|
clkgpio::ComputeBestLO(tunefreq,0); // compute PWM divider according to MasterPLL clkgpio::PllFixDivider
|
||||||
|
double FloatMult=((double)(tunefreq)*clkgpio::PllFixDivider)/(double)(XOSC_FREQUENCY);
|
||||||
|
uint32_t freqctl = FloatMult*((double)(1<<20)) ;
|
||||||
|
int IntMultiply= freqctl>>20; // Need to be calculated to have a center frequency
|
||||||
|
freqctl&=0xFFFFF; // Fractionnal is 20bits
|
||||||
|
uint32_t FracMultiply=freqctl&0xFFFFF;
|
||||||
|
clkgpio::SetMasterMultFrac(IntMultiply,FracMultiply);
|
||||||
|
fprintf(stderr,"PWM Mult %d Frac %d Div %d\n",IntMultiply,FracMultiply,clkgpio::PllFixDivider);
|
||||||
|
|
||||||
|
|
||||||
|
pwmgpio::clk.gpioreg[PWMCLK_DIV] = 0x5A000000 | ((clkgpio::PllFixDivider)<<12); // PWM clock input divider
|
||||||
|
usleep(100);
|
||||||
|
pwmgpio::clk.gpioreg[PWMCLK_CNTL]= 0x5A000000 | (pwmgpio::Mash << 9) | pwmgpio::pllnumber|(1 << 4) ; //4 is START CLK
|
||||||
|
usleep(100);
|
||||||
|
pwmgpio::SetPrediv(32); //SetMode should be called before
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enablepwm(12,0); // By default PWM on GPIO 12/pin 32
|
||||||
|
|
||||||
|
|
||||||
|
pcmgpio::SetPllNumber(clk_plld,1);// Clk for Samplerate by PCM
|
||||||
|
pcmgpio::SetFrequency(SampleRate);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SetDmaAlgo();
|
||||||
|
|
||||||
|
uint32_t ZeroPhase=0;
|
||||||
|
switch(NumbPhase)
|
||||||
|
{
|
||||||
|
case 2:ZeroPhase=0xAAAAAAAA;break;//1,0,1,0 1,0,1,0
|
||||||
|
case 4:ZeroPhase=0xCCCCCCCC;break;//1,1,0,0 //4
|
||||||
|
case 8:ZeroPhase=0xF0F0F0F0;break;//1,1,1,1,0,0,0,0 //8
|
||||||
|
case 16:ZeroPhase=0xFF00FF00;break;//1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 //16
|
||||||
|
case 32:ZeroPhase=0xFFFF0000;break;//1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //32
|
||||||
|
default:fprintf(stderr,"Zero phase not initialized\n");break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i=0;i<NumbPhase;i++)
|
||||||
|
{
|
||||||
|
TabPhase[i]=ZeroPhase;
|
||||||
|
fprintf(stderr,"Phase[%d]=%x\n",i,TabPhase[i]);
|
||||||
|
ZeroPhase=(ZeroPhase<<1)|(ZeroPhase>>31);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
phasedmasync::~phasedmasync()
|
||||||
|
{
|
||||||
|
disablepwm(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void phasedmasync::SetDmaAlgo()
|
||||||
|
{
|
||||||
|
dma_cb_t *cbp = cbarray;
|
||||||
|
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP ;
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
|
||||||
|
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PCM_TX);
|
||||||
|
cbp->src = mem_virt_to_phys(cbarray); // Data is not important as we use it only to feed the PWM
|
||||||
|
cbp->dst = 0x7E000000 + (PCM_FIFO_A<<2) + PCM_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
cbp--;
|
||||||
|
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
|
||||||
|
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void phasedmasync::SetPhase(uint32_t Index,int Phase)
|
||||||
|
{
|
||||||
|
Index=Index%buffersize;
|
||||||
|
Phase=Phase%NumbPhase;
|
||||||
|
sampletab[Index]=TabPhase[Phase];
|
||||||
|
PushSample(Index);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
22
src/phasedmasync.h
Normal file
22
src/phasedmasync.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef DEF_PHASEDMASYNC
|
||||||
|
#define DEF_PHASEDMASYNC
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "dma.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
|
||||||
|
class phasedmasync:public bufferdma,public clkgpio,public pwmgpio,public pcmgpio,public generalgpio
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
uint64_t tunefreq;
|
||||||
|
int NumbPhase=2;
|
||||||
|
|
||||||
|
uint32_t TabPhase[32];//32 is Max Phase
|
||||||
|
public:
|
||||||
|
phasedmasync(uint64_t TuneFrequency,uint32_t SampleRate,int NumberOfPhase,int Channel,uint32_t FifoSize);
|
||||||
|
~phasedmasync();
|
||||||
|
void SetDmaAlgo();
|
||||||
|
void SetPhase(uint32_t Index,int Phase);
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
763
src/raspberry_pi_revision.c
Normal file
763
src/raspberry_pi_revision.c
Normal file
|
@ -0,0 +1,763 @@
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Andrew Duncan
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
// the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "raspberry_pi_revision.h"
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// The file /proc/cpuinfo contains a line such as:-
|
||||||
|
//
|
||||||
|
// Revision : 0003
|
||||||
|
//
|
||||||
|
// that holds the revision number of the Raspberry Pi.
|
||||||
|
// Known revisions (prior to the Raspberry Pi 2) are:
|
||||||
|
//
|
||||||
|
// +----------+---------+---------+--------+-------------+
|
||||||
|
// | Revision | Model | PCB Rev | Memory | Manufacture |
|
||||||
|
// +----------+---------+---------+--------+-------------+
|
||||||
|
// | 0000 | | | | |
|
||||||
|
// | 0001 | | | | |
|
||||||
|
// | 0002 | B | 1 | 256 MB | |
|
||||||
|
// | 0003 | B | 1 | 256 MB | |
|
||||||
|
// | 0004 | B | 2 | 256 MB | Sony |
|
||||||
|
// | 0005 | B | 2 | 256 MB | Qisda |
|
||||||
|
// | 0006 | B | 2 | 256 MB | Egoman |
|
||||||
|
// | 0007 | A | 2 | 256 MB | Egoman |
|
||||||
|
// | 0008 | A | 2 | 256 MB | Sony |
|
||||||
|
// | 0009 | A | 2 | 256 MB | Qisda |
|
||||||
|
// | 000a | | | | |
|
||||||
|
// | 000b | | | | |
|
||||||
|
// | 000c | | | | |
|
||||||
|
// | 000d | B | 2 | 512 MB | Egoman |
|
||||||
|
// | 000e | B | 2 | 512 MB | Sony |
|
||||||
|
// | 000f | B | 2 | 512 MB | Qisda |
|
||||||
|
// | 0010 | B+ | 1 | 512 MB | Sony |
|
||||||
|
// | 0011 | compute | 1 | 512 MB | Sony |
|
||||||
|
// | 0012 | A+ | 1 | 256 MB | Sony |
|
||||||
|
// | 0013 | B+ | 1 | 512 MB | Embest |
|
||||||
|
// | 0014 | compute | 1 | 512 MB | Sony |
|
||||||
|
// | 0015 | A+ | 1 | 256 MB | Sony |
|
||||||
|
// +----------+---------+---------+--------+-------------+
|
||||||
|
//
|
||||||
|
// If the Raspberry Pi has been over-volted (voiding the warranty) the
|
||||||
|
// revision number will have 100 at the front. e.g. 1000002.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// With the release of the Raspberry Pi 2, there is a new encoding of the
|
||||||
|
// Revision field in /proc/cpuinfo. The bit fields are as follows
|
||||||
|
//
|
||||||
|
// +----+----+----+----+----+----+----+----+
|
||||||
|
// |FEDC|BA98|7654|3210|FEDC|BA98|7654|3210|
|
||||||
|
// +----+----+----+----+----+----+----+----+
|
||||||
|
// | | | | | | | |AAAA|
|
||||||
|
// | | | | | |BBBB|BBBB| |
|
||||||
|
// | | | | |CCCC| | | |
|
||||||
|
// | | | |DDDD| | | | |
|
||||||
|
// | | | EEE| | | | | |
|
||||||
|
// | | |F | | | | | |
|
||||||
|
// | | G| | | | | | |
|
||||||
|
// | | H | | | | | | |
|
||||||
|
// +----+----+----+----+----+----+----+----+
|
||||||
|
// |1098|7654|3210|9876|5432|1098|7654|3210|
|
||||||
|
// +----+----+----+----+----+----+----+----+
|
||||||
|
//
|
||||||
|
// +---+-------+--------------+--------------------------------------------+
|
||||||
|
// | # | bits | contains | values |
|
||||||
|
// +---+-------+--------------+--------------------------------------------+
|
||||||
|
// | A | 00-03 | PCB Revision | (the pcb revision number) |
|
||||||
|
// | B | 04-11 | Model name | A, B, A+, B+, B Pi2, Alpha, Compute Module |
|
||||||
|
// | | | | unknown, unknown, Zero |
|
||||||
|
// | C | 12-15 | Processor | BCM2835, BCM2836, BCM2837 |
|
||||||
|
// | D | 16-19 | Manufacturer | Sony, Egoman, Embest, unknown, Embest |
|
||||||
|
// | E | 20-22 | Memory size | 256 MB, 512 MB, 1024 MB |
|
||||||
|
// | F | 23-23 | encoded flag | (if set, revision is a bit field) |
|
||||||
|
// | G | 24-24 | waranty bit | (if set, warranty void - Pre Pi2) |
|
||||||
|
// | H | 25-25 | waranty bit | (if set, warranty void - Post Pi2) |
|
||||||
|
// +---+-------+--------------+--------------------------------------------+
|
||||||
|
//
|
||||||
|
// Also, due to some early issues the warranty bit has been move from bit
|
||||||
|
// 24 to bit 25 of the revision number (i.e. 0x2000000).
|
||||||
|
//
|
||||||
|
// e.g.
|
||||||
|
//
|
||||||
|
// Revision : A01041
|
||||||
|
//
|
||||||
|
// A - PCB Revision - 1 (first revision)
|
||||||
|
// B - Model Name - 4 (Model B Pi 2)
|
||||||
|
// C - Processor - 1 (BCM2836)
|
||||||
|
// D - Manufacturer - 0 (Sony)
|
||||||
|
// E - Memory - 2 (1024 MB)
|
||||||
|
// F - Endcoded flag - 1 (encoded cpu info)
|
||||||
|
//
|
||||||
|
// Revision : A21041
|
||||||
|
//
|
||||||
|
// A - PCB Revision - 1 (first revision)
|
||||||
|
// B - Model Name - 4 (Model B Pi 2)
|
||||||
|
// C - Processor - 1 (BCM2836)
|
||||||
|
// D - Manufacturer - 2 (Embest)
|
||||||
|
// E - Memory - 2 (1024 MB)
|
||||||
|
// F - Endcoded flag - 1 (encoded cpu info)
|
||||||
|
//
|
||||||
|
// Revision : 900092
|
||||||
|
//
|
||||||
|
// A - PCB Revision - 2 (second revision)
|
||||||
|
// B - Model Name - 9 (Model Zero)
|
||||||
|
// C - Processor - 0 (BCM2835)
|
||||||
|
// D - Manufacturer - 0 (Sony)
|
||||||
|
// E - Memory - 1 (512 MB)
|
||||||
|
// F - Endcoded flag - 1 (encoded cpu info)
|
||||||
|
//
|
||||||
|
// Revision : A02082
|
||||||
|
//
|
||||||
|
// A - PCB Revision - 2 (first revision)
|
||||||
|
// B - Model Name - 8 (Model B Pi 3)
|
||||||
|
// C - Processor - 2 (BCM2837)
|
||||||
|
// D - Manufacturer - 0 (Sony)
|
||||||
|
// E - Memory - 2 (1024 MB)
|
||||||
|
// F - Endcoded flag - 1 (encoded cpu info)
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static RASPBERRY_PI_MEMORY_T revisionToMemory[] =
|
||||||
|
{
|
||||||
|
RPI_MEMORY_UNKNOWN, // 0
|
||||||
|
RPI_MEMORY_UNKNOWN, // 1
|
||||||
|
RPI_256MB, // 2
|
||||||
|
RPI_256MB, // 3
|
||||||
|
RPI_256MB, // 4
|
||||||
|
RPI_256MB, // 5
|
||||||
|
RPI_256MB, // 6
|
||||||
|
RPI_256MB, // 7
|
||||||
|
RPI_256MB, // 8
|
||||||
|
RPI_256MB, // 9
|
||||||
|
RPI_MEMORY_UNKNOWN, // A
|
||||||
|
RPI_MEMORY_UNKNOWN, // B
|
||||||
|
RPI_MEMORY_UNKNOWN, // C
|
||||||
|
RPI_512MB, // D
|
||||||
|
RPI_512MB, // E
|
||||||
|
RPI_512MB, // F
|
||||||
|
RPI_512MB, // 10
|
||||||
|
RPI_512MB, // 11
|
||||||
|
RPI_256MB, // 12
|
||||||
|
RPI_512MB, // 13
|
||||||
|
RPI_512MB, // 14
|
||||||
|
RPI_256MB // 15
|
||||||
|
};
|
||||||
|
|
||||||
|
static RASPBERRY_PI_MEMORY_T bitFieldToMemory[] =
|
||||||
|
{
|
||||||
|
RPI_256MB,
|
||||||
|
RPI_512MB,
|
||||||
|
RPI_1024MB
|
||||||
|
};
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static RASPBERRY_PI_PROCESSOR_T bitFieldToProcessor[] =
|
||||||
|
{
|
||||||
|
RPI_BROADCOM_2835,
|
||||||
|
RPI_BROADCOM_2836,
|
||||||
|
RPI_BROADCOM_2837
|
||||||
|
};
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static RASPBERRY_PI_I2C_DEVICE_T revisionToI2CDevice[] =
|
||||||
|
{
|
||||||
|
RPI_I2C_DEVICE_UNKNOWN, // 0
|
||||||
|
RPI_I2C_DEVICE_UNKNOWN, // 1
|
||||||
|
RPI_I2C_0, // 2
|
||||||
|
RPI_I2C_0, // 3
|
||||||
|
RPI_I2C_1, // 4
|
||||||
|
RPI_I2C_1, // 5
|
||||||
|
RPI_I2C_1, // 6
|
||||||
|
RPI_I2C_1, // 7
|
||||||
|
RPI_I2C_1, // 8
|
||||||
|
RPI_I2C_1, // 9
|
||||||
|
RPI_I2C_DEVICE_UNKNOWN, // A
|
||||||
|
RPI_I2C_DEVICE_UNKNOWN, // B
|
||||||
|
RPI_I2C_DEVICE_UNKNOWN, // C
|
||||||
|
RPI_I2C_1, // D
|
||||||
|
RPI_I2C_1, // E
|
||||||
|
RPI_I2C_1, // F
|
||||||
|
RPI_I2C_1, // 10
|
||||||
|
RPI_I2C_1, // 11
|
||||||
|
RPI_I2C_1, // 12
|
||||||
|
RPI_I2C_1, // 13
|
||||||
|
RPI_I2C_1, // 14
|
||||||
|
RPI_I2C_1 // 15
|
||||||
|
};
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static RASPBERRY_PI_MODEL_T bitFieldToModel[] =
|
||||||
|
{
|
||||||
|
RPI_MODEL_A,
|
||||||
|
RPI_MODEL_B,
|
||||||
|
RPI_MODEL_A_PLUS,
|
||||||
|
RPI_MODEL_B_PLUS,
|
||||||
|
RPI_MODEL_B_PI_2,
|
||||||
|
RPI_MODEL_ALPHA,
|
||||||
|
RPI_COMPUTE_MODULE,
|
||||||
|
RPI_MODEL_UNKNOWN,
|
||||||
|
RPI_MODEL_B_PI_3,
|
||||||
|
RPI_MODEL_ZERO
|
||||||
|
};
|
||||||
|
|
||||||
|
static RASPBERRY_PI_MODEL_T revisionToModel[] =
|
||||||
|
{
|
||||||
|
RPI_MODEL_UNKNOWN, // 0
|
||||||
|
RPI_MODEL_UNKNOWN, // 1
|
||||||
|
RPI_MODEL_B, // 2
|
||||||
|
RPI_MODEL_B, // 3
|
||||||
|
RPI_MODEL_B, // 4
|
||||||
|
RPI_MODEL_B, // 5
|
||||||
|
RPI_MODEL_B, // 6
|
||||||
|
RPI_MODEL_A, // 7
|
||||||
|
RPI_MODEL_A, // 8
|
||||||
|
RPI_MODEL_A, // 9
|
||||||
|
RPI_MODEL_UNKNOWN, // A
|
||||||
|
RPI_MODEL_UNKNOWN, // B
|
||||||
|
RPI_MODEL_UNKNOWN, // C
|
||||||
|
RPI_MODEL_B, // D
|
||||||
|
RPI_MODEL_B, // E
|
||||||
|
RPI_MODEL_B, // F
|
||||||
|
RPI_MODEL_B_PLUS, // 10
|
||||||
|
RPI_COMPUTE_MODULE, // 11
|
||||||
|
RPI_MODEL_A_PLUS, // 12
|
||||||
|
RPI_MODEL_B_PLUS, // 13
|
||||||
|
RPI_COMPUTE_MODULE, // 14
|
||||||
|
RPI_MODEL_A_PLUS // 15
|
||||||
|
};
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static RASPBERRY_PI_MANUFACTURER_T bitFieldToManufacturer[] =
|
||||||
|
{
|
||||||
|
RPI_MANUFACTURER_SONY,
|
||||||
|
RPI_MANUFACTURER_EGOMAN,
|
||||||
|
RPI_MANUFACTURER_EMBEST,
|
||||||
|
RPI_MANUFACTURER_UNKNOWN,
|
||||||
|
RPI_MANUFACTURER_EMBEST
|
||||||
|
};
|
||||||
|
|
||||||
|
static RASPBERRY_PI_MANUFACTURER_T revisionToManufacturer[] =
|
||||||
|
{
|
||||||
|
RPI_MANUFACTURER_UNKNOWN, // 0
|
||||||
|
RPI_MANUFACTURER_UNKNOWN, // 1
|
||||||
|
RPI_MANUFACTURER_UNKNOWN, // 2
|
||||||
|
RPI_MANUFACTURER_UNKNOWN, // 3
|
||||||
|
RPI_MANUFACTURER_SONY, // 4
|
||||||
|
RPI_MANUFACTURER_QISDA, // 5
|
||||||
|
RPI_MANUFACTURER_EGOMAN, // 6
|
||||||
|
RPI_MANUFACTURER_EGOMAN, // 7
|
||||||
|
RPI_MANUFACTURER_SONY, // 8
|
||||||
|
RPI_MANUFACTURER_QISDA, // 9
|
||||||
|
RPI_MANUFACTURER_UNKNOWN, // A
|
||||||
|
RPI_MANUFACTURER_UNKNOWN, // B
|
||||||
|
RPI_MANUFACTURER_UNKNOWN, // C
|
||||||
|
RPI_MANUFACTURER_EGOMAN, // D
|
||||||
|
RPI_MANUFACTURER_SONY, // E
|
||||||
|
RPI_MANUFACTURER_QISDA, // F
|
||||||
|
RPI_MANUFACTURER_SONY, // 10
|
||||||
|
RPI_MANUFACTURER_SONY, // 11
|
||||||
|
RPI_MANUFACTURER_SONY, // 12
|
||||||
|
RPI_MANUFACTURER_EMBEST, // 13
|
||||||
|
RPI_MANUFACTURER_SONY, // 14
|
||||||
|
RPI_MANUFACTURER_SONY // 15
|
||||||
|
};
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static int revisionToPcbRevision[] =
|
||||||
|
{
|
||||||
|
0, // 0
|
||||||
|
0, // 1
|
||||||
|
1, // 2
|
||||||
|
1, // 3
|
||||||
|
2, // 4
|
||||||
|
2, // 5
|
||||||
|
2, // 6
|
||||||
|
2, // 7
|
||||||
|
2, // 8
|
||||||
|
2, // 9
|
||||||
|
0, // A
|
||||||
|
0, // B
|
||||||
|
0, // C
|
||||||
|
2, // D
|
||||||
|
2, // E
|
||||||
|
2, // F
|
||||||
|
1, // 10
|
||||||
|
1, // 11
|
||||||
|
1, // 12
|
||||||
|
1, // 13
|
||||||
|
1, // 14
|
||||||
|
1 // 15
|
||||||
|
};
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Remove leading and trailing whitespace from a string.
|
||||||
|
|
||||||
|
static char *
|
||||||
|
trimWhiteSpace(
|
||||||
|
char *string)
|
||||||
|
{
|
||||||
|
if (string == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (isspace(*string))
|
||||||
|
{
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*string == '\0')
|
||||||
|
{
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *end = string;
|
||||||
|
|
||||||
|
while (*end)
|
||||||
|
{
|
||||||
|
++end;
|
||||||
|
}
|
||||||
|
--end;
|
||||||
|
|
||||||
|
while ((end > string) && isspace(*end))
|
||||||
|
{
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(end + 1) = 0;
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int
|
||||||
|
getRaspberryPiRevision()
|
||||||
|
{
|
||||||
|
int raspberryPiRevision = 0;
|
||||||
|
|
||||||
|
FILE *fp = fopen("/proc/cpuinfo", "r");
|
||||||
|
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
perror("/proc/cpuinfo");
|
||||||
|
return raspberryPiRevision;
|
||||||
|
}
|
||||||
|
|
||||||
|
char entry[80];
|
||||||
|
|
||||||
|
while (fgets(entry, sizeof(entry), fp) != NULL)
|
||||||
|
{
|
||||||
|
char* saveptr = NULL;
|
||||||
|
|
||||||
|
char *key = trimWhiteSpace(strtok_r(entry, ":", &saveptr));
|
||||||
|
char *value = trimWhiteSpace(strtok_r(NULL, ":", &saveptr));
|
||||||
|
|
||||||
|
if (strcasecmp("Revision", key) == 0)
|
||||||
|
{
|
||||||
|
raspberryPiRevision = strtol(value, NULL, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return raspberryPiRevision;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int
|
||||||
|
getRaspberryPiInformation(
|
||||||
|
RASPBERRY_PI_INFO_T *info)
|
||||||
|
{
|
||||||
|
int revision = getRaspberryPiRevision();
|
||||||
|
|
||||||
|
return getRaspberryPiInformationForRevision(revision, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int
|
||||||
|
getRaspberryPiInformationForRevision(
|
||||||
|
int revision,
|
||||||
|
RASPBERRY_PI_INFO_T *info)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (info != NULL)
|
||||||
|
{
|
||||||
|
info->memory = RPI_MEMORY_UNKNOWN;
|
||||||
|
info->processor = RPI_PROCESSOR_UNKNOWN;
|
||||||
|
info->i2cDevice = RPI_I2C_DEVICE_UNKNOWN;
|
||||||
|
info->model = RPI_MODEL_UNKNOWN;
|
||||||
|
info->manufacturer = RPI_MANUFACTURER_UNKNOWN;
|
||||||
|
info->pcbRevision = 0;
|
||||||
|
info->warrantyBit = 0;
|
||||||
|
info->revisionNumber = revision;
|
||||||
|
info->peripheralBase = RPI_PERIPHERAL_BASE_UNKNOWN;
|
||||||
|
|
||||||
|
if (revision != 0)
|
||||||
|
{
|
||||||
|
size_t maxOriginalRevision = (sizeof(revisionToModel) /
|
||||||
|
sizeof(revisionToModel[0])) - 1;
|
||||||
|
|
||||||
|
// remove warranty bit
|
||||||
|
|
||||||
|
revision &= ~0x3000000;
|
||||||
|
|
||||||
|
if (revision & 0x800000)
|
||||||
|
{
|
||||||
|
// Raspberry Pi2 style revision encoding
|
||||||
|
|
||||||
|
result = 2;
|
||||||
|
|
||||||
|
if (info->revisionNumber & 0x2000000)
|
||||||
|
{
|
||||||
|
info->warrantyBit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int memoryIndex = (revision & 0x700000) >> 20;
|
||||||
|
size_t knownMemoryValues = sizeof(bitFieldToMemory)
|
||||||
|
/ sizeof(bitFieldToMemory[0]);
|
||||||
|
|
||||||
|
if (memoryIndex < knownMemoryValues)
|
||||||
|
{
|
||||||
|
info->memory = bitFieldToMemory[memoryIndex];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info->memory = RPI_MEMORY_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int processorIndex = (revision & 0xF000) >> 12;
|
||||||
|
size_t knownProcessorValues = sizeof(bitFieldToProcessor)
|
||||||
|
/ sizeof(bitFieldToProcessor[0]);
|
||||||
|
if (processorIndex < knownProcessorValues)
|
||||||
|
{
|
||||||
|
info->processor = bitFieldToProcessor[processorIndex];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info->processor = RPI_PROCESSOR_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If some future firmware changes the Rev number of
|
||||||
|
// older Raspberry Pis, then need to work out the i2c
|
||||||
|
// device.
|
||||||
|
|
||||||
|
info->i2cDevice = RPI_I2C_1;
|
||||||
|
|
||||||
|
int modelIndex = (revision & 0xFF0) >> 4;
|
||||||
|
size_t knownModelValues = sizeof(bitFieldToModel)
|
||||||
|
/ sizeof(bitFieldToModel[0]);
|
||||||
|
|
||||||
|
if (modelIndex < knownModelValues)
|
||||||
|
{
|
||||||
|
info->model = bitFieldToModel[modelIndex];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info->model = RPI_MODEL_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int madeByIndex = (revision & 0xF0000) >> 16;
|
||||||
|
size_t knownManufacturerValues = sizeof(bitFieldToManufacturer)
|
||||||
|
/ sizeof(bitFieldToManufacturer[0]);
|
||||||
|
|
||||||
|
if (madeByIndex < knownManufacturerValues)
|
||||||
|
{
|
||||||
|
info->manufacturer = bitFieldToManufacturer[madeByIndex];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info->manufacturer = RPI_MANUFACTURER_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->pcbRevision = revision & 0xF;
|
||||||
|
}
|
||||||
|
else if (revision <= maxOriginalRevision)
|
||||||
|
{
|
||||||
|
// Original revision encoding
|
||||||
|
|
||||||
|
result = 1;
|
||||||
|
|
||||||
|
if (info->revisionNumber & 0x1000000)
|
||||||
|
{
|
||||||
|
info->warrantyBit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->memory = revisionToMemory[revision];
|
||||||
|
info->i2cDevice = revisionToI2CDevice[revision];
|
||||||
|
info->model = revisionToModel[revision];
|
||||||
|
info->manufacturer = revisionToManufacturer[revision];
|
||||||
|
info->pcbRevision = revisionToPcbRevision[revision];
|
||||||
|
|
||||||
|
if (info->model == RPI_MODEL_UNKNOWN)
|
||||||
|
{
|
||||||
|
info->processor = RPI_PROCESSOR_UNKNOWN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info->processor = RPI_BROADCOM_2835;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (info->processor)
|
||||||
|
{
|
||||||
|
case RPI_PROCESSOR_UNKNOWN:
|
||||||
|
|
||||||
|
info->peripheralBase = RPI_PERIPHERAL_BASE_UNKNOWN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_BROADCOM_2835:
|
||||||
|
|
||||||
|
info->peripheralBase = RPI_BROADCOM_2835_PERIPHERAL_BASE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_BROADCOM_2836:
|
||||||
|
|
||||||
|
info->peripheralBase = RPI_BROADCOM_2836_PERIPHERAL_BASE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_BROADCOM_2837:
|
||||||
|
|
||||||
|
info->peripheralBase = RPI_BROADCOM_2837_PERIPHERAL_BASE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const char *
|
||||||
|
raspberryPiMemoryToString(
|
||||||
|
RASPBERRY_PI_MEMORY_T memory)
|
||||||
|
{
|
||||||
|
const char *string = "unknown";
|
||||||
|
|
||||||
|
switch(memory)
|
||||||
|
{
|
||||||
|
case RPI_256MB:
|
||||||
|
|
||||||
|
string = "256 MB";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_512MB:
|
||||||
|
|
||||||
|
string = "512 MB";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_1024MB:
|
||||||
|
|
||||||
|
string = "1024 MB";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const char *
|
||||||
|
raspberryPiProcessorToString(
|
||||||
|
RASPBERRY_PI_PROCESSOR_T processor)
|
||||||
|
{
|
||||||
|
const char *string = "unknown";
|
||||||
|
|
||||||
|
switch(processor)
|
||||||
|
{
|
||||||
|
case RPI_BROADCOM_2835:
|
||||||
|
|
||||||
|
string = "Broadcom BCM2835";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_BROADCOM_2836:
|
||||||
|
|
||||||
|
string = "Broadcom BCM2836";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_BROADCOM_2837:
|
||||||
|
|
||||||
|
string = "Broadcom BCM2837";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const char *
|
||||||
|
raspberryPiI2CDeviceToString(
|
||||||
|
RASPBERRY_PI_I2C_DEVICE_T i2cDevice)
|
||||||
|
{
|
||||||
|
const char *string = "unknown";
|
||||||
|
|
||||||
|
switch(i2cDevice)
|
||||||
|
{
|
||||||
|
case RPI_I2C_0:
|
||||||
|
|
||||||
|
string = "/dev/i2c-0";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_I2C_1:
|
||||||
|
|
||||||
|
string = "/dev/i2c-1";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const char *
|
||||||
|
raspberryPiModelToString(
|
||||||
|
RASPBERRY_PI_MODEL_T model)
|
||||||
|
{
|
||||||
|
const char *string = "unknown";
|
||||||
|
|
||||||
|
switch(model)
|
||||||
|
{
|
||||||
|
case RPI_MODEL_A:
|
||||||
|
|
||||||
|
string = "Model A";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_MODEL_B:
|
||||||
|
|
||||||
|
string = "Model B";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_MODEL_A_PLUS:
|
||||||
|
|
||||||
|
string = "Model A+";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_MODEL_B_PLUS:
|
||||||
|
|
||||||
|
string = "Model B+";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_MODEL_B_PI_2:
|
||||||
|
|
||||||
|
string = "Model B Pi 2";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_MODEL_ALPHA:
|
||||||
|
|
||||||
|
string = "Alpha";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_COMPUTE_MODULE:
|
||||||
|
|
||||||
|
string = "Compute Module";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_MODEL_ZERO:
|
||||||
|
|
||||||
|
string = "Model Zero";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_MODEL_B_PI_3:
|
||||||
|
|
||||||
|
string = "Model B Pi 3";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const char *
|
||||||
|
raspberryPiManufacturerToString(
|
||||||
|
RASPBERRY_PI_MANUFACTURER_T manufacturer)
|
||||||
|
{
|
||||||
|
const char *string = "unknown";
|
||||||
|
|
||||||
|
switch(manufacturer)
|
||||||
|
{
|
||||||
|
case RPI_MANUFACTURER_SONY:
|
||||||
|
|
||||||
|
string = "Sony";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_MANUFACTURER_EGOMAN:
|
||||||
|
|
||||||
|
string = "Egoman";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_MANUFACTURER_QISDA:
|
||||||
|
|
||||||
|
string = "Qisda";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPI_MANUFACTURER_EMBEST:
|
||||||
|
|
||||||
|
string = "Embest";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
163
src/raspberry_pi_revision.h
Normal file
163
src/raspberry_pi_revision.h
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Andrew Duncan
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
// the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef RASPBERRY_PI_INFO_H
|
||||||
|
#define RASPBERRY_PI_INFO_H
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define RPI_PERIPHERAL_BASE_UNKNOWN 0
|
||||||
|
#define RPI_BROADCOM_2835_PERIPHERAL_BASE 0x20000000
|
||||||
|
#define RPI_BROADCOM_2836_PERIPHERAL_BASE 0x3F000000
|
||||||
|
#define RPI_BROADCOM_2837_PERIPHERAL_BASE 0x3F000000
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
RPI_MEMORY_UNKNOWN = -1,
|
||||||
|
RPI_256MB = 256,
|
||||||
|
RPI_512MB = 512,
|
||||||
|
RPI_1024MB = 1024,
|
||||||
|
}
|
||||||
|
RASPBERRY_PI_MEMORY_T;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
RPI_PROCESSOR_UNKNOWN = -1,
|
||||||
|
RPI_BROADCOM_2835 = 2835,
|
||||||
|
RPI_BROADCOM_2836 = 2836,
|
||||||
|
RPI_BROADCOM_2837 = 2837
|
||||||
|
}
|
||||||
|
RASPBERRY_PI_PROCESSOR_T;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
RPI_I2C_DEVICE_UNKNOWN = -1,
|
||||||
|
RPI_I2C_0 = 0,
|
||||||
|
RPI_I2C_1 = 1
|
||||||
|
}
|
||||||
|
RASPBERRY_PI_I2C_DEVICE_T;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
RPI_MODEL_UNKNOWN = -1,
|
||||||
|
RPI_MODEL_A,
|
||||||
|
RPI_MODEL_B,
|
||||||
|
RPI_MODEL_A_PLUS,
|
||||||
|
RPI_MODEL_B_PLUS,
|
||||||
|
RPI_MODEL_B_PI_2,
|
||||||
|
RPI_MODEL_ALPHA,
|
||||||
|
RPI_COMPUTE_MODULE,
|
||||||
|
RPI_MODEL_ZERO,
|
||||||
|
RPI_MODEL_B_PI_3
|
||||||
|
}
|
||||||
|
RASPBERRY_PI_MODEL_T;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
RPI_MANUFACTURER_UNKNOWN = -1,
|
||||||
|
RPI_MANUFACTURER_SONY,
|
||||||
|
RPI_MANUFACTURER_EGOMAN,
|
||||||
|
RPI_MANUFACTURER_QISDA,
|
||||||
|
RPI_MANUFACTURER_EMBEST,
|
||||||
|
}
|
||||||
|
RASPBERRY_PI_MANUFACTURER_T;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
RASPBERRY_PI_MEMORY_T memory;
|
||||||
|
RASPBERRY_PI_PROCESSOR_T processor;
|
||||||
|
RASPBERRY_PI_I2C_DEVICE_T i2cDevice;
|
||||||
|
RASPBERRY_PI_MODEL_T model;
|
||||||
|
RASPBERRY_PI_MANUFACTURER_T manufacturer;
|
||||||
|
int pcbRevision;
|
||||||
|
int warrantyBit;
|
||||||
|
int revisionNumber;
|
||||||
|
uint32_t peripheralBase;
|
||||||
|
}
|
||||||
|
RASPBERRY_PI_INFO_T;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// getRaspberryPiInformation()
|
||||||
|
//
|
||||||
|
// return - 0 - failed to get revision from /proc/cpuinfo
|
||||||
|
// 1 - found classic revision number
|
||||||
|
// 2 - found Pi 2 style revision number
|
||||||
|
|
||||||
|
int
|
||||||
|
getRaspberryPiInformation(
|
||||||
|
RASPBERRY_PI_INFO_T *info);
|
||||||
|
|
||||||
|
int
|
||||||
|
getRaspberryPiInformationForRevision(
|
||||||
|
int revision,
|
||||||
|
RASPBERRY_PI_INFO_T *info);
|
||||||
|
|
||||||
|
int
|
||||||
|
getRaspberryPiRevision(void);
|
||||||
|
|
||||||
|
const char *
|
||||||
|
raspberryPiMemoryToString(
|
||||||
|
RASPBERRY_PI_MEMORY_T memory);
|
||||||
|
|
||||||
|
const char *
|
||||||
|
raspberryPiProcessorToString(
|
||||||
|
RASPBERRY_PI_PROCESSOR_T processor);
|
||||||
|
|
||||||
|
const char *
|
||||||
|
raspberryPiI2CDeviceToString(
|
||||||
|
RASPBERRY_PI_I2C_DEVICE_T i2cDevice);
|
||||||
|
|
||||||
|
const char *
|
||||||
|
raspberryPiModelToString(
|
||||||
|
RASPBERRY_PI_MODEL_T model);
|
||||||
|
|
||||||
|
const char *
|
||||||
|
raspberryPiManufacturerToString(
|
||||||
|
RASPBERRY_PI_MANUFACTURER_T manufacturer);
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif
|
94
src/serialdmasync.cpp
Normal file
94
src/serialdmasync.cpp
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2018 Evariste COURJAUD F5OEO
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "serialdmasync.h"
|
||||||
|
|
||||||
|
|
||||||
|
serialdmasync::serialdmasync(uint32_t SampleRate,int Channel,uint32_t FifoSize,bool dualoutput):bufferdma(Channel,FifoSize,1,1)
|
||||||
|
{
|
||||||
|
if(dualoutput) //Fixme if 2pin we want maybe 2*SRATE as it is distributed over 2 pin
|
||||||
|
{
|
||||||
|
pwmgpio::SetMode(pwm2pin);
|
||||||
|
SampleRate*=2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pwmgpio::SetMode(pwm1pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SampleRate>250000)
|
||||||
|
{
|
||||||
|
pwmgpio::SetPllNumber(clk_plld,1);
|
||||||
|
pwmgpio::SetFrequency(SampleRate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pwmgpio::SetPllNumber(clk_osc,1);
|
||||||
|
pwmgpio::SetFrequency(SampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
enablepwm(12,0); // By default PWM on GPIO 12/pin 32
|
||||||
|
enablepwm(13,0); // By default PWM on GPIO 13/pin 33
|
||||||
|
|
||||||
|
SetDmaAlgo();
|
||||||
|
|
||||||
|
|
||||||
|
// Note : Spurious are at +/-(19.2MHZ/2^20)*Div*N : (N=1,2,3...) So we need to have a big div to spurious away BUT
|
||||||
|
// Spurious are ALSO at +/-(19.2MHZ/2^20)*(2^20-Div)*N
|
||||||
|
// Max spurious avoid is to be in the center ! Theory shoud be that spurious are set away at 19.2/2= 9.6Mhz ! But need to get account of div of PLLClock
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
serialdmasync::~serialdmasync()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void serialdmasync::SetDmaAlgo()
|
||||||
|
{
|
||||||
|
dma_cb_t *cbp = cbarray;
|
||||||
|
for (uint32_t samplecnt = 0; samplecnt < buffersize; samplecnt++)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP |BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(DREQ_PWM);
|
||||||
|
cbp->src = mem_virt_to_phys(&usermem[samplecnt*registerbysample]);
|
||||||
|
cbp->dst = 0x7E000000 + (PWM_FIFO<<2) + PWM_BASE ;
|
||||||
|
cbp->length = 4;
|
||||||
|
cbp->stride = 0;
|
||||||
|
cbp->next = mem_virt_to_phys(cbp + 1);
|
||||||
|
//fprintf(stderr,"cbp : sample %x src %x dest %x next %x\n",samplecnt,cbp->src,cbp->dst,cbp->next);
|
||||||
|
cbp++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cbp--;
|
||||||
|
cbp->next = mem_virt_to_phys(cbarray); // We loop to the first CB
|
||||||
|
//fprintf(stderr,"Last cbp : src %x dest %x next %x\n",cbp->src,cbp->dst,cbp->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialdmasync::SetSample(uint32_t Index,int Sample)
|
||||||
|
{
|
||||||
|
Index=Index%buffersize;
|
||||||
|
sampletab[Index]=Sample;
|
||||||
|
|
||||||
|
PushSample(Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
20
src/serialdmasync.h
Normal file
20
src/serialdmasync.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef DEF_SERIALDMASYNC
|
||||||
|
#define DEF_SERIALDMASYNC
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "dma.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
|
||||||
|
class serialdmasync:public bufferdma,public clkgpio,public pwmgpio
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
uint64_t tunefreq;
|
||||||
|
bool syncwithpwm;
|
||||||
|
public:
|
||||||
|
serialdmasync(uint32_t SampleRate,int Channel,uint32_t FifoSize,bool dualoutput);
|
||||||
|
~serialdmasync();
|
||||||
|
void SetDmaAlgo();
|
||||||
|
|
||||||
|
void SetSample(uint32_t Index,int Sample);
|
||||||
|
};
|
||||||
|
#endif
|
Loading…
Reference in a new issue