Base code for dtplug : Core, drivers, lib and some external drivers.
authorNathael Pajani <nathael.pajani@ed3l.fr>
Wed, 26 Aug 2015 22:25:37 +0000 (00:25 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Wed, 26 Aug 2015 22:25:37 +0000 (00:25 +0200)
This code comes from a merge of several parts :
 - the old repository
 - the modules support code
 - code from Gabriel's work on Ethernet and SDcard support (to come in future commits)
 - code from Cyprien's work on the modules

55 files changed:
.gitignore [new file with mode: 0644]
LICENCE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
core/bootstrap.c [new file with mode: 0644]
core/fault_handlers.c [new file with mode: 0644]
core/iap.c [new file with mode: 0644]
core/pio.c [new file with mode: 0644]
core/rom_helpers.c [new file with mode: 0644]
core/system.c [new file with mode: 0644]
core/systick.c [new file with mode: 0644]
drivers/adc.c [new file with mode: 0644]
drivers/gpio.c [new file with mode: 0644]
drivers/i2c.c [new file with mode: 0644]
drivers/serial.c [new file with mode: 0644]
drivers/ssp.c [new file with mode: 0644]
drivers/timers.c [new file with mode: 0644]
drivers/usbcore.c [new file with mode: 0644]
extdrv/cc1101.c [new file with mode: 0644]
extdrv/eeprom.c [new file with mode: 0644]
extdrv/epaper.c [new file with mode: 0644]
extdrv/tmp101_temp_sensor.c [new file with mode: 0644]
include/core/iap.h [new file with mode: 0644]
include/core/lpc_core_cm3.h [new file with mode: 0644]
include/core/lpc_regs_17xx.h [new file with mode: 0644]
include/core/pio.h [new file with mode: 0644]
include/core/system.h [new file with mode: 0644]
include/core/systick.h [new file with mode: 0644]
include/drivers/adc.h [new file with mode: 0644]
include/drivers/gpio.h [new file with mode: 0644]
include/drivers/i2c.h [new file with mode: 0644]
include/drivers/serial.h [new file with mode: 0644]
include/drivers/ssp.h [new file with mode: 0644]
include/drivers/timers.h [new file with mode: 0644]
include/drivers/usbcore.h [new file with mode: 0644]
include/extdrv/cc1101.h [new file with mode: 0644]
include/extdrv/eeprom.h [new file with mode: 0644]
include/extdrv/epaper.h [new file with mode: 0644]
include/extdrv/tmp101_temp_sensor.h [new file with mode: 0644]
include/lib/bit_arithm.h [new file with mode: 0644]
include/lib/dt_mod_identification.h [new file with mode: 0644]
include/lib/errno.h [new file with mode: 0644]
include/lib/font.h [new file with mode: 0644]
include/lib/list.h [new file with mode: 0644]
include/lib/stddef.h [new file with mode: 0644]
include/lib/stdio.h [new file with mode: 0644]
include/lib/string.h [new file with mode: 0644]
include/lib/usb.h [new file with mode: 0644]
lib/bit_arithm.c [new file with mode: 0644]
lib/dt_mod_identification.c [new file with mode: 0644]
lib/font.c [new file with mode: 0644]
lib/string.c [new file with mode: 0644]
lib/usb.c [new file with mode: 0644]
lib/vsprintf.c [new file with mode: 0644]
lpc_link_lpc1764.ld [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..92034fa
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# NOTE! Please use 'git ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+# Normal rules
+#
+*.o
+*.d
+*.bin
+*.elf
+*.map
+*/objs/*
+*.zip
+*.svg
+*.dump
+*.img
+*.bak
+tags
diff --git a/LICENCE b/LICENCE
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,674 @@
+                    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>.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..ffd375c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,79 @@
+# Makefile for GPIO Demo Module
+
+TARGET_DIR = apps/$(NAME)
+
+LPC = lpc1764
+CPU = cortex-m3
+ARCH = armv6-m
+
+#CROSS_COMPILE ?= arm-none-eabi-
+CROSS_COMPILE ?= arm-linux-gnueabi-
+CC = $(CROSS_COMPILE)gcc
+FOPTS = -fno-builtin -ffunction-sections -fdata-sections -ffreestanding
+CFLAGS = -Wall -O2 -mthumb -mcpu=$(CPU) $(FOPTS)
+LINKOPTS = -static -nostartfiles -nostdlib \
+                  -Wl,--gc-sections -Wl,--build-id=none \
+                  -Wl,-Map=$(TARGET_DIR)/lpc_map_$(LPC).map -Tlpc_link_$(LPC).ld
+
+
+APPS = $(subst apps/,,$(wildcard apps/*))
+
+.PHONY: all $(APPS)
+all: $(APPS)
+
+INCLUDES = include/
+TARGET_INCLUDES = $(TARGET_DIR)/
+OBJDIR = objs
+
+SRC = $(wildcard */*.c)
+OBJS = ${SRC:%.c=${OBJDIR}/%.o}
+DEPS = ${OBJS:%.o=$(OBJDIR)/%.d}
+
+NAME_SRC = $(wildcard $(TARGET_DIR)/*.c)
+NAME_OBJS = ${NAME_SRC:%.c=${OBJDIR}/%.o}
+NAME_DEPS = ${NAME_OBJS:%.o=$(OBJDIR)/%.d}
+
+-include $(DEPS) $(NAME_DEPS)
+
+.SECONDARY: $(OBJS) $(NAME_OBJS)
+.PRECIOUS: %.elf
+%.elf: $(OBJS) $(NAME_OBJS)
+       @echo "Linking $(NAME) ..."
+       @$(CC) $(LINKOPTS) $(OBJS) $(NAME_OBJS) -o $@
+
+%.bin: %.elf
+       @echo "Creating image : \e[32m$@\e[39m"
+       @$(CROSS_COMPILE)objcopy -R .stack -R .bss -O binary $^ $@
+       @ls -l $@
+       @echo Done.
+
+${OBJDIR}/%.o: %.c
+       @mkdir -p $(dir $@)
+       @echo "-- compiling" $<
+       @$(CC) -MMD -MP -MF ${OBJDIR}/$*.d $(CFLAGS) $< -c -o $@ -I$(INCLUDES) -I$(TARGET_INCLUDES)
+
+
+$(APPS):
+       @make --no-print-directory NAME=$@ apps/$@/$@.bin
+
+all_apps: $(APPS)
+
+clean:
+       rm -rf $(OBJDIR)
+
+mrproper: clean
+       rm -f apps/*/*.bin apps/*/*.elf apps/*/*.map
+
+
+# Some notes :
+# The command "make -f /path/to/here/Makefile app_name" does not work, as well
+# as the command "make -f /path/to/here/apps/app_name/Makefile".
+# This could be solved in the app Makefiles by replacing
+#   "NAME = $(shell basename $(CURDIR))"
+# with
+#   "NAME = $(shell basename $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))"
+# and possibly some similar trick for the base Makefile but this is just
+# unreadable and moslty unusefull, so it won't be supported.
+# Use "make -C /path/to/here/ app_name" or "make -C /path/to/here/apps/app_name"
+# instead.
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..3bae08a
--- /dev/null
+++ b/README
@@ -0,0 +1,115 @@
+dtplug code repository for the DTPlug gateway from Techno-Innov.
+
+It has support for the LPC1764 as used on the DTPlug, and for the peripherals
+found on the DTPlug board.
+Support for various other cool stuff is added when we play with it.
+
+Example applications are created in the apps directory, with one
+sub-directory for each application. These are (and must stay) independent.
+
+More usefull stuff is up to you. Creating an app is *very* simple. Copy
+an example from apps/ to the name you want and start coding.
+** Please, no spaces (or special characters) in the directory name ! **
+
+
+********************
+BUID and FLASH
+
+Build has been tested using gcc, and only gcc, in the version provided by
+Debian GNU/Linux distribution, and a few other binary versions available for
+download on the Internet, but any ARM gcc toolchain should do.
+
+In order to get the debian ARM gcc cross-toolchain you should install the
+following packaages : gcc-arm-none-eabi, binutils-arm-none-eabi
+
+There's no need for the related libc package here, the libc does not fit
+in our micro-controller memory. Instead have a look at the content of the
+lib/ directory, and add stuff there.
+
+Once done you should build using the provided makefile by running the
+simple "make" command in the base directory, which will build all apps, or
+run "make <app_name>" to build a specific application. You can also run the
+simple "make" command in the specific app subdirectory to compile this
+application alone.
+
+To flash the binary (the one with .bin) to the LPC Flash you will need the
+lpctool package, now packaged for Debian, starting with Jessie, or available
+in our git repository : http://git.techno-innov.fr/lpctools (Clone using :
+git clone http://gitclone.techno-innov.fr/lpctools and then build (make) and
+use :)
+Usual command lines :
+   lpcprog -d /dev/ttyUSB0 -c id
+   lpcprog -d /dev/ttyUSB0 -c flash app_name.bin
+See lpctools readme and lpcprog or isp help (-h) or manpages for more
+information.
+
+
+********************
+SUPPORTED FEATURES and INTERFACES
+
+- LPC176x micro-controller definitions
+   - Cortex-M3 specific definitions
+   - Cortex-M3 and LPC176x Registers
+   - Interrupts
+   - Utility functions to access special instructions
+              (endianness swapping, bit operations, ...)
+   - IAP ROM based functions (tested for user flash access only)
+
+- Bootstrap
+   - vector table
+   - reset handler
+
+- System
+   - flash accelerator configuration
+   - watchdog (stop)
+   - clock / PLL config
+   - systick
+   - precise msleep and usleep functions (using systick)
+   - pio configuration
+
+- Simple C Library
+   - memcpy and memset
+   - strcpy, strncpy, strcmp, strncmp, strchr, strrchr, strlen, strnlen
+   - snprintf, vsnprintf
+
+- Integrated Interface drivers
+   - UART (as UART or RS485)
+   - I²C
+   - ADC
+   - GPIO
+   - GPIO interrupts
+   - SSP
+   - Counter / Timers
+
+- External Device drivers
+   - I²C EEPROM
+   - TMP101 I²C temperature sensor
+   - CC1101 Sub 1GHz RF Transceiver
+   - Epaper display
+
+- Other
+   - 8x8 font for use with Epaper display
+
+
+
+********************
+TODO :
+
+- Sleep / power-down support.
+- Test all the GPIO in different modes
+- Add support for SDCard over SPI
+- Check PWM config in timer code
+- RTC Support
+- DAC support
+- Watchdog support
+- Test UART IrDA mode
+- I2S support
+- Ethernet support
+- USB support
+- CAN support
+- Repetitive itn timer support
+- Motor control support
+- Quadrature encoder interface support
+- DMA support
+
+
diff --git a/core/bootstrap.c b/core/bootstrap.c
new file mode 100644 (file)
index 0000000..6fd83a4
--- /dev/null
@@ -0,0 +1,183 @@
+/****************************************************************************
+ *   core/bootstrap.c
+ *
+ * This file holds the bootstrap code, the vector table, and nothing more.
+ * The bootstrap code is the code of the reset handler, which is called by
+ *   the bootloader (executed from internal ROM after power on or reset).
+ * The reset handler code perform copy of data section, clears bss, and
+ *   calls the main function.
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * Example code from frozeneskimo.com :
+ *   http://dev.frozeneskimo.com/notes/getting_started_with_cortex_m3_cmsis_and_gnu_tools
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *****************************************************************************/
+
+
+extern unsigned int _end_stack;
+extern unsigned int _end_text;
+extern unsigned int _start_data;
+extern unsigned int _end_data;
+extern unsigned int _start_bss;
+extern unsigned int _end_bss;
+
+extern int main(void);
+
+/* Cortex M0 core interrupt handlers */
+void Reset_Handler(void);
+void NMI_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void HardFault_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void MemFault_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void BusFault_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void UsageFault_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void SVC_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PendSV_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void SysTick_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+/* LPC17xx specific interrupt handlers */
+void WDT_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void TIMER_0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void TIMER_1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void TIMER_2_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void TIMER_3_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void UART_0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void UART_1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void UART_2_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void UART_3_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PWM_1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void I2C_0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void I2C_1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void I2C_2_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void SPI_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void SSP_0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void SSP_1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PLL_0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void RTC_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void EINT0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void EINT1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void EINT2_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void EINT3_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void ADC_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void BOD_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void USB_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void CAN_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void GPDMA_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void I2S_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Ethernet_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Repetitive_Int_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Motor_Ctrl_PWM_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Quadrature_Enc_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void PLL_1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void USB_Act_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void CAN_Act_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+
+
+
+void Dummy_Handler(void);
+
+
+/***************************************************************************** */
+/*                      Vector table                                           */
+/***************************************************************************** */
+void *vector_table[] __attribute__ ((section(".vectors"))) = {
+       &_end_stack, /* Initial SP value */ /* 0 */
+       Reset_Handler,
+       NMI_Handler,
+       HardFault_Handler,
+       MemFault_Handler,
+       BusFault_Handler, /* 5 */
+       UsageFault_Handler,
+       /* Entry 7 (8th entry) must contain the 2’s complement of the check-sum
+          of table entries 0 through 6. This causes the checksum of the first 8
+          table entries to be 0 */
+       (void *)0xDEADBEEF, /* Actually, this is done using an external tool. */
+       0,
+       0,
+       0, /* 10 */
+       SVC_Handler,
+       0,
+       0,
+       PendSV_Handler,
+       SysTick_Handler, /* 15 */
+       /* LPC17xx specific interrupt vectors, see chapter 6 of LPC17xx User manual (UM10360) */
+       WDT_Handler,     /* 16 */
+       TIMER_0_Handler,
+       TIMER_1_Handler,
+       TIMER_2_Handler,
+       TIMER_3_Handler, /* 20 */
+       UART_0_Handler,
+       UART_1_Handler,
+       UART_2_Handler,
+       UART_3_Handler,
+       PWM_1_Handler,   /* 25 */
+       I2C_0_Handler,
+       I2C_1_Handler,
+       I2C_2_Handler,
+       SPI_Handler,
+       SSP_0_Handler,   /* 30 */
+       SSP_1_Handler,
+       PLL_0_Handler,
+       RTC_Handler,
+       EINT0_Handler,
+       EINT1_Handler,   /* 35 */
+       EINT2_Handler,
+       EINT3_Handler,
+       ADC_Handler,
+       BOD_Handler,
+       USB_Handler,     /* 40 */
+       CAN_Handler,
+       GPDMA_Handler,
+       I2S_Handler,
+       Ethernet_Handler,
+       Repetitive_Int_Handler, /* 45 */
+       Motor_Ctrl_PWM_Handler,
+       Quadrature_Enc_Handler,
+       PLL_1_Handler,
+       USB_Act_Handler,
+       CAN_Act_Handler, /* 50 */
+};
+
+
+extern void rom_helpers_init(void);
+/*
+ * This is the entry point of the programm
+ * It does the set up of the memory and then starts the main.
+ */
+void Reset_Handler(void) {
+       unsigned int *src, *dst;
+       
+       /* Copy data section from flash to RAM */
+       src = &_end_text;
+       dst = &_start_data;
+       while (dst < &_end_data)
+               *dst++ = *src++;
+
+       /* Clear the bss section */
+       dst = &_start_bss;
+       while (dst < &_end_bss)
+               *dst++ = 0;
+
+       /* Initialize rom based helpers */
+       rom_helpers_init();
+       /* Start main programm */
+       main();
+}
+
+void Dummy_Handler(void) {
+       while (1);
+}
+
diff --git a/core/fault_handlers.c b/core/fault_handlers.c
new file mode 100644 (file)
index 0000000..623a37f
--- /dev/null
@@ -0,0 +1,64 @@
+/****************************************************************************
+ *   core/fault_handlers.c
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * Example code from frozeneskimo.com :
+ *   http://dev.frozeneskimo.com/notes/getting_started_with_cortex_m3_cmsis_and_gnu_tools
+ *
+ * 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 "core/lpc_regs_17xx.h"
+
+void fault_info(const char* name, uint32_t len) __attribute__ ((weak, alias ("Dummy_Fault_Handler")));
+
+void Dummy_Fault_Handler(const char* name, uint32_t len) {
+       while (1);
+}
+
+/* Cortex M3 core interrupt handlers */
+void NMI_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+void HardFault_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+void MemFault_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+void BusFault_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+void UsageFault_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+void SVC_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+void PendSV_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+
+
+
diff --git a/core/iap.c b/core/iap.c
new file mode 100644 (file)
index 0000000..3e214ea
--- /dev/null
@@ -0,0 +1,50 @@
+/****************************************************************************
+ *   core/iap.c
+ *
+ * In Application Programming
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include <stdint.h>
+
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/iap.h"
+
+
+/***************************************************************************** */
+/*       IAP support                                                           */
+/***************************************************************************** */
+
+/*
+ * Note : All the rom helper functions are in core/rom_helpers.c
+ */
+
+void lpc_iap_program(unsigned int src, unsigned int dest, unsigned int size)
+{
+       /* Turn off watchdog if enabled */
+       /* FIXME */
+       /* Erase destination Flash */
+       /* FIXME */
+       /* Copy RAM to Flash */
+       /* FIXME */
+}
+
+
+
diff --git a/core/pio.c b/core/pio.c
new file mode 100644 (file)
index 0000000..0a62843
--- /dev/null
@@ -0,0 +1,76 @@
+/****************************************************************************
+ *  core/pio.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/***************************************************************************** */
+/*                GPIOs                                                        */
+/***************************************************************************** */
+
+/*   Public access to Pins setup   */
+
+
+#include <stdint.h>
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "core/pio.h"
+
+
+
+/* Simple copy function. */
+void pio_copy(struct pio* dst, const struct pio* src)
+{
+       if ((dst == NULL) || (src == NULL)) {
+               return;
+       }
+       dst->port = src->port;
+       dst->pin = src->pin;
+       dst->alt_setting = src->alt_setting;
+}
+
+/* Configure the pin in the requested function and mode. */
+void config_pio(const struct pio* pp, uint32_t mode)
+{
+       struct lpc_pin_func_control* io_ctl = LPC_PIN_FUNCTION_CONTROL;
+       if ((pp == NULL) || (pp->port > 4) || (pp->pin > 31)) {
+               return;
+       }
+       /* Set function */
+       io_ctl->func_sel[ LPC_IO_PIN_REG(pp->port, pp->pin) ] &= ~(0x03 << LPC_IO_PIN_OFFSET(pp->pin));
+       io_ctl->func_sel[ LPC_IO_PIN_REG(pp->port, pp->pin) ] |= (pp->alt_setting << LPC_IO_PIN_OFFSET(pp->pin));
+       /* Set mode */
+       io_ctl->mode_sel[ LPC_IO_PIN_REG(pp->port, pp->pin) ] &= ~(0x03 << LPC_IO_PIN_OFFSET(pp->pin));
+       io_ctl->mode_sel[ LPC_IO_PIN_REG(pp->port, pp->pin) ] |= ((mode & 0x03) << LPC_IO_PIN_OFFSET(pp->pin));
+       /* Set open drain (or not) */
+       if (mode & LPC_IO_MODE_OPEN_DRAIN) {
+               io_ctl->opendrain_ctrl[ pp->port ] |= (0x01 << pp->pin);
+       } else {
+               io_ctl->opendrain_ctrl[ pp->port ] &= ~(0x01 << pp->pin);
+       }
+}
+
+
+void set_pins(const struct pio_config* pins)
+{
+       int i = 0;
+       for (i = 0; pins[i].pio.port != 0xFF; i++) {
+               config_pio(&(pins[i].pio), pins[i].mode);
+       }
+}
+
diff --git a/core/rom_helpers.c b/core/rom_helpers.c
new file mode 100644 (file)
index 0000000..298c3f0
--- /dev/null
@@ -0,0 +1,114 @@
+/****************************************************************************
+ *   core/rom_helpers.c
+ *
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include <stdint.h>
+#include "core/system.h"
+#include "core/lpc_core_cm3.h"
+
+
+/*******************************************************************************/
+/*            In Application Programming ROM based routines                    */
+/*******************************************************************************/
+
+enum iap_status {
+       IAP_STATUS_CMD_SUCCESS = 0,
+       IAP_STATUS_INVALID_COMMAND,
+       IAP_STATUS_SRC_ADDR_ERROR,
+       IAP_STATUS_DST_ADDR_ERROR,
+       IAP_STATUS_SRC_ADDR_NOT_MAPPED,
+       IAP_STATUS_DST_ADDR_NOT_MAPPED,
+       IAP_STATUS_COUNT_ERROR,
+       IAP_STATUS_INVALID_SECTOR,
+       IAP_STATUS_SECTOR_NOT_BLANK,
+       IAP_STATUS_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION,
+       IAP_STATUS_COMPARE_ERROR,
+       IAP_STATUS_BUSY,
+};
+
+enum iap_commands {
+       IAP_CMD_PREPARE_SECTORS_FOR_WRITE = 50,
+       IAP_CMD_COPY_RAM_TO_FLASH = 51,
+       IAP_CMD_ERASE_SECTORS = 52,
+       IAP_CMD_BLANK_CHECK_SECTORS = 53,
+       IAP_CMD_READ_PART_ID = 54,
+       IAP_CMD_READ_BOOT_CODE_VERSION = 55,
+       IAP_CMD_COMPARE = 56,
+       IAP_CMD_REINVOQUE_ISP = 57,
+       IAP_CMD_READ_UID = 58,
+};
+
+typedef void (*iap_entry_func)(uint32_t*, uint32_t*);
+iap_entry_func iap_entry;
+
+static uint32_t params[5];
+static uint32_t results[4];
+
+int iap_prepare_flash(uint32_t start_sector, uint32_t end_sector)
+{
+       params[0] = IAP_CMD_PREPARE_SECTORS_FOR_WRITE;
+       params[1] = start_sector;
+       params[2] = end_sector;
+       iap_entry(params, results);
+       return results[0];
+}
+
+int iap_erase_flash_sectors(uint32_t start_sector, uint32_t end_sector)
+{
+       params[0] = IAP_CMD_ERASE_SECTORS;
+       params[1] = start_sector;
+       params[2] = end_sector;
+       params[3] = (get_main_clock() / 1000);
+       lpc_disable_irq();
+       iap_entry(params, results);
+       lpc_enable_irq();
+       return results[0];
+}
+
+int iap_copy_ram_to_flash(uint32_t dest, uint32_t src, uint32_t size)
+{
+       params[0] = IAP_CMD_COPY_RAM_TO_FLASH;
+       params[1] = dest & ~(0x03);
+       params[2] = src & ~(0x03);
+       params[3] = size & ~(0x03);
+       params[4] = (get_main_clock() / 1000);
+       lpc_disable_irq();
+       iap_entry(params, results);
+       lpc_enable_irq();
+       return results[0];
+}
+
+uint32_t iap_read_part_id(void)
+{
+       params[0] = IAP_CMD_READ_PART_ID;
+       iap_entry(params, results);
+       return results[1];
+}
+
+
+/*******************************************************************************/
+/*            Rom based routines initialisation                                */
+/*******************************************************************************/
+#define LPC_176x_IAP_ROM_LOC (0x1FFF1FF1)
+
+void rom_helpers_init(void)
+{
+       iap_entry = (iap_entry_func)LPC_176x_IAP_ROM_LOC;
+}
+
diff --git a/core/system.c b/core/system.c
new file mode 100644 (file)
index 0000000..a36d114
--- /dev/null
@@ -0,0 +1,344 @@
+/****************************************************************************
+ *   core/system.c (OK)
+ *
+ * All low-level functions for clocks configuration and switch, system
+ *  power-up, reset, and power-down.
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include <stdint.h>
+
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "core/pio.h"
+
+
+/* Private defines */
+#define LPC_XTAL         (12000000UL)  /* Oscillator frequency : 12MHz on lpc_private board */
+#define LPC_SYS_OSC_CLK  (LPC_XTAL)    /* Main oscillator frequency */
+#define LPC_IRC_OSC_CLK  (4000000UL)  /* Internal RC oscillator frequency : 4MHz */
+
+
+/***************************************************************************** */
+/*                     Global data                                             */
+/***************************************************************************** */
+struct lpc_desc_private {
+       uint32_t main_clock;
+       uint32_t brown_out_detection_enabled;
+};
+static struct lpc_desc_private lpc_private = {
+       .main_clock = LPC_IRC_OSC_CLK,
+       .brown_out_detection_enabled = 0,
+};
+
+/***************************************************************************** */
+/*                     Required system inits                                  */
+/***************************************************************************** */
+/* Set up number of CPU clocks for flash access (see chapter 5.4 of LPC17xx User
+ *  manual (UM10360.pdf))
+ * freq_sel : code for CPU freq, as defined in system.h header file :
+ * A clock frequency is defined as the integer value in MHz shifted by 3 and or'ed
+ * with the value to be programmed in the flash config register for the flash access
+ * time at the given frequency.
+ */
+static void flash_accelerator_config(uint32_t freq_sel)
+{
+       struct lpc_flash_control* fcfg = LPC_FLASH_CONTROL;
+       fcfg->flash_cfg &= ~(LPC_FLASH_CFG_MASK);
+       fcfg->flash_cfg |= ((freq_sel & 0x07) << LPC_FLASH_CFG_SHIFT);
+}
+
+
+/* Stop the watchdog
+ * Note that after reset the Watchdog is not running.
+ */
+void stop_watchdog(void)
+{
+    struct lpc_watchdog* wdt = LPC_WDT;
+       /* Stop watchdog */
+    wdt->mode = LPC_WDT_DISABLE;
+    wdt->feed_seqence = 0xAA;
+    wdt->feed_seqence = 0x55;
+}
+
+/* Configure the brown-out detection */
+void system_brown_out_detection_config(uint32_t level)
+{
+       struct lpc_sys_control* ctrl = LPC_SYS_CONTROL;
+
+       if (level == 0) {
+               /* Disable Brown_Out detection and clear flags */
+               ctrl->power_mode_ctrl |= (LPC_BOD_FULL_DISABLE | LPC_CLEAR_ALL_SLEEP_FLAGS);
+               /* Disable Brown-Out Detection, power it down */
+               lpc_private.brown_out_detection_enabled = 0;
+       } else {
+               /* Enable Brown-Out Detection. */
+               /* FIXME */
+               lpc_private.brown_out_detection_enabled = 1;
+               /* Configure Brown-Out Detection */
+       }
+}
+
+/***************************************************************************** */
+/*            Peripheral Power and Clocks                                      */
+/***************************************************************************** */
+/* Change reset power state to our default, removing power from unused (all but
+ *  the RTC and GPIO) interfaces
+ */
+void system_set_default_power_state(void)
+{
+       struct lpc_sys_control* ctrl = LPC_SYS_CONTROL;
+       /* Set lpc_sys_control->periph_power_ctrl (PCONP) to apropriate bitmask */
+       ctrl->periph_power_ctrl = (LPC_RTC_POWER_ON | LPC_GPIO_POWER_ON);
+}
+
+/* Set the Peripheral Clock divider in PCLKSEL0 and PCLKSEL1
+ * The default value at reset is LPC_PCLK_CCLK_QUARTER which divides the CCLK by 4.
+ */
+void set_subsystem_clk_divider(uint32_t subsystem, uint32_t clk_div)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+
+       sys_ctrl->pclk_sel[ (subsystem & 0x80) ] = ((clk_div & 0x03) << (subsystem & 0x1E));
+}
+
+
+/* Power ON or OFF a subsystem
+ * Power OFF if 'on_off' is 0, turn ON otherwise
+ * 'power_bit' uses defines from core/lpc_regs_17xx.h : LPC_xxxx_POWER_ON
+ */
+void subsystem_power(uint32_t power_bit, uint32_t on_off)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       if (on_off != 0) {
+               sys_ctrl->periph_power_ctrl |= power_bit; /* Power on */
+       } else {
+               sys_ctrl->periph_power_ctrl &= ~(power_bit);
+       }
+}
+
+/***************************************************************************** */
+/* Sleep and power-down modes */
+/* There are four sleep / power down modes in the LPC176x micro-controller
+ *   Sleep - Deep Sleep - Power Down - Deep Power Down
+ *
+ * Note : Refer to chapter 4.8 'Power control' page 58 and following ones in UM10360 User manual
+ */
+
+/* Enter deep sleep. */
+void enter_deep_sleep(void)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       struct syst_ctrl_block_regs* sys_ctrl_block = LPC_SCB;
+       uint32_t tmp = sys_ctrl->power_mode_ctrl;
+       /* Configure for sleep */
+       tmp &= LPC_BOD_FULL_DISABLE; /* Remove all bits but those for BOD, preserve flags */
+       tmp |= LPC_SLEEP_ENTRY;
+       sys_ctrl->power_mode_ctrl = tmp;
+       /* Configure for deep sleep */
+       sys_ctrl_block->scr |= SCB_SCR_SLEEPDEEP; /* FIXME : do we set SEVONPEND and/or SLEEPONEXIT */
+       /* Enter deep sleep */
+       wfe();
+
+       /* We will return in execution mode here */
+       /* FIXME : Wait for OSCSTAT in SCS and Restore PLLs */
+}
+
+/* FIXME : Add support for other sleep / power-down modes */
+
+
+/***************************************************************************** */
+/*                      System Clock                                           */
+/***************************************************************************** */
+static void propagate_main_clock(void);
+
+/* Main clock config : set up the system clock
+ * We use internal RC oscilator as sys_pllclkin if PLL is ussed
+ * Note that during PLL lock wait we are running on internal RC
+ * Note for M and N calculation : FCCO must be between 275MHz and 550MHz
+ *                                M ranges from 6 to 512
+ *                                N ranges from 1 to 32
+ */
+void clock_config(uint32_t freq_sel)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       uint32_t M = 0; /* M = (FCCO × N) / (2 × FIN) */
+       uint32_t N = 0; /* N = (2 × M × FIN) / FCCO */
+       uint32_t div = 0; /* divider of PLL0 output to provide desired frequency */
+
+       /* Select dividers M, N, and PLL0 output divider (div) */
+       /* Note : We will generate USB clock using PLL1 */
+       switch (freq_sel) {
+               case FREQ_SEL_48MHz:
+                       lpc_private.main_clock = (48*1000*1000);
+                       M = 12;  N = 1;  div = 6;
+                       break;
+               case FREQ_SEL_50MHz:
+                       lpc_private.main_clock = (50*1000*1000);
+                       M = 25;  N = 2;  div = 6;
+                       break;
+               case FREQ_SEL_60MHz:
+                       lpc_private.main_clock = (60*1000*1000);
+                       M = 15;  N = 1;  div = 6;
+                       break;
+               case FREQ_SEL_72MHz:
+                       lpc_private.main_clock = (72*1000*1000);
+                       M = 12;  N = 1;  div = 4;
+                       break;
+               case FREQ_SEL_100MHz:
+               default:
+                       lpc_private.main_clock = (100*1000*1000);
+                       M = 25;  N = 2;  div = 3;
+                       break;
+       }
+       /* Configure PLL 0 for CPU */
+       /* Note :  ALL STEPS ARE REQUIRED ! */
+       /* First of all, turn off interrupts, nothing should happen between the two writes of the
+          feed sequence (writting of 0xAA and 0x55 to pll0_feed) */
+       lpc_disable_irq();
+       /* Disable PLL if requiered */
+       if ((sys_ctrl->pll0_status & (0x03 << 24)) != 0) {
+               /* Disconnect PLL first */
+               sys_ctrl->pll0_control &= ~(LPC_PLL_CTRL_PLL_CONNECT);
+               sys_ctrl->pll0_feed = 0xAA;
+               sys_ctrl->pll0_feed = 0x55;
+               /* Then disable PLL */
+               sys_ctrl->pll0_control = 0;
+               sys_ctrl->pll0_feed = 0xAA;
+               sys_ctrl->pll0_feed = 0x55;
+       }
+       /* PLL now off. Set clock div to 1 to get max freq */
+       sys_ctrl->cpu_clk_cfg = 0; /* Set div to 1 : possible because PLL is not used */
+       /* Make sure that external crystal is enabled and ready */
+       sys_ctrl->sys_osc_ctrl_and_status = (LPC_SYS_CTRL_OSC_EN | LPC_SYS_CTRL_OSC_RANGE_UNDER_20MHZ);
+       while ( ! (sys_ctrl->sys_osc_ctrl_and_status & LPC_SYS_CTRL_OSC_STAT) );
+       /* Use external crystal as source */
+       sys_ctrl->sys_clk_src_sel = LPC_CLK_PLL0_SRC_XTAL;
+       /* Setup PLL */
+       sys_ctrl->pll0_config = (((M - 1) & 0x7FFF) | (((N - 1) & 0x3F) << 16));
+       sys_ctrl->pll0_feed = 0xAA;
+       sys_ctrl->pll0_feed = 0x55;
+       /* Enable PLL */
+       sys_ctrl->pll0_control = LPC_PLL_CTRL_PLL_ENABLE;
+       sys_ctrl->pll0_feed = 0xAA;
+       sys_ctrl->pll0_feed = 0x55;
+       /* Set divisor for CPU Clock before connecting PLL (must NOT stay as 1) */
+       sys_ctrl->cpu_clk_cfg = ((div - 1) & 0xFF);
+       /* Set flash accelerator CPU cycles for flash access with new speed */
+       flash_accelerator_config(freq_sel);
+       /* Wait for PLL lock (note : interrupts are disabled) */
+       while ( ! (sys_ctrl->pll0_status & (0x01 << 26)) );
+       /* Connect PLL */
+       sys_ctrl->pll0_control = (LPC_PLL_CTRL_PLL_ENABLE | LPC_PLL_CTRL_PLL_CONNECT);
+       sys_ctrl->pll0_feed = 0xAA;
+       sys_ctrl->pll0_feed = 0x55;
+       /* Propagate Main clock change before enabling interrupts back */
+       propagate_main_clock();
+       /* Turn interrupts on once again*/
+       lpc_enable_irq();
+}
+
+uint32_t get_main_clock(void)
+{
+       return lpc_private.main_clock;
+}
+
+/***************************************************************************** */
+/*                     Peripheral Clocks                                       */
+/***************************************************************************** */
+void Dummy_Clk_Updater(void) {
+       do { } while (0);
+}
+
+void uart_clk_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater")));
+void i2c_clock_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater")));
+void ssp_clk_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater")));
+void adc_clk_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater")));
+
+static void propagate_main_clock(void)
+{
+       uart_clk_update();
+       i2c_clock_update();
+       ssp_clk_update();
+       adc_clk_update();
+}
+
+
+/***************************************************************************** */
+/*                    CLK Out                                                  */
+/***************************************************************************** */
+/* This is mainly a debug feature, but can be used to provide a clock to an
+ * external peripheral */
+/* Note that PIO0_12 is the only pin possible for CLK_Out, and is multiplexed
+ * with ISP mode selection on reset.
+ * The pin must be enabled using a pio table passed to the set_pins() function.
+ */
+
+/* Debug : the clkout is only connected to a testpoint (P15) */
+void clkout_on(uint32_t src, uint32_t div)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       struct pio clkout = LPC_CLKOUT_PIO_1_27;
+
+       if (src > LPC_CLKOUT_SRC_MAX) {
+               src = LPC_CLKOUT_SRC_CPU;
+       }
+       /* Setup CLKOUT pin */
+       config_pio(&clkout, 0);
+       /* Configure :             SRC       |       DIV           |  Enable   */
+       sys_ctrl->clkout_cfg = ((src & 0x07) | LPC_CLKOUT_DIV(div) | LPC_CLKOUT_ENABLE);
+}
+void clkout_off()
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       sys_ctrl->clkout_cfg = 0;
+}
+
+
+
+
+/***************************************************************************** */
+/*                    Default sleep function                                   */
+/***************************************************************************** */
+/* Note that if the systick core functions are used these will be overridden */
+
+/* This "msleep" is a simple wait routine which is close to a millisecond sleep
+ * whith a CPU Clock of 24MHz, but has no exact relation to time.
+ * It is highly dependent to CPU clock speed anyway.
+ * Note : This is an active sleep !
+ */
+static void def_msleep(uint32_t ms)
+{
+       volatile uint32_t dec = ms * 2667;
+       while (dec--);
+}
+
+/* Something that's not too far from a microsecond sleep at 24MHz CPU Clock
+ * Note : This is an active sleep !
+ */
+static inline void def_usleep(uint32_t us)
+{
+       volatile uint32_t dec = us * 2;
+       while (dec--);
+}
+
+void msleep(uint32_t ms) __attribute__ ((weak, alias ("def_msleep")));
+void usleep(uint32_t us) __attribute__ ((weak, alias ("def_usleep")));
+
diff --git a/core/systick.c b/core/systick.c
new file mode 100644 (file)
index 0000000..46a396c
--- /dev/null
@@ -0,0 +1,334 @@
+/****************************************************************************
+ *  core/systick.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+
+/***************************************************************************** */
+/*               System Tick Timer                                             */
+/***************************************************************************** */
+
+#include <stdint.h>
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "core/systick.h"
+
+/* FIXME : Actual use of sleep_count is OK in single tasking environment.
+ *    for multitasking, change the sleep function behaviour.
+ */
+
+/* Static variables */
+static volatile uint32_t sleep_count = 0;
+static volatile uint32_t tick_ms = 0;
+static volatile uint32_t systick_running = 0;
+static volatile uint32_t tick_reload = 0;
+
+/* Wraps every 50 days or so with a 1ms tick */
+static volatile uint32_t global_wrapping_system_ticks = 0;
+/* The systick cycles run at get_main_clock(), and would wrap more often! */
+static volatile uint32_t global_wrapping_system_clock_cycles = 0;
+
+
+struct systick_callback {
+       void (*callback) (uint32_t);
+       uint16_t period;
+       uint16_t countdown;
+};
+static volatile struct systick_callback cbs[MAX_SYSTICK_CALLBACKS] = {};
+
+/* System Tick Timer Interrupt Handler */
+void SysTick_Handler(void)
+{
+       int i = 0;
+       global_wrapping_system_ticks++;
+       global_wrapping_system_clock_cycles += tick_reload;
+       if (sleep_count != 0) {
+               sleep_count--;
+       }
+       for (i = 0; i < MAX_SYSTICK_CALLBACKS; i++) {
+               if (cbs[i].callback != NULL) {
+                       cbs[i].countdown--;
+                       if (cbs[i].countdown == 0) {
+                               cbs[i].countdown = cbs[i].period;
+                               cbs[i].callback(global_wrapping_system_ticks);
+                       }
+               }
+       }
+}
+
+
+/* Register a callback to be called every 'period' system ticks.
+ * returns the callback number if registration was OK.
+ * returns negative value on error.
+ * The callback will get the "global_wrapping_system_ticks" as argument, which wraps every 50 days
+ *   or so with a 1ms tick
+ */
+int add_systick_callback(void (*callback) (uint32_t), uint16_t period)
+{
+       int i = 0;
+       if (period == 0) {
+               return -EINVAL;
+       }
+       for (i = 0; i < MAX_SYSTICK_CALLBACKS; i++) {
+               if (cbs[i].callback == NULL) {
+                       cbs[i].callback = callback;
+                       cbs[i].period = period;
+                       cbs[i].countdown = period;
+                       return i;
+               }
+       }
+       return -EBUSY;
+}
+
+int remove_systick_callback(void (*callback) (uint32_t))
+{
+       int i = 0;
+       for (i = 0; i < MAX_SYSTICK_CALLBACKS; i++) {
+               if (cbs[i].callback == callback) {
+                       cbs[i].callback = NULL;
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+/***************************************************************************** */
+/* systick timer control function */
+
+/* Start the system tick timer
+ * Starting the systick timer also resets the internal tick counters.
+ * If you need a value that goes beyond one start/stop cycle and accross resets,
+ *    then it's up to you to keep track of this using systick_get_tick_count() and/or
+ *    systick_get_clock_cycles().
+ */
+void systick_start(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       systick->value = 0;
+       systick_running = 1;
+       global_wrapping_system_ticks = 0;
+       global_wrapping_system_clock_cycles = tick_reload;
+       systick->control |= LPC_SYSTICK_CTRL_ENABLE;
+}
+/* Stop the system tick timer */
+void systick_stop(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       systick->control &= ~(LPC_SYSTICK_CTRL_ENABLE);
+       systick_running = 0;
+       systick->value = 0;
+}
+/* Reset the system tick timer, making it count down from the reload value again
+ * Reseting the systick timer also resets the internal tick counters.
+ * If you need a value that goes beyond one start/stop cycle and accross resets,
+ *    then it's up to you to keep track of this using systick_get_tick_count() and/or
+ *    systick_get_clock_cycles().
+ */
+void systick_reset(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       systick->value = 0;
+       global_wrapping_system_ticks = 0;
+       global_wrapping_system_clock_cycles = tick_reload;
+}
+
+/* Get system tick timer current value (counts at get_main_clock() !) */
+uint32_t systick_get_timer_val(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       return systick->value;
+}
+
+/* Check if systick is running (return 1) or not (return 0) */
+uint32_t is_systick_running(void)
+{
+       return systick_running;
+}
+
+/* Get the system tick period in ms
+ * A vaue of 0 means the system tick timer has not been configured.
+ * Note : calls to msleep() or usleep() will configure the system tick timer
+ *        with a value of 1ms if it was not configured yet.
+ */
+uint32_t systick_get_tick_ms_period(void)
+{
+       return tick_ms;
+}
+
+/* Get the "timer wrapped" indicator.
+ * Used in usleep() function.
+ * Note : the first to call this function will get the right information.
+ * All subsequent calls will get wrong indication.
+ * Thus this function is not exported to user space, user should compare global
+ * ticks values or tick counter values. */
+static uint32_t systick_counted_to_zero(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       return (systick->control & LPC_SYSTICK_CTRL_COUNTFLAG);
+}
+
+
+/* Get the number of system ticks ... since last wrapping of the counter, which
+ * is about 50 days with a 1ms system tick. */
+uint32_t systick_get_tick_count(void)
+{
+       return global_wrapping_system_ticks;
+}
+
+/* Get the number of clock cycles ... since last wrapping of the counter. */
+uint32_t systick_get_clock_cycles(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       /* global_wrapping_system_clock_cycles has been initialised to reload value, thus there is
+        * no need to add it here, making the call quicker */
+       return global_wrapping_system_clock_cycles - systick->value;
+}
+
+/***************************************************************************** */
+/* Power up the system tick timer.
+ * ms is the interval between system tick timer interrupts. If set to 0, the default
+ *     value is used, which should provide a 1ms period.
+ */
+void systick_timer_on(uint32_t ms)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       uint32_t reload; /* The reload value for the counter */
+
+       /* Set the reload value */
+       if (ms != 0) {
+               reload = ((get_main_clock() / 1000) * ms) - 1;
+       } else {
+               reload = (get_main_clock() / 1000) - 1;
+               ms = 1;
+       }
+       /* For the LPC1224 the system tick clock is fixed to half the frequency of the system clock */
+       reload = reload >> 1; /* Divide by 2 */
+       systick->reload_val = (reload & 0xffffff);
+       tick_ms = ms;
+       tick_reload = systick->reload_val;
+
+       /* Start counting from the reload value, writting anything would do ... */
+       systick->value = reload;
+       /* Consider we already counted one cycle, making further reading of this count easier */
+       global_wrapping_system_clock_cycles = tick_reload;
+
+       /* And enable counter interrupt */
+       systick->control = LPC_SYSTICK_CTRL_TICKINT;
+       systick_running = 0;
+
+       /* FIXME : document this */
+       NVIC_SetPriority(SYSTICK_IRQ, ((1 << LPC_NVIC_PRIO_BITS) - 1));
+}
+
+/* Removes the main clock from the selected timer block */
+void systick_timer_off(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       systick->control = 0;
+       systick->reload_val = 0;
+       tick_ms = 0;
+       tick_reload = 0;
+       systick_running = 0;
+}
+
+
+/***************************************************************************** */
+/* Sleeping functions */
+
+/* Set the sleep countdown value
+ * A sleep will end when this value reaches 0
+ * Note that calls to this function while a sleep() has been initiated will change the
+ *   sleep duration ....
+ */
+void set_sleep(uint32_t ticks)
+{
+       sleep_count = ticks;
+}
+/* Return current sleep count_down counter */
+uint32_t get_sleep(void)
+{
+       return sleep_count;
+}
+
+/* Actual sleep function, checks that system tick counter is configured to generate
+ * an interrupt to move sleep_count down to 0
+ */
+#define SYSTICK_CAN_SLEEP   (LPC_SYSTICK_CTRL_TICKINT | LPC_SYSTICK_CTRL_ENABLE)
+static uint32_t sleep(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       if ((systick->control & SYSTICK_CAN_SLEEP) != SYSTICK_CAN_SLEEP) {
+               return -1;
+       }
+       do { } while (sleep_count != 0);
+       return 0;
+}
+
+/* This msleep sleeps less than the required amount of time as it forgets about
+ * the already elapsed time of the systick timer since last tick. */
+void msleep(uint32_t ms)
+{
+       uint32_t ticks = 0;
+
+       if (tick_ms == 0) {
+               systick_timer_on(1);
+               ticks = ms;
+       } else {
+               ticks = ms / tick_ms;
+       }
+       set_sleep(ticks);
+       if (systick_running == 0) {
+               systick_start();
+       }
+       sleep();
+}
+
+void usleep(uint32_t us)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       uint32_t start = systick->value; /* Grab the starting (call time) value now */
+       uint32_t count = 0;
+       uint32_t end = 0;
+
+       end = systick_counted_to_zero(); /* erase loop indicator */
+       if (us > 1000) {
+               msleep(us / 1000);
+               us = us % 1000;
+       } else {
+               if (systick_running == 0) {
+                       if (tick_ms == 0) {
+                               systick_timer_on(1);
+                       }
+                       systick_start();
+               }
+       }
+       count = get_main_clock() / (1000 * 1000) * us;
+       if (count > start) {
+               end = (systick->reload_val - (count - start));
+               do { } while (systick_counted_to_zero() == 0); /* Wait for timer loop */
+               do { } while (systick->value > end); /* Wait for sleep duration */
+       } else {
+               end = start - count;
+               /* Wait for sleep duration.
+                * If the counter looped, it means we already waited too much */
+               do { } while ((systick->value > end) && (systick_counted_to_zero() == 0));
+       }
+}
+
diff --git a/drivers/adc.c b/drivers/adc.c
new file mode 100644 (file)
index 0000000..e60a684
--- /dev/null
@@ -0,0 +1,219 @@
+/****************************************************************************
+ *  drivers/adc.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+
+/***************************************************************************** */
+/*                Analog to Digital Converter (ADC)                            */
+/***************************************************************************** */
+
+#include <stdint.h>
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "drivers/adc.h"
+
+/* Should be as near to 13MHz as possible, but under. */
+#define adc_clk_Val  13000000
+
+
+
+/***************************************************************************** */
+/* Generic ADC handler */
+void ADC_Handler(void)
+{
+/*
+       volatile struct lpc_adc* adc = LPC_ADC;
+       uint32_t status = adc->status;
+*/
+       /* .... What to do ... is specific to your application */
+       /* FIXME : Add an handler callback. */
+}
+
+/* Read the conversion from the given channel (0 to 7) 
+ * This function reads the conversion value directly in the data register and
+ * always returns a value.
+ * Return 0 if the value is a new one and no overrun occured.
+ * Return -1 if channel does not exist
+ * Retuen 1 if the value is an old one
+ * Return 2 if an overrun occured
+ */
+int adc_get_value(uint16_t * val, int channel)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       uint32_t save_reg = 0;
+
+       if (channel > 7)
+               return -1;
+
+       /* Save the whole register as some bits are cleared when register is read */
+       save_reg = adc->data[channel];
+       *val = ((save_reg >> LPC_ADC_RESULT_SHIFT) & LPC_ADC_RESULT_MASK);
+       /* Has this conversion value been already read ? */
+       if (! (save_reg & LPC_ADC_CONV_DONE)) {
+               return 1;
+       }
+       if (save_reg & LPC_ADC_OVERRUN) {
+               return 2;
+       }
+       return 0;
+}
+
+/* Start a conversion on the given channel (0 to 7) */
+void adc_start_convertion_once(unsigned int channel, int use_int)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       uint32_t reg_val = 0;
+
+       if (channel > 7)
+               return;
+
+       /* Get a clean control register */
+       reg_val = adc->ctrl & ~(LPC_ADC_CHANNEL_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST);
+
+       /* Set conversion channel bit */
+       reg_val |= LPC_ADC_CHANNEL(channel);
+
+       /*  Use of interrupts for the specified channel ? */
+       if (use_int) {
+               /* Set interrupt Bit */
+               adc->int_en = LPC_ADC_CHANNEL(channel);
+       } else {
+               adc->int_en = 0;
+       }
+
+       /* Start conversion */
+       reg_val |= LPC_ADC_START_CONV_NOW;
+       adc->ctrl = (reg_val & LPC_ADC_CTRL_MASK);
+}
+
+
+/* Start burst conversions.
+ * channels is a bit mask of requested channels.
+ * Use LPC_ADC_CHANNEL(x) (x = 0 .. 7) for channels selection.
+ */
+void adc_start_burst_conversion(uint8_t channels)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       uint32_t reg_val = 0;
+
+       /* Get a clean control register */
+       reg_val = adc->ctrl & ~(LPC_ADC_CHANNEL_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST);
+
+       /* Set conversion channel bits and burst mode */
+       reg_val |= channels;
+       reg_val |= LPC_ADC_BURST;
+
+       /*  Use of interrupts for the specified channels ? */
+       /* FIXME : Need to choose between one single global interrupt or specific interrupts .... */
+       /* FIXME : Actually none. */
+       adc->int_en = 0;
+
+       /* Start conversion */
+       adc->ctrl = (reg_val & LPC_ADC_CTRL_MASK);
+}
+
+
+/* This should be used to configure conversion start on falling or rising edges of
+ * some signals, or on timer for burst conversions.
+ */
+void adc_prepare_conversion_on_event(uint8_t channels, uint8_t event, int use_int)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       uint32_t reg_val = 0;
+
+       /* Get a clean control register */
+       reg_val = adc->ctrl & ~(LPC_ADC_CHANNEL_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST);
+       /* Set conversion channel bits and burst mode */
+       reg_val |= channels;
+       /* Set conversion condition bits */
+       switch (event) {
+               case ADC_CONV_ON_CT32B0_MAT0_RISING :
+                       reg_val |= LPC_ADC_START_CONV_EVENT(LPC_ADC_START_CONV_EDGE_CT32B0_MAT0);
+                       reg_val |= LPC_ADC_START_EDGE_RISING;
+                       break;
+               case ADC_CONV_ON_CT16B0_MAT0_RISING :
+                       reg_val |= LPC_ADC_START_CONV_EVENT(LPC_ADC_START_CONV_EDGE_CT16B0_MAT0);
+                       reg_val |= LPC_ADC_START_EDGE_RISING;
+                       break;
+               default:
+                       break;
+       }
+
+       /*  Use of interrupts for the specified channel ? */
+       if (use_int) {
+               /* FIXME : Need to choose between one single global interrupt or specific interrupts .... */
+       } else {
+               adc->int_en = 0;
+       }
+
+       /* Enable conversion on selected event */
+       adc->ctrl = (reg_val & LPC_ADC_CTRL_MASK);
+}
+
+
+
+/***************************************************************************** */
+/*   ADC Setup : private part : Clocks, Power and Mode   */
+
+void adc_clk_update(void)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       uint32_t main_clock = get_main_clock();
+       uint32_t clkdiv = 0;
+
+       /* Set CCLK divider for PCLK */
+       set_subsystem_clk_divider(LPC_ADC_PCLK, LPC_PCLK_CCLK);
+       /* Configure ADC clock to get the 13MHz sample clock */
+       clkdiv = (main_clock / adc_clk_Val);
+       adc->ctrl |= ((clkdiv & 0xFF) << 8);
+}
+
+
+void adc_on(void)
+{
+       struct lpc_adc* adc = LPC_ADC;
+
+       /* Disable ADC Interrupt */
+       NVIC_DisableIRQ(ADC_IRQ);
+
+       /* Provide clock to ADC */
+       subsystem_power(LPC_ADC_POWER_ON, 1);
+       adc_clk_update();
+
+       /* Prevent unconfigured conversion start */
+       adc->ctrl &= ~LPC_ADC_START_CONV_MASK;
+
+       /* Remove the default global interrupt enabled setting */
+       adc->int_en = 0;
+
+       /* Enable ADC Interrupt */
+       NVIC_EnableIRQ(ADC_IRQ);
+}
+
+void adc_off(void)
+{
+       /* Disable ADC Interrupt */
+       NVIC_DisableIRQ(ADC_IRQ);
+       /* Remove clock from ADC block */
+       subsystem_power(LPC_ADC_POWER_ON, 0);
+}
+
diff --git a/drivers/gpio.c b/drivers/gpio.c
new file mode 100644 (file)
index 0000000..d0a2a99
--- /dev/null
@@ -0,0 +1,186 @@
+/****************************************************************************
+ *  drivers/gpio.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/***************************************************************************** */
+/*                GPIOs and GPIO Interrupts                                    */
+/***************************************************************************** */
+
+
+
+#include <stdint.h>
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "drivers/gpio.h"
+
+
+
+/***************************************************************************** */
+/*   GPIO setup   */
+
+/* IMPORTANT NOTICE : 
+ *    GPIO Power is on after reset and should be left ON as it also powers the
+ *      PIO configuration block.
+ *    Turn it off manually using subsystem_power() if you have configured all
+ *      your PIO functions and do not use GPIO.
+ */
+
+
+/* GPIO Configuration
+ * This function calls the config_pio() function for the gpio with the given
+ * mode, configures the direction of the pin and sets the initial state.
+ */
+void config_gpio(const struct pio* gpio, uint32_t mode, uint8_t dir, uint8_t ini_val)
+{
+       struct lpc_gpio_port_control* gpio_port = &(LPC_GPIO_PORTS->p[gpio->port]);
+
+       /* Configure as GPIO */
+       config_pio(gpio, mode);
+
+       if (dir == GPIO_DIR_IN) {
+               gpio_port->data_dir &= ~(1 << gpio->pin);
+       } else {
+               gpio_port->data_dir |= (1 << gpio->pin);
+               if (ini_val == 0) {
+                       gpio_port->clear = (1 << gpio->pin);
+               } else {
+                       gpio_port->set = (1 << gpio->pin);
+               }
+       }
+}
+
+/***************************************************************************** */
+/* GPIO Interrupts Callbacks */
+static void (*gpio_callbacks_port0[PORT0_MAX_PIN_NUM + 1]) (uint32_t);
+static void (*gpio_callbacks_port2[PORT2_MAX_PIN_NUM + 1]) (uint32_t);
+
+int set_gpio_callback(void (*callback) (uint32_t), const struct pio* gpio, uint8_t sense)
+{
+       struct lpc_gpio_port_control* gpio_port = &(LPC_GPIO_PORTS->p[gpio->port]);
+       struct lpc_gpio_interrupts* gpio_int = LPC_GPIO_INTERRUPTS;
+       struct lpc_gpio_port_int* gpio_port_int = NULL;
+       uint32_t irq = EINT3_IRQ;
+
+       /* Register the callback */
+       /* FIXME : we should check that there were none registered for the selected pin */
+       switch (gpio->port) {
+               case 0:
+                       if (gpio->pin > PORT0_MAX_PIN_NUM)
+                               return -EINVAL;
+                       gpio_callbacks_port0[gpio->pin] = callback;
+                       gpio_port_int = &(gpio_int->port0);
+                       break;
+               case 2:
+                       if (gpio->pin > PORT2_MAX_PIN_NUM)
+                               return -EINVAL;
+                       gpio_callbacks_port2[gpio->pin] = callback;
+                       gpio_port_int = &(gpio_int->port2);
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       /* Configure the pin as interrupt source */
+       gpio_port->data_dir &= ~(1 << gpio->pin); /* Input */
+       config_pio(gpio, 0);
+       switch (sense) {
+               case EDGES_BOTH:
+                       gpio_port_int->rising_enable |= (1 << gpio->pin);
+                       gpio_port_int->falling_enable |= (1 << gpio->pin);
+                       break;
+               case EDGE_RISING:
+                       gpio_port_int->rising_enable |= (1 << gpio->pin);
+                       gpio_port_int->falling_enable &= ~(1 << gpio->pin);
+                       break;
+               case EDGE_FALLING:
+                       gpio_port_int->rising_enable &= ~(1 << gpio->pin);
+                       gpio_port_int->falling_enable |= (1 << gpio->pin);
+                       break;
+               default: /* Not handled, do not activate the interrupt */
+                       return -EINVAL;
+       }
+       NVIC_EnableIRQ(irq);
+       return 0;
+}
+void remove_gpio_callback(const struct pio* gpio)
+{
+       struct lpc_gpio_interrupts* gpio_int = LPC_GPIO_INTERRUPTS;
+       struct lpc_gpio_port_int* gpio_port_int = NULL;
+
+       /* Remove the handler */
+       switch (gpio->port) {
+               case 0:
+                       if (gpio->pin > PORT0_MAX_PIN_NUM)
+                               return;
+                       gpio_callbacks_port0[gpio->pin] = NULL;
+                       gpio_port_int = &(gpio_int->port0);
+                       break;
+               case 2:
+                       if (gpio->pin > PORT2_MAX_PIN_NUM)
+                               return;
+                       gpio_callbacks_port2[gpio->pin] = NULL;
+                       gpio_port_int = &(gpio_int->port2);
+                       break;
+               default:
+                       return;
+       }
+       /* And disable the interrupt */
+       gpio_port_int->rising_enable &= ~(1 << gpio->pin);
+       gpio_port_int->falling_enable &= ~(1 << gpio->pin);
+}
+
+
+/* Interrupt Handlers */
+/* Those handlers are far from the most effective if used without concertation
+ * with the people doing the electronic design.
+ * Use them if you place the signals generating interrupts on low numbered pins
+ */
+void PIO_Handler(struct lpc_gpio_port_int* port_int, void (**callbacks) (uint32_t))
+{
+       uint32_t status = (port_int->rising_status | port_int->falling_status);
+       uint32_t rising = port_int->rising_status;
+       uint32_t i = 0;
+
+       port_int->clear = status;
+       /* Call interrupt handlers */
+       while (status) {
+               if (status & 1) {
+                       /* Is there an handler for this one ? */
+                       if (callbacks[i] != NULL) {
+                               callbacks[i](rising & (1 << i)); /* Tell whether it was a rising edge interrupt or not */
+                       }
+               }
+               status >>= 1;
+               i++;
+       }
+}
+
+void EINT3_Handler(void)
+{
+       struct lpc_gpio_interrupts* gpio_int = LPC_GPIO_INTERRUPTS;
+       if (gpio_int->overall_int_status & LPC_GPIO_INT_PORT0_PENDING) {
+               PIO_Handler(&(gpio_int->port0), gpio_callbacks_port0);
+       }
+       if (gpio_int->overall_int_status & LPC_GPIO_INT_PORT2_PENDING) {
+               PIO_Handler(&(gpio_int->port2), gpio_callbacks_port2);
+       }
+}
+
diff --git a/drivers/i2c.c b/drivers/i2c.c
new file mode 100644 (file)
index 0000000..1f42c0f
--- /dev/null
@@ -0,0 +1,550 @@
+/****************************************************************************
+ *   drivers/i2c.c
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+/**************************************************************************** */
+/*                      I2C                                                   */
+/**************************************************************************** */
+
+#include <stdint.h>
+
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "lib/string.h"
+#include "drivers/i2c.h"
+
+
+/*
+ * I2C Bus structure
+ *
+ * clock : current i2c clock.
+ * state : global state of the i2c engine.
+ * master_status : status returned by i2c block as found in "status" register.
+ *
+ * repeated_start_restart : This buffer, if used, must have the SAME size as out_buff.
+ *           Then, instead of simply moving to the next byte, the corresponding condition
+ *           will be executed : I2C_CONT, I2C_DO_REPEATED_START, I2C_DO_STOP_START or I2C_STOP.
+ * restart_after_addr : Can be used instead of repeated_start_restart buffer to perform a
+ *           single repeated start or stop/start sequence after first adress got sent.
+ * restart_after_data : Can be used instead of repeated_start_restart buffer to perform a
+ *           single repeated start or stop/start sequence after given data byte.
+ */
+struct i2c_bus {
+       struct lpc_i2c* regs;
+       uint8_t irq;
+       uint8_t pclk_bit;
+       uint32_t power_bit;
+       uint32_t clock;
+       volatile uint32_t state;
+       volatile uint32_t master_status;
+       volatile uint32_t slave_status;
+       volatile uint32_t timeout;
+
+       volatile const char* out_buff;
+       volatile const char* repeated_start_restart;
+       volatile uint32_t write_length;
+       volatile uint32_t write_index;
+       volatile uint32_t restart_after_addr;
+       volatile uint32_t restart_after_data;
+
+       volatile char* in_buff;
+       volatile uint32_t read_length;
+       volatile uint32_t read_index;
+};
+
+
+/* FIXME : Handle multiple I2C busses ! */
+static struct i2c_bus i2c_buses[3] = {
+       {
+               .regs = (struct lpc_i2c*)LPC_I2C0,
+               .irq = I2C0_IRQ,
+               .power_bit = LPC_I2C0_POWER_ON,
+               .pclk_bit = LPC_I2C0_PCLK,
+               .state = I2C_OK,
+       },
+       {
+               .regs = (struct lpc_i2c*)LPC_I2C1,
+               .irq = I2C1_IRQ,
+               .power_bit = LPC_I2C1_POWER_ON,
+               .pclk_bit = LPC_I2C1_PCLK,
+               .state = I2C_OK,
+       },
+       {
+               .regs = (struct lpc_i2c*)LPC_I2C2,
+               .irq = I2C2_IRQ,
+               .power_bit = LPC_I2C2_POWER_ON,
+               .pclk_bit = LPC_I2C2_PCLK,
+               .state = I2C_OK,
+       },
+};
+
+
+/* FIXME : Should add a field "what to do on addr NACK" to i2c_bus structure, and use
+   it with the timeout to create a retry mechanism */
+/* FIXME : For case 58 ... What would be the use of a restart ?? perform periodic reads ? */
+/* FIXME : Implement Slave when arbitration lost ? */
+
+
+
+/* I2C Interrupt handler */
+/* Actual version will stop on NACKs */
+/* See LPC1764 user's manual UM10360 on page 457 (19.9.5) for details on I2C State machine */
+void I2C_Handler(struct i2c_bus* i2c)
+{
+       uint8_t status;
+
+       i2c->timeout = 0;
+
+       /* this handler deals with master read and master write only */
+       status = (i2c->regs->status & 0xFF);
+       i2c->master_status = status; /* Store current status */
+
+       /* I2C State Machine ! */
+       switch (status) {
+
+       /* All modes */
+               case 0x00: /* Bus Error. Enter not addressed Slave mode and release bus. */
+                       i2c->regs->ctrl_set = (I2C_ASSERT_ACK | I2C_STOP_FLAG);
+                       i2c->state = I2C_BUS_ERROR;
+                       break;
+               case 0x08:  /* A START condition has been transmitted. */
+                       i2c->write_index = 0;
+                       if (i2c->write_length != 0) {
+                               /* Send Slave Address (SLA)
+                                * Depending on R/W bit, Master Receive or master Transmit mode will be enterred. */
+                               i2c->regs->data = i2c->out_buff[i2c->write_index++];
+                               i2c->regs->ctrl_clear = I2C_START_FLAG;
+                       } else {
+                               i2c->regs->ctrl_clear = I2C_START_FLAG;
+                               i2c->regs->ctrl_set = I2C_STOP_FLAG;
+                               i2c->state = I2C_NO_DATA;
+                       }
+                       break;
+               case 0x10:  /* A repeated START has been transmitted. */
+                       /* Setting read_index to 0 is usefull only if next data byte is
+                        *    Slave Address + Read (SLA + R), but it's OK if we perform a write too, and
+                        *    is necessary for read with a null data length used to probe for devices.
+                        */
+                       i2c->read_index = 0;
+                       /* Send Slave Address and Read/Write bit (SLA + R/W)
+                        * Depending on R/W bit, Master Receive or master Transmit mode will be enterred. */
+                       i2c->regs->data = i2c->out_buff[i2c->write_index++];
+                       /* FIXME : Shouldn't this be done only in receiver mode (SLA + R) ? */
+                       i2c->regs->ctrl_clear = I2C_START_FLAG;
+                       break;
+               case 0x38: /* Arbitration lost. We don't deal with multiple master situation */
+                       /* FIXME : We have two option :
+                        *  - do nothing, which will release the bus. Will lead to "Not Addressed Slave" state.
+                        *      This options allows handling of multiple master topologies.
+                        *  - Set start flag, and a start condition will be transmitted when bus becomes free.
+                        */
+                       /* We choose to do nothing, we ARE the true master after all ! */
+                       i2c->state = I2C_ARBITRATION_LOST;
+                       break;
+
+       /* Master Transmitter Mode Only */
+               case 0x18:  /* Address + Write transmitted and ACK'ed */
+                       if (i2c->write_length == 1) { /* Nothing more to send, we must stop. */
+                               /* This one is used to probe devices, or wait for completion */
+                               i2c->regs->ctrl_set = I2C_STOP_FLAG;
+                               i2c->state = I2C_NO_DATA;
+                       } else {
+                               uint32_t condition = i2c->restart_after_addr;
+                               if (i2c->repeated_start_restart)
+                                       condition = i2c->repeated_start_restart[i2c->write_index - 1];
+                               switch (condition) {
+                                       case I2C_CONT: /* Send next data byte */
+                                               i2c->regs->data = i2c->out_buff[i2c->write_index++];
+                                               break;
+                                       case I2C_DO_REPEATED_START: /* Send repeated start condition */
+                                               i2c->regs->ctrl_set = I2C_START_FLAG;
+                                               break;
+                                       case I2C_DO_STOP_START: /* Send STOP / START condition */
+                                               i2c->regs->ctrl_set = I2C_STOP_FLAG | I2C_START_FLAG;
+                                               break;
+                                       case I2C_STOP: /* Send STOP condition */
+                                               i2c->regs->ctrl_set = I2C_STOP_FLAG;
+                                               i2c->state = I2C_NO_DATA;
+                                               break;
+                               }
+                               if (i2c->restart_after_addr)
+                                       i2c->restart_after_addr = 0; /* This one must be defused once used */
+                       }
+                       break;
+               case 0x20:  /* NACK on Address + Write (SLA + W) */
+               case 0x30:  /* NACK on Data byte */
+                       /* FIXME : We have three other options : Resend / Repeated START / STOP + START
+                        *     If I'm right, Resend would require moving write_index back and using same data
+                        *     Repeated START ? ignore the NACK and move to reading data ?
+                        *     STOP + START ? Start over ? write_index will be set to 0 in I2C_STARTED case (0x08)
+                        * Sending a STOP condition will end transactions and let the driver take the decision.
+                        */
+                       i2c->regs->ctrl_set = I2C_STOP_FLAG;
+                       i2c->state = I2C_NACK;
+                       break;
+               case 0x28: /* Data byte has been transmitted and ACK received */
+                       if (i2c->write_index < i2c->write_length) {
+                               /* More to write, but what do we do ? */
+                               uint32_t condition = I2C_CONT;
+                               if (i2c->restart_after_data == i2c->write_index)
+                                       condition = I2C_DO_REPEATED_START;
+                               else if (i2c->repeated_start_restart)
+                                       condition = i2c->repeated_start_restart[i2c->write_index - 1];
+                               switch (condition) {
+                                       case I2C_CONT: /* Send next data byte */
+                                               i2c->regs->data = i2c->out_buff[i2c->write_index++];
+                                               break;
+                                       case I2C_DO_REPEATED_START: /* Send repeated start condition */
+                                               i2c->regs->ctrl_set = I2C_START_FLAG;
+                                               break;
+                                       case I2C_DO_STOP_START: /* Send STOP / START condition */
+                                               i2c->regs->ctrl_set = I2C_STOP_FLAG | I2C_START_FLAG;
+                                               break;
+                                       case I2C_STOP: /* Send STOP condition */
+                                               /* Hey, why sending a STOP and terminate communication if we are not at
+                                                * the end of the write buffer ?? */
+                                               i2c->regs->ctrl_set = I2C_STOP_FLAG;
+                                               i2c->state = I2C_OK;
+                                               break;
+                               }
+                       } else {
+                               if (i2c->read_length != 0) { /* Anything to read ? */
+                                       i2c->regs->ctrl_set = I2C_START_FLAG;
+                               } else {
+                                       i2c->regs->ctrl_set = I2C_STOP_FLAG;
+                                       i2c->state = I2C_OK;
+                               }
+                       }
+                       break;
+
+       /* Master Receiver Mode Only */
+               case 0x40:  /* Address + Read transmitted and ACK'ed */
+                       if ((i2c->read_index + 1) < i2c->read_length) {
+                               /* Will go to State 0x50 (assert ACK after data is received) */
+                               i2c->regs->ctrl_set = I2C_ASSERT_ACK;
+                       } else {
+                               /* Will go to State 0x58 (NACK after data is received) */
+                               i2c->regs->ctrl_clear = I2C_ASSERT_ACK;
+                       }
+                       break;
+
+               case 0x48:  /* NACK on Address + Read (SLA + R) */
+                       /* FIXME : We have two other options : Repeated START / STOP + START */
+                       i2c->regs->ctrl_set = I2C_STOP_FLAG;
+                       i2c->state = I2C_NACK;
+                       break;
+
+               case 0x50: /* Data byte has been received and ACK sent */
+                       i2c->in_buff[i2c->read_index++] = i2c->regs->data;
+                       if ((i2c->read_index + 1) < i2c->read_length) {
+                               /* assert ACK after data is received, requesting next Data from slave */
+                               i2c->regs->ctrl_set = I2C_ASSERT_ACK;
+                       } else {
+                               /* Assert NACK on last byte, telling the slave to stop transmitting data
+                                  and release the I2C Bus */
+                               i2c->regs->ctrl_clear = I2C_ASSERT_ACK;
+                       }
+                       break;
+
+               case 0x58: /* Data byte has been received and NACK "sent" */
+                       /* This tells the slave it was the last byte. We should be done. */
+                       i2c->in_buff[i2c->read_index++] = i2c->regs->data;
+                       /* FIXME : We have two other options : Repeated START or STOP + START,
+                        *    but what for ? periodic reads ? */
+                       i2c->regs->ctrl_set = I2C_STOP_FLAG;
+                       i2c->state = I2C_OK;
+                       break;
+
+               default:
+                       i2c->state = I2C_ERROR_UNKNOWN;
+                       break;
+       }
+
+       /* Clear interrupt flag. This has to be done last. */
+       i2c->regs->ctrl_clear = I2C_INTR_FLAG;
+       return;
+}
+
+void I2C_0_Handler(void)
+{
+       I2C_Handler(&(i2c_buses[0]));
+}
+void I2C_1_Handler(void)
+{
+       I2C_Handler(&(i2c_buses[1]));
+}
+void I2C_2_Handler(void)
+{
+       I2C_Handler(&(i2c_buses[2]));
+}
+
+
+/***************************************************************************** */
+/*                        I2C access                                           */
+/***************************************************************************** */
+static int i2c_perform_data_transfer(struct i2c_bus* i2c)
+{
+       int ret = 0;
+
+       /* Start the process */
+       i2c->state = I2C_BUSY;
+       i2c->regs->ctrl_set = I2C_START_FLAG;
+       /* Wait for process completion */
+       do {} while (i2c->state == I2C_BUSY);  /* FIXME : OS should schedule here */
+
+       /* Handle returned state (errors or OK) */
+       switch (i2c->state) {
+               case I2C_OK:
+               case I2C_NO_DATA:
+                       /* Return 0 : success */
+                       break;
+               case I2C_NACK:
+                       ret = -EREMOTEIO;
+                       break;
+               case I2C_ARBITRATION_LOST:
+                       ret = -EBUSY;
+                       break;
+               case I2C_BUS_ERROR: /* This one is bad ... */
+               case I2C_ERROR_UNKNOWN:
+               default:
+                       ret = -EIO;
+                       break;
+       }
+
+       /* Force device to release the bus :
+        *    send a START followed by a STOP (initiate transmission with nul write_length) */
+       i2c->state = I2C_BUSY;
+       i2c->write_length = 0;
+       i2c->regs->ctrl_set = I2C_START_FLAG;
+       do {} while (i2c->state == I2C_BUSY); /* FIXME : OS should schedule here */
+       i2c->state = I2C_OK;
+
+       return ret;
+}
+
+/* Read
+ * Performs a non-blocking read on the module's i2c bus.
+ *   bus_num : I2C bus number to use.
+ *   cmd_buf : buffer containing all control byte to be sent on the i2c bus
+ *   cmd_size : size of the cmd_buf command buffer
+ *   ctrl_buf : buffer containing action to be done after sending, like repeated START conditions
+ *         if not NULL, ctrl_buf has the same size as cmd_buf
+ *   inbuff : the buffer where read data will be put. May be NULL if count is 0.
+ *   count : the number of bytes to be read.
+ * RETURN VALUE
+ *   Upon successfull completion, returns the number of bytes read. On error, returns a negative
+ *   integer equivalent to errors from glibc.
+ *   -EBADFD : Device not initialized (-77)
+ *   -EBUSY : Device or ressource Busy or Arbitration lost (-16)
+ *   -EAGAIN : Device already in use (-11)
+ *   -EINVAL : Invalid argument (no cmd_buf, or no inbuff when count > 0) (-22)
+ *   -EREMOTEIO : Device did not acknowledge (-121)
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine (-5)
+ */
+int i2c_read(uint8_t bus_num, const void *cmd_buf, size_t cmd_size, const void* ctrl_buf, void* inbuff, size_t count)
+{
+       int ret = 0;
+       struct i2c_bus* i2c = NULL;
+
+       if (bus_num >= NB_I2C_BUSSES) {
+               return -EINVAL;
+       }
+       i2c = &(i2c_buses[bus_num]);
+
+       /* Checks */
+       if (i2c->clock == 0)
+               return -EBADFD;
+       if (cmd_buf == NULL)
+               return -EINVAL;
+       if ((inbuff == NULL) && (count > 0))
+               return -EINVAL;
+
+       if (i2c->state == I2C_BUSY) {
+               return -EBUSY;
+       }
+       if (i2c->state != I2C_OK) {
+               /* What should we do ??? someone failed to reset status ? */
+       }
+
+       /* Set up mod_i2c for read operation */
+       /* command (write) buffer */
+       i2c->out_buff = cmd_buf;
+       i2c->write_length = cmd_size;
+       /* control buffer, if any. Note that it's the only way to control
+        *   operations on modules i2C bus to simplify the interface */
+       i2c->repeated_start_restart = ctrl_buf;
+       i2c->restart_after_addr = I2C_CONT;
+       i2c->restart_after_data = 0;
+       /* read buffer */
+       i2c->in_buff = inbuff;
+       i2c->read_length = count;
+       i2c->read_index = 0;
+
+       ret = i2c_perform_data_transfer(i2c);
+       if (ret == 0) {
+               return i2c->read_index;
+       } else {
+               return ret;
+       }
+}
+
+/* Write
+ * Performs a non-blocking write on the module's i2c bus.
+ *   bus_num : I2C bus number to use.
+ *   buf : buffer containing all byte to be sent on the i2c bus,
+ *         including conrtol bytes (address, offsets, ...)
+ *   count : the number of bytes to be sent, including address bytes and so on.
+ *   ctrl_buf : buffer containing action to be done after sending, like repeated START conditions
+ *         FIXME : note that STOP + START conditions are not allowed, the STOP would lead to sending
+ *         the first bytes of buf, creating an infinite loop.
+ * RETURN VALUE
+ *   Upon successfull completion, returns the number of bytes written. On error, returns a negative
+ *   integer equivalent to errors from glibc.
+ *   -EBADFD : Device not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EAGAIN : Device already in use
+ *   -EINVAL : Invalid argument (buf)
+ *   -EREMOTEIO : Device did not acknowledge
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+int i2c_write(uint8_t bus_num, const void *buf, size_t count, const void* ctrl_buf)
+{
+       int ret = 0;
+       struct i2c_bus* i2c = NULL;
+
+       if (bus_num >= NB_I2C_BUSSES) {
+               return -EINVAL;
+       }
+       i2c = &(i2c_buses[bus_num]);
+
+       /* Checks */
+       if (i2c->clock == 0)
+               return -EBADFD;
+       if (buf == NULL)
+               return -EINVAL;
+
+       if (i2c->state == I2C_BUSY) {
+               return -EBUSY;
+       }
+       if (i2c->state != I2C_OK) {
+               /* What should we do ??? someone failed to reset status ? */
+       }
+
+       /* Clear read information to prevent entering master receiver states */
+       i2c->read_length = 0;
+       i2c->in_buff = NULL;
+       i2c->state = I2C_BUSY;
+       /* Set up mod_i2c for write operation */
+       i2c->out_buff = buf;
+       i2c->write_length = count;
+       /* control buffer, if any. Note that it's the only way to control
+        *   operations on modules i2C bus to simplify the interface */
+       i2c->restart_after_addr = I2C_CONT;
+       i2c->repeated_start_restart = ctrl_buf;
+       i2c->restart_after_data = 0;
+
+       ret = i2c_perform_data_transfer(i2c);
+       if (ret == 0) {
+               return count;
+       } else {
+               return ret;
+       }
+}
+
+
+
+/***************************************************************************** */
+/*                I2C Init                                                     */
+/***************************************************************************** */
+static void i2c_clock_on(struct i2c_bus* i2c)
+{
+       uint32_t main_clock = get_main_clock();
+       uint32_t scl_clk = 0;
+
+       /* Setup I2C clock */
+       scl_clk = (main_clock / i2c->clock);
+       i2c->regs->clk_duty_high = (scl_clk / 2);
+       i2c->regs->clk_duty_low = (scl_clk - i2c->regs->clk_duty_high);
+}
+
+/* I2C on / off
+ *   bus_num : I2C bus number to use.
+ *   i2c_clk_freq : I2C clock freqeuncy in Hz
+ */
+int i2c_on(uint8_t bus_num, uint32_t i2c_clk_freq)
+{
+       struct i2c_bus* i2c = NULL;
+
+       if (bus_num >= NB_I2C_BUSSES) {
+               return -EINVAL;
+       }
+       i2c = &(i2c_buses[bus_num]);
+
+       NVIC_DisableIRQ(i2c->irq);
+       /* Power on I2C block */
+       subsystem_power(i2c->power_bit, 1);
+       
+       /* Set CCLK divider for PCLK */
+       set_subsystem_clk_divider(i2c->pclk_bit, LPC_PCLK_CCLK);
+       /* Set clock */
+       i2c->clock = i2c_clk_freq;
+       i2c_clock_on(i2c);
+       /* Enable I2C */
+       /* FIXME: if enabling slave functions, add I2C_ASSERT_ACK flag */
+       i2c->regs->ctrl_set = (I2C_ENABLE_FLAG);
+       /* And enable interrupts */
+       NVIC_EnableIRQ(i2c->irq);
+
+       return 0;
+}
+
+int i2c_off(uint8_t bus_num)
+{
+       struct i2c_bus* i2c = NULL;
+
+       if (bus_num >= NB_I2C_BUSSES) {
+               return -EINVAL;
+       }
+       i2c = &(i2c_buses[bus_num]);
+       
+       NVIC_DisableIRQ(i2c->irq);
+       subsystem_power(i2c->power_bit, 0);
+       i2c->clock = 0;
+
+       return 0;
+}
+
+/* Allow system to propagate main clock */
+void i2c_clock_update(void)
+{
+       int i = 0;
+
+       for (i = 0; i < NB_I2C_BUSSES; i++) {
+               if (i2c_buses[i].clock != 0) {
+               /* FIXME : we should stop I2C transfers, disable I2C interrupts and stop I2C clock. */
+                       i2c_clock_on(&(i2c_buses[i]));
+               }
+       }
+}
+
+
diff --git a/drivers/serial.c b/drivers/serial.c
new file mode 100644 (file)
index 0000000..f4b809d
--- /dev/null
@@ -0,0 +1,455 @@
+/****************************************************************************
+ *  drivers/serial.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+
+/***************************************************************************** */
+/*                UARTs                                                        */
+/***************************************************************************** */
+/* Both UARTs are available, UART numbers are in the range 0 - 1 */
+
+#include <stdint.h>
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "lib/string.h"
+#include "lib/bit_arithm.h"
+#include "drivers/serial.h"
+
+#define SERIAL_OUT_BUFF_SIZE 64
+struct uart_device
+{
+       uint32_t num;
+       struct lpc_uart* regs;
+       uint32_t baudrate;
+       uint32_t config;
+       uint32_t capabilities;
+       uint32_t current_mode;
+
+       /* Output buffer */
+       volatile char out_buff[SERIAL_OUT_BUFF_SIZE];
+       volatile uint32_t sending; /* Actual sending position in out buffer */
+       /* This lock only prevents multiple calls to serial_write() to execute simultaneously */
+       volatile uint32_t out_lock;
+       volatile uint32_t out_length; /* actual position to add in out buffer */
+
+       /* Input */
+       void (*rx_callback)(uint8_t); /* Possible RX callback */
+};
+
+#define NUM_UARTS 4
+static struct uart_device uarts[NUM_UARTS] = {
+       {
+               .num = 0,
+               .regs = (struct lpc_uart*)LPC_UART_0,
+               .baudrate = 0,
+               .config = (LPC_UART_8BIT | LPC_UART_NO_PAR | LPC_UART_1STOP),
+               .out_buff = {0},
+               .sending = 0,
+               .out_lock = 0,
+               .rx_callback = NULL,
+               .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_IRDA),
+               .current_mode = SERIAL_MODE_UART,
+       },
+       {
+               .num = 1,
+               .regs = (struct lpc_uart*)LPC_UART_1,
+               .baudrate = 0,
+               .config = (LPC_UART_8BIT | LPC_UART_NO_PAR | LPC_UART_1STOP),
+               .out_buff = {0},
+               .sending = 0,
+               .out_lock = 0,
+               .rx_callback = NULL,
+               .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_RS485 | SERIAL_CAP_FULL_MODEM),
+               .current_mode = SERIAL_MODE_UART,
+       },
+       {
+               .num = 2,
+               .regs = (struct lpc_uart*)LPC_UART_2,
+               .baudrate = 0,
+               .config = (LPC_UART_8BIT | LPC_UART_NO_PAR | LPC_UART_1STOP),
+               .out_buff = {0},
+               .sending = 0,
+               .out_lock = 0,
+               .rx_callback = NULL,
+               .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_IRDA),
+               .current_mode = SERIAL_MODE_UART,
+       },
+       {
+               .num = 3,
+               .regs = (struct lpc_uart*)LPC_UART_3,
+               .baudrate = 0,
+               .config = (LPC_UART_8BIT | LPC_UART_NO_PAR | LPC_UART_1STOP),
+               .out_buff = {0},
+               .sending = 0,
+               .out_lock = 0,
+               .rx_callback = NULL,
+               .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_IRDA),
+               .current_mode = SERIAL_MODE_UART,
+       },
+};
+
+static void uart_check_rx(struct uart_device* uart, uint32_t intr)
+{
+       if ((intr & LPC_UART_INT_MASK) == LPC_UART_INT_RX) {
+               uint8_t data = uart->regs->func.buffer;
+               if (uart->rx_callback != NULL) {
+                       /* Call the Rx callback */
+                       uart->rx_callback(data);
+               } else {
+                       /* Echo */
+                       uart->regs->func.buffer = data;
+               }
+       }
+}
+
+static void uart_check_tx(struct uart_device* uart, uint32_t intr)
+{
+       /* We are currently sending, send next char */
+       if ((intr & LPC_UART_INT_MASK) == LPC_UART_INT_TX) {
+               if (uart->out_buff && uart->sending && (uart->out_length > uart->sending)) {
+                       uart->regs->func.buffer = uart->out_buff[uart->sending];
+                       uart->sending++;
+               } else {
+                       uart->sending = 0;
+               }
+       }
+}
+
+/* Generic UART handler */
+static void UART_Handler(struct uart_device* uart)
+{
+       uint32_t intr = uart->regs->func.intr_pending;
+
+       uart_check_rx(uart, intr);
+       uart_check_tx(uart, intr);
+}
+
+
+/* Handlers */
+void UART_0_Handler(void)
+{
+       UART_Handler(&uarts[0]);
+}
+void UART_1_Handler(void)
+{
+       UART_Handler(&uarts[1]);
+}
+
+
+/* Start sending buffer content */
+static void uart_start_sending(uint32_t uart_num)
+{
+       struct uart_device* uart = &uarts[uart_num];
+
+       if (uart->out_buff == NULL)
+               return;
+
+       if (!uart->sending && (uart->out_length != 0)) {
+               uart->sending++;
+               uart->regs->func.buffer = uart->out_buff[0];
+       }
+}
+
+
+
+/***************************************************************************** */
+/*    Serial Write
+ *
+ * Try to send at most "length" characters from "buf" on the requested uart.
+ * Returns -1 on error, or number of characters copied into output buffer, witch
+ * may be less than requested "length"
+ * Possible errors: requested uart does not exists or unable to acquire uart lock.
+ *
+ * Warning for Real Time : This implementation will block if there's already a
+ * transmission ongoing.
+ */
+int serial_write(uint32_t uart_num, const char *buf, uint32_t length)
+{
+       struct uart_device* uart = NULL;
+
+       if (uart_num >= NUM_UARTS)
+               return -1;
+
+       uart = &uarts[uart_num];
+       /* Lock acquire */
+       if (sync_lock_test_and_set(&uart->out_lock, 1) == 1) {
+               return -1;
+       }
+
+       /* If UART is sending wait for buffer empty */
+       /* FIXME : be smart for OS, call scheduler or return */
+       while (uart->sending != 0) {
+               if (get_priority_mask() == 0)
+                       uart_check_tx(uart, uart->regs->func.intr_pending);
+       }
+
+       if (length > SERIAL_OUT_BUFF_SIZE) {
+               length = SERIAL_OUT_BUFF_SIZE;
+       }
+       memcpy((char*)uart->out_buff, buf, length);
+       uart->out_length = length;
+
+       /* Turn output on */
+       uart_start_sending(uart_num);
+
+       /* Release the lock */
+       sync_lock_release(&uart->out_lock);
+
+       return length;
+}
+
+
+/***************************************************************************** */
+/*    Serial Flush
+ *
+ * Wait until all characters have been sent
+ * Returns -1 on error, 0 on success.
+ * Possible errors: requested uart does not exists or unable to acquire uart lock.
+ *
+ * Warning for Real Time : This implementation will block if there's already a
+ * transmission ongoing.
+ */
+int serial_flush(uint32_t uart_num)
+{
+       struct uart_device* uart = NULL;
+
+       if (uart_num >= NUM_UARTS)
+               return -1;
+
+       uart = &uarts[uart_num];
+
+       /* Active wait for message to be sent. If interrupts are
+        * disabled, call the UART handler while waiting. */
+       while (uart->sending) {
+               if (get_priority_mask() == 0)
+                       uart_check_tx(uart, uart->regs->func.intr_pending);
+       }
+
+       return 0;
+}
+
+
+/***************************************************************************** */
+/*   UART Setup : private part : Clocks, Pins, Power and Mode   */
+
+struct uart_def
+{
+       uint8_t irq;
+       uint8_t clk_num;
+       uint32_t power_offset;
+};
+static struct uart_def uart_defs[NUM_UARTS] = {
+       { UART0_IRQ, LPC_UART0_PCLK, LPC_UART0_POWER_ON },
+       { UART1_IRQ, LPC_UART1_PCLK, LPC_UART1_POWER_ON },
+       { UART2_IRQ, LPC_UART2_PCLK, LPC_UART2_POWER_ON },
+       { UART3_IRQ, LPC_UART3_PCLK, LPC_UART3_POWER_ON },
+};
+
+/* FIXME : compute values for other Clock rates and add a pclk parameter or define
+ *    to select between pclk frequencies
+ */
+struct uart_clk_cfg {
+       uint32_t baudrate;
+       uint8_t divisor_latch_lsb;
+       uint8_t div_add_val;
+       uint8_t mul_val;
+};
+static struct uart_clk_cfg uart_clk_table[] = {
+       { 1152000, 2, 4, 13},
+       { 0, 0, 0, 0, },
+};
+
+/* UART Clock Setup */
+/* Note : for both uarts we use full peripheral clock.
+ *    With a minimum main clock of 12MHz, this gives 12MHz/16 = 750kbauds at least
+ *    for UARTs baudrates.
+ * Note : IRQ are off, whether called by system update or by UART on helper
+ */
+static void uart_clk_on(uint32_t uart_num, uint32_t baudrate)
+{
+       struct lpc_uart* uart = uarts[uart_num].regs; /* Get the right registers */
+       uint32_t div = 0, pclk = 0;
+       /* Save baudrate value */
+       uarts[uart_num].baudrate = baudrate;
+       /* Configure UART clock */
+       set_subsystem_clk_divider(uart_defs[uart_num].clk_num, LPC_PCLK_CCLK);
+       pclk = get_main_clock(); /* See above note */
+       div = (pclk / (baudrate * 16));
+       /* The easy one : divider is an integer, or baudrate is low enought for the aproximation */
+       if ((baudrate <= 115200) || ((div * baudrate * 16) == pclk)) {
+               uart->line_ctrl |= LPC_UART_ENABLE_DLAB;
+               uart->ctrl.divisor_latch_lsb = (div & 0xff);
+               uart->ctrl.divisor_latch_msb = ((div >> 8) & 0xFF);
+               uart->line_ctrl &= ~LPC_UART_ENABLE_DLAB;
+       } else {
+               int i = 0;
+               /* Do not try to communicate at high speed with a low speed clock ... or compute the table
+                * for your clock rate */
+               if (pclk != (48 * 1000 * 1000)) {
+                       return;
+               }
+               while (uart_clk_table[i].baudrate != 0) {
+                       if (uart_clk_table[i].baudrate < baudrate) {
+                               i++;
+                               continue;
+                       }
+                       uart->line_ctrl |= LPC_UART_ENABLE_DLAB;
+                       uart->ctrl.divisor_latch_lsb = uart_clk_table[i].divisor_latch_lsb;
+                       uart->ctrl.divisor_latch_msb = 0;
+                       uart->fractional_div = (uart_clk_table[i].div_add_val | (uart_clk_table[i].mul_val << 4));
+                       uart->line_ctrl &= ~LPC_UART_ENABLE_DLAB;
+                       break;
+               }
+       }
+}
+
+static uint32_t uart_setup(uint32_t uart_num)
+{
+       struct lpc_uart* uart = uarts[uart_num].regs; /* Get the right registers */
+       uint32_t status = 0;
+       /* Set up UART mode */
+       uart->line_ctrl = uarts[uart_num].config;;
+       /* Clear all fifo, reset and enable them */
+       /* Note : fifo trigger level is one bit */
+       uart->ctrl.fifo_ctrl = (LPC_UART_FIFO_EN | LPC_UART_TX_CLR | LPC_UART_RX_CLR);
+       /* Clear the Line Status Register, return it to prevent compiler from removing the read */
+       status = uart->line_status;
+       /* Enable UART Interrupt */
+       uart->func.intr_enable = (LPC_UART_RX_INT_EN | LPC_UART_TX_INT_EN);
+
+       return status;
+}
+
+/***************************************************************************** */
+/*   Public access to UART setup   */
+
+/* Allow any change to the main clock to be forwarded to us */
+void uart_clk_update(void)
+{
+       int i = 0;
+       for (i = 0; i < NUM_UARTS; i++) {
+               if (uarts[i].baudrate != 0) {
+                       uart_clk_on(i, uarts[i].baudrate);
+               }
+       }
+}
+
+/* Change uart mode to RS485
+ * return -ENODEV when the device does not support RS485 mode.
+ */
+int uart_set_mode_rs485(uint32_t uart_num, uint32_t control, uint8_t addr, uint8_t delay)
+{
+       struct uart_device* uart = NULL;
+       struct lpc_uart* uart_regs = NULL;
+       if (uart_num >= NUM_UARTS)
+               return -EINVAL;
+       uart = &uarts[uart_num];
+       uart_regs = uart->regs; /* Get the right registers */
+
+       if (!(uart->capabilities & SERIAL_CAP_RS485)) {
+               return -ENODEV;
+       }
+       /* Disable all other modes */
+       uart_regs->irda_ctrl = 0;
+
+       /* Set current mode */
+       uart->current_mode = SERIAL_MODE_RS485;
+       uart_regs->RS485_ctrl = (control & 0xFF);
+       uart_regs->RS485_addr_match = LPC_RS485_ADDR(addr);
+       uart_regs->RS485_dir_ctrl_delay = LPC_RS485_DIR_DELAY(delay);
+       return 0;
+}
+
+/* Change uart mode to IRDA
+ * pulse_width is the number of clock cycles for a pulse. Should dbe a power of 2.
+ * return -ENODEV when the device does not support IrDA mode.
+ */
+int uart_set_mode_irda(uint32_t uart_num, uint32_t control, uint16_t pulse_width)
+{
+       struct uart_device* uart = NULL;
+       struct lpc_uart* uart_regs = NULL;
+       uint8_t pulse_div = 0;
+
+       if (uart_num >= NUM_UARTS)
+               return -EINVAL;
+       uart = &uarts[uart_num];
+       uart_regs = uart->regs; /* Get the right registers */
+
+       if (!(uart->capabilities & SERIAL_CAP_IRDA)) {
+               return -ENODEV;
+       }
+       /* Disable all other modes */
+       uart_regs->RS485_ctrl = 0;
+
+       /* Set current mode */
+       uart->current_mode = SERIAL_MODE_IRDA;
+       /* Setup IrDA */
+       if (pulse_width < 2) {
+               pulse_div = 0;
+       } else {
+               pulse_div = (31 - clz(pulse_width & 0x1FF));
+       }
+       uart_regs->irda_ctrl = control | LPC_IRDA_PULSEDIV(pulse_div);
+       return 0;
+}
+
+
+/* Do we need to allow setting of other parameters ? (Other than 8n1) */
+int uart_on(uint32_t uart_num, uint32_t baudrate, void (*rx_callback)(uint8_t))
+{
+       struct uart_def* uart = NULL;
+       uint32_t status = 0;
+
+       if (uart_num >= NUM_UARTS)
+               return -EINVAL;
+       uart = &uart_defs[uart_num];
+       uarts[uart_num].rx_callback = rx_callback;
+
+       NVIC_DisableIRQ( uart->irq );
+       /* Turn On power */
+       subsystem_power(uart->power_offset, 1);
+       /* Setup clock acording to baudrate */
+       uart_clk_on(uart_num, baudrate);
+       /* Setup mode, fifo, ... */
+       status = uart_setup(uart_num);
+       /* Enable interrupts back on */
+       NVIC_EnableIRQ( uart->irq );
+
+       return status;
+}
+
+void uart_off(uint32_t uart_num)
+{
+       struct uart_def* uart = NULL;
+       if (uart_num >= NUM_UARTS)
+               return;
+       uart = &uart_defs[uart_num];
+
+       NVIC_DisableIRQ( uart->irq );
+       /* Turn Off power */
+       subsystem_power(uart->power_offset, 0);
+       uarts[uart_num].baudrate = 0;
+       uarts[uart_num].rx_callback = NULL;
+}
+
+
+
diff --git a/drivers/ssp.c b/drivers/ssp.c
new file mode 100644 (file)
index 0000000..7547655
--- /dev/null
@@ -0,0 +1,407 @@
+/****************************************************************************
+ *  drivers/ssp.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+
+/***************************************************************************** */
+/*                SSP                                                          */
+/***************************************************************************** */
+
+#include <stdint.h>
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "lib/string.h"
+#include "drivers/ssp.h"
+
+
+struct ssp_device
+{
+       uint32_t num;
+       struct lpc_ssp* regs;
+       uint32_t current_clk;
+       uint32_t mutex;
+       volatile uint32_t int_rx_stats;
+       volatile uint32_t int_overrun_stats;
+       volatile uint32_t int_rx_timeout_stats;
+
+       uint8_t irq;
+       uint8_t pclk_bit;
+       uint32_t power_bit;
+};
+
+#define NUM_SSPS 2
+static struct ssp_device ssps[NUM_SSPS] = {
+       {
+               .num = 0,
+               .regs = LPC_SSP0,
+               .current_clk = 0,
+               .mutex = 0,
+               .int_rx_stats = 0,
+               .int_overrun_stats = 0,
+               .int_rx_timeout_stats = 0,
+               .irq = SSP0_IRQ,
+               .pclk_bit = (uint8_t)LPC_SSP0_POWER_ON,
+               .power_bit = LPC_SSP0_PCLK,
+       },
+       {
+               .num = 0,
+               .regs = LPC_SSP1,
+               .current_clk = 0,
+               .mutex = 0,
+               .int_rx_stats = 0,
+               .int_overrun_stats = 0,
+               .int_rx_timeout_stats = 0,
+               .irq = SSP1_IRQ,
+               .pclk_bit = (uint8_t)LPC_SSP1_POWER_ON,
+               .power_bit = LPC_SSP1_PCLK,
+       },
+};
+
+
+
+/* Handlers */
+void SSP_0_Handler(void)
+{
+       struct lpc_ssp* ssp = LPC_SSP0;
+       uint32_t intr_flags = ssp->masked_int_status;
+
+       /* Clear the interrupts. Other bits are cleared by fifo access */
+       ssp->int_clear = (intr_flags & (LPC_SSP_INTR_RX_OVERRUN | LPC_SSP_INTR_RX_TIMEOUT));
+       if (intr_flags & LPC_SSP_INTR_RX_OVERRUN) {
+               ssps[0].int_overrun_stats += 1;
+       }
+       if (intr_flags & LPC_SSP_INTR_RX_TIMEOUT) {
+               ssps[0].int_rx_timeout_stats += 1;
+       }
+}
+
+
+
+/***************************************************************************** */
+/* SPI Bus mutex */
+
+#if MULTITASKING == 1
+int spi_get_mutex(uint8_t ssp_num)
+{
+       /* Note : a multitasking OS should call the scheduler here. Any other system
+        *   will get frozen, unless some interrupt routine has been set to release
+        *   the mutex.
+        */
+       do {} while (sync_lock_test_and_set(&(ssps[ssp_num].mutex), 1) == 1);
+       return 1;
+}
+#else
+int spi_get_mutex(uint8_t ssp_num)
+{
+       if (sync_lock_test_and_set(&(ssps[ssp_num].mutex), 1) == 1) {
+               return -EBUSY;
+       }
+       return 1;
+}
+#endif
+void spi_release_mutex(uint8_t ssp_num)
+{
+       sync_lock_release(&(ssps[ssp_num].mutex));
+}
+
+
+/***************************************************************************** */
+/* This function is used to transfer a word (4 to 16 bits) to AND from a device
+ * As the SPI bus is full duplex, data can flow in both directions, but the clock is
+ *   always provided by the master. The SPI clock cannont be activated without sending
+ *   data, which means we must send data to the device when we want to read data from
+ *   the device.
+ * Note : the SSP device number is not checked, thus a value above the number of SSP
+ *   devices present on the micro-controller may break your programm.
+ *   Double check the value of the ssp_num parameter. The check is made on the call to
+ *   ssp_master_on() or ssp_slave_on().
+ * This function does not take care of the SPI chip select.
+ */
+uint16_t spi_transfer_single_frame(uint8_t ssp_num, uint16_t data)
+{
+       struct lpc_ssp* ssp_regs = ssps[ssp_num].regs;
+       ssp_regs->data = data;
+       /* Wait until the busy bit is cleared */
+       while (ssp_regs->status & LPC_SSP_ST_BUSY);
+       return ssp_regs->data;
+}
+
+
+
+/***************************************************************************** */
+/* Multiple words (4 to 16 bits) transfer function on the SPI bus. */
+
+/* Internal function used to send 9 to 16 bits wide data */
+static int spi_transfer_words(struct lpc_ssp* ssp, uint16_t* data_out, uint16_t* data_in, int size)
+{
+       int count = 0;
+       uint16_t data_read = 0; /* Used to store SPI Rx data */
+
+       /* Transfer */
+       do {
+               /* Fill Tx fifo with available data, but stop if rx fifo is full */
+               while ((count < size) &&
+                         ((ssp->status & (LPC_SSP_ST_TX_NOT_FULL | LPC_SSP_ST_RX_FULL)) == LPC_SSP_ST_TX_NOT_FULL)) {
+                       ssp->data = *data_out;
+                       count++;
+                       data_out++;
+               }
+
+               /* Read some of the replies, but stop if there's still data to send and the fifo
+                *  is running short */
+               while ((ssp->status & LPC_SSP_ST_RX_NOT_EMPTY) &&
+                               !((count < size) && (ssp->raw_int_status & LPC_SSP_INTR_TX_HALF_EMPTY))) {
+                       /* Read the data (mandatory) */
+                       data_read = ssp->data;
+                       if (data_in != NULL) {
+                               /* And store when requested */
+                               *data_in = data_read;
+                               data_in++;
+                       }
+               }
+       /* Go on till both all data is sent and all data is received */
+       } while ((count < size) || (ssp->status & (LPC_SSP_ST_BUSY | LPC_SSP_ST_RX_NOT_EMPTY)));
+
+       return count;
+}
+/* Internal function used to send 4 to 8 bits wide data */
+static int spi_transfer_bytes(struct lpc_ssp* ssp, uint8_t* data_out, uint8_t* data_in, int size)
+{
+       int count = 0;
+       uint8_t data_read = 0; /* Used to store SPI Rx data */
+
+       /* Transfer */
+       do {
+               /* Fill Tx fifo with available data, but stop if rx fifo is full */
+               while ((count < size) &&
+                         ((ssp->status & (LPC_SSP_ST_TX_NOT_FULL | LPC_SSP_ST_RX_FULL)) == LPC_SSP_ST_TX_NOT_FULL)) {
+                       ssp->data = (uint16_t)(*data_out);
+                       count++;
+                       data_out++;
+               }
+
+               /* Read some of the replies, but stop if there's still data to send and the fifo
+                *  is running short */
+               while ((ssp->status & LPC_SSP_ST_RX_NOT_EMPTY) &&
+                               !((count < size) && (ssp->raw_int_status & LPC_SSP_INTR_TX_HALF_EMPTY))) {
+                       /* Read the data (mandatory) */
+                       data_read = (uint8_t)ssp->data;
+                       if (data_in != NULL) {
+                               /* And store when requested */
+                               *data_in = data_read;
+                               data_in++;
+                       }
+               }
+       /* Go on till both all data is sent and all data is received */
+       } while ((count < size) || (ssp->status & (LPC_SSP_ST_BUSY | LPC_SSP_ST_RX_NOT_EMPTY)));
+
+       return count;
+}
+
+
+/* Multiple words (4 to 16 bits) transfer function on the SPI bus.
+ * The SSP fifo is used to leave as little time between frames as possible.
+ * Parameters :
+ *  ssp_num : ssp device number. The SSP device number is not checked, thus a value above
+ *            the number of SSP devices present on the micro-controller may break your
+ *            programm. Double check the value of the ssp_num parameter. The check is made
+ *            on the call to ssp_master_on() or ssp_slave_on().
+ *  size is the number of frames, each one having the configured data width (4 to 16 bits).
+ *  data_out : data to be sent. Data will be read in the lower bits of the 16 bits values
+ *             pointed by "data_out" for each frame. If NULL, then the content of data_in
+ *             will be used.
+ *  data_in : buffer for read data. If NULL, read data will be discarded.
+ * Returns the number of data words transfered or negative value on error.
+ * As the SPI bus is full duplex, data can flow in both directions, but the clock is
+ *   always provided by the master. The SPI clock cannont be activated without sending
+ *   data, which means we must send data to the device when we want to read data from
+ *   the device.
+ * This function does not take care of the SPI chip select.
+ * Note: there's no need to count Rx data as it is equal to Tx data
+ * Note : the SSP device number is not checked, thus a value above the number of SSP
+ *   devices present on the micro-controller may break your programm.
+ *   Double check the value of the ssp_num parameter. The check is made on the call to
+ *   ssp_master_on() or ssp_slave_on().
+ */
+int spi_transfer_multiple_frames(uint8_t ssp_num, void* data_out, void* data_in, int size, int width)
+{
+       struct lpc_ssp* ssp_regs = ssps[ssp_num].regs;
+
+       /* Did the user provide a buffer to send data ? */
+       if (data_out == NULL) {
+               if (data_in == NULL) {
+                       return -EINVAL;
+               }
+               data_out = data_in;
+       }
+       /* Transfer using either byte or word transfer functions */
+       if (width > 8) {
+               return spi_transfer_words(ssp_regs, (uint16_t*)data_out, (uint16_t*)data_in, size);
+       } else {
+               return spi_transfer_bytes(ssp_regs, (uint8_t*)data_out, (uint8_t*)data_in, size);
+       }
+}
+
+
+
+/***************************************************************************** */
+uint32_t ssp_clk_on(uint8_t ssp_num, uint32_t rate)
+{
+       struct lpc_ssp* ssp_regs = ssps[ssp_num].regs;
+       uint32_t prescale = 0, pclk_div = 0;
+       uint32_t pclk = 0, div = 0;
+
+       /* Do not divide by 0 */
+       if (rate == 0) {
+               return 0;
+       }
+
+       /* Set cclk divider for PCLK */
+       set_subsystem_clk_divider(ssps[ssp_num].pclk_bit, LPC_PCLK_CCLK);
+
+       pclk = get_main_clock();
+
+       /* Make sure we can get this clock rate */
+       /* NOTE: We use only to divisors, so we could achieve lower clock rates by using
+        *   the third one. Any need for this though ?
+        */
+       if ((pclk / rate) > 0xFFF0) {
+               /* What should we do ? */
+               div = 0xFFF0;
+       } else {
+               div = pclk / rate;
+       }
+
+       do {
+               prescale += 2; /* Minimum value is 2, and must be even */
+               pclk_div = (div / prescale);
+       } while ((prescale > 0xFF) || (pclk_div > 0xFF));
+
+
+       /* Set the prescaler */
+       ssp_regs->clk_prescale = prescale;
+
+       /* And return the achieved clock */
+       return (pclk / (prescale * pclk_div));
+}
+
+void ssp_clk_update(void)
+{
+       int i = 0;
+       for (i = 0; i < NUM_SSPS; i++) {
+               if (ssps[i].current_clk) {
+                       ssp_clk_on(i, ssps[i].current_clk);
+               }
+       }
+}
+
+
+/***************************************************************************** */
+/* SSP Setup as master */
+/* Returns 0 on success
+ * Parameters :
+ *  frame_type is SPI, TI or MICROWIRE (use apropriate defines for this one).
+ *  data_width is a number between 4 and 16.
+ *  rate : The bit rate, in Hz.
+ * The SPI Chip Select is not handled by the SPI driver in master SPI mode as it's
+ *   handling highly depends on the device on the other end of the wires. Use a GPIO
+ *   to activate the device's chip select (usually active low)
+ */
+int ssp_master_on(uint8_t ssp_num, uint8_t frame_type, uint8_t data_width, uint32_t rate)
+{
+       struct ssp_device* ssp = NULL;
+       struct lpc_ssp* ssp_regs = NULL;
+
+       if (ssp_num >= NUM_SSPS)
+               return -EINVAL;
+       ssp = &ssps[ssp_num];
+       ssp_regs = ssp->regs;
+
+       NVIC_DisableIRQ(ssp->irq);
+
+       /* Power up the ssp block */
+       subsystem_power(ssp->power_bit, 1);
+
+       /* Configure the SSP mode */
+       ssp_regs->ctrl_0 = (LPC_SSP_DATA_WIDTH(data_width) | frame_type | LPC_SSP_SPI_CLK_LOW | LPC_SSP_SPI_CLK_FIRST);
+       ssp_regs->ctrl_1 = LPC_SSP_MASTER_MODE;
+
+       /* Configure the clock : done after basic configuration */
+       ssp->current_clk = ssp_clk_on(ssp_num, rate);
+
+       /* Enable SSP */
+       ssp_regs->ctrl_1 |= LPC_SSP_ENABLE;
+
+       NVIC_EnableIRQ(ssp->irq);
+       return 0; /* Config OK */
+}
+
+int ssp_slave_on(uint8_t ssp_num, uint8_t frame_type, uint8_t data_width, uint8_t out_en, uint32_t max_rate)
+{
+       struct ssp_device* ssp = NULL;
+       struct lpc_ssp* ssp_regs = NULL;
+
+       if (ssp_num >= NUM_SSPS)
+               return -EINVAL;
+       ssp = &ssps[ssp_num];
+       ssp_regs = ssp->regs;
+
+       NVIC_DisableIRQ(ssp->irq);
+       /* Power up the ssp block */
+       subsystem_power(ssp->power_bit, 1);
+
+       /* Configure the SSP mode */
+       ssp_regs->ctrl_0 = LPC_SSP_DATA_WIDTH(data_width);
+       ssp_regs->ctrl_0 |= (frame_type | LPC_SSP_SPI_CLK_LOW | LPC_SSP_SPI_CLK_FIRST);
+       ssp_regs->ctrl_1 = LPC_SSP_SLAVE_MODE;
+       if (!out_en) {
+               ssp_regs->ctrl_1 |= LPC_SSP_SLAVE_OUT_DISABLE;
+       }
+
+       /* Configure the clock : done after basic configuration.
+        * Our clock must be at least 12 times the master clock */
+       ssp->current_clk = ssp_clk_on(ssp_num, max_rate * 16);
+
+       /* Enable SSP */
+       ssp_regs->ctrl_1 |= LPC_SSP_ENABLE;
+
+       NVIC_EnableIRQ(ssp->irq);
+       return 0; /* Config OK */
+}
+
+/* Turn off the SSP block */
+void ssp_off(uint8_t ssp_num)
+{
+       struct ssp_device* ssp = NULL;
+
+       if (ssp_num >= NUM_SSPS)
+               return;
+       ssp = &ssps[ssp_num];
+
+       ssp->current_clk = 0;
+       NVIC_DisableIRQ(ssp->irq);
+       subsystem_power(ssp->power_bit, 0);
+
+       /* Can be done even if we don't hold the mutex */
+       sync_lock_release(&ssp->mutex);
+}
+
diff --git a/drivers/timers.c b/drivers/timers.c
new file mode 100644 (file)
index 0000000..d7d5709
--- /dev/null
@@ -0,0 +1,273 @@
+/****************************************************************************
+ *  drivers/timers.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+
+/***************************************************************************** */
+/*                Timers                                                       */
+/***************************************************************************** */
+
+#include <stdint.h>
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "lib/string.h"
+#include "drivers/timers.h"
+
+
+/* These are local to our file */
+struct timer_device
+{
+       struct lpc_timer* regs;
+       uint32_t power_bit;
+       uint8_t pclk_bit;
+       uint8_t irq;
+       void (*callback)(uint8_t); /* Possible RX callback */
+};
+static struct timer_device timer_devices[NUM_TIMERS] = {
+       { LPC_TMR32B0, LPC_TIMER0_POWER_ON, LPC_TIMER0_PCLK, TIMER0_IRQ }, 
+       { LPC_TMR32B1, LPC_TIMER1_POWER_ON, LPC_TIMER1_PCLK, TIMER1_IRQ },
+       { LPC_TMR32B2, LPC_TIMER2_POWER_ON, LPC_TIMER2_PCLK, TIMER2_IRQ },
+       { LPC_TMR32B3, LPC_TIMER3_POWER_ON, LPC_TIMER3_PCLK, TIMER3_IRQ },
+       { LPC_TMR_PWM, LPC_PWM1_POWER_ON, LPC_PWM1_PCLK, PWM1_IRQ },
+};
+
+
+
+/* Handlers */
+void TIMER_Handler(struct timer_device* timer)
+{
+       struct lpc_timer* regs = timer->regs;
+       uint32_t intr_flags = regs->int_reg; /* Backup the flags */
+
+       /* Clear the interrupt */
+       regs->int_reg = intr_flags;
+       /* And call the user routine if one has been registered */
+       if (timer->callback != NULL) {
+               timer->callback(intr_flags);
+       }
+}
+void TIMER_0_Handler(void)
+{
+       TIMER_Handler(&timer_devices[0]);
+}
+void TIMER_1_Handler(void)
+{
+       TIMER_Handler(&timer_devices[1]);
+}
+void TIMER_2_Handler(void)
+{
+       TIMER_Handler(&timer_devices[2]);
+}
+void TIMER_3_Handler(void)
+{
+       TIMER_Handler(&timer_devices[3]);
+}
+
+
+
+/* Start the timer :
+ * Remove the reset flag if present and set timer enable flag.
+ * Timer must be turned on and configured (no checks done here).
+ */
+void timer_start(uint32_t timer_num)
+{
+       if (timer_num >= NUM_TIMERS)
+               return;
+       /* Remove reset flag and set timer enable flag */
+       timer_devices[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_ENABLE;
+}
+void timer_continue(uint32_t timer_num) __attribute__ ((alias ("timer_start")));
+/* Pause the timer counter, does not reset */
+void timer_pause(uint32_t timer_num)
+{
+       if (timer_num >= NUM_TIMERS)
+               return;
+       /* Remove timer enable flag */
+       timer_devices[timer_num].regs->timer_ctrl = 0;
+}
+/* Stops and resets the timer counter */
+void timer_stop(uint32_t timer_num)
+{
+       if (timer_num >= NUM_TIMERS)
+               return;
+       /* Remove timer enable flag */
+       timer_devices[timer_num].regs->timer_ctrl |= LPC_TIMER_COUNTER_RESET;
+       timer_devices[timer_num].regs->timer_ctrl = 0;
+}
+/* Resets the timer and lets it count again imediately */
+void timer_restart(uint32_t timer_num)
+{
+       if (timer_num >= NUM_TIMERS)
+               return;
+       /* Set and remove timer reset flag */
+       timer_devices[timer_num].regs->timer_ctrl |= LPC_TIMER_COUNTER_RESET;
+       timer_devices[timer_num].regs->timer_ctrl &= ~LPC_TIMER_COUNTER_RESET;
+}
+
+uint32_t timer_get_capture_val(uint32_t timer_num, uint32_t channel)
+{
+       if (timer_num >= NUM_TIMERS)
+               return 0;
+       /* FIXME */
+       return 0;
+}
+uint32_t timer_get_counter_val(uint32_t timer_num)
+{
+       if (timer_num >= NUM_TIMERS)
+               return 0;
+       return timer_devices[timer_num].regs->timer_counter;
+}
+
+/* Change the match value of a single timer channel */
+void timer_set_match(uint32_t timer_num, uint32_t channel, uint32_t val)
+{
+       if (timer_num >= NUM_TIMERS)
+               return;
+       if (channel > 2)
+               return;
+
+       timer_devices[timer_num].regs->match_reg[channel] = val;
+}
+
+
+/***************************************************************************** */
+/*   Timer Setup */
+/* Returns 0 on success
+ * Takes a timer number and a timer config structure as arguments.
+ * Refer to timer config structure for details.
+ */
+int timer_setup(uint32_t timer_num, struct timer_config* conf)
+{
+       struct timer_device* timer = NULL;
+       int i = 0;
+       if (timer_num >= NUM_TIMERS)
+               return -ENODEV;
+       timer = &(timer_devices[timer_num]);
+
+       /* Configure the reset on capture functionality */
+       if (conf->reset_on_capture != 0x00) {
+               timer->regs->count_ctrl = LPC_COUNTER_CLEAR_ON_EVENT_EN;
+               timer->regs->count_ctrl |= ((conf->reset_on_capture & 0x07) << LPC_COUNTER_CLEAR_ON_EVENT_SHIFT);
+       }
+
+       switch (conf->mode) {
+               case LPC_TIMER_MODE_TIMER:
+                       timer->regs->capture_ctrl = 0; /* Timer mode ! */
+                       timer->regs->count_ctrl = LPC_COUNTER_IS_TIMER;
+                       break;
+               case LPC_TIMER_MODE_COUNTER:
+                       if ((conf->config[0] & 0x03) == 0x00) {
+                               return -EINVAL;
+                       }
+                       /* Must set capture chanel N config to 0b000 in capture control register,
+                        * (see remarks in user manual UM10441 page 268 section 14.7.11)
+                        * Use the LPC_COUNTER_INC_INPUT(x) set by the user to do so automatically
+                        */
+                       timer->regs->capture_ctrl &= ~LPC_TIMER_CAPTURE_ERASE(((conf->config[0] >> LPC_COUNTER_INC_INPUT_SHIFT) & 0x03) * 3);
+                       /* Configure the counter */
+                       timer->regs->count_ctrl |= (conf->config[0] & 0x0F);
+                       break;
+               case LPC_TIMER_MODE_CAPTURE:
+                       timer->regs->capture_ctrl = 0;
+                       for (i = 0; i < NUM_CHANS; i++) {
+                               timer->regs->capture_ctrl |= ((conf->config[i] & 0x07) << LPC_TIMER_CAPTURE_SHIFT(i));
+                       }
+                       break;
+               case LPC_TIMER_MODE_MATCH:
+                       timer->regs->match_ctrl = 0;
+                       timer->regs->external_match = 0;
+                       for (i = 0; i < NUM_CHANS; i++) {
+                               timer->regs->match_ctrl |= ((conf->config[i] & 0x07) << LPC_TIMER_MATCH_SHIFT(i));
+                               timer->regs->match_reg[i] = conf->match[i];
+                               timer->regs->external_match |= ((conf->ext_match_config[i] & 0x03) << (LPC_TIMER_EXT_MATCH0_SHIFT + i*2));
+                       }
+                       break;
+               case LPC_TIMER_MODE_PWM:
+                       if (timer_num != LPC_TIMER_PWM) {
+                               return -EINVAL;
+                       }
+                       if (conf->match[ conf->config[1] ] != 0) {
+                               return -EINVAL; /* Force use of Channel 0 for PWM cycle length */
+                       }
+                       /* Activate selected PWM channels */
+                       /* FIXME check config for PWM (see EXTRA_PWM_NUM_CHANS in drivers/timer.h) */
+                       timer->regs->pwm_ctrl = (conf->config[0] & 0x07);
+                       /* Use Channel 3 for PWM cycle length as recommended in the manual */
+                       timer->regs->match_ctrl &= ~(LPC_TIMER_MATCH_ERASE(conf->config[1]));
+                       timer->regs->match_ctrl |= (LPC_TIMER_RESET_ON_MATCH << LPC_TIMER_MATCH_SHIFT(conf->config[1]));
+                       for (i = 0; i < NUM_CHANS; i++) {
+                               timer->regs->match_reg[i] = conf->match[i];
+                       }
+                       break;
+               case LPC_TIMER_MODE_PWD:
+                       break;
+       }
+       return 0; /* Config OK */
+}
+
+
+/* Power up a timer.
+ * Note that clkrate should be a divider of the main clock frequency chosed
+ *   for your application as it will be used to divide the main clock to get
+ *   the prescaler value.
+ * Set clkrate to 0 to disable the prescaler.
+ */
+void timer_on(uint32_t timer_num, uint32_t clkrate, void (*callback)(uint8_t))
+{
+       struct timer_device* timer = NULL;
+       uint32_t prescale; /* The clock divider for the counter */
+
+       if (timer_num >= NUM_TIMERS)
+               return;
+       timer = &(timer_devices[timer_num]);
+
+       NVIC_DisableIRQ( timer->irq );
+       /* Power up the timer */
+       subsystem_power(timer->power_bit, 1);
+       /* Set the timer pclk divider */
+       set_subsystem_clk_divider(timer->pclk_bit, LPC_PCLK_CCLK);
+
+       /* Reset counter on next PCLK positive edge, and disable counter */
+       timer->regs->timer_ctrl = LPC_TIMER_COUNTER_RESET;
+
+       /* Store the callback, OK even if none given */
+       timer->callback = callback;
+
+       /* Set the prescaler value */
+       if (clkrate == 0) {
+               prescale = 0;
+       } else {
+               prescale = (get_main_clock() / clkrate) - 1;
+       }
+       timer->regs->prescale = prescale;
+
+       NVIC_EnableIRQ(timer_devices[timer_num].irq);
+}
+
+/* Removes the main clock from the selected timer block */
+void timer_off(uint32_t timer_num)
+{
+       if (timer_num >= NUM_TIMERS)
+               return;
+       NVIC_DisableIRQ( timer_devices[timer_num].irq );
+       subsystem_power(timer_devices[timer_num].power_bit, 0);
+}
diff --git a/drivers/usbcore.c b/drivers/usbcore.c
new file mode 100644 (file)
index 0000000..931554e
--- /dev/null
@@ -0,0 +1,642 @@
+/****************************************************************************
+ *   drivers/usbcore.c
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+/*
+ * This file holds all the hardware related functions for the USB subsystem
+ */
+
+#include <stdint.h>
+
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+
+//extern char* UARTBUFFER;
+//extern volatile int UARTPTR;
+//static char* HEXA = "0123456789ABCDEF";
+
+/***************************************************************************** */
+/*          USB configuration                                                  */
+/***************************************************************************** */
+/* Turn on USB Clock
+ * USB Clock is generated using PPL1, allowing easier setting of system clock
+ *   to any desired value. This will consume some more power, but the LPC1764
+ *   used on the DTPlug board has only device USB, thus we are certainly
+ *   connected to a big computer using tens or hundreds of Watts - don't care.
+ *
+ * M and P values determinatinn :
+ *    M = (48MHz / Fosc) and Fosc is 12MHz
+ *      ==> M = 4
+ *    P = FCCO / (2 × M × Fosc) and FCCO must be between 156 and 320MHz
+ *    P must be even  ... if P is 2 we have FCCO = 2 * 2 * 4 * 12MHz = 192MHz
+ *      ==> P = 2
+ */
+static void usb_clk_on(void)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       uint32_t M = 4; /* M = (48MHz / Fosc) and Fosc is 12MHz */
+       uint32_t P = 2; /* P = FCCO / (2 × M × Fosc) and FCCO must be between 156 and 320MHz */
+
+       /* Configure PLL 1 for USB */
+       /* Note :  ALL STEPS ARE REQUIRED ! */
+       /* First of all, turn off interrupts, nothing should happen between the two writes of the
+          feed sequence (writting of 0xAA and 0x55 to pll1_feed) */
+       lpc_disable_irq();
+       /* Disable PLL if requiered */
+       if ((sys_ctrl->pll1_status & (0x03 << 8)) != 0) {
+               /* Disconnect PLL first */
+               sys_ctrl->pll1_control &= ~(LPC_PLL_CTRL_PLL_CONNECT);
+               sys_ctrl->pll1_feed = 0xAA;
+               sys_ctrl->pll1_feed = 0x55;
+               /* Then disable PLL */
+               sys_ctrl->pll1_control = 0;
+               sys_ctrl->pll1_feed = 0xAA;
+               sys_ctrl->pll1_feed = 0x55;
+       }
+       /* PLL now off. Set clock div to 1 to get max freq */
+       /* Make sure that external crystal is enabled and ready */
+       if (!(sys_ctrl->sys_osc_ctrl_and_status & (0x01 << 6))) {
+               sys_ctrl->sys_osc_ctrl_and_status |= (1 << 5);
+               while ( ! (sys_ctrl->sys_osc_ctrl_and_status & (0x01 << 6)) );
+       }
+       /* Setup PLL */
+       sys_ctrl->pll1_config = (((M - 1) & 0x1F) | ((P >> 1) & 0x3) << 5);
+       sys_ctrl->pll1_feed = 0xAA;
+       sys_ctrl->pll1_feed = 0x55;
+       /* Enable PLL */
+       sys_ctrl->pll1_control = LPC_PLL_CTRL_PLL_ENABLE;
+       sys_ctrl->pll1_feed = 0xAA;
+       sys_ctrl->pll1_feed = 0x55;
+       /* Wait for PLL lock (note : interrupts are disabled) */
+       while ( ! (sys_ctrl->pll1_status & (0x01 << 10)) );
+       /* Connect PLL */
+       sys_ctrl->pll1_control = (LPC_PLL_CTRL_PLL_ENABLE | LPC_PLL_CTRL_PLL_CONNECT);
+       sys_ctrl->pll1_feed = 0xAA;
+       sys_ctrl->pll1_feed = 0x55;
+       /* Turn interrupts on once again*/
+       lpc_enable_irq();
+}
+
+void usb_clk_off(void)
+{
+       /* FIXME */
+}
+
+#if 0
+/* Setup all USB pins according to their function for the DTPlug */
+void set_usb_pins(void)
+{
+       /* D+ and D- */
+       lpc_set_pin_func(0, 29, LPC_IO_FUNC_ALT1, LPC_IO_MODE_NO_PULL, LPC_IO_STD);
+       lpc_set_pin_func(0, 30, LPC_IO_FUNC_ALT1, LPC_IO_MODE_NO_PULL, LPC_IO_STD);
+       /* Link */
+       lpc_set_pin_func(1, 18, LPC_IO_FUNC_ALT1, LPC_IO_MODE_PULL_UP, LPC_IO_STD);
+       /* VBUS */
+       lpc_set_pin_func(1, 30, LPC_IO_FUNC_ALT2, LPC_IO_MODE_NO_PULL, LPC_IO_STD);
+       /* Soft Connect */
+       lpc_set_pin_func(2,  9, LPC_IO_FUNC_ALT1, LPC_IO_MODE_PULL_UP, LPC_IO_STD);
+}
+#endif
+
+/* Enable clocks to USB block and AHB master */
+void usb_up(void)
+{
+       struct lpc_usb_clock* usb_clk = LPC_USB_CLOCK;
+       /* Enable USB Device and AHB clock */
+       usb_clk->control = LPC_USB_CLK_ON; /* Set DEV_CLK_EN and AHB_CLK_EN in the USBClkCtrl register */
+       /* and wait for them (DEV_CLK_ON in USBClkSt) */
+       while ((usb_clk->status & LPC_USB_CLK_ON) != LPC_USB_CLK_ON);
+}
+
+/* Setup USB
+ *  calls usb_clk_on to configure PLL1 and turn on USB Clock
+ *  enable the clocks to the USB block and AHB master
+ */
+void usb_on(void)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+
+       NVIC_DisableIRQ(USB_IRQ);
+
+       /* Provide power to USB Block */
+       subsystem_power(LPC_USB_POWER_ON, 1);
+       /* Turn on USB Clock (PLL 1) */
+       usb_clk_on();
+       /* Enable clocks to USB block and AHB master */
+       usb_up();
+
+       /* Disable all DMA */
+       usb_dev->ep_dma_disable = ~(0x0UL);
+       usb_dev->dma_int_enable = 0;
+       /* Enable USB interrupt */
+       usb_dev->dev_int_enable = 0;
+       usb_dev->dev_int_clear = ~(0x0UL);
+       usb_dev->ep_int_enable = 0;
+       usb_dev->ep_int_clear  = ~(0x0UL);
+       NVIC_EnableIRQ(USB_IRQ);
+}
+
+/***************************************************************************** */
+/*         USB subsystem functions                                             */
+/***************************************************************************** */
+/* Activate and configure an endpoint
+ *    ep_num is the logical endpoint number
+ *    dir is either USB_DIR_IN or USB_DIR_OUT
+ */
+void usb_endpoint_realize(uint32_t ep_num, uint32_t max_packet_size, int dir)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+//     uint32_t inf_flags = usb_dev->dev_int_enable;
+       uint32_t physical_ep = ((ep_num * 2) + (dir ? 1 : 0));
+
+       /* Remove USB_EP_RLZED_INT from usb interrupts (if it was in) */
+//     usb_dev->dev_int_enable &= ~USB_EP_RLZED_INT;
+       /* Clear the EP_realized bit in int status */
+       usb_dev->dev_int_clear = USB_EP_RLZED_INT;
+       /* Set up enpoint */
+       usb_dev->realize_ep |= (1 << physical_ep);
+       usb_dev->ep_index = physical_ep;
+       usb_dev->max_packet_size = max_packet_size;
+       usb_dev->ep_int_enable |= (USB_EP_Rx_INT(ep_num) | USB_EP_Tx_INT(ep_num));
+       /* Wait for endpoint realized */
+       while ((usb_dev->dev_int_status & USB_EP_RLZED_INT) == 0);
+       /* Clear the EP_realized bit in int status */
+       usb_dev->dev_int_clear = USB_EP_RLZED_INT;
+       /* Restore interrupt flags */
+//     usb_dev->dev_int_enable = inf_flags;
+}
+/* Deactivate an endpoint, see usb_endpoint_realize() for comments */
+void usb_endpoint_remove(uint32_t ep_num, int dir)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+       uint32_t physical_ep = ((ep_num * 2) + (dir ? 1 : 0));
+//     uint32_t inf_flags = usb_dev->dev_int_enable;
+
+//     usb_dev->dev_int_enable &= ~USB_EP_RLZED_INT;
+       usb_dev->dev_int_clear = USB_EP_RLZED_INT;
+       usb_dev->ep_int_enable &= ~(USB_EP_Rx_INT(ep_num) | USB_EP_Tx_INT(ep_num));
+       usb_dev->realize_ep &= ~(1 << physical_ep);
+       while ((usb_dev->dev_int_status & USB_EP_RLZED_INT) == 0);
+       usb_dev->dev_int_clear = USB_EP_RLZED_INT;
+//     usb_dev->dev_int_enable = inf_flags;
+}
+
+/* Reset USB sub-system */
+/* Called on USB Reset by the user USB interrupt handler */
+void usb_reset(uint32_t usb_ctrl_endpoint_max_pkt_size)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+
+       NVIC_DisableIRQ(USB_IRQ);
+       /* Set-up control endpoints */
+       usb_endpoint_realize(0, usb_ctrl_endpoint_max_pkt_size, USB_DIR_OUT);
+       usb_endpoint_realize(0, usb_ctrl_endpoint_max_pkt_size, USB_DIR_IN);
+
+       /* Disable all DMA */
+       usb_dev->ep_dma_disable = ~(0x0UL);
+       usb_dev->dma_int_enable = 0;
+       /* Setup USB interrupt */
+       usb_dev->ep_int_clear  = ~(0x0UL);
+       usb_dev->dev_int_clear = ~(0x0UL);
+       /* control endpoints interrupts */
+       usb_dev->ep_int_enable = (USB_EP_Rx_INT(0) | USB_EP_Tx_INT(0));
+       usb_dev->ep_int_priority = 0; /* FIXME */
+       /* Device interrupts */
+       /* FIXME */
+       usb_dev->dev_int_enable = (USB_DEV_STAT_INT | USB_EP_SLOW_INT);
+       /* usb_dev->dev_int_enable |= (USB_ERR_INT); */
+       /* usb_dev->dev_int_enable |= (USB_FRAME_INT); *//* Used only for isochronous transfers */
+       NVIC_EnableIRQ(USB_IRQ);
+}
+
+/***************************************************************************** */
+/*        Serial Interface Engine (SIE)                                        */
+/***************************************************************************** */
+/* Perform SIE Command */
+void usb_cmd(uint8_t cmd)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+#if 0
+       uint32_t inf_flags = usb_dev->dev_int_enable;
+       /* Clear CCEMPTY and CDFULL interrupts and mask them */
+       usb_dev->dev_int_enable &= ~(USB_CMD_CODE_EMPTY_INT | USB_CMD_DATA_FULL_INT);
+       usb_dev->dev_int_clear = (USB_CMD_CODE_EMPTY_INT | USB_CMD_DATA_FULL_INT);
+#endif
+       usb_dev->dev_int_clear = USB_CMD_CODE_EMPTY_INT;
+       /* SIE Command */
+       usb_dev->command_code = USB_CMD_COMMAND(cmd);
+       while ((usb_dev->dev_int_status & USB_CMD_CODE_EMPTY_INT) == 0);
+#if 0
+       usb_dev->dev_int_clear = USB_CMD_CODE_EMPTY_INT;
+       /* Restore interrupts */
+       usb_dev->dev_int_enable = inf_flags;
+#endif
+}
+/* Perform SIE Command + SIE Write */
+void usb_cmd_write(uint8_t cmd, uint8_t val)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+#if 0
+       uint32_t inf_flags = usb_dev->dev_int_enable;
+       /* Clear CCEMPTY and CDFULL interrupts and mask them */
+       usb_dev->dev_int_enable &= ~(USB_CMD_CODE_EMPTY_INT | USB_CMD_DATA_FULL_INT);
+       usb_dev->dev_int_clear = (USB_CMD_CODE_EMPTY_INT | USB_CMD_DATA_FULL_INT);
+#endif
+       /* SIE Command */
+       usb_dev->dev_int_clear = USB_CMD_CODE_EMPTY_INT;
+       usb_dev->command_code = USB_CMD_COMMAND(cmd);
+       while ((usb_dev->dev_int_status & USB_CMD_CODE_EMPTY_INT) == 0);
+       /* SIE Write */
+       usb_dev->dev_int_clear = USB_CMD_CODE_EMPTY_INT;
+       usb_dev->command_code = USB_CMD_WRITE(val);
+       while ((usb_dev->dev_int_status & USB_CMD_CODE_EMPTY_INT) == 0);
+#if 0
+       usb_dev->dev_int_clear = USB_CMD_CODE_EMPTY_INT;
+       /* Restore interrupts */
+       usb_dev->dev_int_enable = inf_flags;
+#endif
+}
+/* Perform SIE Command + SIE Read
+ * If width is two, the perform a second SIE Read to get MSB byte
+ */
+uint32_t usb_cmd_read(uint8_t cmd, uint8_t width)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+       uint32_t result = 0;
+#if 0
+       uint32_t inf_flags = usb_dev->dev_int_enable;
+       /* Clear CCEMPTY and CDFULL interrupts and mask them */
+       usb_dev->dev_int_enable &= ~(USB_CMD_CODE_EMPTY_INT | USB_CMD_DATA_FULL_INT);
+       usb_dev->dev_int_clear = (USB_CMD_CODE_EMPTY_INT | USB_CMD_DATA_FULL_INT);
+#endif
+       /* SIE Command */
+       usb_dev->dev_int_clear = USB_CMD_CODE_EMPTY_INT;
+       usb_dev->command_code = USB_CMD_COMMAND(cmd);
+       while ((usb_dev->dev_int_status & USB_CMD_CODE_EMPTY_INT) == 0);
+       /* SIE Read */
+       usb_dev->dev_int_clear = USB_CMD_DATA_FULL_INT;
+       usb_dev->command_code = USB_CMD_READ(cmd);
+       while ((usb_dev->dev_int_status & USB_CMD_DATA_FULL_INT) == 0);
+       result = usb_dev->command_data;
+       /* Second SIE Read to get MSB byte */
+       if (width == 2) {
+               usb_dev->dev_int_clear = USB_CMD_DATA_FULL_INT;
+               usb_dev->command_code = USB_CMD_READ(cmd);
+               while ((usb_dev->dev_int_status & USB_CMD_DATA_FULL_INT) == 0);
+               result |= (usb_dev->command_data << 8);
+       }
+#if 0
+       /* Restore interrupts */
+       usb_dev->dev_int_enable = inf_flags;
+#endif
+       return result;
+}
+
+/* Set device address */
+void usb_set_address(uint8_t addr)
+{
+       /* The LPC1764 user manual says that "The address set in the device will take
+        *   effect after the status stage of the control transaction."
+        * The UM10139 for LPC214x says also : "(Alternately, issuing the Set Address
+        *   command twice will set the address in the device)"
+        * Issue the USB_SIE_SET_ADDRESS command twice to set it right now
+        * Another way would be to force the status stage to happen ? */
+       usb_cmd_write(USB_SIE_SET_ADDRESS, (addr | USB_DEVICE_ENABLE));
+}
+/* Disable USB device */
+void usb_disable(void)
+{
+       usb_cmd_write(USB_SIE_SET_ADDRESS, 0x00);
+}
+/* Read current frame number */
+uint16_t usb_read_current_frame_number(void)
+{
+       uint16_t cfn = (uint16_t)usb_cmd_read(USB_SIE_READ_CFN, 2);
+       return cfn;
+}
+/* This will activate the Good link (UP_LED signal) indicator */
+void usb_dev_set_configured(void)
+{
+       usb_cmd_write(USB_SIE_CONFIGURE_DEV, USB_DEVICE_CONFIGURED);
+}
+/* Test USB clocks 
+ * Read the Test register, read should return 0xA50F if the USB clocks
+ *  (usbclk and AHB slave clock) are running
+ * returns 1 if OK, 0 if not running */
+#define USB_CLOCKS_RUNNING 0xA50F
+uint32_t usb_clocks_running(void)
+{
+       uint16_t result = (uint16_t)usb_cmd_read(USB_SIE_READ_TEST_REG, 2);
+       if (result == USB_CLOCKS_RUNNING);
+               return 1;
+       return 0;
+}
+/* USB soft connect
+ * Connect / disconnect can be done by software by setting the CON Bit
+ *   using the SIE Set Device Status command
+ */
+void usb_connect(void)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+       /* FIXME : do I need to mask device status change interrupt and wait for
+        *    status change notification ?
+        */
+       usb_dev->dev_int_clear = USB_DEV_STAT_INT; /* Clear the device status change interrupt */
+       usb_cmd_write(USB_SIE_DEV_STATUS, USB_DEVSTAT_CONNECT); /* all other bits have no effet on write ? */
+}
+
+
+/* Read endpoint status
+ * ep_num is logical endpoint number
+ * returns the value read using SIE command ored with the endpoint status in bit 7.
+ */
+uint8_t usb_read_endpoint_status(uint32_t ep_num, int dir)
+{
+       uint32_t physical_ep = ((ep_num * 2) + (dir ? 1 : 0));
+       uint8_t result = (uint8_t)usb_cmd_read(USB_SIE_SELECT_EP(physical_ep), 1);
+       return (result & USB_EPSTAT_MASK);
+}
+
+static uint32_t endpoints_halted = ~(0); /* Default is to have all endpoints disabled */
+uint8_t usb_endpoint_halted(uint32_t ep_num, int dir)
+{
+       uint32_t physical_ep = ((ep_num * 2) + (dir ? 1 : 0));
+       return ((endpoints_halted >> physical_ep) & 0x01);
+}
+/* Reset endpoint / Enable USB endpoint / Un-Stall endpoint
+ * ep_num is logical endpoint number
+ */
+void usb_endpoint_reset(uint32_t ep_num, int dir)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+       uint32_t physical_ep = ((ep_num * 2) + (dir ? 1 : 0));
+       /* reset only for realized endpoints */
+       if (usb_dev->realize_ep & (1 << physical_ep)) {
+               usb_cmd_write(USB_SIE_SET_EP_STAT(physical_ep), 0x00);
+               /* Store endpoint status */
+               endpoints_halted &= ~(1 << physical_ep);
+       }
+}
+/* Disable USB endpoint
+ * ep_num is logical endpoint number
+ */
+void usb_endpoint_disable(uint32_t ep_num, int dir)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+       uint32_t physical_ep = ((ep_num * 2) + (dir ? 1 : 0));
+       /* only for realized endpoints */
+       if (usb_dev->realize_ep & (1 << physical_ep)) {
+               usb_cmd_write(USB_SIE_SET_EP_STAT(physical_ep), USB_EP_SET_STAT_DISABLED);
+               /* Store endpoint status */
+               endpoints_halted |= (1 << physical_ep);
+       }
+}
+/* Stall  USB endpoint
+ * ep_num is logical endpoint number
+ */
+void usb_endpoint_stall(uint32_t ep_num, int dir)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+       uint32_t physical_ep = ((ep_num * 2) + (dir ? 1 : 0));
+       /* reset only for realized endpoints */
+       if (usb_dev->realize_ep & (1 << physical_ep)) {
+               usb_cmd_write(USB_SIE_SET_EP_STAT(physical_ep), USB_EP_SET_STAT_STALLED);
+       }
+}
+
+
+/* Clear the endpoint (OUT) buffer (received data) so new data can be received.
+ * ep_num is the logical endpoint number (0-15)
+ * If the endpoint is the control endpoint, returns 1 if the previously received packet
+ *    was over-written by a later SETUP packet.
+ * returns 0 in all other cases
+ */
+uint8_t usb_clear_buffer(uint32_t ep_num)
+{
+       uint32_t physical_ep = (ep_num * 2);
+       usb_cmd(USB_SIE_SELECT_EP(physical_ep));
+       if (ep_num == 0) {
+               return (usb_cmd_read(USB_SIE_EP_CLEAR_BUF, 1) & 0x01);
+       }
+       usb_cmd(USB_SIE_EP_CLEAR_BUF);
+       return 0;
+}
+/* Validate the endpoint (IN) buffer for sending
+ * ep_num is the logical endpoint number (0-15)
+ */
+void usb_validate_buffer(uint32_t ep_num)
+{
+       uint32_t physical_ep = ((ep_num * 2) + 1);
+       usb_cmd(USB_SIE_SELECT_EP(physical_ep));
+       usb_cmd(USB_SIE_EP_VALIDATE_BUF);
+}
+
+/* FIXME : Implement error code handling ? (get error code and read error status)
+ * Error code handling must actually be done by user code.
+ */
+/* Get device status */
+uint8_t usb_get_dev_status(void)
+{
+       return (uint8_t)usb_cmd_read(USB_SIE_DEV_STATUS, 1);
+}
+/* Get device error status */
+uint8_t usb_get_dev_error_status(void)
+{
+       return (uint8_t)usb_cmd_read(USB_SIE_READ_ERROR_STATUS, 1);
+}
+/* Get device error code */
+uint8_t usb_get_dev_error_code(void)
+{
+       return (uint8_t)usb_cmd_read(USB_SIE_GET_ERROR_CODE, 1);
+}
+
+
+/***************************************************************************** */
+/*        Endpoint read and write                                              */
+/***************************************************************************** */
+/* Note that this code does NOT support interleaved read and write operations, which is
+ permited on the same endpoint. */
+
+/* Read data from an endpoint
+ * ep_num is the logical endpoint number
+ * buf is a data buffer big enougth for this endpoint's max packet size, and MUST be word
+ *    aligned
+ * isochronous can be set for isochronous endpoints to skip the clear buffer.
+ */
+uint32_t usb_ep_read(uint8_t ep_num, char* buf, uint8_t isochronous)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+       uint32_t* bufp = (uint32_t*)((uint32_t)buf & ~(0x03));
+       uint32_t length = 0, nb = 0;
+       uint32_t packet;
+
+       /* Did we already read an overwritten setup packet ? */
+       if (length != 0 ) {
+               usb_dev->ep_int_clear = (1 << (ep_num * 2));
+       }
+       /* Programm the USBCtrl register : set RD_EN and LOG_ENDPOINT and wait
+        * data to be ready */
+       usb_dev->control = (USB_READ_ENABLE | USB_CTRL_LOG_EP(ep_num));
+
+       do {
+               packet = usb_dev->rx_pkt_length;
+       } while (!(packet & USB_PKT_READY));
+
+       /* Grab the data */
+       length = (packet & USB_PKT_REMAIN_LENGTH_MASK);
+       nb = ((length + 3) / 4);
+       while (nb--) {
+               *bufp++ = usb_dev->rx_data;
+       }
+
+       usb_dev->control = 0;
+       usb_clear_buffer(ep_num);
+
+       return length;
+}
+/* Write data to an endpoint
+ * ep_num is the logical endpoint number
+ */
+uint32_t usb_ep_write(uint8_t ep_num, char* buf, uint32_t length)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+       uint32_t* bufp = (uint32_t*)((uint32_t)buf & ~(0x03));
+       uint32_t nb = ((length + 3) / 4);
+       /* Programm the USBCtrl register : set WR_EN and LOG_ENDPOINT */
+       usb_dev->control = (USB_WRITE_ENABLE | USB_CTRL_LOG_EP(ep_num));
+       /* Programm the number of bytes to be written and put the data in the internal buffer */
+       usb_dev->tx_pkt_length = (length & USB_PKT_REMAIN_LENGTH_MASK);
+//     usb_dev->dev_int_enable &= ~(USB_DEV_STAT_INT); /* Do not get interrupt on TxENDPKT */
+       while (nb--) {
+               usb_dev->tx_data = *bufp++;
+       }
+       /* Do not wait for end of output if we wrote nothing */
+//     if (length & USB_PKT_REMAIN_LENGTH_MASK) {
+//             while (!(usb_dev->dev_int_status & USB_TxENDPKT_INT));
+//     }
+       usb_dev->control = 0;
+//     usb_dev->dev_int_enable |= USB_DEV_STAT_INT; /* Restore Device status interrupt */
+       /* Validate the buffer for sending */
+       usb_validate_buffer(ep_num);
+       return 0;
+}
+
+
+
+/* These dummy handlers should be overwritten by any user code using USB */
+void Dummy_USB_Handler(uint32_t event) {
+       do { } while (0);
+}
+/* usb_status_handler receives the device status. */
+void usb_status_handler(uint32_t event) __attribute__ ((weak, alias ("Dummy_USB_Handler")));
+/* Called when USB_FRAME_INT happens, with value 0 */
+void usb_sof_handler(uint32_t event) __attribute__ ((weak, alias ("Dummy_USB_Handler")));
+/* Called upon error, with (error_status | (error_code << 8)) as parameter */
+void usb_error_handler(uint32_t event) __attribute__ ((weak, alias ("Dummy_USB_Handler")));
+/* Called upon endpoint interrupt, once for each endpoint having an interrup pending
+ *    with (endpoint_logical_num | USB_DIR_* | (endpoint_status << 8)) as parameter */
+void usb_ep_handler(uint32_t event) __attribute__ ((weak, alias ("Dummy_USB_Handler")));
+
+
+/* USB Interrupts Handler */
+void USB_Handler(void)
+{
+       struct lpc_usb_device* usb_dev = LPC_USB_DEVICE;
+       uint32_t dev_intr = usb_dev->dev_int_status; /* Store Device Interrupt Status */
+
+       /* Clear interrupt */
+       usb_dev->dev_int_clear = ~(0x0UL);
+
+       if (dev_intr & USB_DEV_STAT_INT) {
+               uint8_t dev_status = usb_get_dev_status();
+               /* Call the user handler ?
+                * Note for OS : This should trigger an event for userspace rather than give
+                *   the hand to some "user code" within an interrupt handler ! */
+               usb_status_handler((uint32_t)dev_status);
+               return;
+       }
+       if (dev_intr & (USB_EP_FAST_INT | USB_EP_RLZED_INT)) {
+               struct lpc_uart* uart = LPC_UART_1;
+               uart->func.buffer = '/';
+       }
+       if (dev_intr & USB_EP_SLOW_INT) {
+               uint32_t ep_intr = usb_dev->ep_int_status;
+               uint32_t mask = 0x01; /* Mask for first physical endpoint */
+               int i = 0;
+               //UARTBUFFER[UARTPTR++] = '+';
+               /* Call endpoint handler for each set endpoint */
+               while ((i < USB_PHY_ENDPOINTS) && ep_intr) {
+                       if (ep_intr & mask) {
+                               /* Get endpoint_logical_num | USB_DIR_* in info */
+                               uint32_t info = ((i >> 1) | ((i & 0x01) << USB_DIR_SHIFT));
+
+                               //UARTBUFFER[UARTPTR++] = HEXA[i%16];
+                               /* Clear this interrupt to get the status */
+                               usb_dev->ep_int_clear = mask;
+                               ep_intr &= ~mask;
+                               while ((usb_dev->dev_int_status & USB_CMD_DATA_FULL_INT) == 0);
+                               /* Add the status to the endpoint and direction information in info */
+                               info |= ((usb_dev->command_data & 0xff) << 8);
+                               /* And call the handler */
+                               usb_ep_handler(info);
+                       }
+                       mask = mask << 1;
+                       i++;
+               }
+       }
+#if 0
+       if (dev_intr & USB_FRAME_INT) {
+               UARTBUFFER[UARTPTR++] = '-';
+               /* Call the user handler ?
+                * Note for OS : This should trigger an event for userspace rather than give
+                *   the hand to some "user code" within an interrupt handler ! */
+               usb_sof_handler(0);
+       }
+#endif
+       if (dev_intr & USB_ERR_INT) {
+               uint32_t err = (usb_get_dev_error_status() & 0xFF);
+               err |= ((usb_get_dev_error_code() & 0xFF) << 8);
+               /* Call the user handler ?
+                * Note for OS : This should trigger an event for userspace rather than give
+                *   the hand to some "user code" within an interrupt handler ! */
+               usb_error_handler(err);
+       }
+}
+/* This one is not handled and should not be enabled ! */
+void USB_Act_Handler(void)
+{
+       NVIC_DisableIRQ(USB_ACT_IRQ);
+}
+
+
+/* Start USB sub-system
+ *  usb_on() MUST have been called, or the USB subsystem is not powered and PLL is not set
+ */
+void usb_start(uint32_t usb_ctrl_endpoint_max_pkt_size)
+{
+       usb_up();
+       usb_reset(usb_ctrl_endpoint_max_pkt_size);
+       usb_set_address(0);
+       /* Enable endpoints 0 and 1 */
+       usb_endpoint_reset(0, 0);
+       usb_endpoint_reset(0, 1);
+       usb_connect();
+}
+
diff --git a/extdrv/cc1101.c b/extdrv/cc1101.c
new file mode 100644 (file)
index 0000000..ae4d234
--- /dev/null
@@ -0,0 +1,481 @@
+/****************************************************************************
+ *  extdrv/cc1101.c
+ *
+ * Copyright 2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include <stdint.h>
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "lib/string.h"
+#include "drivers/ssp.h"
+#include "drivers/gpio.h"
+#include "extdrv/cc1101.h"
+
+
+/***************************************************************************** */
+/*                CC1101                                                       */
+/***************************************************************************** */
+struct cc1101_device {
+       uint8_t spi_num;
+       struct pio cs_pin; /* SPI CS pin, used as chip select */
+       struct pio miso_pin; /* SPI MISO pin, used to monitor "device ready" from CC1101 chip */
+       /* Signal indication */
+       uint8_t rx_sig_strength; /* Received signal strength indication */
+       uint8_t link_quality; /* link quality */
+};
+static struct cc1101_device cc1101 = {
+       .rx_sig_strength = 0,
+       .link_quality = 0,
+};
+
+
+/***************************************************************************** */
+/* Main SPI transfer function */
+uint8_t cc1101_spi_transfer(uint8_t addr, uint8_t* out, uint8_t* in, uint8_t size)
+{
+       uint8_t status = 0;
+
+       /* Set CS Low */
+       gpio_clear(cc1101.cs_pin);
+
+       /* Wait for ready state (GDO_1 / MISO going low) */
+       do {} while (gpio_isset(cc1101.miso_pin));
+
+       /* Send address and get global status */
+       status = (uint8_t)spi_transfer_single_frame(cc1101.spi_num, (uint16_t)addr);
+       /* Perform transfer */
+       if (size != 0) {
+               spi_transfer_multiple_frames(cc1101.spi_num, out, in, size, 8);
+       }
+       /* Release Chip select */
+       gpio_set(cc1101.cs_pin);
+
+       return status;
+}
+
+
+/***************************************************************************** */
+/* SPI registers and commands access Wrappers */
+
+/* Send command and return global status byte */
+uint8_t cc1101_send_cmd(uint8_t addr)
+{
+       return cc1101_spi_transfer((addr | CC1101_WRITE_OFFSET), NULL, NULL, 0);
+}
+void cc1101_reset(void)
+{
+       cc1101_send_cmd(CC1101_CMD(reset));
+}
+void cc1101_power_up_reset(void) __attribute__ ((alias ("cc1101_reset")));
+
+void cc1101_flush_tx_fifo(void)
+{
+       /* Make sure that the radio is in IDLE state before flushing the FIFO */
+       cc1101_send_cmd(CC1101_CMD(state_idle));
+       cc1101_send_cmd(CC1101_CMD(flush_tx));
+}
+void cc1101_flush_rx_fifo(void)
+{
+       /* Make sure that the radio is in IDLE state before flushing the FIFO */
+       cc1101_send_cmd(CC1101_CMD(state_idle));
+       cc1101_send_cmd(CC1101_CMD(flush_rx));
+}
+
+void cc1101_enter_rx_mode(void)
+{
+       cc1101_send_cmd(CC1101_CMD(state_idle));
+       cc1101_send_cmd(CC1101_CMD(state_rx));
+}
+
+static uint8_t cc1101_enter_tx_mode(void)
+{
+       uint8_t status = 0;
+       status = (cc1101_read_status() & CC1101_STATE_MASK);
+       if (status != CC1101_STATE_TX) {
+               cc1101_send_cmd(CC1101_CMD(state_idle));
+               cc1101_send_cmd(CC1101_CMD(state_tx));
+       }
+       /* Wait until chip is in Tx state */
+       do {
+               status = (cc1101_read_status() & CC1101_STATE_MASK);
+               if (status == CC1101_STATE_TXFIFO_UNDERFLOW) {
+                       cc1101_flush_tx_fifo();
+                       return status;
+               }
+               if (status == CC1101_STATE_RXFIFO_OVERFLOW) {
+                       cc1101_flush_rx_fifo();
+                       return status;
+               }
+       } while (status != CC1101_STATE_TX);
+       return 0;
+}
+
+/* Read global status byte */
+uint8_t cc1101_read_status(void)
+{
+       return cc1101_send_cmd(CC1101_CMD(no_op));
+}
+
+/* Read and return single register value */
+uint8_t cc1101_read_reg(uint8_t addr)
+{
+       uint8_t ret = 0;
+       cc1101_spi_transfer((addr | CC1101_READ_OFFSET), NULL, &ret, 1);
+       return ret;
+}
+/* Read nb registers from start_addr into buffer. Return the global status byte. */
+uint8_t cc1101_read_burst_reg(uint8_t start_addr, uint8_t* buffer, uint8_t nb)
+{
+       uint8_t addr = (start_addr | CC1101_READ_OFFSET | CC1101_BURST_MODE);
+       return cc1101_spi_transfer(addr, NULL, buffer, nb);
+}
+/* Write single register value. Return the global status byte */
+uint8_t cc1101_write_reg(uint8_t addr, uint8_t val)
+{
+       return cc1101_spi_transfer((addr | CC1101_WRITE_OFFSET), &val, NULL, 1);
+}
+uint8_t cc1101_write_burst_reg(uint8_t start_addr, uint8_t* buffer, uint8_t nb)
+{
+       uint8_t addr = (start_addr | CC1101_WRITE_OFFSET | CC1101_BURST_MODE);
+       return cc1101_spi_transfer(addr, buffer, NULL, nb);
+}
+
+
+
+/***************************************************************************** */
+/* Signal strength and link quality */
+
+/* Return the signal strength indication based in the last packet received */
+uint8_t cc1101_get_signal_strength_indication(void)
+{
+       uint8_t val = cc1101.rx_sig_strength;
+       if (val >= 128) {
+               val = 255 - val;
+       }
+       return (val >> 1) + 74;  /* val/2 + 74 */
+}
+/* Return the link quality indication based in the last packet received */
+uint8_t cc1101_get_link_quality(void)
+{
+       return (0x3F - (cc1101.link_quality & 0x3F));
+}
+
+
+/***************************************************************************** */
+/* Rx fifo state :
+ * Return 0 when fifo is empty, or number of remaining bytes when non empty and no
+ *    overflow occured.
+ * Return -1 when an overflow occured.
+ * Upon overflow, the radio is placed in idle state and the RX fifo flushed.
+ * Else the radio is placed in RX state.
+ */
+int cc1101_rx_fifo_state(void)
+{
+       uint8_t rx_status = 0;
+
+       cc1101_send_cmd(CC1101_CMD(state_rx));
+       rx_status = cc1101_read_reg(CC1101_STATUS(rx_bytes));
+
+       /* Check for buffer overflow */
+       if (rx_status & CC1101_RX_FIFO_OVERFLOW) {
+               cc1101_flush_rx_fifo();
+               return -1;
+       }
+       return rx_status;
+}
+
+/* Tx fifo state :
+ * Return 0 when fifo is empty, or number of remaining bytes when non empty and no
+ *    overflow occured.
+ * Return a negative value on error:
+ *     when an underflow occured, return value is -1
+ *     on other errors return value is (-1) * (global status byte)
+ * Upon error, the radio is placed in idle state and the TX fifo flushed.
+ * Else the radio is placed in TX state.
+ */
+int cc1101_tx_fifo_state(void)
+{
+       uint8_t tx_status = 0, ret = 0;
+
+       ret = cc1101_enter_tx_mode();
+       if (ret != 0) {
+               return -ret;
+       }
+       tx_status = cc1101_read_reg(CC1101_STATUS(tx_bytes));
+
+       /* Check for buffer  */
+       if (tx_status & CC1101_TX_FIFO_UNDERFLOW) {
+               cc1101_flush_tx_fifo();
+               return -1;
+       }
+       return tx_status;
+}
+
+/***************************************************************************** */
+/* Send packet
+ * When using a packet oriented communication with packet size and address included
+ *   in the packet, these must be included in the packet by the software before
+ *   calling this function.
+ * In order to send packets of more than 64 bytes (including length and address) the
+ *   user will have to write his own function.
+ */
+int cc1101_send_packet(uint8_t* buffer, uint8_t size)
+{
+       uint8_t ret = 0;
+       if (size > CC1101_FIFO_SIZE) {
+               return -E2BIG;
+       }
+       cc1101_write_burst_reg(CC1101_FIFO_BURST, buffer, size);
+       ret = cc1101_enter_tx_mode();
+       if (ret != 0) {
+               return -ret;
+       }
+       return size;
+}
+
+/* Receive packet
+ * This function can be used to receive a packet of variable packet length (first byte
+ *   in the packet must be the length byte). The packet length should not exceed
+ *   the RX FIFO size.
+ * The buffer provided must be able to hold "size" bytes from the receive fifo.
+ * Returns the size filled in the buffer if everything went right.
+ * Returns a negative value upon error.
+ *    CC1101_ERR_RCV_PKT_TOO_BIG: Received packet said to be bigger than fifo size
+ *    CC1101_ERR_BUFF_TOO_SMALL: Provided buffer is smaller than received packet
+ *    CC1101_ERR_INCOMPLET_PACKET: Fifo hodls less data than received packet length
+ *    CC1101_OVERFLOW: RX fifo overflow
+ *    CC1101_ERR_CRC: Packet CRC error. The fifo has been flushed.
+ *    In every case we read as many data as possible, which is the provided buffer
+ *    size in case of CC1101_ERR_BUFF_TOO_SMALL. In other cases, it is the maximum
+ *    possible depending on available bytes in fifo (status provides this), the
+ *    buffer size, and the packet size (provided in buffer[0]).
+ */
+int cc1101_receive_packet(uint8_t* buffer, uint8_t size, uint8_t* status)
+{
+       uint8_t rx_status = 0;
+       uint8_t read_size = 0, pkt_length = 0;
+       int ret = 0;
+       uint8_t st_buff[2];
+
+       /* Get fifo state */
+       rx_status = cc1101_read_reg(CC1101_STATUS(rx_bytes));
+       if (status != NULL) {
+               *status = rx_status;
+       }
+
+       /* Empty fifo ? */
+       if (rx_status == 0) {
+               return 0;
+       }
+       /* Receive one packet at most */
+       pkt_length = cc1101_read_reg(CC1101_FIFO);
+       if (pkt_length > (CC1101_FIFO_SIZE - 1)) {
+               ret = -CC1101_ERR_RCV_PKT_TOO_BIG;
+               if (size < (rx_status & CC1101_BYTES_IN_FIFO_MASK)) {
+                       read_size = size;
+               } else {
+                       read_size = (rx_status & CC1101_BYTES_IN_FIFO_MASK);
+               }
+       } else if ((pkt_length + 1) > size) {
+               ret = -CC1101_ERR_BUFF_TOO_SMALL;
+               read_size = size;
+       } else if (pkt_length > (rx_status & CC1101_BYTES_IN_FIFO_MASK)) {
+               ret = -CC1101_ERR_INCOMPLET_PACKET;
+               read_size = (rx_status & CC1101_BYTES_IN_FIFO_MASK);
+       } else {
+               ret = pkt_length + 1;
+               read_size = pkt_length + 1;
+       }
+       /* Fill the buffer ! */
+       buffer[0] = pkt_length;
+       read_size--;
+       cc1101_read_burst_reg(CC1101_FIFO_BURST, &(buffer[1]), read_size);
+
+       /* Update the link quality and signal strength information */
+       cc1101_read_burst_reg(CC1101_FIFO_BURST, st_buff, 2);
+       cc1101.link_quality = st_buff[1];
+       cc1101.rx_sig_strength  = st_buff[0];
+
+       /* CRC error */
+       if (!(cc1101.link_quality & CC1101_CRC_OK)) {
+               cc1101_flush_rx_fifo();
+               return -CC1101_ERR_CRC;
+       }
+       /* Overflow ? */
+       if (rx_status & CC1101_RX_FIFO_OVERFLOW) {
+               cc1101_flush_rx_fifo();
+               return -CC1101_ERR_OVERFLOW;
+       }
+       return ret;
+}
+
+/***************************************************************************** */
+/* CC1101 Initialisation */
+
+
+/* Change the CC1101 address
+ * Only packets addressed to the specified address (or broadcasted) will be
+*    received.
+ * Adresses 0x00 and 0xFF are broadcast
+ * This function places the CC1101 chip in idle state.
+ */
+void cc1101_set_address(uint8_t address)
+{
+       cc1101_send_cmd(CC1101_CMD(state_idle));
+       cc1101_write_reg(CC1101_REGS(device_addr), address);
+}
+
+/* Change a configuration byte.
+ * This function places the CC1101 chip in idle state.
+ */
+void cc1101_set_config(uint8_t byte_addr, uint8_t value)
+{
+       cc1101_send_cmd(CC1101_CMD(state_idle));
+       cc1101_write_reg(byte_addr, value);
+}
+
+/* Table of initial settings, in the form of address / value pairs. */
+static uint8_t rf_init_settings[] = {
+       CC1101_REGS(gdo_config[0]), 0x2E, /* GDO_2 - High impedance (Disabled) */
+       CC1101_REGS(gdo_config[1]), 0x29, /* GDO_1 - Chip ready | Low drive strength */
+       CC1101_REGS(gdo_config[2]), 0x07, /* GDO_0 - Assert on CRC OK | Disable temp sensor */
+
+       /* RX FIFO and TX FIFO thresholds - 0x03 - FIFOTHR */
+       CC1101_REGS(fifo_thresholds), 0x07, /* Bytes in TX FIFO:33 - Bytes in RX FIFO:32 */
+       /* Packet length - 0x06 - PKTLEN */
+       CC1101_REGS(packet_length), 0x3F, /* Max packet length of 63 bytes */
+
+       /* Packet automation control - 0x07 .. 0x08 - PKTCTRL1..0 */
+       CC1101_REGS(pkt_ctrl[0]), 0x07, /* Accept all sync, No CRC auto flush, Append, Addr check and Bcast */
+       CC1101_REGS(pkt_ctrl[1]), 0x05, /* No data Whitening, Use fifos, CRC check, Variable pkt length */
+
+       /* Device address - 0x09 - ADDR */
+       CC1101_REGS(device_addr), 0x00, /* 0x00 and 0xFF are broadcast */
+       /* Channel number - 0x0A - CHANNR */
+       CC1101_REGS(channel_number), 0x00, /* Channel 0 */
+
+       /* Frequency synthesizer control - 0x0B .. 0x0C - FSCTRL1..0 */
+       CC1101_REGS(freq_synth_ctrl[0]), 0x0C, /* Used for ?? IF: 304.6875 KHz */
+
+       /* Carrier Frequency control - FREQ2..0 : Fcarrier == 867.999939 MHz */
+       CC1101_REGS(freq_control[0]), 0x21, /* 0x216276 == Fcarrier * 2^16 / Fxtal */
+       CC1101_REGS(freq_control[1]), 0x62, /*          == approx(868 MHz) * 65536 / 26 MHz */
+       CC1101_REGS(freq_control[2]), 0x76,
+
+       /* Modem configuration - MDMCFG4..0 */
+       /* MDMCFG4..3 : RX filterbandwidth = 541.666667 kHz and Datarate = 249.938965 kBaud */
+       CC1101_REGS(modem_config[0]), 0x2D,
+       CC1101_REGS(modem_config[1]), 0x3B,
+       /* MDMCFG2 : 30/32 sync word bits + sensitivity, Manchester disabled, GFSK, Digital DC filter enabled */
+       CC1101_REGS(modem_config[2]), 0x13,
+       /* MDMCFG1..0 : FEC disabled, 4 preamble bytes, Channel spacing = 199.951172 kHz */
+       CC1101_REGS(modem_config[3]), 0x22,
+       CC1101_REGS(modem_config[4]), 0xF8,
+       /* Modem deviation : DEVIATN */
+       CC1101_REGS(modem_deviation), 0x62, /* Deviation = 127 kHz */
+
+       /* Front End Rx/Tx config : use defaults */
+//     CC1101_REGS(front_end_rx_cfg), 0x56,
+//     CC1101_REGS(front_end_tx_cfg), 0x10,
+
+       /* Main Radio Control State Machine Configuration - MCSM2..0 */
+       CC1101_REGS(radio_stm[1]), 0x3F, /* CCA mode if RSSI below threshold, Stay in RX, Go to RX */
+       CC1101_REGS(radio_stm[2]), 0x18, /* PO timeout 149-155us, Auto calibrate from idle to rx/tx */
+
+       /* Frequency Offset Compensation configuration - FOCCFG */
+       CC1101_REGS(freq_offset_comp), 0x1D, /* 4K before, K/2 after, BWchan/8 */
+       CC1101_REGS(bit_sync), 0x1C, /* 1*Ki, 2*Kp, Ki/2, Kp, +0 (no data rate compensation) */
+
+       /* AGC control - 0x1B .. 0x1D - AGCCTRL2..0 */
+       CC1101_REGS(agc_ctrl[0]), 0xC7, /* Don't use 3highest gain, Max LNA gain, 42dB amp from chan filter */
+       CC1101_REGS(agc_ctrl[1]), 0x00, /* LNA 2 gain decr first, Carrier sense relative threshold disabled */
+       CC1101_REGS(agc_ctrl[2]), 0xB0, /* Medium settings, 24 samples wait time, normal op. */
+
+       /* Frequency synthesizer calibration - 0x23 .. 0x26 - FSCAL3..0 */
+       CC1101_REGS(freq_synth_cal[0]), 0xEA,
+       CC1101_REGS(freq_synth_cal[1]), 0x2A,
+       CC1101_REGS(freq_synth_cal[2]), 0x00,
+       CC1101_REGS(freq_synth_cal[3]), 0x1F,
+       /* Frequency synthesizer calibration control - 0x29 - FSTEST */
+       CC1101_REGS(freq_synth_cal_ctrl), 0x59,
+
+       /* Various test settings - 0x2C .. 0x2E - TEST2..0 */
+//     CC1101_REGS(test[0]), 0x88,
+//     CC1101_REGS(test[1]), 0x31,
+       CC1101_REGS(test[2]), 0x09, /* Disable VCO selection calibration stage */
+};
+
+static uint8_t paTable[] = {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+
+/* Configure pins, reset the CC1101, and put the CC1101 chip in idle state */
+void cc1101_init(uint8_t ssp_num, const struct pio* cs_pin, const struct pio* miso_pin)
+{
+       if ((cs_pin == NULL) || (miso_pin == NULL)) {
+               return;
+       }
+
+       cc1101.spi_num = ssp_num;
+       /* Copy CS pin info and configure pin as GPIO output */
+       pio_copy(&(cc1101.cs_pin), cs_pin);
+       /* Configure CS as output and set high */
+       config_gpio(cs_pin, LPC_IO_MODE_PULL_UP, GPIO_DIR_OUT, 1);
+
+       /* Copy MISO pin info (no config, should be already configured as SPI) */
+       pio_copy(&(cc1101.miso_pin), miso_pin);
+
+       cc1101_power_up_reset();
+       cc1101_send_cmd(CC1101_CMD(state_idle));
+}
+
+/* Write / send all the configuration register values to the CC1101 chip */
+void cc1101_config(void)
+{
+       int i = 0;
+       cc1101_send_cmd(CC1101_CMD(state_idle));
+       /* Write RF initial settings to CC1101 */
+       for (i = 0; i < sizeof(rf_init_settings); i += 2) {
+               cc1101_write_reg(rf_init_settings[i], rf_init_settings[i + 1]);
+       }
+       /* Write PA Table value */
+       cc1101_write_reg(CC1101_PATABLE, paTable[0]);
+}
+
+/* Update CC1101 config
+ * Arguments are the settings table which is a table of address and value pairs,
+ *   and the table length, which must be even.
+ */
+void cc1101_update_config(uint8_t* settings, uint8_t len)
+{
+       int i = 0;
+       if (len & 0x01) {
+               return;
+       }
+       for (i = 0; i < len; i += 2) {
+               cc1101_write_reg(settings[i], settings[i + 1]);
+       }
+}
+
+/* Change PA Table value */
+void cc1101_set_patable(uint8_t val)
+{
+       cc1101_write_reg(CC1101_PATABLE, val);
+}
+
diff --git a/extdrv/eeprom.c b/extdrv/eeprom.c
new file mode 100644 (file)
index 0000000..fcdf4e4
--- /dev/null
@@ -0,0 +1,218 @@
+/****************************************************************************
+ *   extdrv/eeprom.c
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include <stdint.h>
+
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "lib/string.h"
+#include "drivers/gpio.h"
+#include "drivers/i2c.h"
+#include "extdrv/eeprom.h"
+
+
+/***************************************************************************** */
+/*          EEPROM Read and Write                                              */
+/***************************************************************************** */
+
+/* Config */
+/* Small eeprom : up to 2k bytes. These use a segment address on the lower three bits
+ *   of the address byte, and thus reply on 8 consecutive addresses */
+#define EEPROM_SMALL_I2C_SIZE  1024
+#define EEPROM_SMALL_PAGE_SIZE 16
+/* Big eeprom : from 4k bytes and above : These use two address bytes, and the three
+ *   physical address pins are used to set the chip address. */
+#define EEPROM_BIG_I2C_SIZE  16*1024
+#define EEPROM_BIG_PAGE_SIZE 64
+
+
+/* Detect the eeprom size
+ * This function will try to access the eeprom on a different address to detect the type.
+ * A "big" eeprom will reply only on it's own address, while "small" ones will rely on
+ *   eight consecutive addresses.
+ * The function returns the eeprom type (EEPROM_TYPE_xxx) on success or a negative value
+ *   on error.
+ */
+int eeprom_detect(uint8_t i2c_bus_num, uint8_t eeprom_addr)
+{
+       int ret = 0;
+       char cmd_buf = (eeprom_addr + 2);
+
+       /* Look for small eeproms first, only these would answer on all addresses */
+       ret = i2c_read(i2c_bus_num, &cmd_buf, 1, NULL, NULL, 0);
+       if (ret == 0) {
+               return EEPROM_TYPE_SMALL;
+       }
+
+       /* No small eeprom ... look for big ones */
+       cmd_buf = eeprom_addr;
+       ret = i2c_read(i2c_bus_num, &cmd_buf, 1, NULL, NULL, 0);
+       if (ret == 0) {
+               return EEPROM_TYPE_BIG;
+       }
+
+       if (ret > 0) {
+               return -EIO;
+       } else if (ret == -EREMOTEIO) {
+               return EEPROM_TYPE_NONE; /* No module */
+       }
+       return ret; /* Error or module size */
+}
+
+
+/* EEPROM Read
+ * Performs a non-blocking read on the eeprom.
+ *   eeprom_addr : address of the I2C eeprom chip (hardware dependent) on most significant bits.
+ *   eeprom_type : one of EEPROM_TYPE_SMALL or EEPROM_TYPE_BIG.
+ *   offset : data offset in eeprom memory.
+ * Return value:
+ *   Upon successfull completion, returns the number of bytes read. On error, returns a negative
+ *   integer equivalent to errors from glibc.
+ *   -EFAULT : address above eeprom size
+ *   -EBADFD : Device not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EAGAIN : Device already in use
+ *   -EINVAL : Invalid argument (buf)
+ *   -EREMOTEIO : Device did not acknowledge
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+#define CMD_BUF_SIZE 4
+int eeprom_read(uint8_t i2c_bus_num, uint8_t eeprom_addr, uint8_t eeprom_type,
+                                       uint32_t offset, void *buf, size_t count)
+{
+       int ret = 0;
+       char cmd_buf[CMD_BUF_SIZE];
+       char ctrl_buf[CMD_BUF_SIZE] = { I2C_CONT, I2C_CONT, I2C_DO_REPEATED_START, I2C_CONT, };
+
+       /* Read the requested data, using the command sequence corresponding to the eeprom type */
+       switch (eeprom_type) {
+               case EEPROM_TYPE_SMALL:
+                       cmd_buf[0] = eeprom_addr | ((offset & 0x700) >> 7);
+                       cmd_buf[1] = offset & 0xFF;
+                       cmd_buf[2] = eeprom_addr | I2C_READ_BIT;
+                       ret = i2c_read(i2c_bus_num, cmd_buf, CMD_BUF_SIZE - 1, ctrl_buf + 1, buf, count);
+                       break;
+               case EEPROM_TYPE_BIG:
+                       cmd_buf[0] = eeprom_addr;
+                       cmd_buf[1] = ((offset & 0xFF00) >> 8);
+                       cmd_buf[2] = offset & 0xFF;
+                       cmd_buf[3] = (eeprom_addr | I2C_READ_BIT);
+                       ret = i2c_read(i2c_bus_num, cmd_buf, CMD_BUF_SIZE, ctrl_buf, buf, count);
+                       break;
+               default:
+                       ret = -1;
+                       break;
+       }
+
+       return ret;
+}
+
+
+/* EEPROM Write
+ * Performs a non-blocking write on the eeprom.
+ *   eeprom_addr : address of the I2C eeprom chip (hardware dependent) on most significant bits.
+ *   eeprom_type : one of EEPROM_TYPE_SMALL or EEPROM_TYPE_BIG.
+ *   offset : data offset in eeprom memory.
+ * Return value:
+ *   Upon successfull completion, returns the number of bytes written. On error, returns a negative
+ *   integer equivalent to errors from glibc.
+ *   -EFAULT : address above eeprom size
+ *   -EBADFD : Device not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EAGAIN : Device already in use
+ *   -EINVAL : Invalid argument (buf)
+ *   -EREMOTEIO : Device did not acknowledge
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+#define CMD_SIZE_SMALL 2
+#define CMD_SIZE_BIG 3
+#define MAX_CMD_SIZE CMD_SIZE_BIG
+#define EEPROM_MAX_PAGE_SIZE EEPROM_BIG_PAGE_SIZE
+int eeprom_write(uint8_t i2c_bus_num, uint8_t eeprom_addr, uint8_t eeprom_type,
+                                       uint32_t offset, const void *buf, size_t count)
+{
+       int ret = 0;
+       uint8_t cmd_size = CMD_SIZE_BIG, page_size = EEPROM_BIG_PAGE_SIZE;
+       int write_count = 0, size = 0;
+       char cmd[MAX_CMD_SIZE];
+       char full_buff[(EEPROM_MAX_PAGE_SIZE + MAX_CMD_SIZE)];
+
+       switch (eeprom_type) {
+               case EEPROM_TYPE_SMALL:
+                       cmd_size = CMD_SIZE_SMALL;
+                       page_size = EEPROM_SMALL_PAGE_SIZE;
+                       break;
+               case EEPROM_TYPE_BIG:
+                       /* already configured */
+                       /* cmd_size = CMD_SIZE_BIG; */
+                       /* page_size = EEPROM_BIG_PAGE_SIZE; */
+                       break;
+               default:
+                       ret = -1;
+                       write_count = count + 1; /* skip the while loop, but return error */
+                       break;
+       }
+       while (write_count < count) {
+               switch (eeprom_type) {
+                       case EEPROM_TYPE_SMALL:
+                               cmd[0] = eeprom_addr | ((offset & 0x700) >> 7);
+                               cmd[1] = offset & 0xFF;
+                               break;
+                       case EEPROM_TYPE_BIG:
+                               cmd[0] = eeprom_addr;
+                               cmd[1] = ((offset & 0xFF00) >> 8);
+                               cmd[2] = offset & 0xFF;
+                               break;
+               }
+               /* make partial first write to allign to page boundaries */
+               if (offset & (page_size - 1)) {
+                       size = (page_size - (offset & (page_size - 1)));
+               } else {
+                       size = page_size;
+               }
+               if (size > (count - write_count))
+                       size = (count - write_count);
+               offset += size;
+               memcpy(full_buff, cmd, cmd_size);
+               memcpy(full_buff + cmd_size, buf + write_count, size);
+               ret = i2c_write(i2c_bus_num, full_buff, (cmd_size + size), NULL);
+
+               if (ret != (cmd_size + size)) {
+                       break;
+               }
+               /* Wait for page write completion : The device does not acknoledge anything during
+                * page write, perform page writes with no data, until it returns 1 */
+               do {
+                       ret = i2c_write(i2c_bus_num, full_buff, 1, NULL);
+               } while (ret != 1);
+
+               write_count += size;
+       }
+
+       if (write_count != count)
+               return ret;
+       return write_count;
+}
+
+
diff --git a/extdrv/epaper.c b/extdrv/epaper.c
new file mode 100644 (file)
index 0000000..d42b842
--- /dev/null
@@ -0,0 +1,450 @@
+/****************************************************************************
+ *   extdrv/epaper.c
+ *
+ *
+ *
+ * Copyright 2013 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+/* This file holds all the code used to handle the 2.7" epaper display from embedded
+ * artists on the GPIO Demo module.
+ */
+
+#include <stdint.h>
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "core/systick.h"
+#include "core/pio.h"
+#include "lib/stdio.h"
+#include "drivers/gpio.h"
+#include "drivers/timers.h"
+#include "drivers/ssp.h"
+#include "extdrv/epaper.h"
+
+
+struct epaper_definition* epd = NULL;
+
+
+/*
+ * Configure all gpio used for e-paper display handling
+ * Also calls timer_setup()
+ * Keeps a pointer to the epaper_definition structure, which MUST stay available.
+ */
+void epaper_config(struct epaper_definition* ep_def)
+{
+       /* Get a pointer to the epaper definition structure */
+       epd = ep_def;
+
+       /* Reset : output */
+       config_gpio(&(epd->pin_reset), LPC_IO_MODE_PULL_UP, GPIO_DIR_OUT, 0);
+       /* Power control : output */
+       config_gpio(&(epd->pin_power_ctrl), LPC_IO_MODE_PULL_UP, GPIO_DIR_OUT, 0);
+       /* Discharge : output */
+       config_gpio(&(epd->pin_discharge), LPC_IO_MODE_PULL_UP, GPIO_DIR_OUT, 0);
+       /* Border control : output */
+       config_gpio(&(epd->pin_border_ctrl), LPC_IO_MODE_PULL_UP, GPIO_DIR_OUT, 0);
+       /* Busy : input */
+       config_gpio(&(epd->pin_busy), LPC_IO_MODE_PULL_UP, GPIO_DIR_IN, 0);
+       /* SPI Chip Select : output */
+       config_gpio(&(epd->pin_spi_cs), LPC_IO_MODE_PULL_UP, GPIO_DIR_OUT, 1);
+
+       /* PWM Timer configuration */
+       timer_setup(epd->pwm_timer_num, &(epd->pwm_timer_conf));
+}
+
+
+
+/*******************************************************************************/
+/*
+ * internal functions for SPI communication with COG driver
+ */
+static void epaper_spi_transfer_single_byte_wait(uint16_t data)
+{
+       do {} while (gpio_isset(epd->pin_busy));
+
+       data = spi_transfer_single_frame(epd->spi_num, data);
+}
+
+static void epaper_spi_transfer(uint8_t* out, uint8_t* in, uint8_t size)
+{
+       /* Set CS Low */
+       gpio_clear(epd->pin_spi_cs);
+       /* Perform transfer */
+       spi_transfer_multiple_frames(epd->spi_num, out, in, size, 8);
+       /* Release CS */
+       gpio_set(epd->pin_spi_cs);
+}
+
+static void epaper_spi_send(uint8_t reg_index, uint8_t* data, uint8_t val, int length)
+{
+       uint8_t buff[9] = { 0 };
+
+       /* Send register index */
+       buff[0] = 0x70;
+       buff[1] = reg_index;
+       epaper_spi_transfer(buff, NULL, 2);
+       usleep(10);
+       /* Send Data */
+       buff[0] = 0x72;
+       if (data != NULL) {
+               memcpy(&(buff[1]), data, length);
+               epaper_spi_transfer(buff, NULL, (length + 1));
+       } else {
+               buff[1] = val;
+               epaper_spi_transfer(buff, NULL, 2);
+       }
+       usleep(10);
+}
+
+
+/*******************************************************************************/
+/*
+ * internal functions for COG driver power on and initialisation
+ */
+static void epaper_cog_power_on()
+{
+       /* Put GPIO in the right states */
+       gpio_clear(epd->pin_border_ctrl);
+       gpio_clear(epd->pin_power_ctrl);
+       gpio_clear(epd->pin_discharge);
+       gpio_clear(epd->pin_spi_cs);
+       gpio_clear(epd->pin_reset);
+
+       /* COG Power On procedure, see Doc No. 4P008-00 From Pervasive display */
+       /* Start PWM : used to eliminate possible negative voltage at low temperature. */
+       timer_start(epd->pwm_timer_num);
+       msleep(5); /* Keep PWM on for >=5 ms before power up */
+
+       /* Power up display */
+       gpio_set(epd->pin_power_ctrl);
+       msleep(10); /* Keep PWM on for 10 more ms */
+
+       /* Remove reset condition and border control */
+       gpio_set(epd->pin_spi_cs);
+       gpio_set(epd->pin_border_ctrl);
+       gpio_set(epd->pin_reset);
+       msleep(5); /* >=5 ms delay */
+       /* Toggle reset */
+       gpio_clear(epd->pin_reset);
+       msleep(5); /* >=5 ms delay */
+       gpio_set(epd->pin_reset);
+       msleep(5); /* >=5 ms delay */
+}
+
+static void epaper_cog_initialize()
+{
+       uint8_t vcom[2] = {0xD0, 0x00};
+
+       /* Wait for ready condition */
+       do {} while (gpio_isset(epd->pin_busy));
+
+       /* Select Channel */
+       epaper_spi_send(0x01, epd->channel, 0, 8);
+       /* DC/DC Frequency setting */
+       epaper_spi_send(0x06, NULL, 0xFF, 1);
+       /* High Power Mode Osc setting */
+       epaper_spi_send(0x07, NULL, 0x9D, 1);
+       /* Disable ADC */
+       epaper_spi_send(0x08, NULL, 0x00, 1);
+       /* Set Vcom level */
+       epaper_spi_send(0x09, vcom, 0, 2);
+       /* Set Gate and Source Voltage level */
+       epaper_spi_send(0x04, NULL, epd->gate_source_level, 1);
+
+       msleep(5); /* >=5 ms delay */
+
+       /* Turn Driver Latch ON and then OFF */
+       epaper_spi_send(0x03, NULL, 0x01, 1);
+       epaper_spi_send(0x03, NULL, 0x00, 1);
+
+       /* Turn on chargepump for positive voltages VGH and VDH */
+       epaper_spi_send(0x05, NULL, 0x01, 1);
+       msleep(30); /* >=30 ms delay */
+
+       /* Turn off PWM */ 
+       timer_stop(epd->pwm_timer_num);
+
+       /* Turn on chargepump for negative voltages VGL and VDL */
+       epaper_spi_send(0x05, NULL, 0x03, 1);
+       msleep(30); /* >=30 ms delay */
+       /* Turn on chargepump for Vcom driver */
+       epaper_spi_send(0x05, NULL, 0x0F, 1);
+       msleep(30); /* >=30 ms delay */
+
+       /* Output enable */
+       epaper_spi_send(0x02, NULL, 0x24, 1);
+}
+
+
+
+/*******************************************************************************/
+/*
+ * Turn Epaper controller On.
+ * Perform both COG driver Power On and Initialization.
+ *
+ * Must be called before any of the display / send frame functions when the display has
+ *  been previously turned off or before first call
+ */
+void epaper_on()
+{
+       epaper_cog_power_on();
+       epaper_cog_initialize();
+}
+
+
+/*******************************************************************************/
+/*
+ * internal function used to send a line to the display.
+ * Line must be long enougth for the display
+ * Line numbering starts at 0
+ */
+static void epaper_send_data_line(const uint8_t line, uint8_t* line_data,
+                                                                 uint8_t fixed_data, uint8_t stage)
+{
+       int i = 0;
+       uint8_t pixels = 0;
+
+       /* Set chargepump voltage level to reduce voltage shift */
+       epaper_spi_send(0x04, NULL, epd->gate_source_level, 1);
+       
+       /* Start with data index register */
+       /* Set CS Low */
+       gpio_clear(epd->pin_spi_cs);
+       epaper_spi_transfer_single_byte_wait(0x70);
+       epaper_spi_transfer_single_byte_wait(0x0A);
+       /* Release CS */
+       gpio_set(epd->pin_spi_cs);
+       usleep(10);
+
+       /* Set CS Low */
+       gpio_clear(epd->pin_spi_cs);
+       epaper_spi_transfer_single_byte_wait(0x72);
+       /* Put even data bits first */
+       if (line_data != NULL) {
+               for (i = epd->bytes_per_line; i > 0; i--) {
+                       pixels = line_data[i - 1] & 0xAA;
+                       switch (stage) {
+                               case epaper_compensate:  /* B -> W, W -> B (Current Image) */
+                                       pixels = 0xAA | ((pixels ^ 0xAA) >> 1);
+                                       break;
+                               case epaper_white:       /* B -> N, W -> W (Current Image) */
+                                       pixels = 0x55 + ((pixels ^ 0xAA) >> 1);
+                                       break;
+                               case epaper_inverse:     /* B -> N, W -> B (New Image) */
+                                       pixels = 0x55 | (pixels ^ 0xAA);
+                                       break;
+                               case epaper_normal:      /* B -> B, W -> W (New Image) */
+                                       pixels = 0xAA | (pixels >> 1);
+                                       break;
+                       }
+                       pixels = pixels & 0xFF;
+                       epaper_spi_transfer_single_byte_wait(pixels);
+               }
+       } else {
+               for (i = epd->bytes_per_line; i > 0; i--) {
+                       epaper_spi_transfer_single_byte_wait(fixed_data);
+               }
+       }
+
+       /* Send scan line ... All set to 0 but one */
+       for (i = 0; i < epd->bytes_per_scan; i++) {
+               if (i == (line >> 2)) {
+                       epaper_spi_transfer_single_byte_wait((0xC0 >> ((line & 0x03) * 2)));
+               } else {
+                       epaper_spi_transfer_single_byte_wait(0x00);
+               }
+       }
+
+       /* And then put odd data bits */
+       if (line_data != NULL) {
+               for (i = 0; i < epd->bytes_per_line; i++) {
+                       uint16_t tmp = 0;
+                       pixels = line_data[i] & 0x55;
+                       switch(stage) {
+                               case epaper_compensate:  /* B -> W, W -> B (Current Image) */
+                                       tmp = 0xaa | (pixels ^ 0x55);
+                                       break;
+                               case epaper_white:       /* B -> N, W -> W (Current Image) */
+                                       tmp = 0x55 + (pixels ^ 0x55);
+                                       break;
+                               case epaper_inverse:     /* B -> N, W -> B (New Image) */
+                                       tmp = 0x55 | ((pixels ^ 0x55) << 1);
+                                       break;
+                               case epaper_normal:      /* B -> B, W -> W (New Image) */
+                                       tmp = 0xaa | pixels;
+                                       break;
+                       }
+                       /* Revert order */
+                       pixels = (((tmp & 0x03) << 6) | ((tmp & 0x0C) << 2) | ((tmp & 0x30) >> 2) | ((tmp & 0xC0) >> 6));
+                       epaper_spi_transfer_single_byte_wait(pixels);
+               }
+       } else {
+               for (i = 0; i < epd->bytes_per_line; i++) {
+                       epaper_spi_transfer_single_byte_wait(fixed_data);
+               }
+       }
+
+       /* Line termination */
+       if (epd->line_termination_required) {
+               epaper_spi_transfer_single_byte_wait(0x00);
+       }
+
+       /* Done with the frame, release chip select */
+       gpio_set(epd->pin_spi_cs);
+
+       /* Turn on output enable to send data from CoG driver to panel */
+       epaper_spi_send(0x02, NULL, 0x2F, 1);
+}
+
+
+
+/*******************************************************************************/
+/* Epaper display functions */
+
+/*
+ * Send whole image, performing only one stage.
+ * Only "epaper_normal" has been tested yet.
+ */
+void epaper_send_frame(uint8_t* image, uint8_t stage)
+{
+       uint32_t start_tick = systick_get_tick_count();
+       int i = 0;
+
+       do {
+               for (i = 0; i < epd->lines; i++) {
+                       epaper_send_data_line(i, (image + (i * epd->bytes_per_line)), 0, stage);
+               }
+       /* FIXME : start_tick will wrapp after 50 days */
+       } while ((systick_get_tick_count() - start_tick) < epd->stage_time);
+}
+
+/*
+ * Update a few lines of the display.
+ * Lines numbering starts at 0.
+ * Only one stage is performed. Sending a set of "white lines" of the same size before the
+ *   new lines gives better results.
+ */
+void epaper_send_partial_frame(uint8_t* image, uint8_t start_line, uint8_t nb_lines, uint8_t stage)
+{
+       uint32_t start_tick = systick_get_tick_count();
+       int i = 0;
+
+       do {
+               for (i = 0; i < nb_lines; i++) {
+                       epaper_send_data_line((start_line + i), (image + (i * epd->bytes_per_line)), 0, stage);
+               }
+       /* FIXME : start_tick will wrapp after 50 days */
+       } while ((systick_get_tick_count() - start_tick) < epd->stage_time);
+}
+
+/*
+ * Send an image (whole screen), preforming all stages:
+ *   - Compensate old image,
+ *   - White,
+ *   - Inversed new image,
+ *   - New image.
+ *
+ * Note : unsupported yet.
+ */
+void epaper_display(uint8_t* old_image_data, uint8_t* new_image_data)
+{
+       /* FIXME: perform all stages: Compensate old image, white, inversed new image, new image */
+}
+
+/*
+ * Turn the whole display white or black
+ * Send 0xFF for black and 0xAA for white.
+ * Note : Other values will create vertical lines (or nothing) depending on the values.
+ *   refer to Pervasive display documentation for more information.
+ */
+void epaper_uniform_display(uint8_t value)
+{
+       uint32_t start_tick = systick_get_tick_count();
+       int i = 0;
+
+       do {
+               for (i = 0; i < epd->lines; i++) {
+                       epaper_send_data_line(i, NULL, value, 0);
+               }
+       /* FIXME : start_tick will wrapp after 50 days */
+       } while ((systick_get_tick_count() - start_tick) < epd->stage_time);
+}
+
+
+
+/*******************************************************************************/
+/* Turn Off Epaper controller */
+void epaper_off()
+{
+       int i = 0;
+
+       /* Write a Nothing frame */
+       for (i = 0; i < epd->lines; i++) {
+               epaper_send_data_line(i, NULL, 0x55, 0); /* Will send all 'N' */
+       }
+       /* Clear register data before power off by writting a dummy line
+        * A line of 0xFF is beyond the number of lines, thus no scan line will be set */
+       epaper_send_data_line(0xFF, NULL, 0x55, 0);
+       msleep(30); /* >25ms */
+       
+       /* Toggle border control */
+       gpio_clear(epd->pin_border_ctrl);
+       msleep(300); /* 200 - 300 ms */
+       gpio_set(epd->pin_border_ctrl);
+
+       /* Latch reset on */
+       epaper_spi_send(0x03, NULL, 0x01, 1);
+       /* Turn off Output enable */
+       epaper_spi_send(0x02, NULL, 0x05, 1);
+       /* Power off Vcom chargepump */
+       epaper_spi_send(0x05, NULL, 0x0E, 1);
+       /* Power off negative voltage chargepump */
+       epaper_spi_send(0x05, NULL, 0x02, 1);
+
+       /* Discharge part 1 */
+       epaper_spi_send(0x04, NULL, 0x0C, 1);
+       msleep(150); /* >=120ms */
+       /* Power off all chargepump */
+       epaper_spi_send(0x05, NULL, 0x00, 1);
+
+       /* Turn off Oscilator */
+       epaper_spi_send(0x07, NULL, 0x0D, 1);
+
+       /* Discharge part 2 */
+       /* internal */
+       epaper_spi_send(0x04, NULL, 0x50, 1);
+       msleep(50); /* >=40ms */
+       epaper_spi_send(0x04, NULL, 0xA0, 1);
+       msleep(50); /* >=40ms */
+       epaper_spi_send(0x04, NULL, 0x00, 1);
+
+       /* Turn everything to 0 */
+       gpio_clear(epd->pin_border_ctrl);
+       gpio_clear(epd->pin_reset);
+       gpio_clear(epd->pin_power_ctrl);
+
+       /* Discharge part 3 */
+       gpio_set(epd->pin_discharge);
+       msleep(180); /* >150ms */
+       gpio_clear(epd->pin_discharge);
+
+}
+
+
diff --git a/extdrv/tmp101_temp_sensor.c b/extdrv/tmp101_temp_sensor.c
new file mode 100644 (file)
index 0000000..31814b7
--- /dev/null
@@ -0,0 +1,204 @@
+/****************************************************************************
+ *   extdrv/tmp101_temp_sensor.c
+ *
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#include <stdint.h>
+
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+#include "core/system.h"
+#include "drivers/i2c.h"
+#include "lib/bit_arithm.h"
+#include "extdrv/tmp101_temp_sensor.h"
+
+
+/***************************************************************************** */
+/*          Support for TMP101 temperature sensors from Texas Instrument       */
+/***************************************************************************** */
+/* This driver is made for the TMP101 version of the chip, though there's few
+ * diferences between the TMP100 and TMP101 version.
+ * This driver does not handle the SMBus Alert command.
+ */
+
+
+enum tmp10x_internal_reg_numbers {
+       TMP_REG_TEMPERATURE = 0,
+       TMP_REG_CONFIG,
+       TMP_REG_ALERT_LOW,
+       TMP_REG_ALERT_HIGH,
+};
+
+
+/* Aditional defines, not exported to userspace */
+/* Mode config */
+#define TMP_SHUTDOWN_MODE_ON            (1 << 0)
+#define TMP_THERMOSTAT_COMPARATOR_MODE  (0 << 1)
+#define TMP_THERMOSTAT_INTERRUPT_MODE   (1 << 1)
+/* Alert signal polarity */
+#define TMP_ALERT_POLARITY_LOW          (0 << 2)
+#define TMP_ALERT_POLARITY_HIGH         (1 << 2)
+/* One-shot measurement trigger */
+#define TMP_ONE_SHOT_TRIGGER            (1 << 7)
+
+
+
+/* This static value is used to keep track of the last register accessed to
+ * prevent sending the pointer register again if we want to read the same
+ * register again. */
+static int last_accessed_register = 0;
+
+/* Check the sensor presence, return 1 if sensor was found.
+ * This is a basic check, it could be anything with the same address ...
+ * addr : the sensor address on most significant bits.
+ */
+int tmp101_probe_sensor(uint8_t i2c_bus_num, uint8_t addr)
+{
+       static int ret = -1;
+       char cmd_buf = (addr | I2C_READ_BIT);
+
+       /* Did we already probe the sensor ? */
+       if (ret != 1) {
+               ret = i2c_read(i2c_bus_num, &cmd_buf, 1, NULL, NULL, 0);
+       }
+       return ret;
+}
+
+/* Convert raw temperature data (expressed as signed value of 16 times the
+ * actual temperature in the twelve higher bits of a sixteen bits wide value)
+ * into a decimal integer value of ten times the actual temperature.
+ * The value returned is thus in tenth of degrees centigrade.
+ */
+int tmp101_convert_to_deci_degrees(uint16_t raw)
+{
+       return (((int16_t)raw * 10) >> 8);
+}
+
+/* Temp Read
+ * Performs a non-blocking read of the temperature from the sensor.
+ * addr : the sensor address on most significant bits.
+ * 'raw' and 'deci_degrees' : integer addresses for conversion result, may be NULL.
+ * Return value(s):
+ *   Upon successfull completion, returns 0 and the temperature read is placed in the
+ *   provided integers. On error, returns a negative integer equivalent to errors from glibc.
+ *   -EBADFD : I2C not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EINVAL : Invalid argument (buf)
+ *   -ENODEV : No such device
+ *   -EREMOTEIO : Device did not acknowledge : Any device present ?
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+#define CMD_BUF_SIZE 3
+int tmp101_sensor_read(uint8_t i2c_bus_num, uint8_t addr, uint16_t* raw, int* deci_degrees)
+{
+       int ret = 0;
+       uint16_t temp = 0;
+       char cmd_buf[CMD_BUF_SIZE] = { addr, TMP_REG_TEMPERATURE, (addr | I2C_READ_BIT), };
+       char ctrl_buf[CMD_BUF_SIZE] = { I2C_CONT, I2C_DO_REPEATED_START, I2C_CONT, };
+
+       if (tmp101_probe_sensor(i2c_bus_num, addr) != 1) {
+               return -ENODEV;
+       }
+
+       /* Read the requested data */
+       if (last_accessed_register == TMP_REG_TEMPERATURE) {
+               /* No need to switch back to temperature register */
+               ret = i2c_read(i2c_bus_num, (cmd_buf + 2), 1, (ctrl_buf + 2), (char*)&temp, 2);
+       } else {
+               /* Send (write) temperature register address to TMP101 internal pointer */
+               ret = i2c_read(i2c_bus_num, cmd_buf, CMD_BUF_SIZE, ctrl_buf, (char*)&temp, 2);
+               last_accessed_register = TMP_REG_TEMPERATURE;
+       }
+
+       if (ret == 2) {
+               if (raw != NULL) {
+                       *raw = byte_swap_16(temp);
+               }
+               if (deci_degrees != NULL) {
+                       *deci_degrees = tmp101_convert_to_deci_degrees(byte_swap_16(temp));
+               }
+               return 0;
+       }
+       return ret;
+}
+
+
+/* Sensor config
+ * Performs default configuration of the temperature sensor.
+ * The sensor is thus placed in shutdown mode, the thermostat is in interrupt mode,
+ * and the polarity is set to active high.
+ * The conversion resolution is set to the provided "resolution".
+ * addr : the sensor address on most significant bits.
+ * Return value :
+ *   Upon successfull completion, returns 0. On error, returns a negative integer
+ *   equivalent to errors from glibc.
+ *   -EBADFD : I2C not initialized
+ *   -EBUSY : Device or ressource Busy or Arbitration lost
+ *   -EINVAL : Invalid argument (buf)
+ *   -ENODEV : No such device
+ *   -EREMOTEIO : Device did not acknowledge : Any device present ?
+ *   -EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ */
+static uint8_t actual_config = 0;
+#define CONF_BUF_SIZE 4
+int tmp101_sensor_config(uint8_t i2c_bus_num, uint8_t addr, uint32_t resolution)
+{
+       int ret = 0;
+       char cmd[CONF_BUF_SIZE] = { addr, TMP_REG_CONFIG, };
+
+       if (tmp101_probe_sensor(i2c_bus_num, addr) != 1) {
+               return -ENODEV;
+       }
+
+       /* Store the new configuration */
+       actual_config = (TMP_SHUTDOWN_MODE_ON | TMP_THERMOSTAT_INTERRUPT_MODE | TMP_ALERT_POLARITY_HIGH);
+       actual_config |= (resolution & (0x03 << 5));
+       cmd[2] = actual_config;
+       ret = i2c_write(i2c_bus_num, cmd, 3, NULL);
+       last_accessed_register = TMP_REG_CONFIG;
+       if (ret == 3) {
+               return 0; /* Config success */
+       }
+       return ret;
+}
+
+/* Start a conversion when the sensor is in shutdown mode.
+ * addr : the sensor address on most significant bits.
+ */
+int tmp101_sensor_start_conversion(uint8_t i2c_bus_num, uint8_t addr)
+{
+       int ret = 0;
+       char cmd[CONF_BUF_SIZE] = { addr, TMP_REG_CONFIG, };
+
+       if (tmp101_probe_sensor(i2c_bus_num, addr) != 1) {
+               return -ENODEV;
+       }
+
+       cmd[2] = actual_config;
+       cmd[2] |= TMP_ONE_SHOT_TRIGGER;
+       ret = i2c_write(i2c_bus_num, cmd, 3, NULL);
+       last_accessed_register = TMP_REG_CONFIG;
+       if (ret == 3) {
+               return 0; /* Conversion start success */
+       }
+       return ret;
+}
+
+
diff --git a/include/core/iap.h b/include/core/iap.h
new file mode 100644 (file)
index 0000000..da4c4ea
--- /dev/null
@@ -0,0 +1,82 @@
+/****************************************************************************
+ *   core/iap.h
+ *
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef CORE_IAP_H
+#define CORE_IAP_H
+
+#include <stdint.h>
+
+
+
+/*******************************************************************************/
+/* Wrapper to IAP routines */
+
+/* FIXME : unimplemented */
+void lpc_iap_program(unsigned int src, unsigned int dest, unsigned int size);
+
+
+/*******************************************************************************/
+/*            In Application Programming ROM based routines                    */
+/*******************************************************************************/
+
+/* Provide access to IAP ROM based routines.
+ * This is the only access to User information block, and allows in-application re-programming
+ *   of the micro-controller (for bootloaders, drivers, loadable RTOS tasks, ....)
+ */
+
+
+/* Prepare sectors from the programm flash memory for erasing or writting
+ * Sectors numbers start at 0. A flash sector size is 4kB (0x1000 bytes)
+ * Provide the same sector number as start and end to prepare a single sector.
+ * Of course, end sector number MUST be higher than (or equal to) start sector number.
+ */
+int iap_prepare_flash(uint32_t start_sector, uint32_t end_sector);
+
+/* Erase full flash sectors from the programm memory
+ * Sectors numbers start at 0. A flash sector size is 4kB (0x1000 bytes)
+ * Provide the same sector number as start and end to erase a single sector.
+ * Of course, end sector number MUST be higher than (or equal to) start sector number.
+ * Use iap_erase_flash_pages() to erase a single page within a sector.
+ * A sector must be prepared for writing before the erase operation.
+ * Interrputs are disabled during this operation.
+ */
+int iap_erase_flash_sectors(uint32_t start_sector, uint32_t end_sector);
+
+/* Copy some data from RAM to Flash.
+ * When writting to the programm flash memory, the sectors must be prepared for writing
+ *   before the copy operation.
+ * Both dest and src parameters must be aligned to 4 bytes boundary and size must be a
+ *   multiple of 4.
+ * dest is the destination address and must be the address of some flash memory.
+ * ser is the source address and must be the address of some RAM memory.
+ * The sector or page in dest must have been erased before writing and no writing operation
+ *   performed between (dest) and (dest+size) addresses. (Writting in other parts of the
+ *   page or sector is OK)
+ * Interrputs are disabled during this operation.
+ */
+int iap_copy_ram_to_flash(uint32_t dest, uint32_t src, uint32_t size);
+
+
+/* Return the part ID */
+uint32_t iap_read_part_id(void);
+
+
+#endif /* CORE_IAP_H */
+
diff --git a/include/core/lpc_core_cm3.h b/include/core/lpc_core_cm3.h
new file mode 100644 (file)
index 0000000..8085c00
--- /dev/null
@@ -0,0 +1,436 @@
+/****************************************************************************
+ *   core/lpc_core_cm3.h
+ *
+ * Helper functions to access some registers and Cortex M3 core functionalities.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef LPC_CORE_CM3_H
+#define LPC_CORE_CM3_H
+
+#include <stdint.h>   /* standard types definitions */
+#include "core/lpc_regs_17xx.h"
+
+
+/*******************************************************************************/
+/*                Core Instructions                                            */
+/*******************************************************************************/
+/* Utility */
+/* NOP */
+#define nop() __asm volatile ("nop" : : : "memory")
+/* SEV : Send Event */
+#define sev() __asm volatile ("sev" : : : "memory")
+/* WFE : Wait For Event */
+#define wfe() __asm volatile ("wfe" : : : "memory")
+/* WFI : Wait For Interrupt */
+#define wfi() __asm volatile ("wfi" : : : "memory")
+
+
+/* Synchronization */
+/* Instruction Synchronization Barrier : Flushes pipeline */
+#define isb() __asm volatile ("isb" : : : "memory")
+/* Data Synchronization Barrier : All explicit memory access completed */
+#define dsb() __asm volatile ("dsb" : : : "memory")
+/* Data Memory Barrier : Ensures apparent order but not completion */
+#define dmb() __asm volatile ("dmb" : : : "memory")
+
+
+
+/* Exclusive load and store */
+#define LOAD_MACRO(instruction, size) \
+static inline size instruction(size* addr) \
+{ \
+       size r; __asm volatile (#instruction" %0, [%1]" : "=r" (r) : "r" (addr)); return (r); \
+}
+/* Exclusive load byte, half word and word */
+LOAD_MACRO(ldrexb, uint8_t)
+LOAD_MACRO(ldrexh, uint16_t)
+LOAD_MACRO(ldrex, uint32_t)
+
+#define STORE_MACRO(instruction, size) \
+static inline uint32_t instruction(size val, size* addr) \
+{ \
+       uint32_t r; __asm volatile (#instruction" %0, %2, [%1]" : "=r" (r) : "r" (addr), "r" (val)); return (r); \
+}
+/* Exclusive load byte, half word and word */
+STORE_MACRO(strexb, uint8_t)
+STORE_MACRO(strexh, uint16_t)
+STORE_MACRO(strex, uint32_t)
+
+
+/* Bit ordering */
+#define BIT_ORDERING_MACRO(instruction, size) \
+static inline size instruction(size val) \
+{ \
+       uint32_t r; __asm volatile (#instruction" %0, %1" : "=r" (r) : "r" (val)); return (r); \
+}
+/* Reverse byte order (32 bit) */
+BIT_ORDERING_MACRO(rev, uint32_t)
+/* Reverse byte order (16 bit) */
+BIT_ORDERING_MACRO(rev16, uint32_t)
+/* Reverse byte order in signed short value with sign extension to integer. */
+BIT_ORDERING_MACRO(revsh, int32_t)
+/* Reverse bit order of value */
+BIT_ORDERING_MACRO(rbit, uint32_t)
+
+
+/* Count leading zeros */
+static inline uint32_t clz(uint32_t val)
+{
+       uint32_t r; __asm volatile ("clz %0, %1" : "=r" (r) : "r" (val)); return (r);
+}
+/* Count trailing zeros */
+static inline uint32_t ctz(uint32_t val)
+{
+       uint32_t r, tmp;
+        __asm volatile ("rbit %0, %1" : "=r" (tmp) : "r" (val));
+        __asm volatile ("clz %0, %1" : "=r" (r) : "r" (tmp));
+       return (r);
+}
+
+
+/* Access to the Application Program Status Register (APSR). */
+static inline uint32_t get_APSR(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, apsr" : "=r" (r)); return (r);
+}
+#define APSR_SATURATION  (get_APSR() & (0x1 << 27))  /* bit 27  Saturation condition flag */
+#define APSR_OVERFLOW    (get_APSR() & (0x1 << 28))  /* bit 28  Overflow condition code flag */
+#define APSR_CARRY       (get_APSR() & (0x1 << 29))  /* bit 29  Carry condition code flag */
+#define APSR_ZERO        (get_APSR() & (0x1 << 30))  /* bit 30  Zero condition code flag */
+#define APSR_NEGATIVE    (get_APSR() & (0x1 << 31))  /* bit 31  Negative condition code flag */
+
+
+/* Access the Interrupt Program Status Register (IPSR). */
+static inline uint32_t get_IPSR(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, ipsr" : "=r" (r)); return (r);
+}
+#define IPSR      (get_IPSR() & 0x1FF)  /* bit:  0..8  Exception number */
+#define IPSR_IRQ0 16
+#define IRQ_NUM   (IPSR - IPSR_IRQ0)
+
+
+/* Control Register */
+static inline uint32_t get_CONTROL(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, control" : "=r" (r)); return (r);
+}
+static inline void set_CONTROL(uint32_t control)
+{
+       __asm volatile ("msr control, %0" : : "r" (control));
+}
+
+
+/* Process Stack Pointer */
+static inline uint32_t get_process_stack_pointer(void)
+{
+       register uint32_t r; __asm volatile ("mrs %0, psp" : "=r" (r)); return (r);
+}
+static inline void set_process_stack_pointer(uint32_t top_of_stack)
+{
+       __asm volatile ("msr psp, %0" : : "r" (top_of_stack));
+}
+
+
+/* Main Stack Pointer */
+static inline uint32_t get_main_stack_pointer(void)
+{
+       register uint32_t r; __asm volatile ("mrs %0, msp" : "=r" (r)); return (r);
+}
+static inline void set_main_stack_pointer(uint32_t top_of_stack)
+{
+       __asm volatile ("msr msp, %0" : : "r" (top_of_stack));
+}
+
+
+/* Priority Mask */
+static inline uint32_t get_priority_mask(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, primask" : "=r" (r)); return (r);
+}
+static inline void set_priority_mask(uint32_t mask)
+{
+       __asm volatile ("msr primask, %0" : : "r" (mask));
+}
+
+
+/* Base Priority */
+static inline uint32_t get_base_priority(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, basepri_max" : "=r" (r)); return (r);
+}
+static inline void set_base_priority(uint32_t prio)
+{
+       __asm volatile ("msr basepri, %0" : : "r" (prio));
+}
+
+
+/* Fault Mask */
+static inline uint32_t get_fault_mask(void)
+{
+       uint32_t r; __asm volatile ("mrs %0, faultmask" : "=r" (r)); return (r);
+}
+static inline void set_fault_mask(uint32_t mask)
+{
+       __asm volatile ("msr faultmask, %0" : : "r" (mask));
+}
+
+
+
+
+
+/*******************************************************************************/
+/*            Interrupts                                                       */
+/*******************************************************************************/
+
+/* Cortex-M3 Processor Exceptions Numbers */
+/* Note : entry 0 is "end stack pointer" */
+#define RESET_IRQ       (-15) /*  1 - Reset ... not an interrupt ... */
+#define NMI_IRQ         (-14) /*  2 - Non Maskable Interrupt */
+#define HARD_FAULT_IRQ  (-13) /*  3 - Cortex-M3 Hard Fault Interrupt */
+#define MEM_FAULT_IRQ   (-12) /*  4 - Cortex-M3 Memory Management Fault Interrupt */
+#define BUS_FAULT_IRQ   (-11) /*  5 - Cortex-M3 Bus Fault Interrupt */
+#define USAGE_FAULT_IRQ (-10) /*  6 - Cortex-M3 Usage Fault Interrupt */
+/* Note : entry 7 is the 2’s complement of the check-sum of the previous 7 entries */
+#define SV_CALL_IRQ     ( -5) /* 11 - Cortex-M3 Supervisor Call Interrupt */
+#define PEND_SV_IRQ     ( -2) /* 14 - Cortex-M3 Pend SV Interrupt */
+#define SYSTICK_IRQ     ( -1) /* 15 - Cortex-M3 System Tick Interrupt */
+
+/* LPC17xx Specific Interrupt Numbers */
+#define WDT_IRQ            0  /* 16 - Watchdog */
+#define TIMER0_IRQ         1  /* 17 - Timer 0 */
+#define TIMER1_IRQ         2  /* 18 - Timer 1 */
+#define TIMER2_IRQ         3  /* 19 - Timer 2 */
+#define TIMER3_IRQ         4  /* 20 - Timer 3 */
+#define UART0_IRQ          5  /* 21 - UART 0 */
+#define UART1_IRQ          6  /* 22 - UART 1 */
+#define UART2_IRQ          7  /* 23 - UART 2 */
+#define UART3_IRQ          8  /* 24 - UART 3 */
+#define PWM1_IRQ           9  /* 25 - PWM 1 */
+#define I2C0_IRQ          10  /* 26 - I2C 0 */
+#define I2C1_IRQ          11  /* 27 - I2C 1 */
+#define I2C2_IRQ          12  /* 28 - I2C 2 */
+#define SPI_IRQ           13  /* 29 - SPI */
+#define SSP0_IRQ          14  /* 30 - SSP 0 */
+#define SSP1_IRQ          15  /* 31 - SSP 1 */
+#define PLL0_IRQ          16  /* 32 - PPL 0 Lock */
+#define RTC_IRQ           17  /* 33 - RTC */
+#define EINT0_IRQ         18  /* 34 - External Interrupt 0 */
+#define EINT1_IRQ         19  /* 35 - External Interrupt 1 */
+#define EINT2_IRQ         20  /* 36 - External Interrupt 2 */
+#define EINT3_IRQ         21  /* 37 - External Interrupt 3 */
+#define ADC_IRQ           22  /* 38 - A/D Converter */
+#define BOD_IRQ           23  /* 39 - Brown Out Detect(BOD) */
+#define USB_IRQ           24  /* 40 - USB */
+#define CAN_IRQ           25  /* 41 - CAN */
+#define GPDMA_IRQ         26  /* 42 - General Purpose DMA */
+#define I2S_IRQ           27  /* 43 - I2S */
+#define ETHERNET_IRQ      28  /* 44 - Ethernet */
+#define REP_INT_IRQ       29  /* 45 - Repetitive Interrupt Timer */
+#define MC_PWM_IRQ        30  /* 46 - Motor Control PWM */
+#define QUAD_ENC_IRQ      31  /* 47 - Quadrature Encoder */
+#define PLL1_IRQ          32  /* 48 - PPL 1 (USB) Lock */
+#define USB_ACT_IRQ       33  /* 49 - USB Activity (USB_NEED_CLK) */
+#define CAN_ACT_IRQ       34  /* 50 - CAN Activity (wakeup) */
+
+
+/* Enable IRQ Interrupts
+  Enables IRQ interrupts by clearing the I-bit in the CPSR.
+  Can only be executed in Privileged modes.
+ */
+static inline void lpc_enable_irq(void)
+{
+       __asm volatile ("cpsie i");
+}
+
+/* Disable IRQ Interrupts
+  Disables IRQ interrupts by setting the I-bit in the CPSR.
+  Can only be executed in Privileged modes.
+ */
+static inline void lpc_disable_irq(void)
+{
+       __asm volatile ("cpsid i");
+}
+
+
+/*******************************************************************************/
+/*                Hardware Abstraction Layer : NVIC Functions                  */
+/*******************************************************************************/
+
+/* The following MACRO handle generation of the register [0..1] selection */
+#define LPC_IRQ_WORD(irq)   (((uint32_t)(irq) & 0x20) >> 5)
+
+/*  Enable External Interrupt
+  This function enables a device specific interrupt in the NVIC interrupt controller.
+  The interrupt number cannot be a negative value.
+  IRQ : Number of the external interrupt to enable
+ */
+static inline void NVIC_EnableIRQ(uint32_t IRQ)
+{
+       struct nvic_regs* nvic = LPC_NVIC;
+       nvic->int_set_enable[ LPC_IRQ_WORD(IRQ) ] = (1 << (IRQ & 0x1F));
+}
+
+/*  Disable External Interrupt
+  This function disables a device specific interupt in the NVIC interrupt controller.
+  The interrupt number cannot be a negative value.
+  IRQ : Number of the external interrupt to disable
+ */
+static inline void NVIC_DisableIRQ(uint32_t IRQ)
+{
+       struct nvic_regs* nvic = LPC_NVIC;
+       nvic->int_clear_enable[ LPC_IRQ_WORD(IRQ) ] = (1 << (IRQ & 0x1F));
+}
+
+/*  Get Pending Interrupt
+  This function reads the pending register in the NVIC and returns the pending bit
+    for the specified interrupt.
+  IRQ : Number of the interrupt for get pending
+  return :
+     0  Interrupt status is not pending
+     1  Interrupt status is pending
+ */
+static inline uint32_t NVIC_GetPendingIRQ(uint32_t IRQ)
+{
+       struct nvic_regs* nvic = LPC_NVIC;
+       return (uint32_t)((nvic->int_set_pending[LPC_IRQ_WORD(IRQ)] & (1 << (IRQ & 0x1F)))?1:0);
+}
+
+/*  Set Pending Interrupt
+  This function sets the pending bit for the specified interrupt.
+  The interrupt number cannot be a negative value.
+  IRQ : Number of the interrupt for set pending
+ */
+static inline void NVIC_SetPendingIRQ(uint32_t IRQ)
+{
+       struct nvic_regs* nvic = LPC_NVIC;
+       nvic->int_set_pending[ LPC_IRQ_WORD(IRQ) ] = (1 << (IRQ & 0x1F));
+}
+
+/*  Clear Pending Interrupt
+  This function clears the pending bit for the specified interrupt.
+  The interrupt number cannot be a negative value.
+  IRQ : Number of the interrupt for clear pending
+ */
+static inline void NVIC_ClearPendingIRQ(uint32_t IRQ)
+{
+       struct nvic_regs* nvic = LPC_NVIC;
+       nvic->int_clear_pending[ LPC_IRQ_WORD(IRQ) ] = (1 << (IRQ & 0x1F));
+}
+
+
+/* The following MACROS handle generation of the register offset and byte masks */
+#define LPC_NVIC_PRIO_BITS  5  /* Number of Bits used for Priority Levels */
+#define LPC_IRQ_BIT_SHIFT(IRQ) (((uint32_t)(IRQ) & 0x03) * 8)
+#define LPC_IRQ_SHP_IDX(IRQ)   ((((int32_t)(IRQ) + 16) >> 2) - 1)
+#define LPC_IRQ_IP_IDX(IRQ)    ((uint32_t)(IRQ) >> 2)
+
+/*  Set Interrupt Priority
+  This function sets the priority for the specified interrupt. The interrupt
+    number can be positive to specify an external (device specific)
+    interrupt, or negative to specify an internal (core) interrupt.
+  Note: The priority cannot be set for every core interrupt.
+  IRQ : Number of the interrupt for set priority
+  priority : Priority to set
+ */
+static inline void NVIC_SetPriority(uint32_t IRQ, uint32_t priority)
+{
+       if ((int32_t)IRQ < 0) {
+               if ((int32_t)IRQ > (-12)) {
+                       struct syst_ctrl_block_regs* scb = LPC_SCB;
+                       scb->shp[LPC_IRQ_SHP_IDX(IRQ)] = (scb->shp[LPC_IRQ_SHP_IDX(IRQ)] & ~(0xFF << LPC_IRQ_BIT_SHIFT(IRQ))) |
+                               (((priority << (8 - LPC_NVIC_PRIO_BITS)) & 0xFF) << LPC_IRQ_BIT_SHIFT(IRQ));
+               }
+       } else if (LPC_IRQ_IP_IDX(IRQ) < 8) {
+               struct nvic_regs* nvic = LPC_NVIC;
+               nvic->int_priority[LPC_IRQ_IP_IDX(IRQ)] = (nvic->int_priority[LPC_IRQ_IP_IDX(IRQ)] & ~(0xFF << LPC_IRQ_BIT_SHIFT(IRQ))) |
+                       (((priority << (8 - LPC_NVIC_PRIO_BITS)) & 0xFF) << LPC_IRQ_BIT_SHIFT(IRQ));
+       }
+}
+
+
+/*  Get Interrupt Priority
+  This function reads the priority for the specified interrupt. The interrupt
+    number can be positive to specify an external (device specific)
+    interrupt, or negative to specify an internal (core) interrupt.
+  The returned priority value is automatically aligned to the implemented
+    priority bits of the microcontroller.
+  IRQ : Number of the interrupt for get priority
+  return : Interrupt Priority
+ */
+static inline uint32_t NVIC_GetPriority(uint32_t IRQ)
+{
+       if ((int32_t)IRQ < 0) {
+               if ((int32_t)IRQ > (-12)) {
+                       struct syst_ctrl_block_regs* scb = LPC_SCB;
+                       /* Get priority for Cortex-M3 system interrupts */
+                       return ((uint32_t)((scb->shp[LPC_IRQ_SHP_IDX(IRQ)] >> LPC_IRQ_BIT_SHIFT(IRQ) ) >> (8 - LPC_NVIC_PRIO_BITS)));
+               }
+       } else if (LPC_IRQ_IP_IDX(IRQ) < 8) {
+               struct nvic_regs* nvic = LPC_NVIC;
+               /* Get priority for device specific interrupts */
+               return ((uint32_t)((nvic->int_priority[LPC_IRQ_IP_IDX(IRQ)] >> LPC_IRQ_BIT_SHIFT(IRQ) ) >> (8 - LPC_NVIC_PRIO_BITS)));
+       }
+}
+
+
+/*  System Reset
+  This function initiate a system reset request to reset the MCU.
+ */
+static inline void NVIC_SystemReset(void)
+{
+       struct syst_ctrl_block_regs* scb = LPC_SCB;
+       dsb(); /* Ensure all outstanding memory accesses included buffered write are completed before reset */
+       scb->aircr = ((0x5FA << SCB_AIRCR_VECTKEY_OFFSET) | SCB_AIRCR_SYS_RESET_REQ);
+       dsb();  /* Ensure completion of memory access */
+       while (1); /* wait until reset */
+}
+
+
+
+/*******************************************************************************/
+/*                Sync lock                                                    */
+/*******************************************************************************/
+/* Memory lock
+ * Test for nul in addr, if nul, store value
+ * Returns 0 on success
+ */
+/* Note : Use of 'it' instruction made mandatory by gcc 4.7 */
+static inline uint32_t sync_lock_test_and_set(volatile uint32_t *addr, uint32_t value)
+{
+       uint32_t result;
+
+       __asm volatile("@ sync_lock_test_and_set\n"
+       "ldrex %0, [%1]\n"
+       "cmp %0, #0\n"
+       "it eq\n"
+       "strexeq %0, %2, [%1]"
+       :"=&r" (result)
+       : "r" (addr), "r" (value)
+       : "cc", "memory" ); /* Condition flags changes, Memory changed */
+
+       return (result);
+}
+/* Remove the lock */
+static inline void sync_lock_release(volatile uint32_t *addr)
+{
+       *addr = 0;
+       dsb();
+}
+
+#endif /* LPC_CORE_CM3_H */
+
diff --git a/include/core/lpc_regs_17xx.h b/include/core/lpc_regs_17xx.h
new file mode 100644 (file)
index 0000000..2f07333
--- /dev/null
@@ -0,0 +1,1169 @@
+/****************************************************************************
+ *   core/lpc17xx_regs.h  (OK)
+ *
+ * Cortex-M3 Core Registers definitions
+ *
+ * Copyright 2012-2015 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+#ifndef CORE_LPC_REGS_H
+#define CORE_LPC_REGS_H
+
+#include <stdint.h>
+#include "lib/stddef.h"
+
+
+
+/***************************************************************************** */
+/*                          Memory Map                                         */
+/***************************************************************************** */
+/* Base addresses */
+#define LPC_FLASH_BASE        (0x00000000UL)
+#define LPC_RAM_BASE          (0x10000000UL)
+#define LPC_APB0_BASE         (0x40000000UL)
+#define LPC_APB1_BASE         (0x40080000UL)
+#define LPC_GPIO_BASE         (0x2009C000UL)
+#define LPC_AHB_BASE          (0x50000000UL)
+
+/* Memory mapping of Cortex-M3 Hardware */
+#define LPC_SCS_BASE        (0xE000E000UL)         /* System Control Space Base Address */
+#define LPC_ITM_BASE        (0xE0000000UL)         /* Instrumentation Trace Macrocell Base Address */
+#define LPC_COREDEBUG_BASE  (0xE000EDF0UL)         /* Core Debug Base Address */
+#define LPC_SYSTICK_BASE    (LPC_SCS_BASE + 0x0010UL)  /* SysTick Base Address */
+#define LPC_NVIC_BASE       (LPC_SCS_BASE + 0x0100UL)  /* NVIC Base Address */
+#define LPC_SCB_BASE        (LPC_SCS_BASE + 0x0D00UL)  /* System Control Block Base Address */
+#define LPC_MPU_BASE        (LPC_SCS_BASE + 0x0D90UL)  /* Memory Protection Unit Base Address */
+
+/* APB0 peripherals (32 blocks, blocks 5, 19-22 and 24-31 reserved) */
+#define LPC_WDT_BASE           (LPC_APB0_BASE + 0x00000)
+#define LPC_TIMER0_BASE        (LPC_APB0_BASE + 0x04000)
+#define LPC_TIMER1_BASE        (LPC_APB0_BASE + 0x08000)
+#define LPC_UART0_BASE         (LPC_APB0_BASE + 0x0C000)
+#define LPC_UART1_BASE         (LPC_APB0_BASE + 0x10000)
+#define LPC_PWM1_BASE          (LPC_APB0_BASE + 0x18000)
+#define LPC_I2C0_BASE          (LPC_APB0_BASE + 0x1C000)
+#define LPC_SPI_BASE           (LPC_APB0_BASE + 0x20000)
+#define LPC_RTC_BASE           (LPC_APB0_BASE + 0x24000) /* RTC and Backup */
+#define LPC_GPIO_INTR_BASE     (LPC_APB0_BASE + 0x28000)
+#define LPC_PIN_CONNECT_BASE   (LPC_APB0_BASE + 0x2C000)
+#define LPC_SSP1_BASE          (LPC_APB0_BASE + 0x30000)
+#define LPC_ADC_BASE           (LPC_APB0_BASE + 0x34000)
+#define LPC_CAN_AF_RAM_BASE    (LPC_APB0_BASE + 0x38000)
+#define LPC_CAN_AF_REGS_BASE   (LPC_APB0_BASE + 0x3C000)
+#define LPC_CAN_COMMONS_BASE   (LPC_APB0_BASE + 0x40000)
+#define LPC_CAN1_BASE          (LPC_APB0_BASE + 0x44000)
+#define LPC_CAN2_BASE          (LPC_APB0_BASE + 0x48000)
+#define LPC_I2C1_BASE          (LPC_APB0_BASE + 0x5C000)
+
+/* APB1 peripherals (32 blocks, blocks 0-1, 9, 13 and 16-30 reserved) */
+#define LPC_SSP0_BASE          (LPC_APB1_BASE + 0x08000)
+#define LPC_DAC_BASE           (LPC_APB1_BASE + 0x0C000)
+#define LPC_TIMER2_BASE        (LPC_APB1_BASE + 0x10000)
+#define LPC_TIMER3_BASE        (LPC_APB1_BASE + 0x14000)
+#define LPC_UART2_BASE         (LPC_APB1_BASE + 0x18000)
+#define LPC_UART3_BASE         (LPC_APB1_BASE + 0x1C000)
+#define LPC_I2C2_BASE          (LPC_APB1_BASE + 0x20000)
+#define LPC_I2S_BASE           (LPC_APB1_BASE + 0x28000)
+#define LPC_REP_INT_TIMER_BASE (LPC_APB1_BASE + 0x30000)
+#define LPC_MOTOR_PWM_BASE     (LPC_APB1_BASE + 0x38000)
+#define LPC_QEI_BASE           (LPC_APB1_BASE + 0x3C000)
+#define LPC_SYSCON_BASE        (LPC_APB1_BASE + 0x7C000)
+
+/* AHB peripherals */
+#define LPC_ETHERNET_BASE      (LPC_AHB_BASE + 0x00000)
+#define LPC_GPDMA_BASE         (LPC_AHB_BASE + 0x04000)
+#define LPC_USB_BASE           (LPC_AHB_BASE + 0x0C000)
+
+/* GPIO */
+#define LPC_GPIO_0_BASE   (LPC_GPIO_BASE  + 0x00)
+#define LPC_GPIO_1_BASE   (LPC_GPIO_BASE  + 0x20)
+#define LPC_GPIO_2_BASE   (LPC_GPIO_BASE  + 0x40)
+#define LPC_GPIO_3_BASE   (LPC_GPIO_BASE  + 0x60)
+#define LPC_GPIO_4_BASE   (LPC_GPIO_BASE  + 0x80)
+
+
+
+/***************************************************************************** */
+/* System control, System Clocking and Power Control */
+struct lpc_sys_control
+{
+       uint32_t reserved_0[32];
+       /* PLL0 (Main PLL) */
+       volatile uint32_t pll0_control;      /* 0x0080 - PLL0CON - PLL0 Control Register (R/W) */
+       volatile uint32_t pll0_config;       /* 0x0084 - PLL0CFG - PLL0 Configuration Register (R/W) */
+       volatile uint32_t pll0_status;       /* 0x0088 - PLL0STAT - PLL0 Status Register (R/ ) */
+       volatile uint32_t pll0_feed;         /* 0x008C - PLL0FEED - PLL0 Feed Register ( /W) */
+       uint32_t reserved_1[4];
+       /* PLL1 (Main PLL) */
+       volatile uint32_t pll1_control;      /* 0x00A0 - PLL1CON - PLL1 Control Register (R/W) */
+       volatile uint32_t pll1_config;       /* 0x00A4 - PLL1CFG - PLL1 Configuration Register (R/W) */
+       volatile uint32_t pll1_status;       /* 0x00A8 - PLL1STAT - PLL1 Status Register (R/ ) */
+       volatile uint32_t pll1_feed;         /* 0x00AC - PLL1FEED - PLL1 Feed Register ( /W) */
+       uint32_t reserved_2[4];
+       /* Power control */
+       volatile uint32_t power_mode_ctrl;        /* 0x00C0 - PCON - Power Mode Control Register (R/W) */
+       volatile uint32_t periph_power_ctrl; /* 0x00C4 - PCONP - Power Control for Peripherals Register (R/W) */
+       uint32_t reserved_3[15];
+       /* Clock dividers */
+       volatile uint32_t cpu_clk_cfg;       /* 0x0104 - CCLKCFG - CPU Clock Configuration Register (R/W) */
+       volatile uint32_t usb_clk_cfg;       /* 0x0108 - USBCLKCFG - USB Clock Configuration Register (R/W) */
+       /* System Clock source selection (PLL0 clock input selection) */
+       volatile uint32_t sys_clk_src_sel;  /* 0x010C - CLKSRCSEL - System clock source select (R/W) */
+       uint32_t reserved_4[12];
+       volatile uint32_t ext_int_flag;     /* 0x0140 - EXTINT - External Interrupt Flag (R/W) */
+       uint32_t reserved_5[1];
+       volatile uint32_t ext_int_mode;     /* 0x0148 - EXTMODE - External Interrupt Mode (R/W) */
+       volatile uint32_t ext_int_polarity; /* 0x014C - EXTPOLAR - External Interrupt Polarity (R/W) */
+       uint32_t reserved_6[12];
+       volatile uint32_t reset_src_identification; /* 0x0180 - RSID - Reset Source Identification (R/W) */
+       uint32_t reserved_7[7];
+       volatile uint32_t sys_osc_ctrl_and_status; /* 0x01A0 - SCS - System Control and Status (R/W) */
+       uint32_t reserved_8[1];
+       /* Peripheral Clock Dividers */
+       volatile uint32_t pclk_sel[2];        /* 0x01A8 - 0x01AC - PCLKSEL0/1 - Peripheral Clock Selection register 0/1 (R/W) */
+       uint32_t reserved_9[6];
+       /* Utility */
+       volatile uint32_t clkout_cfg;        /* 0x01C8 - CLKOUTCFG - Clock Output Configuration Register (R/W) */
+};
+#define LPC_SYS_CONTROL     ((struct lpc_sys_control *) LPC_SYSCON_BASE)
+
+/* System clock source select */
+#define LPC_CLK_PLL0_SRC_IRC   (0x00)
+#define LPC_CLK_PLL0_SRC_XTAL  (0x01)
+#define LPC_CLK_PLL0_SRC_RTC_XTAL (0x02)
+
+/* PLL Control */
+#define LPC_PLL_CTRL_PLL_ENABLE  (0x01)
+#define LPC_PLL_CTRL_PLL_CONNECT (0x02)
+
+/*
+#define USB_DEV_CLK_EN  (1ul << 1)
+#define USB_AHB_CLK_EN  (1ul << 4)
+#define USB_CLK_ON (USB_DEV_CLK_EN | USB_AHB_CLK_EN)
+*/
+
+/* External interrupts bits */
+#define LPC_EXT_INT(x)     (0x01 << ((x) & 0x03))
+#define LPC_EXT_INT_LEVEL(x)   0x00
+#define LPC_EXT_INT_EDGE(x)    LPC_EXT_INT(x)
+#define LPC_EXT_INT_LOW(x)     0x00
+#define LPC_EXT_INT_HIGH(x)    LPC_EXT_INT(x)
+#define LPC_EXT_INT_FALLING(x) 0x00
+#define LPC_EXT_INT_RISING(x)  LPC_EXT_INT(x)
+
+/* Reset Source Identification register bits */
+#define LPC_RESET_SRC_POR       (0x01 << 0)
+#define LPC_RESET_SRC_EXTR      (0x01 << 1)
+#define LPC_RESET_SRC_WATCHDOG  (0x01 << 2)
+#define LPC_RESET_SRC_BODR      (0x01 << 3)
+
+/* System Oscilator Control */
+#define LPC_SYS_CTRL_OSC_RANGE_UNDER_20MHZ  0x00
+#define LPC_SYS_CTRL_OSC_RANGE_ABOVE_15MHZ  (0x01 << 4)
+#define LPC_SYS_CTRL_OSC_EN     (0x01 << 5)
+#define LPC_SYS_CTRL_OSC_STAT   (0x01 << 6) /* Read only bit */
+
+/* Power Mode Control */
+/* Sleep Entry */
+#define LPC_SLEEP_ENTRY            (0x00 << 0)
+#define LPC_POWER_DOWN_ENTRY       (0x01 << 0)
+#define LPC_DEEP_POWER_DOWN_ENTRY  (0x03 << 0)
+/* Brown Out detection Disable bits */
+#define LPC_BOD_DISABLE_IN_SLEEP   (0x01 << 2)
+#define LPC_BOD_GLOBAL_DISABLE     (0x01 << 3)
+#define LPC_BOD_RESET_DISABLE      (0x01 << 4)
+#define LPC_BOD_FULL_DISABLE       (0x07 << 2)
+/* Flags */
+#define LPC_SLEEP_ENTRY_FLAG            (0x01 << 8)  /* SMFLAG */
+#define LPC_DEEP_SLEEP_ENTRY_FLAG       (0x01 << 9)  /* DSFLAG */
+#define LPC_POWER_DOWN_ENTRY_FLAG       (0x01 << 10) /* PDFLAG */
+#define LPC_DEEP_POWER_DOWN_ENTRY_FLAG  (0x01 << 11) /* DPDFLAG */
+#define LPC_CLEAR_ALL_SLEEP_FLAGS       (0x0F << 8)
+
+/* Peripheral clock control defines : pclk_sel_0 and pclk_sel_1 - PCLKSEL0 and PCLKSEL1 */
+#define LPC_PCLK_CCLK          0x01
+#define LPC_PCLK_CCLK_HALF     0x02
+#define LPC_PCLK_CCLK_QUARTER  0x00 /* Default value */
+#define LPC_PCLK_CCLK_EIGHTH   0x03
+/* PCLKSEL0 */
+#define LPC_WDT_PCLK        ( 0 | (0 << 7))
+#define LPC_TIMER0_PCLK     ( 2 | (0 << 7))
+#define LPC_TIMER1_PCLK     ( 4 | (0 << 7))
+#define LPC_UART0_PCLK      ( 6 | (0 << 7))
+#define LPC_UART1_PCLK      ( 8 | (0 << 7))
+#define LPC_PWM1_PCLK       (12 | (0 << 7))
+#define LPC_I2C0_PCLK       (14 | (0 << 7))
+#define LPC_SPI_PCLK        (16 | (0 << 7))
+#define LPC_SSP1_PCLK       (20 | (0 << 7))
+#define LPC_DAC_PCLK        (22 | (0 << 7))
+#define LPC_ADC_PCLK        (24 | (0 << 7))
+#define LPC_CAN1_PCLK       (26 | (0 << 7))
+#define LPC_CAN2_PCLK       (28 | (0 << 7))
+#define LPC_CAN_ACF_PCLK    (30 | (0 << 7))
+/* PCLKSEL1 */
+#define LPC_QUADRAT_PCLK    ( 1 | (1 << 7))
+#define LPC_GPIO_INT_PCLK   ( 2 | (1 << 7))
+#define LPC_GPIO_CONN_PCLK  ( 4 | (1 << 7))
+#define LPC_I2C1_PCLK       ( 6 | (1 << 7))
+#define LPC_SSP0_PCLK       (10 | (1 << 7))
+#define LPC_TIMER2_PCLK     (12 | (1 << 7))
+#define LPC_TIMER3_PCLK     (14 | (1 << 7))
+#define LPC_UART2_PCLK      (16 | (1 << 7))
+#define LPC_UART3_PCLK      (18 | (1 << 7))
+#define LPC_I2C2_PCLK       (21 | (1 << 7))
+#define LPC_I2S_PCLK        (22 | (1 << 7))
+#define LPC_RIT_PCLK        (26 | (1 << 7))
+#define LPC_SYS_CON_PCLK    (28 | (1 << 7))
+#define LPC_MOTOR_PWM_PCLK  (31 | (1 << 7))
+
+/* Peripheral power control defines : periph_power_ctrl - PCONP */
+#define LPC_TIMER0_POWER_ON    (1 <<  1)
+#define LPC_TIMER1_POWER_ON    (1 <<  2)
+#define LPC_UART0_POWER_ON     (1 <<  3)
+#define LPC_UART1_POWER_ON     (1 <<  4)
+#define LPC_PWM1_POWER_ON      (1 <<  6)
+#define LPC_I2C0_POWER_ON      (1 <<  7)
+#define LPC_SPI_POWER_ON       (1 <<  8)
+#define LPC_RTC_POWER_ON       (1 <<  9)
+#define LPC_SSP1_POWER_ON      (1 << 10)
+#define LPC_ADC_POWER_ON       (1 << 12)
+#define LPC_CAN1_POWER_ON      (1 << 13)
+#define LPC_CAN2_POWER_ON      (1 << 14)
+#define LPC_GPIO_POWER_ON      (1 << 15)
+#define LPC_RIT_POWER_ON       (1 << 16)
+#define LPC_MOTOR_PWM_POWER_ON (1 << 17)
+#define LPC_QUADRAT_POWER_ON   (1 << 18)
+#define LPC_I2C1_POWER_ON      (1 << 19)
+#define LPC_SSP0_POWER_ON      (1 << 21)
+#define LPC_TIMER2_POWER_ON    (1 << 22)
+#define LPC_TIMER3_POWER_ON    (1 << 23)
+#define LPC_UART2_POWER_ON     (1 << 24)
+#define LPC_UART3_POWER_ON     (1 << 25)
+#define LPC_I2C2_POWER_ON      (1 << 26)
+#define LPC_I2S_POWER_ON       (1 << 27)
+#define LPC_GPDMA_POWER_ON     (1 << 29)
+#define LPC_ETHERNET_POWER_ON  (1 << 30)
+#define LPC_USB_POWER_ON       (1 << 31)
+
+/* CLK Out Configuration */
+/* Source selection */
+#define LPC_CLKOUT_SRC_CPU        (0x00)
+#define LPC_CLKOUT_SRC_MAIN_OSC   (0x01)
+#define LPC_CLKOUT_SRC_IRC        (0x02)
+#define LPC_CLKOUT_SRC_USB_CLK    (0x03)
+#define LPC_CLKOUT_SRC_RTC_CLK    (0x04)
+#define LPC_CLKOUT_SRC_MAX        (0x04)
+/* Divider */
+#define LPC_CLKOUT_DIV(x)   (((x) & 0x0F) << 4)
+/* Control */
+#define LPC_CLKOUT_ENABLE         (0x01 << 8)
+#define LPC_CLKOUT_ACT_INDICATOR  (0x01 << 9)
+
+/***************************************************************************** */
+/*                  Flash Control                                              */
+/***************************************************************************** */
+/* Flash configuration */
+struct lpc_flash_control
+{
+       volatile uint32_t flash_cfg;  /* 0x0000 - FLASHCFG Flash Accelerator Configuration Register (R/W) */
+};
+#define LPC_FLASH_CFG_SHIFT  12
+#define LPC_FLASH_CFG_MASK   (0x07 << LPC_FLASH_CFG_SHIFT)
+#define LPC_FLASH_CYCLES(speed)  (((speed / (20*1000*1000)) & 0x07) << LPC_FLASH_CFG_SHIFT)
+
+#define LPC_FLASH_CONTROL     ((struct lpc_flash_control *) LPC_SYSCON_BASE)
+
+
+/***************************************************************************** */
+/*                 Cortex-M3 NVIC (Nested Vector Interupt Controler)           */
+/***************************************************************************** */
+/* Cortex-M3 NVIC Registers - 0xE000E100 */
+struct nvic_regs {
+       volatile uint32_t int_set_enable[2];    /* 0x000 - ISER[0..1] - Interrupt Set Enable Registers (R/W) */
+       uint32_t reserved_0[30];
+       volatile uint32_t int_clear_enable[2];  /* 0x080 - ICER[0..1] - Interrupt Clear Enable Registers (R/W) */
+       uint32_t reserved_1[30];
+       volatile uint32_t int_set_pending[2];   /* 0x100 - ISPR[0..1] - Interrupt Set Pending Registers (R/W) */
+       uint32_t reserved_2[30];
+       volatile uint32_t int_clear_pending[2]; /* 0x180 - ICPR[0..1] - Interrupt Clear Pending Registers (R/W) */
+       uint32_t reserved_3[30];
+       volatile uint32_t int_active_bit[2];    /* 0x200 - IABR[0..1] - Interrupt Active Bit Registers (R/ ) */
+       uint32_t reserved_4[62];
+       volatile uint32_t int_priority[9];      /* 0x300 - IPR[0..8] - Interrupt Priority Registers (R/W) */
+       uint32_t reserved_5[695];
+       volatile uint32_t software_trigger;     /* 0xE00 - STIR - Software Trigger Interrupt Register ( /W) */
+};
+#define LPC_NVIC      ((struct nvic_regs *) LPC_NVIC_BASE)        /* NVIC configuration struct */
+
+
+/***************************************************************************** */
+/*                   Cortex-M3 SCB (System Control Block)                      */
+/***************************************************************************** */
+/* Cortex-M3 System Control Block Registers */
+struct syst_ctrl_block_regs {
+       volatile const uint32_t cpuid; /* 0x000 : CPU ID Base Register (R/ ) */
+       volatile uint32_t icsr;    /* 0x004 : Interrupt Control State Register (R/W) */
+       volatile uint32_t vtor;    /* 0x008 : Vector Table Base Offset */
+       volatile uint32_t aircr;   /* 0x00C : Application Interrupt / Reset Control Register (R/W) */
+       volatile uint32_t scr;     /* 0x010 : System Control Register (R/W) */
+       volatile uint32_t ccr;     /* 0x014 : Configuration Control Register (R/W) */
+       volatile uint32_t shp[3];  /* 0x018 - 0x020 : System Handlers Priority Registers (R/W) */
+       volatile uint32_t shcrs;   /* 0x024 : */
+       volatile uint32_t cfsr;    /* 0x028 : */
+       volatile uint32_t hfsr;    /* 0x02C : */
+       uint32_t reserved_0[1];
+       volatile uint32_t mmfar;   /* 0x034 : */
+       volatile uint32_t bfar;    /* 0x038 : */
+};
+#define LPC_SCB       ((struct syst_ctrl_block_regs *) LPC_SCB_BASE) /* SCB configuration struct */
+
+/* SCB CPUID Register Definitions */
+#define SCB_CPUID_IMPLEMENTER      (0xFFUL << 24)     /* SCB CPUID: IMPLEMENTER Mask */
+#define SCB_CPUID_VARIANT          (0xFUL << 20)      /* SCB CPUID: VARIANT Mask */
+#define SCB_CPUID_ARCHITECTURE     (0xFUL << 16)      /* SCB CPUID: ARCHITECTURE Mask */
+#define SCB_CPUID_PARTNO           (0xFFFUL << 4)     /* SCB CPUID: PARTNO Mask */
+#define SCB_CPUID_REVISION         (0xFUL << 0)       /* SCB CPUID: REVISION Mask */
+
+/* SCB Interrupt Control State Register Definitions */
+#define SCB_ICSR_NMIPENDSET        (1UL << 31)        /* SCB ICSR: NMIPENDSET Mask */
+#define SCB_ICSR_PENDSVSET         (1UL << 28)        /* SCB ICSR: PENDSVSET Mask */
+#define SCB_ICSR_PENDSVCLR         (1UL << 27)        /* SCB ICSR: PENDSVCLR Mask */
+#define SCB_ICSR_PENDSTSET         (1UL << 26)        /* SCB ICSR: PENDSTSET Mask */
+#define SCB_ICSR_PENDSTCLR         (1UL << 25)        /* SCB ICSR: PENDSTCLR Mask */
+#define SCB_ICSR_ISRPREEMPT        (1UL << 23)        /* SCB ICSR: ISRPREEMPT Mask */
+#define SCB_ICSR_ISRPENDING        (1UL << 22)        /* SCB ICSR: ISRPENDING Mask */
+#define SCB_ICSR_VECTPENDING       (0x1FFUL << 12)    /* SCB ICSR: VECTPENDING Mask */
+#define SCB_ICSR_VECTACTIVE        (0x1FFUL << 0)     /* SCB ICSR: VECTACTIVE Mask */
+
+/* SCB Application Interrupt and Reset Control Register Definitions */
+#define SCB_AIRCR_VECTKEY_OFFSET   16
+#define SCB_AIRCR_VECTKEY          (0xFFFFUL << 16)   /* SCB AIRCR: VECTKEY Mask */
+#define SCB_AIRCR_VECTKEYSTAT      (0xFFFFUL << 16)   /* SCB AIRCR: VECTKEYSTAT Mask */
+#define SCB_AIRCR_ENDIANESS        (1UL << 15)        /* SCB AIRCR: ENDIANESS Mask */
+#define SCB_AIRCR_SYS_RESET_REQ    (1UL << 2)         /* SCB AIRCR: SYSRESETREQ Mask */
+#define SCB_AIRCR_VECT_CLR_ACTIVE    (1UL << 1)         /* SCB AIRCR: VECTCLRACTIVE Mask */
+
+/* SCB System Control Register Definitions */
+#define SCB_SCR_SEVONPEND          (1UL << 4)         /* SCB SCR: SEVONPEND Mask */
+#define SCB_SCR_SLEEPDEEP          (1UL << 2)         /* SCB SCR: SLEEPDEEP Mask */
+#define SCB_SCR_SLEEPONEXIT        (1UL << 1)         /* SCB SCR: SLEEPONEXIT Mask */
+
+/* SCB Configuration Control Register Definitions */
+#define SCB_CCR_STKALIGN           (1UL << 9)         /* SCB CCR: STKALIGN Mask */
+#define SCB_CCR_UNALIGN_TRP        (1UL << 3)         /* SCB CCR: UNALIGN_TRP Mask */
+
+
+
+/***************************************************************************** */
+/*                   Cortex-M3 SysTick (System Timer)                          */
+/***************************************************************************** */
+/* Cortex-M3 System Timer Registers */
+struct lpc_system_tick {
+       volatile uint32_t control;     /* 0x000 : SysTick Control and Status Register (R/W) */
+       volatile uint32_t reload_val;  /* 0x004 : SysTick Reload Value Register (R/W) */
+       volatile uint32_t value;       /* 0x008 : SysTick Current Value Register (R/W) */
+       volatile const uint32_t calibration;  /* 0x00C : SysTick Calibration Register (R/ ) */
+};
+#define LPC_SYSTICK  ((struct lpc_system_tick*) LPC_SYSTICK_BASE) /* SysTick configuration struct */
+
+/* SysTick Control / Status Register Definitions */
+#define LPC_SYSTICK_CTRL_COUNTFLAG  (1UL << 16)   /* SysTick CTRL: COUNTFLAG Mask */
+#define LPC_SYSTICK_CTRL_CLKSOURCE  (1UL << 2)    /* SysTick CTRL: CLKSOURCE Mask */
+#define LPC_SYSTICK_CTRL_TICKINT    (1UL << 1)    /* SysTick CTRL: TICKINT Mask */
+#define LPC_SYSTICK_CTRL_ENABLE     (1UL << 0)    /* SysTick CTRL: ENABLE Mask */
+
+/* SysTick Reload Register Definitions */
+#define LPC_SYSTICK_LOAD_RELOAD     (0xFFFFFFUL)  /* SysTick LOAD: RELOAD Mask */
+
+/* SysTick Current Register Definitions */
+#define LPC_SYSTICK_VAL_CURRENT     (0xFFFFFFUL)  /* SysTick VAL: CURRENT Mask */
+
+/* SysTick Calibration Register Definitions */
+#define LPC_SYSTICK_CALIB_NOREF     (1UL << 31)   /* SysTick CALIB: NOREF Mask */
+#define LPC_SYSTICK_CALIB_SKEW      (1UL << 30)   /* SysTick CALIB: SKEW Mask */
+#define LPC_SYSTICK_CALIB_TENMS     (0xFFFFFFUL)  /* SysTick CALIB: TENMS Mask */
+
+
+
+/***************************************************************************** */
+/*                    Cortex-M3 RTC (Real-Time Clock)                          */
+/***************************************************************************** */
+/* Cortex-M3 RTC Registers */
+struct time {
+       volatile uint32_t seconds;
+       volatile uint32_t minutes;
+       volatile uint32_t hours;
+       volatile uint32_t day_of_month;
+       volatile uint32_t day_of_week;
+       volatile uint32_t day_of_year;
+       volatile uint32_t month;
+       volatile uint32_t year;
+};
+struct lpc_rtc {
+       /* Misc */
+       volatile uint32_t interrupt_location;    /* 0x000 : Interrupt Location register (R/W) */
+       uint32_t reserved_0[1];
+       volatile uint32_t clk_ctrl;              /* 0x008 : Clock Control register (R/W) */
+       volatile uint32_t cntr_inc_intr;         /* 0x00C : Counter Increment Interrupt register (R/W) */
+       volatile uint32_t alarm_mask;            /* 0x010 : Alarm Mask register (R/W) */
+       volatile uint32_t consolidated_time[3];  /* 0x014 - 0x01C : Consolidated Time registers (R/-) */
+       /* Time counter regs */
+       struct time current_time;                /* 0x020 - 0x03C : Current time (R/W) */
+       volatile uint32_t calibration;           /* 0x040 : Calibration Value register (R/W) */
+       /* General purpose regs */
+       volatile uint32_t gp_data[5];            /* 0x044 - 0x054 : General purpose registers (R/W) */
+       /* Auxiliary */
+       volatile uint32_t rtc_aux_en;            /* 0x058 : RTC Auxiliary Enable register (R/W) */
+       volatile uint32_t rtc_aux_ctrl;          /* 0x05C : RTC Auxiliary Control register (R/W) */
+       /* Alarm */
+       struct time alarm;                       /* 0x060 - 0x07C : Alarm registers (R/W) */
+};
+#define LPC_RTC  ((struct lpc_rtc*) LPC_RTC_BASE) /* SysTick configuration struct */
+
+/* FIXME : define RTC bits */
+
+
+
+/***************************************************************************** */
+/*                Pin Connect Block                                            */
+/***************************************************************************** */
+/* Pin Connect Block */
+struct lpc_pin_func_control
+{
+       volatile uint32_t func_sel[10];  /* 0x000 - 0x024 : PINSEL[0..9] : Pin function select registers 0..9 */
+       volatile uint32_t trace_en;      /* 0x028 : PINSEL10 : Pin function select register 10 : force trace on */
+       uint32_t reserved_0[5];
+       volatile uint32_t mode_sel[10];  /* 0x040 - 0x064 : PINMODE[0..9] : Pin mode select registers 0..9 */
+       volatile uint32_t opendrain_ctrl[5]; /* 0x068 - 0x078 : PINMODE_OD[0..4] : Pin open-drain mode select registers 0..4 */
+       volatile uint32_t i2c_config;    /* 0x07C : I2CPADCFG : I2C_0 Pin configuration */
+};
+
+#define LPC_PIN_FUNCTION_CONTROL  ((struct lpc_pin_func_control *) LPC_PIN_CONNECT_BASE)
+
+#define LPC_IO_FUNC_PRIMARY (0x00)
+#define LPC_IO_FUNC_GPIO (0x00)
+#define LPC_IO_FUNC_ALT1 (0x01)
+#define LPC_IO_FUNC_ALT2 (0x02)
+#define LPC_IO_FUNC_ALT3 (0x03)
+
+#define LPC_TRACE_ACTIVATE (0x01 << 3)
+
+#define LPC_IO_MODE_PULL_UP     (0x00)
+#define LPC_IO_MODE_REPEATER    (0x01)
+#define LPC_IO_MODE_NO_PULL     (0x02)
+#define LPC_IO_MODE_PULL_DOWN   (0x03)
+#define LPC_IO_MODE_OPEN_DRAIN  (0x04)
+
+#define LPC_IO_STD        (0x0)
+#define LPC_IO_OPEN_DRAIN (0x1)
+
+/* Pin registers selection helpers */
+#define LPC_IO_PIN_REG(port, pin)  ((port << 1) | ((pin & 0x10) >> 4))
+#define LPC_IO_PIN_OFFSET(pin)     ((pin & 0x0F) << 1)
+
+/* I2C function config */
+#define LPC_I2C_PIO_FAST_MODE_PLUS    ((0x01 << 0) | (0x01 << 2))
+#define LPC_I2C_PIO_FILTERING_DISABLE ((0x01 << 1) | (0x01 << 3))
+
+
+
+/***************************************************************************** */
+/*                GPIO Control                                                 */
+/***************************************************************************** */
+/* Fast masked GPIO access */
+struct lpc_gpio_port_control
+{
+       volatile uint32_t data_dir;  /* 0x00 : FIODIR : Fast GPIO Port Direction control register */
+       uint32_t reserved_0[3];
+       volatile uint32_t mask; /* 0x10 : FIOMASK : Fast Mask register for port */
+       volatile uint32_t value;  /* 0x14 : FIOPIN : Fast Port Pin value register using FIOMASK */
+       volatile uint32_t set;  /* 0x18 : FIOSET : Fast Port Output Set register using FIOMASK */
+       volatile uint32_t clear;  /* 0x1C : FIOCLR : Fast Port Output Clear register using FIOMASK */
+};
+#define LPC_GPIO_0  ((struct lpc_gpio_port_control *) LPC_GPIO_0_BASE)
+#define LPC_GPIO_1  ((struct lpc_gpio_port_control *) LPC_GPIO_1_BASE)
+#define LPC_GPIO_2  ((struct lpc_gpio_port_control *) LPC_GPIO_2_BASE)
+#define LPC_GPIO_3  ((struct lpc_gpio_port_control *) LPC_GPIO_3_BASE)
+#define LPC_GPIO_4  ((struct lpc_gpio_port_control *) LPC_GPIO_4_BASE)
+
+struct lpc_gpio_ports
+{
+       struct lpc_gpio_port_control p[5];
+}__attribute__ ((packed));
+#define LPC_GPIO_PORTS ((struct lpc_gpio_ports *) LPC_GPIO_BASE)
+
+/* Support for byte access to fio registers */
+struct lpc_gpio_port_byte_control
+{
+       volatile uint8_t data_dir[4];  /* 0x00 : FIODIR : Fast GPIO Port Direction control register */
+       uint32_t reserved_0[3];
+       volatile uint8_t mask[4]; /* 0x10 : FIOMASK : Fast Mask register for port */
+       volatile uint8_t value[4];  /* 0x14 : FIOPIN : Fast Port Pin value register using FIOMASK */
+       volatile uint8_t set[4];  /* 0x18 : FIOSET : Fast Port Output Set register using FIOMASK */
+       volatile uint8_t clear[4];  /* 0x1C : FIOCLR : Fast Port Output Clear register using FIOMASK */
+};
+#define LPC_GPIO_BYTE_0  ((struct lpc_gpio_port_byte_control *) LPC_GPIO_0_BASE)
+#define LPC_GPIO_BYTE_1  ((struct lpc_gpio_port_byte_control *) LPC_GPIO_1_BASE)
+#define LPC_GPIO_BYTE_2  ((struct lpc_gpio_port_byte_control *) LPC_GPIO_2_BASE)
+#define LPC_GPIO_BYTE_3  ((struct lpc_gpio_port_byte_control *) LPC_GPIO_3_BASE)
+#define LPC_GPIO_BYTE_4  ((struct lpc_gpio_port_byte_control *) LPC_GPIO_4_BASE)
+
+struct lpc_gpio_byte_ports
+{
+       struct lpc_gpio_port_byte_control p[5];
+}__attribute__ ((packed));
+#define LPC_GPIO_BYTE_PORTS ((struct lpc_gpio_byte_ports *) LPC_GPIO_BASE)
+
+/* Support for byte and half-word access to fio registers */
+struct lpc_gpio_port_halfword_control
+{
+       volatile uint16_t data_dir[2];  /* 0x00 : FIODIR : Fast GPIO Port Direction control register */
+       uint32_t reserved_0[3];
+       volatile uint16_t mask[2]; /* 0x10 : FIOMASK : Fast Mask register for port */
+       volatile uint16_t value[2];  /* 0x14 : FIOPIN : Fast Port Pin value register using FIOMASK */
+       volatile uint16_t set[2];  /* 0x18 : FIOSET : Fast Port Output Set register using FIOMASK */
+       volatile uint16_t clear[2];  /* 0x1C : FIOCLR : Fast Port Output Clear register using FIOMASK */
+};
+#define LPC_GPIO_HALFWORD_0  ((struct lpc_gpio_port_halfword_control *) LPC_GPIO_0_BASE)
+#define LPC_GPIO_HALFWORD_1  ((struct lpc_gpio_port_halfword_control *) LPC_GPIO_1_BASE)
+#define LPC_GPIO_HALFWORD_2  ((struct lpc_gpio_port_halfword_control *) LPC_GPIO_2_BASE)
+#define LPC_GPIO_HALFWORD_3  ((struct lpc_gpio_port_halfword_control *) LPC_GPIO_3_BASE)
+#define LPC_GPIO_HALFWORD_4  ((struct lpc_gpio_port_halfword_control *) LPC_GPIO_4_BASE)
+
+struct lpc_gpio_halfword_ports
+{
+       struct lpc_gpio_port_halfword_control p[5];
+}__attribute__ ((packed));
+#define LPC_GPIO_HALFWORD_PORTS ((struct lpc_gpio_halfword_ports *) LPC_GPIO_BASE)
+
+
+#define LPC_GPIO_INPUT   0x00
+#define GPIO_DIR_IN  0x00
+#define LPC_GPIO_OUTPUT  0x01
+#define GPIO_DIR_OUT 0x01
+
+
+/* Interrupts */
+struct lpc_gpio_port_int
+{
+       volatile uint32_t rising_status;
+       volatile uint32_t falling_status;
+       volatile uint32_t clear;
+       volatile uint32_t rising_enable;
+       volatile uint32_t falling_enable;
+       uint32_t pad[3];
+}__attribute__ ((packed));
+struct lpc_gpio_interrupts
+{
+       uint32_t reserved_0[32];
+       volatile uint32_t overall_int_status; /* 0x080 : IOIntStatus : GPIO Overall Interrupt Status register (R/?) */
+       struct lpc_gpio_port_int port0; /* 0x084 - 0x0A0 */
+       struct lpc_gpio_port_int port2; /* 0x0A4 - 0x0C0 */
+}__attribute__ ((packed));
+#define LPC_GPIO_INTERRUPTS ((struct lpc_gpio_interrupts *) LPC_GPIO_INTR_BASE)
+
+#define LPC_GPIO_INT_PORT0_PENDING  (0x01 << 0)
+#define LPC_GPIO_INT_PORT2_PENDING  (0x01 << 2)
+
+
+/***************************************************************************** */
+/*               Universal Asynchronous Receiver Transmitter (UART)            */
+/***************************************************************************** */
+/* UART
+ * Note : For LPC1764 IrDA is only available on UART 0/2/3 and RS485 is only
+ *  available on UART 1
+ * Note : lpc_uart_ctrl is selected and accessible when Divisor Latch Access Bit (DLAB) is
+ *  set (bit 7 in UART Line Control Register (line_ctrl - LCR))
+ */
+struct lpc_uart_func {
+       volatile uint32_t buffer; /* 0x000 : Transmit / Receiver Buffer Register (R/W) */
+       volatile uint32_t intr_enable; /* 0x004 : Interrupt Enable Register (R/W) */
+       volatile uint32_t intr_pending; /* 0x008 : Interrupt ID Register (R/-) */
+};
+struct lpc_uart_ctrl {
+       volatile uint32_t divisor_latch_lsb;  /* 0x000 : Divisor Latch LSB (R/W) */
+       volatile uint32_t divisor_latch_msb;  /* 0x004 : Divisor Latch MSB (R/W) */
+       volatile uint32_t fifo_ctrl;  /* 0x008 : Fifo Control Register (-/W) */
+};
+struct lpc_uart
+{
+       union {
+               struct lpc_uart_func func;
+               struct lpc_uart_ctrl ctrl;
+       };
+       volatile uint32_t line_ctrl;   /* 0x00C : Line Control Register (R/W) */
+       volatile uint32_t modem_ctrl;  /* 0x010 : Modem Control Register (R/W) */
+       volatile const uint32_t line_status;   /* 0x014 : Line Status Register (R/ ) */
+       volatile const uint32_t modem_status;  /* 0x018 : Modem Status Register (R/ ) */
+       volatile uint32_t scratch_pad;  /* 0x01C : Scratch Pad Register (R/W) */
+       volatile uint32_t auto_baud_ctrl;  /* 0x020 : Auto-baud Control Register (R/W) */
+       volatile uint32_t irda_ctrl;       /* 0x024 : UART IrDA Control Register (R/W) */
+       volatile uint32_t fractional_div;  /* 0x028 : Fractional Divider Register (R/W) */
+       uint32_t reserved_0;
+       volatile uint32_t transmit_enable;  /* 0x030 : Transmit Enable Register (R/W) */
+       uint32_t reserved_1[6];
+       volatile uint32_t RS485_ctrl;       /* 0x04C : RS-485/EIA-485 Control Register (R/W) */
+       volatile uint32_t RS485_addr_match; /* 0x050 : RS-485/EIA-485 address match Register (R/W) */
+       volatile uint32_t RS485_dir_ctrl_delay;  /* 0x054 : RS-485/EIA-485 direction control delay Register (R/W) */
+       volatile uint32_t fifo_level;  /* 0x058 : Fifo Level Register (R/-) */
+};
+#define LPC_UART_0        ((struct lpc_uart *) LPC_UART0_BASE)
+#define LPC_UART_1        ((struct lpc_uart *) LPC_UART1_BASE)
+#define LPC_UART_2        ((struct lpc_uart *) LPC_UART2_BASE)
+#define LPC_UART_3        ((struct lpc_uart *) LPC_UART3_BASE)
+
+/* Line Control Register */
+#define LPC_UART_5BIT          (0x00 << 0)
+#define LPC_UART_6BIT          (0x01 << 0)
+#define LPC_UART_7BIT          (0x02 << 0)
+#define LPC_UART_8BIT          (0x03 << 0)
+#define LPC_UART_1STOP         (0x00 << 2)
+#define LPC_UART_2STOP         (0x01 << 2)
+#define LPC_UART_NO_PAR        (0x00 << 3)
+#define LPC_UART_ODD_PAR      ((0x01 << 3) | (0x00 << 4))
+#define LPC_UART_EVEN_PAR      ((0x01 << 3) | (0x01 << 4))
+#define LPC_UART_ENABLE_DLAB   (0x01 << 7)
+/* FIFO Control Register */
+#define LPC_UART_FIFO_EN       (0x01 << 0)
+#define LPC_UART_RX_CLR        (0x01 << 1)
+#define LPC_UART_TX_CLR        (0x01 << 2)
+#define LPC_UART_DMA_MODE_EN   (0x01 << 3)
+#define LPC_UART_FIFO_TRIG(x)  ((x & 0x03) << 6) /* 1 / 4 / 8 / 14 chars */
+/* Interrupt Enable Register */
+#define LPC_UART_RX_INT_EN     (0x01 << 0)
+#define LPC_UART_TX_INT_EN     (0x01 << 1)
+#define LPC_UART_RX_STATUS_INT_EN   (0x01 << 2)
+/* Interrupt status */
+#define LPC_UART_INT_MASK      (0x7 << 1)
+#define LPC_UART_INT_MODEM     (0x0 << 1)
+#define LPC_UART_INT_TX        (0x1 << 1)
+#define LPC_UART_INT_RX        (0x2 << 1)
+#define LPC_UART_INT_RX_STATUS (0x3 << 1)
+#define LPC_UART_INT_TIMEOUT   (0x6 << 1)
+/* RS485 Control */
+#define LPC_RS485_ENABLE       (0x1 << 0)
+#define LPC_RS485_RX_DIS       (0x1 << 1)
+#define LPC_RS485_AUTO_ADDR_EN (0x1 << 2)
+#define LPC_RS485_DIR_PIN_RTS  (0x0 << 3)
+#define LPC_RS485_DIR_PIN_DTR  (0x1 << 3)
+#define LPC_RS485_AUTO_DIR_EN  (0x1 << 4)
+#define LPC_RS485_DIR_CTRL_INV (0x1 << 5)
+/* RS485 */
+#define LPC_RS485_ADDR(x)  ((x) & 0xFF)
+#define LPC_RS485_DIR_DELAY(x)  ((x) & 0xFF)
+/* IrDA */
+#define LPC_IRDA_PULSEDIV(x)  (((x) & 0x07) << 3)
+
+
+/***************************************************************************** */
+/*                     Inter-Integrated Circuit  (I2C)                         */
+/***************************************************************************** */
+/* I2C */
+struct lpc_i2c
+{
+       volatile uint32_t ctrl_set;      /* 0x000 : I2C Control Set Register (R/W) */
+       volatile const uint32_t status;  /* 0x004 : I2C Status Register (R/-) */
+       volatile uint32_t data;          /* 0x008 : I2C Data Register (R/W) */
+       volatile uint32_t slave_addr_0;  /* 0x00C : I2C Slave Address Register 0 (R/W) */
+       volatile uint32_t clk_duty_high; /* 0x010 : SCL Duty Cycle Register High Half Word (R/W) */
+       volatile uint32_t clk_duty_low;  /* 0x014 : SCL Duty Cycle Register Low Half Word (R/W) */
+       volatile uint32_t ctrl_clear;    /* 0x018 : I2C Control Clear Register (-/W) */
+       volatile uint32_t monitor_mode_ctrl;  /* 0x01C : Monitor mode control register (R/W) */
+       volatile uint32_t slave_addr_1;  /* 0x020 : I2C Slave Address Register 1 (R/W) */
+       volatile uint32_t slave_addr_2;  /* 0x024 : I2C Slave Address Register 2 (R/W) */
+       volatile uint32_t slave_addr_3;  /* 0x028 : I2C Slave Address Register 3 (R/W) */
+       volatile const uint32_t data_buffer;  /* 0x02C : Data buffer register (-/W) */
+       volatile uint32_t slave_addr_mask[4]; /* 0x030 to 0x03C : I2C Slave address mask register 0 to 3 (R/W) */
+};
+#define LPC_I2C0   ((struct lpc_i2c *) LPC_I2C0_BASE)
+#define LPC_I2C1   ((struct lpc_i2c *) LPC_I2C1_BASE)
+#define LPC_I2C2   ((struct lpc_i2c *) LPC_I2C2_BASE)
+
+#define I2C_ASSERT_ACK   (0x01 << 2)
+#define I2C_INTR_FLAG    (0x01 << 3)
+#define I2C_STOP_FLAG    (0x01 << 4)
+#define I2C_START_FLAG   (0x01 << 5)
+#define I2C_ENABLE_FLAG  (0x01 << 6)
+
+
+/***************************************************************************** */
+/*                     Synchronous Serial Communication                        */
+/***************************************************************************** */
+/* Synchronous Serial Communication (SSP) */
+struct lpc_ssp
+{
+       volatile uint32_t ctrl_0;        /* 0x000 : Control Register 0 (R/W) */
+       volatile uint32_t ctrl_1;        /* 0x004 : Control Register 1 (R/W) */
+       volatile uint32_t data;          /* 0x008 : Data Register (R/W) */
+       volatile const uint32_t status;  /* 0x00C : Status Registe (R/-) */
+       volatile uint32_t clk_prescale;  /* 0x010 : Clock Prescale Register (R/W) */
+       volatile uint32_t int_mask;      /* 0x014 : Interrupt Mask Set and Clear Register (R/W) */
+       volatile uint32_t raw_int_status;     /* 0x018 : Raw Interrupt Status Register (R/-) */
+       volatile uint32_t masked_int_status;  /* 0x01C : Masked Interrupt Status Register (R/-) */
+       volatile uint32_t int_clear;     /* 0x020 : SSPICR Interrupt Clear Register (-/W) */
+       volatile uint32_t dma_ctrl;      /* 0x024 : DMA Control Register (R/W) */
+};
+#define LPC_SSP0  ((struct lpc_ssp *) LPC_SSP0_BASE)
+#define LPC_SSP1  ((struct lpc_ssp *) LPC_SSP1_BASE)
+
+/* SSP Control 0 register */
+#define LPC_SSP_DATA_WIDTH(x)    (((x) - 1) & 0x0F) /* Use 4 for 4 bits, 5 for 5 bits, .... */
+#define LPC_SSP_FRAME_SPI        (0x00 << 4)
+#define LPC_SSP_FRAME_TI         (0x01 << 4)
+#define LPC_SSP_FRAME_MICROWIRE  (0x02 << 4)
+#define LPC_SSP_SPI_CLK_LOW      (0x00 << 6)
+#define LPC_SSP_SPI_CLK_HIGH     (0x01 << 6)
+#define LPC_SSP_SPI_CLK_FIRST    (0x00 << 7)
+#define LPC_SSP_SPI_CLK_LAST     (0x01 << 7)
+#define LPC_SSP_SPI_CLK_RATE_DIV(x) (((x) & 0xFF) << 8)
+/* SSP Control 1 register */
+#define LPC_SSP_LOOPBACK_MODE      (0x01 << 0)
+#define LPC_SSP_ENABLE             (0x01 << 1)
+#define LPC_SSP_MASTER_MODE        (0x00 << 2)
+#define LPC_SSP_SLAVE_MODE         (0x01 << 2)
+#define LPC_SSP_SLAVE_OUT_DISABLE  (0x01 << 3)
+
+/* SSP Status register */
+#define LPC_SSP_ST_TX_EMPTY      (0x01 << 0)
+#define LPC_SSP_ST_TX_NOT_FULL   (0x01 << 1)
+#define LPC_SSP_ST_RX_NOT_EMPTY  (0x01 << 2)
+#define LPC_SSP_ST_RX_FULL       (0x01 << 3)
+#define LPC_SSP_ST_BUSY          (0x01 << 4)
+
+/* SSP Interrupt Mask, Raw, Status, Clear */
+#define LPC_SSP_INTR_RX_OVERRUN      (0x01 << 0)
+#define LPC_SSP_INTR_RX_TIMEOUT      (0x01 << 1)
+#define LPC_SSP_INTR_RX_HALF_FULL    (0x01 << 2)
+#define LPC_SSP_INTR_TX_HALF_EMPTY   (0x01 << 3)
+
+/* SSP DMA Control */
+#define LPC_SSP_RX_DMA_EN   (0x01 << 0)
+#define LPC_SSP_TX_DMA_EN   (0x01 << 1)
+
+
+
+/***************************************************************************** */
+/*                Serial Peripheral Interface                                  */
+/***************************************************************************** */
+struct lpc_spi
+{
+       volatile uint32_t control;        /* 0x000 : Control register (R/W) */
+       volatile uint32_t status;         /* 0x004 : Status register (R/-) */
+       volatile uint32_t data;           /* 0x008 : Data Register (R/W) */
+       volatile uint32_t clock_counter;  /* 0x00C : Clock Conter register (R/W) */
+       volatile uint32_t reserved_0[3];
+       volatile uint32_t interrupt;      /* 0x01C : Interrupt flag register (R/W) */
+};
+
+#define LPC_SPI  ((struct lpc_spi *) LPC_SPI_BASE)
+
+/* FIXME : add bitfields for SPI */
+
+
+/***************************************************************************** */
+/*                Timer/Counter and PWM                                        */
+/***************************************************************************** */
+/* Timer/Counter and PWM control */
+struct lpc_timer
+{
+       volatile uint32_t int_reg;        /* 0x000 : Interrupt Register (R/W) */
+       volatile uint32_t timer_ctrl;     /* 0x004 : Timer Control Register (R/W) */
+       volatile uint32_t timer_counter;  /* 0x008 : Timer Counter Register (R/W) */
+       volatile uint32_t prescale;       /* 0x00C : Prescale Register (R/W) */
+       volatile uint32_t prescale_counter;  /* 0x010 : Prescale Counter Register (R/W) */
+       volatile uint32_t match_ctrl;     /* 0x014 : Match Control Register (R/W) */
+       volatile uint32_t match_reg[4];   /* 0x018 : Match Register 0 to 3 (R/W) */
+       volatile uint32_t capture_ctrl;   /* 0x028 : Capture Control Register (R/W) */
+       volatile const uint32_t capture_reg[4]; /* 0x02C : Capture Register 0 to 3 (R/ ) */
+       volatile uint32_t external_match; /* 0x03C : External Match Register (R/W) */
+       volatile uint32_t match_reg_pwm[3]; /* 0x040 - 0x048 : Match Registers 4 to 6 (R/W) */
+       volatile uint32_t pwm_ctrl;       /* 0x04C : PWM Control Register (R/W) */
+       volatile uint32_t load_enable;    /* 0x050 : PWM Load Enable Register (R/W) */
+       uint32_t reserved_2[7];
+       volatile uint32_t count_ctrl;     /* 0x070 : Count Control Register (R/W) */
+};
+#define LPC_TMR32B0     ((struct lpc_timer *) LPC_TIMER0_BASE)
+#define LPC_TMR32B1     ((struct lpc_timer *) LPC_TIMER1_BASE)
+#define LPC_TMR32B2     ((struct lpc_timer *) LPC_TIMER2_BASE)
+#define LPC_TMR32B3     ((struct lpc_timer *) LPC_TIMER3_BASE)
+#define LPC_TMR_PWM     ((struct lpc_timer *) LPC_PWM1_BASE)
+
+#define LPC_TIMER_COUNTER_ENABLE (1 << 0) /* CEN */
+#define LPC_TIMER_COUNTER_RESET  (1 << 1) /* CRST */
+
+/* Match internal configuration */
+#define LPC_TIMER_INTERRUPT_ON_MATCH   0x01
+#define LPC_TIMER_RESET_ON_MATCH       0x02
+#define LPC_TIMER_STOP_ON_MATCH        0x04
+#define LPC_TIMER_MATCH_ERASE(x)       (0x07 << ((x) * 3))
+#define LPC_TIMER_MATCH_SHIFT(x)       ((x) * 3)
+/* Capture internal configuration */
+#define LPC_TIMER_CAP_ON_RISING_EDGE   0x01
+#define LPC_TIMER_CAP_ON_FALLING_EDGE  0x02
+#define LPC_TIMER_INTERRUPT_ON_CAPTURE 0x04
+#define LPC_TIMER_CAPTURE_ERASE(x)     (0x07 << ((x) * 3))
+#define LPC_TIMER_CAPTURE_SHIFT(x)     ((x) * 3)
+/* Match external configuration */
+#define LPC_TIMER_NOTHING_ON_MATCH     0x00
+#define LPC_TIMER_CLEAR_ON_MATCH       0x01
+#define LPC_TIMER_SET_ON_MATCH         0x02
+#define LPC_TIMER_TOGGLE_ON_MATCH      0x03
+#define LPC_TIMER_EXT_MATCH0_SHIFT     4
+#define LPC_TIMER_EXT_MATCH1_SHIFT     6
+#define LPC_TIMER_EXT_MATCH2_SHIFT     8
+#define LPC_TIMER_EXT_MATCH3_SHIFT     10
+/* Counter */
+#define LPC_COUNTER_IS_TIMER           0x00
+#define LPC_COUNTER_INC_ON_RISING      0x01
+#define LPC_COUNTER_INC_ON_FALLING     0x02
+#define LPC_COUNTER_INC_ON_BOTH        0x03
+#define LPC_COUNTER_INC_INPUT_SHIFT    2
+#define LPC_COUNTER_INC_INPUT(x)       (((x) & 0x03) << LPC_COUNTER_INC_INPUT_SHIFT)
+#define LPC_COUNTER_CLEAR_ON_EVENT_EN  (0x01 << 4)
+#define LPC_COUNTER_CLEAR_ON_EVENT_SHIFT  5
+#define LPC_COUNTER_CLEAR_ON_CHAN0_RISE   0x00
+#define LPC_COUNTER_CLEAR_ON_CHAN0_FALL   0x01
+#define LPC_COUNTER_CLEAR_ON_CHAN1_RISE   0x02
+#define LPC_COUNTER_CLEAR_ON_CHAN1_FALL   0x03
+#define LPC_COUNTER_CLEAR_ON_CHAN2_RISE   0x04
+#define LPC_COUNTER_CLEAR_ON_CHAN2_FALL   0x05
+#define LPC_COUNTER_CLEAR_ON_CHAN3_RISE   0x06
+#define LPC_COUNTER_CLEAR_ON_CHAN3_FALL   0x07
+/* PWM */
+#define LPC_PWM_CHANNEL_ENABLE(x)    (0x01 << (x))
+
+
+
+/***************************************************************************** */
+/*                     Watchdog Timer                                          */
+/***************************************************************************** */
+/* Watchdog Timer (WDT) */
+struct lpc_watchdog
+{
+       volatile uint32_t mode;          /* 0x000 : Watchdog mode register (R/W) */
+       volatile uint32_t timer_const;   /* 0x004 : Watchdog timer constant register (R/W) */
+       volatile uint32_t feed_seqence;  /* 0x008 : Watchdog feed sequence register ( /W) */
+       volatile const uint32_t timer_value;  /* 0x00C : Watchdog timer value register (R/ ) */
+       volatile uint32_t clk_src_sel;   /* 0x010 : Wathdog Clock Source Selection Register (R/W) */
+};
+#define LPC_WDT         ((struct lpc_watchdog *) LPC_WDT_BASE)
+
+#define LPC_WDT_DISABLE  (0x00)
+#define LPC_WDT_ENABLE   (0x01 << 0)
+/* FIXME : support all bitfields for Watchdog */
+
+
+
+
+
+/***************************************************************************** */
+/*                     Analog-to-Digital Converter                             */
+/***************************************************************************** */
+/* Analog-to-Digital Converter (ADC) */
+struct lpc_adc
+{
+       volatile uint32_t ctrl;         /* 0x000 : A/D Control Register (R/W) */
+       volatile uint32_t global_data;  /* 0x004 : A/D Global Data Register (R/W) */
+       uint32_t reserved_0;
+       volatile uint32_t int_en;  /* 0x00C : A/D Interrupt Enable Register (R/W) */
+       volatile uint32_t data[8]; /* Offset: 0x010-0x02C A/D Channel 0..7 Data Register (R/W) */
+       volatile const uint32_t status; /* 0x030 : A/D Status Register (R/ ) */
+       volatile uint32_t trim;    /* 0x034 : A/D Trim Register (R/W) */
+};
+#define LPC_ADC         ((struct lpc_adc *) LPC_ADC_BASE)
+
+/* ADC Control register bits */
+#define LPC_ADC_CTRL_MASK  0x0F01FFFF
+/* LPC_ADC_CHANNEL_* are also used for interrupt register */
+#define LPC_ADC_CHANNEL_MASK (0xFF << 0)
+#define LPC_ADC_CHANNEL(x)  (0x01 << ((x) & 0x07))
+#define LPC_ADC_BURST     (0x01 << 16)
+
+#define LPC_ADC_10BITS  (0x00 << 17)
+#define LPC_ADC_9BITS  (0x01 << 17)
+#define LPC_ADC_8BITS  (0x02 << 17)
+#define LPC_ADC_7BITS  (0x03 << 17)
+#define LPC_ADC_6BITS  (0x04 << 17)
+
+#define LPC_ADC_CONV_AD0   (0x01 << 0)
+#define LPC_ADC_INT_EN_AD0 (0x01 << 0)
+
+#define LPC_ADC_START_CONV_NOW  (0x01 << 24)
+#define LPC_ADC_START_CONV_MASK (0x07 << 24)
+enum lpc_adc_start_conv_events {
+       LPC_ADC_START_CONV_EDGE_CT16B0_CAP0 = 2,
+       LPC_ADC_START_CONV_EDGE_CT32B0_CAP0,
+       LPC_ADC_START_CONV_EDGE_CT32B0_MAT0,
+       LPC_ADC_START_CONV_EDGE_CT32B0_MAT1,
+       LPC_ADC_START_CONV_EDGE_CT16B0_MAT0,
+       LPC_ADC_START_CONV_EDGE_CT16B0_MAT1,
+};
+#define LPC_ADC_START_CONV_EVENT(x) (((x) & 0x7) << 24)
+#define LPC_ADC_START_EDGE_FALLING  (0x1 << 27)
+#define LPC_ADC_START_EDGE_RISING   (0x0 << 27)
+#define LPC_ADC_START_CONV_MASK (0x07 << 24)
+
+/* ADC Data register bits */
+#define LPC_ADC_RESULT_SHIFT  6
+#define LPC_ADC_RESULT_MASK   0x3FF
+#define LPC_ADC_OVERRUN    (0x01 << 30)
+#define LPC_ADC_CONV_DONE  (0x01 << 31)
+
+/* For more readability when selecting a channel number */
+#define LPC_ADC_NUM(x)    (x)
+
+
+
+/***************************************************************************** */
+/*                Ethernet                                                     */
+/***************************************************************************** */
+
+/*------------- Ethernet Media Access Controller (EMAC) ----------------------*/
+struct lpc_ethernet
+{
+       /* MAC Registers */
+       volatile uint32_t mac1;
+       volatile uint32_t mac2;
+       volatile uint32_t inter_packet_gap;
+       volatile uint32_t non_inter_packet_gap;
+       volatile uint32_t collision_window;
+       volatile uint32_t max_frame;
+       volatile uint32_t phy_support;
+       volatile uint32_t test;
+       volatile uint32_t mii_config;
+       volatile uint32_t mii_command;
+       volatile uint32_t mii_address;
+       volatile uint32_t mii_write;
+       volatile uint32_t mii_read;
+       volatile uint32_t mii_indicators;
+       volatile uint32_t reserved_0[2];
+       volatile uint32_t station_address0;
+       volatile uint32_t station_address1;
+       volatile uint32_t station_address2;
+       volatile uint32_t reserved_1[45];
+       /* Control Registers */
+       volatile uint32_t command;
+       volatile uint32_t status;
+       volatile uint32_t rx_descriptor;
+       volatile uint32_t rx_status;
+       volatile uint32_t rx_descriptor_number;
+       volatile uint32_t rx_produce_index;
+       volatile uint32_t rx_consume_index;
+
+       volatile uint32_t tx_descriptor;
+       volatile uint32_t tx_status;
+       volatile uint32_t tx_descriptor_number;
+       volatile uint32_t tx_produce_index;
+       volatile uint32_t tx_consume_index;
+
+       volatile uint32_t reserved_2[10];
+       volatile uint32_t transmit_status_vector0;
+       volatile uint32_t transmit_status_vector1;
+       volatile uint32_t receive_status_vector;
+       volatile uint32_t reserved_3[3];
+       volatile uint32_t flow_control_counter;
+       volatile uint32_t flow_control_status;
+       volatile uint32_t reserved_4[34];
+       /* Rx Filter Registers */
+       volatile uint32_t rx_filter_ctrl;
+       volatile uint32_t rx_filter_WoL_status;
+       volatile uint32_t rx_filter_WoL_clear;
+       volatile uint32_t reserved_5;
+       volatile uint32_t hash_filter_LSB;
+       volatile uint32_t hash_filter_MSB;
+       volatile uint32_t reserved_6[882];
+       /* Module Control Registers */
+       volatile uint32_t int_status;
+       volatile uint32_t int_enable;
+       volatile uint32_t int_clear;
+       volatile uint32_t int_set;
+       volatile uint32_t reserved_7;
+       volatile uint32_t power_down;
+       volatile uint32_t reserved_8;
+       volatile uint32_t Module_ID;
+};
+#define LPC_EMAC  ((struct lpc_ethernet *) LPC_ETHERNET_BASE)
+
+
+/***************************************************************************** */
+/*               USB                                                           */
+/***************************************************************************** */
+struct lpc_usb_clock
+{
+       /* Clock control registers */
+       volatile uint32_t control;  /* 0xFF4 : USBClkCtrl : Clock Control (R/W) */
+       volatile uint32_t status;   /* 0xFF8 : USBClkSt : Clock Status (R/ ) */
+};
+#define LPC_USB_CLOCK ((struct lpc_usb_clock *) (LPC_USB_BASE + 0xFF4))
+
+#define LPC_USB_DEV_CLK_EN  (0x01 << 1)
+#define LPC_USB_AHB_CLK_EN  (0x01 << 4)
+#define LPC_USB_CLK_ON  (LPC_USB_DEV_CLK_EN | LPC_USB_AHB_CLK_EN)
+
+struct lpc_usb_device
+{
+       uint32_t reserved_0[112];
+       /* Interrupt */
+       volatile uint32_t int_status; /* 0x1C0 : USBIntSt : interrupt status (R/W) */
+       uint32_t reserved_1[15];
+       /* Device interrupt */
+       volatile uint32_t dev_int_status;   /* 0x200 : USBDevIntSt : interrupt status (R/ ) */
+       volatile uint32_t dev_int_enable;   /* 0x204 : USBDevIntEn : interrupt enable (R/W) */
+       volatile uint32_t dev_int_clear;    /* 0x208 : USBDevIntClr : interrupt clear ( /W) */
+       volatile uint32_t dev_int_set;      /* 0x20C : USBDevIntSet : interrupt set ( /W) */
+       /* Command regs */
+       volatile uint32_t command_code;     /* 0x210 : USBCmdCode : Command Code ( /W) */
+       volatile uint32_t command_data;     /* 0x214 : USBCmdData : Command Data (R/ ) */
+       /* Transfer regs */
+       volatile uint32_t rx_data;          /* 0x218 : USBRxData : Receive Data (R/ ) */
+       volatile uint32_t tx_data;          /* 0x21C : USBTxData : Transmit Data ( /W) */
+       volatile uint32_t rx_pkt_length;    /* 0x220 : USBRxPLen : Receive Packet Length (R/ ) */
+       volatile uint32_t tx_pkt_length;    /* 0x224 : USBTxPLen : Transmit Packet Length ( /W) */
+       volatile uint32_t control;          /* 0x228 : USBCtrl : Control (R/W) */
+       volatile uint32_t dev_int_priority; /* 0x22C : USBDevIntPri : interrupt priority ( /W) */
+       /* Endpoint interrupt */
+       volatile uint32_t ep_int_status;    /* 0x230 : USBEpIntSt : interrupt status (R/ ) */
+       volatile uint32_t ep_int_enable;    /* 0x234 : USBEpIntEn : interrupt enable (R/W) */
+       volatile uint32_t ep_int_clear;     /* 0x238 : USBEpIntClr : interrupt clear ( /W) */
+       volatile uint32_t ep_int_set;       /* 0x23C : USBEpIntSet : interrupt set ( /W) */
+       volatile uint32_t ep_int_priority;  /* 0x240 : USBEpIntPri : interrupt priority ( /W) */
+       /* Endpoint realization regs */
+       volatile uint32_t realize_ep;       /* 0x244 : USBReEp : Realize Endpoint (R/W) */
+       volatile uint32_t ep_index;         /* 0x248 : USBEpIn : Endpoint Index ( /W) */
+       volatile uint32_t max_packet_size;  /* 0x24C : USBMaxPSize : MaxPacketSize (R/W) */
+       /* DMA */
+       volatile uint32_t dma_req_status;   /* 0x250 : USBDMARSt : DMA Request Status (R/ ) */
+       volatile uint32_t dma_req_clear;    /* 0x254 : USBDMARClr : DMA Request Clear ( /W) */
+       volatile uint32_t dma_req_set;      /* 0x258 : USBDMARSet : DMA Request Set ( /W) */
+       uint32_t reserved_2[9];
+       volatile uint32_t udca_head;        /* 0x280 : USBUDCAH : UDCA Head (R/W) */
+       volatile uint32_t warning_int_compare; /* 0x014 : Watchdog Warning Interrupt compare value. */
+       volatile uint32_t window_compare;      /* 0x018 : Watchdog Window compare value. */
+       volatile uint32_t ep_dma_status;    /* 0x284 : USBEpDMASt : Endpoint DMA Status (R/W) */
+       volatile uint32_t ep_dma_enable;    /* 0x288 : USBEpDMAEn : Endpoint DMA Enable ( /W) */
+       volatile uint32_t ep_dma_disable;   /* 0x28C : USBEpDMADis : Endpoint DMA Disable ( /W) */
+       volatile uint32_t dma_int_status;   /* 0x290 : USBDMAIntSt : DMA Interrupt Status (R/ ) */
+       volatile uint32_t dma_int_enable;   /* 0x294 : USBDMAIntEn : DMA Interrupt Enable (R/W) */
+       uint32_t reserved_3[2];
+       volatile uint32_t eot_int_status;   /* 0x2A0 : USBEoTIntSt : End of Transfer Interrupt Status (R/ ) */
+       volatile uint32_t eot_int_clear;    /* 0x2A4 : USBEoTIntClr : End of Transfer Interrupt Clear ( /W) */
+       volatile uint32_t eot_int_set;      /* 0x2A8 : USBEoTIntSet : End of Transfer Interrupt Set ( /W) */
+       volatile uint32_t new_dd_req_int_status; /* 0x2AC : USBNDDRIntSt : New DD Request Interrupt Status (R/ ) */
+       volatile uint32_t new_dd_req_int_clear;  /* 0x2B0 : USBNDDRIntClr : New DD Request Interrupt Clear ( /W) */
+       volatile uint32_t new_dd_req_int_set;    /* 0x2B4 : USBNDDRIntSet : New DD Request Interrupt Set ( /W) */
+       volatile uint32_t syst_err_int_status;   /* 0x2B8 : USBSysErrIntSt : System Error Interrupt Status (R/ ) */
+       volatile uint32_t syst_err_int_clear;    /* 0x2BC : USBSysErrIntClr : System Error Interrupt Clear ( /W) */
+       volatile uint32_t syst_err_int_set;      /* 0x2C0 : USBSysErrIntSet : System Error Interrupt Set ( /W) */
+};
+#define LPC_USB_DEVICE  ((struct lpc_usb_device *) LPC_USB_BASE)
+
+
+/* USB Device Interrupts */
+#define USB_FRAME_INT           (1 << 0)
+#define USB_EP_FAST_INT         (1 << 1)
+#define USB_EP_SLOW_INT         (1 << 2)
+#define USB_DEV_STAT_INT        (1 << 3)
+#define USB_CMD_CODE_EMPTY_INT  (1 << 4) /* CCEMPTY : Commande Code empty */
+#define USB_CMD_DATA_FULL_INT   (1 << 5) /* CDFULL : Command Data Full */
+#define USB_RxENDPKT_INT        (1 << 6)
+#define USB_TxENDPKT_INT        (1 << 7)
+#define USB_EP_RLZED_INT        (1 << 8)
+#define USB_ERR_INT             (1 << 9)
+/* USB Endpoint Interrupts */
+#define USB_EP_Rx_INT(ep)  (1 << (ep * 2))
+#define USB_EP_Tx_INT(ep)  (1 << ((ep * 2) + 1))
+
+/*  USB Endpoints  */
+/* Remember that directions are defined with respect to the host.
+ *    OUT is from host to device
+ *    IN is from device to host
+ */
+#define USB_DIR_OUT         0       /* to device */
+#define USB_DIR_IN          0x80    /* to host */
+#define USB_DIR_SHIFT       7
+#define USB_PHY_ENDPOINTS   32
+#define USB_LOG_ENDPOINTS   16
+
+/* Tx / Rx Packet Length register */
+#define USB_PKT_REMAIN_LENGTH_MASK  0x03FF
+#define USB_PKT_DATA_VALID   (1 << 10)
+#define USB_PKT_READY        (1 << 11)
+/* Control register */
+#define USB_READ_ENABLE      (1 << 0)
+#define USB_WRITE_ENABLE     (1 << 1)
+#define USB_CTRL_LOG_EP(ep)  ((ep & 0x0F) << 2)
+
+/* SIE Command Code register */
+#define USB_CMD_PHASE_WRITE  (0x01 << 8)
+#define USB_CMD_PHASE_READ   (0x02 << 8)
+#define USB_CMD_PHASE_CMD    (0x05 << 8)
+#define USB_CMD_CODE(code)   ((code & 0xFF) << 16)
+#define USB_CMD_WDATA(data)  ((data & 0xFF) << 16)
+/* Wrappers for SIE Command Code register */
+#define USB_CMD_READ(code)     (USB_CMD_PHASE_READ | USB_CMD_CODE(code))
+#define USB_CMD_COMMAND(code)  (USB_CMD_PHASE_CMD | USB_CMD_CODE(code))
+#define USB_CMD_WRITE(data)    (USB_CMD_PHASE_WRITE | USB_CMD_WDATA(data))
+/* SIE Command DATA register */
+#define USB_CMD_DATA_MASK    0xFF
+/* SIE Commands */
+#define USB_SIE_SET_ADDRESS       0xD0
+#define USB_SIE_CONFIGURE_DEV     0xD8
+#define USB_SIE_SET_MODE          0xF3
+#define USB_SIE_READ_CFN          0xF5 /* Read Current Frame Number */
+#define USB_SIE_READ_TEST_REG     0xFD /* Read Test Register */
+#define USB_SIE_DEV_STATUS        0xFE
+#define USB_SIE_GET_ERROR_CODE    0xFF
+#define USB_SIE_READ_ERROR_STATUS 0xFB
+#define USB_SIE_SELECT_EP(ep)     (0x00 + ep) /* ep is physical endpoint number */
+#define USB_SIE_UNUSED 0 /* UM recommends not to use the Select Endpoint command to clear interrupt status */
+#define USB_SIE_SET_EP_STAT(ep)   (0x40 + ep) /* ep is physical endpoint number */
+#define USB_SIE_EP_CLEAR_BUF      0xF2
+#define USB_SIE_EP_VALIDATE_BUF   0xFA
+/* SIE Command bits */
+#define USB_DEVICE_ENABLE      (1 << 7)
+#define USB_DEVICE_CONFIGURED  (1 << 0)
+/* SIE Command Set Mode Bits */
+#define USB_MODE_ALWAYS_PLL    (1 << 0)
+#define USB_MODE_INAK_CTRL_IN  (1 << 1)
+#define USB_MODE_INAK_CTRL_OUT (1 << 2)
+#define USB_MODE_INAK_INT_IN   (1 << 3)
+#define USB_MODE_INAK_INT_OUT  (1 << 4)
+#define USB_MODE_INAK_BULK_IN  (1 << 5)
+#define USB_MODE_INAK_BULK_OUT (1 << 6)
+/* SIE Command Set Device Status */
+#define USB_DEVSTAT_CONNECT      (1 << 0)
+#define USB_DEVSTAT_CONN_CHANGE  (1 << 1)
+#define USB_DEVSTAT_SUSPEND      (1 << 2)
+#define USB_DEVSTAT_SUSP_CHANGE  (1 << 3)
+#define USB_DEVSTAT_RESET        (1 << 4)
+/* SIE Endpoint Read Status */
+#define USB_EPSTAT_MASK        0x7F
+#define USB_EPSTAT_FULL_EMPTY    (1 << 0)
+#define USB_EPSTAT_STALLED       (1 << 1)
+#define USB_EPSTAT_SETUP         (1 << 2)
+#define USB_EPSTAT_PKT_OVERWRITE (1 << 3)
+#define USB_EPSTAT_NAK           (1 << 4)
+#define USB_EPSTAT_B1_FULL       (1 << 5)
+#define USB_EPSTAT_B2_FULL       (1 << 6)
+/* SIE Endpoint Set Status */
+#define USB_EP_SET_STAT_STALLED    (1 << 0)
+#define USB_EP_SET_STAT_DISABLED   (1 << 5)
+#define USB_EP_SET_STAT_RF_MODE    (1 << 6) /* RF = Rate Feedback */
+#define USB_EP_SET_STAT_CND_STALL  (1 << 7) /* Conditional Stall bit, valid only for control out endpoint */
+
+
+#endif  /* CORE_LPC_REGS_H */
diff --git a/include/core/pio.h b/include/core/pio.h
new file mode 100644 (file)
index 0000000..df746fa
--- /dev/null
@@ -0,0 +1,440 @@
+/****************************************************************************
+ *  core/pio.h
+ *
+ * Copyright 2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ****************************************************************************/
+
+#ifndef CORE_PIO_H
+#define CORE_PIO_H
+
+/* The "PIO" module gives access to the configuration of all the pins of the
+ * micro-controller, whatever the function of the pin.
+ * It has nothing related to GPIO function of the pins.
+ */
+
+#include <stdint.h>
+
+struct pio {
+    uint8_t port;  /* 0xFF indicates the end of a pin array */
+    uint8_t pin;
+    uint8_t alt_setting;
+};
+
+#define ARRAY_LAST_PIN   {0xFF, 0xFF, 0xFF}
+#define PIO_LAST   ARRAY_LAST_PIN
+
+struct pio_config {
+       struct pio pio;
+       uint32_t mode;
+};
+#define ARRAY_LAST_PIO  { PIO_LAST, 0xFF }
+
+
+#define PORT0_NB_PINS 28
+#define PORT1_NB_PINS 24
+#define PORT2_NB_PINS 14
+#define PORT3_NB_PINS 2
+#define PORT4_NB_PINS 2
+
+#define PORT0_MAX_PIN_NUM 30
+#define PORT1_MAX_PIN_NUM 31
+#define PORT2_MAX_PIN_NUM 13
+#define PORT3_MAX_PIN_NUM 26
+#define PORT4_MAX_PIN_NUM 29
+
+
+
+/* Simple copy function. */
+void pio_copy(struct pio* dst, const struct pio* src);
+
+/* Configure the pin in the requested function and mode. */
+void config_pio(const struct pio* pp, uint32_t mode);
+
+/* Configure a set (array) of pins in a single loop */
+void set_pins(const struct pio_config* pins);
+
+/****************************************************************************/
+/*  GPIO Pins  */
+#define LPC_GPIO_0_0  {0,  0, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_1  {0,  1, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_2  {0,  2, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_3  {0,  3, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_4  {0,  4, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_5  {0,  5, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_6  {0,  6, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_7  {0,  7, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_8  {0,  8, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_9  {0,  9, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_10 {0, 10, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_11 {0, 11, LPC_IO_FUNC_GPIO}
+/* No PIO_0_12 to PIO_0_14 */
+#define LPC_GPIO_0_15 {0, 15, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_16 {0, 16, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_17 {0, 17, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_18 {0, 18, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_19 {0, 19, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_20 {0, 20, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_21 {0, 21, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_22 {0, 22, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_23 {0, 23, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_24 {0, 24, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_25 {0, 25, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_26 {0, 26, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_27 {0, 27, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_28 {0, 28, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_29 {0, 29, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_0_30 {0, 30, LPC_IO_FUNC_GPIO}
+/* No PIO_0_31 */
+
+#define LPC_GPIO_1_0  {1,  0, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_1  {1,  1, LPC_IO_FUNC_GPIO}
+/* No PIO_1_2 and PIO_1_3 */
+#define LPC_GPIO_1_4  {1,  4, LPC_IO_FUNC_GPIO}
+/* No PIO_1_5 to PIO_1_7 */
+#define LPC_GPIO_1_8  {1,  8, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_9  {1,  9, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_10 {1, 10, LPC_IO_FUNC_GPIO}
+/* No PIO_1_11 to PIO_1_13 */
+#define LPC_GPIO_1_14 {1, 14, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_15 {1, 15, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_16 {1, 16, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_17 {1, 17, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_18 {1, 18, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_19 {1, 19, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_20 {1, 20, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_21 {1, 21, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_22 {1, 22, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_23 {1, 23, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_24 {1, 24, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_25 {1, 25, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_26 {1, 26, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_27 {1, 27, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_28 {1, 28, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_29 {1, 29, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_30 {1, 30, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_1_31 {1, 31, LPC_IO_FUNC_GPIO}
+
+#define LPC_GPIO_2_0  {2,  0, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_1  {2,  1, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_2  {2,  2, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_3  {2,  3, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_4  {2,  4, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_5  {2,  5, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_6  {2,  6, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_7  {2,  7, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_8  {2,  8, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_9  {2,  9, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_10 {2, 10, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_11 {2, 11, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_12 {2, 12, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_2_13 {2, 13, LPC_IO_FUNC_GPIO}
+/* No PIO_2_14 to PIO_2_31 */
+
+/* Port 3 has only two available pins */
+#define LPC_GPIO_3_25 {3, 25, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_3_26 {3, 26, LPC_IO_FUNC_GPIO}
+
+/* Port 4 has only two available pins */
+#define LPC_GPIO_4_28 {4, 28, LPC_IO_FUNC_GPIO}
+#define LPC_GPIO_4_29 {4, 29, LPC_IO_FUNC_GPIO}
+
+/****************************************************************************/
+/*  CLKOUT Pin  */
+#define LPC_CLKOUT_PIO_1_27  {1, 27, LPC_IO_FUNC_ALT1}
+
+/* Systick CLK Input */
+#define LPC_SYSTICK_CLK_IN_PIO_3_26  {3, 26, LPC_IO_FUNC_ALT1}
+
+/* Note : Reset, SWD and JTAG are on dedicated pins, not available for any other
+ *   function, and not user configurable
+ */
+
+/* External Interrupts pins */
+#define LPC_EINT_0_PIO_2_10  {2, 10, LPC_IO_FUNC_ALT1}
+#define LPC_EINT_1_PIO_2_11  {2, 11, LPC_IO_FUNC_ALT1}
+#define LPC_EINT_2_PIO_2_12  {2, 12, LPC_IO_FUNC_ALT1}
+#define LPC_EINT_3_PIO_2_13  {2, 13, LPC_IO_FUNC_ALT1}
+/* NMI interrupt */
+#define LPC_NMI_PIO_2_10     {2, 10, LPC_IO_FUNC_ALT2}
+
+/* Trace */
+/* Note : trace functions on pins 2.2 to 2.6 is activated using PINSEL10 resgister
+ *   (lpc_pin_func_control->trace_en). Refer to UM10360 Section 8.5.8 "Pin Function
+ *   Select Register 10".
+ */
+
+
+/****************************************************************************/
+/* UART Pins */
+/*  UART0 Rx/Tx Pins  */
+#define LPC_UART0_TX_PIO_0_2  {0,  2, LPC_IO_FUNC_ALT1}
+#define LPC_UART0_RX_PIO_0_3  {0,  3, LPC_IO_FUNC_ALT1}
+
+/*  UART1 Rx/Tx option 1 Pins  */
+#define LPC_UART1_TX_PIO_0_15  {0, 15, LPC_IO_FUNC_ALT1}
+#define LPC_UART1_RX_PIO_0_16  {0, 16, LPC_IO_FUNC_ALT1}
+/* UART1 - Other UART function pins */
+#define LPC_UART1_CTS_PIO_0_17 {0, 17, LPC_IO_FUNC_ALT1}
+#define LPC_UART1_DCD_PIO_0_18 {0, 18, LPC_IO_FUNC_ALT1}
+#define LPC_UART1_DSR_PIO_0_19 {0, 19, LPC_IO_FUNC_ALT1}
+#define LPC_UART1_DTR_PIO_0_20 {0, 20, LPC_IO_FUNC_ALT1}
+#define LPC_UART1_RI_PIO_0_21  {0, 21, LPC_IO_FUNC_ALT1}
+#define LPC_UART1_RTS_PIO_0_22 {0, 22, LPC_IO_FUNC_ALT1}
+/*  UART1 Rx/Tx option 2 Pins  */
+#define LPC_UART1_TX_PIO_2_0   {2,  0, LPC_IO_FUNC_ALT2}
+#define LPC_UART1_RX_PIO_2_1   {2,  1, LPC_IO_FUNC_ALT2}
+/* UART1 - Other UART function pins */
+#define LPC_UART1_CTS_PIO_2_2  {2,  2, LPC_IO_FUNC_ALT2}
+#define LPC_UART1_DCD_PIO_2_3  {2,  3, LPC_IO_FUNC_ALT2}
+#define LPC_UART1_DSR_PIO_2_4  {2,  4, LPC_IO_FUNC_ALT2}
+#define LPC_UART1_DTR_PIO_2_5  {2,  5, LPC_IO_FUNC_ALT2}
+#define LPC_UART1_RI_PIO_2_6   {2,  6, LPC_IO_FUNC_ALT2}
+#define LPC_UART1_RTS_PIO_2_7  {2,  7, LPC_IO_FUNC_ALT2}
+
+
+/*  UART2 Rx/Tx option 1 Pins  */
+#define LPC_UART2_TX_PIO_0_10 {0, 10, LPC_IO_FUNC_ALT1}
+#define LPC_UART2_RX_PIO_0_11 {0, 11, LPC_IO_FUNC_ALT1}
+/* UART2 option 2 */
+#define LPC_UART2_TX_PIO_2_8  {2,  8, LPC_IO_FUNC_ALT2}
+#define LPC_UART2_RX_PIO_2_9  {2,  9, LPC_IO_FUNC_ALT2}
+
+/*  UART3 Rx/Tx option 1 Pins  */
+#define LPC_UART3_TX_PIO_0_0  {0,  0, LPC_IO_FUNC_ALT2}
+#define LPC_UART3_RX_PIO_0_1  {0,  1, LPC_IO_FUNC_ALT2}
+/* UART3 option 2 */
+#define LPC_UART3_TX_PIO_0_25 {0, 25, LPC_IO_FUNC_ALT3}
+#define LPC_UART3_RX_PIO_0_26 {0, 26, LPC_IO_FUNC_ALT3}
+/* UART3 option 3 */
+#define LPC_UART3_TX_PIO_4_28 {4, 28, LPC_IO_FUNC_ALT3}
+#define LPC_UART3_RX_PIO_4_29 {4, 29, LPC_IO_FUNC_ALT3}
+
+
+/****************************************************************************/
+/* Can Pins */
+/*  CAN0 Pins  */
+#define LPC_CAN0_RD_PIO_9_0  {0,  0, 9}
+#define LPC_CAN0_TD_PIO_9_0  {0,  0, 9}
+
+/*  CAN1 Pins option 1 */
+#define LPC_CAN1_RD_PIO_0_0  {0,  0, LPC_IO_FUNC_ALT1}
+#define LPC_CAN1_TD_PIO_0_1  {0,  1, LPC_IO_FUNC_ALT1}
+/*  CAN1 Pins option 2 */
+#define LPC_CAN1_RD_PIO_0_21 {0, 21, LPC_IO_FUNC_ALT3}
+#define LPC_CAN1_TD_PIO_0_22 {0, 22, LPC_IO_FUNC_ALT3}
+
+/*  CAN2 Pins option 1 */
+#define LPC_CAN2_RD_PIO_0_4  {0,  4, LPC_IO_FUNC_ALT2}
+#define LPC_CAN2_TD_PIO_0_5  {0,  5, LPC_IO_FUNC_ALT2}
+/*  CAN2 Pins option 2 */
+#define LPC_CAN2_RD_PIO_2_7  {2,  7, LPC_IO_FUNC_ALT1}
+#define LPC_CAN2_TD_PIO_2_8  {2,  8, LPC_IO_FUNC_ALT1}
+
+
+/****************************************************************************/
+/* I2C Pins */
+/*  I2C0 Pins  */
+#define LPC_I2C0_SDA_PIO_0_27 {0, 27, LPC_IO_FUNC_ALT1}
+#define LPC_I2C0_SCL_PIO_0_28 {0, 28, LPC_IO_FUNC_ALT1}
+
+/*  I2C1 Pins  */
+#define LPC_I2C1_SDA_PIO_0_0  {0,  0, LPC_IO_FUNC_ALT3}
+#define LPC_I2C1_SCL_PIO_0_1  {0,  1, LPC_IO_FUNC_ALT3}
+#define LPC_I2C1_SDA_PIO_0_19 {0, 19, LPC_IO_FUNC_ALT3}
+#define LPC_I2C1_SCL_PIO_0_20 {0, 20, LPC_IO_FUNC_ALT3}
+
+/*  I2C2 Pins  */
+#define LPC_I2C2_SDA_PIO_0_10 {0, 10, LPC_IO_FUNC_ALT2}
+#define LPC_I2C2_SCL_PIO_0_11 {0, 11, LPC_IO_FUNC_ALT2}
+
+
+/****************************************************************************/
+/*  SSP / SPI Pins  */
+/* SSP 0 */
+#define LPC_SSP0_SCLK_PIO_0_15 {0, 15, LPC_IO_FUNC_ALT2}
+#define LPC_SSP0_SSEL_PIO_0_16 {0, 16, LPC_IO_FUNC_ALT2}
+#define LPC_SSP0_MISO_PIO_0_17 {0, 17, LPC_IO_FUNC_ALT2}
+#define LPC_SSP0_MOSI_PIO_0_18 {0, 18, LPC_IO_FUNC_ALT2}
+#define LPC_SSP0_SCLK_PIO_1_20 {1, 20, LPC_IO_FUNC_ALT3}
+#define LPC_SSP0_SSEL_PIO_1_21 {1, 21, LPC_IO_FUNC_ALT3}
+#define LPC_SSP0_MISO_PIO_1_23 {1, 23, LPC_IO_FUNC_ALT3}
+#define LPC_SSP0_MOSI_PIO_1_24 {1, 24, LPC_IO_FUNC_ALT3}
+
+/* SPI */
+#define LPC_SPI_SCLK_PIO_0_15 {0, 15, LPC_IO_FUNC_ALT3}
+#define LPC_SPI_SSEL_PIO_0_16 {0, 16, LPC_IO_FUNC_ALT3}
+#define LPC_SPI_MISO_PIO_0_17 {0, 17, LPC_IO_FUNC_ALT3}
+#define LPC_SPI_MOSI_PIO_0_18 {0, 18, LPC_IO_FUNC_ALT3}
+
+/* SSP 1 */
+#define LPC_SSP1_SSEL_PIO_0_6  {0,  6, LPC_IO_FUNC_ALT2}
+#define LPC_SSP1_SCLK_PIO_0_7  {0,  7, LPC_IO_FUNC_ALT2}
+#define LPC_SSP1_SCLK_PIO_1_31 {1, 31, LPC_IO_FUNC_ALT2}
+#define LPC_SSP1_MISO_PIO_0_8  {0,  8, LPC_IO_FUNC_ALT2}
+#define LPC_SSP1_MOSI_PIO_0_9  {0,  9, LPC_IO_FUNC_ALT2}
+
+
+/****************************************************************************/
+/*  ADC Pins  */
+#define LPC_ADC_AD0_PIO_0_23 {0, 23, LPC_IO_FUNC_ALT1}
+#define LPC_ADC_AD1_PIO_0_24 {0, 24, LPC_IO_FUNC_ALT1}
+#define LPC_ADC_AD2_PIO_0_25 {0, 25, LPC_IO_FUNC_ALT1}
+#define LPC_ADC_AD3_PIO_0_26 {0, 26, LPC_IO_FUNC_ALT1}
+#define LPC_ADC_AD4_PIO_1_30 {1, 30, LPC_IO_FUNC_ALT3}
+#define LPC_ADC_AD5_PIO_1_31 {1, 31, LPC_IO_FUNC_ALT3}
+#define LPC_ADC_AD6_PIO_0_3  {0,  3, LPC_IO_FUNC_ALT1}
+#define LPC_ADC_AD7_PIO_0_2  {0,  2, LPC_IO_FUNC_ALT1}
+
+
+/****************************************************************************/
+/*  DAC Pins  */
+#define LPC_DAC_OUT_PIO_0_26  {0, 26, LPC_IO_FUNC_ALT2}
+
+
+/****************************************************************************/
+/*  I2S Pins  */
+/* Master Clock */
+#define LPC_I2SRX_MCLK_PIO_4_28  {4, 28, LPC_IO_FUNC_ALT1}
+#define LPC_I2STX_MCLK_PIO_4_29  {4, 29, LPC_IO_FUNC_ALT1}
+/* Rx option 1 */
+#define LPC_I2SRX_CLK_PIO_0_4  {0,  4, LPC_IO_FUNC_ALT1}
+#define LPC_I2SRX_WS_PIO_0_5   {0,  5, LPC_IO_FUNC_ALT1}
+#define LPC_I2SRX_SDA_PIO_0_6  {0,  6, LPC_IO_FUNC_ALT1}
+/* Rx option 2 */
+#define LPC_I2SRX_CLK_PIO_0_23 {0, 23, LPC_IO_FUNC_ALT2}
+#define LPC_I2SRX_WS_PIO_0_24  {0, 24, LPC_IO_FUNC_ALT2}
+#define LPC_I2SRX_SDA_PIO_0_25 {0, 25, LPC_IO_FUNC_ALT2}
+/* Tx option 1 */
+#define LPC_I2STX_CLK_PIO_0_7  {0,  7, LPC_IO_FUNC_ALT1}
+#define LPC_I2STX_WS_PIO_0_8   {0,  8, LPC_IO_FUNC_ALT1}
+#define LPC_I2STX_SDA_PIO_0_9  {0,  9, LPC_IO_FUNC_ALT1}
+/* Tx option 2 */
+#define LPC_I2STX_CLK_PIO_2_11 {2, 11, LPC_IO_FUNC_ALT3}
+#define LPC_I2STX_WS_PIO_2_12  {2, 12, LPC_IO_FUNC_ALT3}
+#define LPC_I2STX_SDA_PIO_2_13 {2, 13, LPC_IO_FUNC_ALT3}
+
+
+/****************************************************************************/
+/*  Timer Pins  */
+
+/* 32 bits timer 0 match pins */
+#define LPC_TIMER_32B0_M0_PIO_1_28 {1, 28, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B0_M1_PIO_1_29 {1, 29, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B0_M0_PIO_3_25 {3, 25, LPC_IO_FUNC_ALT2}
+#define LPC_TIMER_32B0_M1_PIO_3_26 {3, 26, LPC_IO_FUNC_ALT2}
+/* 32 bits timer 0 capture pins */
+#define LPC_TIMER_32B0_C0_PIO_1_26 {1, 26, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B0_C1_PIO_1_27 {1, 27, LPC_IO_FUNC_ALT3}
+
+/* 32 bits timer 1 match pins */
+#define LPC_TIMER_32B1_M0_PIO_1_22 {1, 22, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B1_M1_PIO_1_25 {1, 25, LPC_IO_FUNC_ALT3}
+/* 32 bits timer 1 capture pins */
+#define LPC_TIMER_32B1_C0_PIO_1_18 {1, 18, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B1_C1_PIO_1_19 {1, 19, LPC_IO_FUNC_ALT3}
+
+/* 32 bits timer 2 match pins */
+#define LPC_TIMER_32B2_M0_PIO_0_6  {0,  6, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B2_M1_PIO_0_7  {0,  7, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B2_M2_PIO_0_8  {0,  8, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B2_M3_PIO_0_9  {0,  9, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B2_M0_PIO_4_28 {4, 28, LPC_IO_FUNC_ALT2}
+#define LPC_TIMER_32B2_M1_PIO_4_29 {4, 29, LPC_IO_FUNC_ALT2}
+/* 32 bits timer 2 capture pins */
+#define LPC_TIMER_32B2_C0_PIO_0_4  {0,  4, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B2_C1_PIO_0_5  {0,  5, LPC_IO_FUNC_ALT3}
+
+/* 32 bits timer 3 match pins */
+#define LPC_TIMER_32B3_M0_PIO_0_10 {0, 10, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B3_M1_PIO_0_11 {0, 11, LPC_IO_FUNC_ALT3}
+/* 32 bits timer 3 capture pins */
+#define LPC_TIMER_32B3_C0_PIO_0_23 {0, 23, LPC_IO_FUNC_ALT3}
+#define LPC_TIMER_32B3_C1_PIO_0_24 {0, 24, LPC_IO_FUNC_ALT3}
+
+
+/****************************************************************************/
+/*  PWM Pins  */
+/* Output option 1 */
+#define LPC_PWM1_OUT1_PIO_1_18   {1, 18, LPC_IO_FUNC_ALT2}
+#define LPC_PWM1_OUT2_PIO_1_20   {1, 20, LPC_IO_FUNC_ALT2}
+#define LPC_PWM1_OUT3_PIO_1_21   {1, 21, LPC_IO_FUNC_ALT2}
+#define LPC_PWM1_OUT4_PIO_1_23   {1, 23, LPC_IO_FUNC_ALT2}
+#define LPC_PWM1_OUT5_PIO_1_24   {1, 24, LPC_IO_FUNC_ALT2}
+#define LPC_PWM1_OUT6_PIO_1_26   {1, 26, LPC_IO_FUNC_ALT2}
+/* Output option 2 */
+#define LPC_PWM1_OUT1_PIO_2_0    {2,  0, LPC_IO_FUNC_ALT1}
+#define LPC_PWM1_OUT2_PIO_2_1    {2,  1, LPC_IO_FUNC_ALT1}
+#define LPC_PWM1_OUT3_PIO_2_2    {2,  2, LPC_IO_FUNC_ALT1}
+#define LPC_PWM1_OUT4_PIO_2_3    {2,  3, LPC_IO_FUNC_ALT1}
+#define LPC_PWM1_OUT5_PIO_2_4    {2,  4, LPC_IO_FUNC_ALT1}
+#define LPC_PWM1_OUT6_PIO_2_5    {2,  5, LPC_IO_FUNC_ALT1}
+/* Output option 3 */
+#define LPC_PWM1_OUT2_PIO_3_25   {3, 25, LPC_IO_FUNC_ALT3}
+#define LPC_PWM1_OUT3_PIO_3_26   {3, 26, LPC_IO_FUNC_ALT3}
+/* Input */
+#define LPC_PWM1_CAP0_PIO_1_28   {1, 28, LPC_IO_FUNC_ALT2}
+#define LPC_PWM1_CAP0_PIO_2_6    {2,  6, LPC_IO_FUNC_ALT1}
+#define LPC_PWM1_CAP1_PIO_1_29   {1, 29, LPC_IO_FUNC_ALT2}
+
+
+/****************************************************************************/
+/*  Motor Control Pins  */
+#define LPC_MCTRL_OUT_A0_PIO_1_19 {1, 19, LPC_IO_FUNC_ALT1}
+#define LPC_MCTRL_IN0_PIO_1_20    {1, 20, LPC_IO_FUNC_ALT1}
+#define LPC_MCTRL_ABORT_PIO_1_21  {1, 21, LPC_IO_FUNC_ALT1}
+#define LPC_MCTRL_OUT_B0_PIO_1_22 {1, 22, LPC_IO_FUNC_ALT1}
+#define LPC_MCTRL_IN1_PIO_1_23    {1, 23, LPC_IO_FUNC_ALT1}
+#define LPC_MCTRL_IN2_PIO_1_24    {1, 24, LPC_IO_FUNC_ALT1}
+#define LPC_MCTRL_OUT_A1_PIO_1_25 {1, 25, LPC_IO_FUNC_ALT1}
+#define LPC_MCTRL_OUT_B1_PIO_1_26 {1, 26, LPC_IO_FUNC_ALT1}
+#define LPC_MCTRL_OUT_A2_PIO_1_28 {1, 28, LPC_IO_FUNC_ALT1}
+#define LPC_MCTRL_OUT_B2_PIO_1_29 {1, 29, LPC_IO_FUNC_ALT1}
+
+
+/****************************************************************************/
+/*  USB Pins  */
+#define LPC_USB_SDA_PIO_0_27        {0, 27, LPC_IO_FUNC_ALT2}
+#define LPC_USB_SCL_PIO_0_28        {0, 28, LPC_IO_FUNC_ALT2}
+#define LPC_USB_DP_PIO_0_29         {0, 29, LPC_IO_FUNC_ALT1}
+#define LPC_USB_DM_PIO_0_30         {0, 30, LPC_IO_FUNC_ALT1}
+#define LPC_USB_UP_LED_PIO_1_18     {1, 18, LPC_IO_FUNC_ALT1}
+#define LPC_USB_PPWR_PIO_1_19       {1, 19, LPC_IO_FUNC_ALT2}
+#define LPC_USB_PWRD_PIO_1_22       {1, 22, LPC_IO_FUNC_ALT2}
+#define LPC_USB_OVRCR_PIO_1_27      {1, 27, LPC_IO_FUNC_ALT2}
+#define LPC_USB_VBUS_PIO_1_30       {1, 30, LPC_IO_FUNC_ALT2}
+#define LPC_USB_CONNECT_PIO_2_9     {2,  9, LPC_IO_FUNC_ALT1}
+
+
+/****************************************************************************/
+/*  Ethernet Pins  */
+#define LPC_ETHER_TXD0_PIO_1_0     {1,  0, LPC_IO_FUNC_ALT1}
+#define LPC_ETHER_TXD1_PIO_1_1     {1,  1, LPC_IO_FUNC_ALT1}
+#define LPC_ETHER_TX_EN_PIO_1_4    {1,  4, LPC_IO_FUNC_ALT1}
+#define LPC_ETHER_CRS_PIO_1_8      {1,  8, LPC_IO_FUNC_ALT1}
+#define LPC_ETHER_RXD0_PIO_1_9     {1,  9, LPC_IO_FUNC_ALT1}
+#define LPC_ETHER_RXD1_PIO_1_10    {1, 10, LPC_IO_FUNC_ALT1}
+#define LPC_ETHER_RX_ER_PIO_1_14   {1, 14, LPC_IO_FUNC_ALT1}
+#define LPC_ETHER_REF_CLK_PIO_1_15 {1, 15, LPC_IO_FUNC_ALT1}
+/* MMII option 1 */
+#define LPC_ETHER_MDC_PIO_1_16     {1, 16, LPC_IO_FUNC_ALT1}
+#define LPC_ETHER_MDIO_PIO_1_17    {1, 17, LPC_IO_FUNC_ALT1}
+/* MMII option 2 */
+#define LPC_ETHER_MDC_PIO_2_8      {2,  8, LPC_IO_FUNC_ALT3}
+#define LPC_ETHER_MDIO_PIO_2_9     {2,  9, LPC_IO_FUNC_ALT3}
+
+
+#endif /* CORE_PIO_H */
diff --git a/include/core/system.h b/include/core/system.h
new file mode 100644 (file)
index 0000000..ff7c87c
--- /dev/null
@@ -0,0 +1,111 @@
+/****************************************************************************
+ *   core/system.h
+ *
+ * All low-level functions for clocks configuration and switch, system
+ *  power-up, reset, and power-down.
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef CORE_SYSTEM_H
+#define CORE_SYSTEM_H
+
+#include <stdint.h>
+#include "lib/stddef.h"
+#include "lib/errno.h"
+
+#include "core/lpc_regs_17xx.h"
+#include "core/lpc_core_cm3.h"
+
+
+
+/***************************************************************************** */
+/*                     Required system inits                                  */
+/***************************************************************************** */
+/* Stop the watchdog */
+void stop_watchdog(void);
+
+/* Configure the brown-out detection. */
+void system_brown_out_detection_config(uint32_t level);
+
+
+
+/***************************************************************************** */
+/*            Peripheral Power and Clocks                                      */
+/***************************************************************************** */
+/* Change reset power state to our default, removing power from unused (all but
+ *  the RTC and GPIO) interfaces
+ */
+void system_set_default_power_state(void);
+
+/* Set the Peripheral Clock divider in PCLKSEL0 and PCLKSEL1
+ * The default value at reset is LPC_PCLK_CCLK_QUARTER which divides the CCLK by 4.
+ */
+void set_subsystem_clk_divider(uint32_t subsystem, uint32_t clk_div);
+
+/* Power ON or OFF a subsystem
+ * Power OFF if 'on_off' is 0, turn ON otherwise
+ * 'power_bit' uses defines from core/lpc_regs_17xx.h : LPC_xxxx_POWER_ON
+ */
+void subsystem_power(uint32_t power_bit, uint32_t on_off);
+
+
+/***************************************************************************** */
+/* Sleep and power-down modes */
+/* There are four sleep / power down modes in the LPC176x micro-controller
+ *   Sleep - Deep Sleep - Power Down - Deep Power Down
+ *
+ * Note : Refer to chapter 4.8 'Power control' page 58 and following ones in UM10360 User manual
+ */
+
+/* Enter deep sleep. */
+void enter_deep_sleep(void);
+
+/***************************************************************************** */
+/*                      System Clock                                           */
+/***************************************************************************** */
+/* A clock frequency is defined as the integer value in MHz shifted by 3 and or'ed
+ * with the value to be programmed in the flash config register for the flash access
+ * time at the given frequency */
+#define FREQ_SEL_100MHz  ((100 << 3) | 0x04)
+#define FREQ_SEL_72MHz   (( 72 << 3) | 0x03)
+#define FREQ_SEL_60MHz   (( 60 << 3) | 0x02)
+#define FREQ_SEL_50MHz   (( 50 << 3) | 0x02)
+#define FREQ_SEL_48MHz   (( 48 << 3) | 0x02)
+
+
+/* Main clock config
+ * We use external crystal and PLL0
+ * Note that during PLL lock wait we are running on internal RC
+ */
+void clock_config(uint32_t freq_sel);
+
+/* return current main clock in HZ */
+uint32_t get_main_clock(void);
+
+
+/* This is mainly a debug feature, but can be used to provide a clock to an
+ * external peripheral */
+void clkout_on(uint32_t src, uint32_t div);
+void clkout_off(void);
+
+void msleep(uint32_t ms);
+void usleep(uint32_t us);
+
+
+#endif /* CORE_SYSTEM_H */
diff --git a/include/core/systick.h b/include/core/systick.h
new file mode 100644 (file)
index 0000000..4d5a527
--- /dev/null
@@ -0,0 +1,94 @@
+/****************************************************************************
+ *   core/systick.h
+ *
+ * All low-level functions for clocks configuration and switch, system
+ *  power-up, reset, and power-down.
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef CORE_SYSTICK_H
+#define CORE_SYSTICK_H
+
+#include <stdint.h>
+
+/***************************************************************************** */
+/*               System Tick Timer                                             */
+/***************************************************************************** */
+
+/* Start the system tick timer
+ * Starting the systick timer also resets the internal tick counters.
+ * If you need a value that goes beyond one start/stop cycle and accross resets,
+ *    then it's up to you to keep track of this using systick_get_tick_count() and/or
+ *    systick_get_clock_cycles().
+ */
+void systick_start(void);
+
+/* Stop the system tick timer */
+void systick_stop(void);
+
+/* Reset the system tick timer, making it count down from the reload value again
+ * Reseting the systick timer also resets the internal tick counters.
+ * If you need a value that goes beyond one start/stop cycle and accross resets,
+ *    then it's up to you to keep track of this using systick_get_tick_count() and/or
+ *    systick_get_clock_cycles().
+ */
+void systick_reset(void);
+
+/* Get system tick timer current value (counts at get_main_clock() !) */
+uint32_t systick_get_timer_val(void);
+
+/* Check if systick is running (return 1) or not (return 0) */
+uint32_t is_systick_running(void);
+
+/* Get the system tick period in ms
+ * A vaue of 0 means the system tick timer has not been configured.
+ * Note : calls to msleep() or usleep() will configure the system tick timer
+ *        with a value of 1ms if it was not configured yet.
+ */
+uint32_t systick_get_tick_ms_period(void);
+
+/* Get the number of system ticks ... since last wrapping of the counter, which
+ * is about 50 days with a 1ms system tick. */
+uint32_t systick_get_tick_count(void);
+
+/* Get the number of clock cycles ... since last wrapping of the counter. */
+uint32_t systick_get_clock_cycles(void);
+
+/* Power up the system tick timer.
+ * ms is the interval between system tick timer interrupts. If set to 0, the default
+ *     value is used, which should provide a 1ms period.
+ */
+void systick_timer_on(uint32_t ms);
+
+/* Removes the main clock from the selected timer block */
+void systick_timer_off(void);
+
+/* Register a callback to be called every 'period' system ticks.
+ * returns the callback number if registration was OK.
+ * returns negative value on error.
+ * The callback will get the "global_wrapping_system_ticks" as argument, which wraps every 50 days
+ *   or so with a 1ms tick
+ */
+#define MAX_SYSTICK_CALLBACKS  4
+int add_systick_callback(void (*callback) (uint32_t), uint16_t period);
+/* Remove a registered callback, given the callback address used to register it. */
+int remove_systick_callback(void (*callback) (uint32_t));
+
+
+#endif /* CORE_SYSTICK_H */
diff --git a/include/drivers/adc.h b/include/drivers/adc.h
new file mode 100644 (file)
index 0000000..0230f65
--- /dev/null
@@ -0,0 +1,81 @@
+/****************************************************************************
+ *  drivers/adc.h
+ *
+ * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef DRIVERS_ADC_H
+#define DRIVERS_ADC_H
+
+
+#include <stdint.h>
+
+/***************************************************************************** */
+/*                Analog to Digital Converter (ADC)                            */
+/***************************************************************************** */
+
+enum adc_events {
+       /* CT32B0 */
+       ADC_CONV_ON_CT32B0_CAP0_RISING,
+       ADC_CONV_ON_CT32B0_CAP0_FALLING,
+       ADC_CONV_ON_CT32B0_MAT0_RISING,
+       ADC_CONV_ON_CT32B0_MAT0_FALLING,
+       ADC_CONV_ON_CT32B0_MAT1_RISING,
+       ADC_CONV_ON_CT32B0_MAT1_FALLING,
+       /* CT16B0 */
+       ADC_CONV_ON_CT16B0_CAP0_RISING,
+       ADC_CONV_ON_CT16B0_CAP0_FALLING,
+       ADC_CONV_ON_CT16B0_MAT0_RISING,
+       ADC_CONV_ON_CT16B0_MAT0_FALLING,
+       ADC_CONV_ON_CT16B0_MAT1_RISING,
+       ADC_CONV_ON_CT16B0_MAT1_FALLING,
+};
+
+
+/* Read the conversion from the given channel (0 to 7)
+ * This function reads the conversion value directly in the data register and
+ * always returns a value.
+ * Return 1 if the value is a new one, else return 0.
+ * Return -1 if channel does not exist
+ */
+int adc_get_value(uint16_t * val, int channel);
+
+/* Start a conversion on the given channel (0 to 7)
+ * Unsupported yet : Set use_int to 1 to have your interrupt callback called upon conversion done.
+ */
+void adc_start_convertion_once(unsigned int channel, int use_int);
+
+/* Start burst conversions.
+ * channels is a bit mask of requested channels.
+ * Use LPC_ADC_CHANNEL(x) (x = 0 .. 7) for channels selection.
+ */
+void adc_start_burst_conversion(uint8_t channels);
+
+/* This should be used to configure conversion start on falling or rising edges of
+ * some signals, or on timer for burst conversions.
+ */
+void adc_prepare_conversion_on_event(uint8_t channels, uint8_t event, int use_int);
+
+
+/***************************************************************************** */