Initial commit, code based on LPC1224 support and LPC812-MAX CMSIS-DAP interface...
authorNathael Pajani <nathael.pajani@ed3l.fr>
Wed, 16 Sep 2015 07:30:37 +0000 (09:30 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Wed, 16 Sep 2015 07:30:37 +0000 (09:30 +0200)
54 files changed:
.gitignore [new file with mode: 0644]
LICENCE.Apache [new file with mode: 0644]
LICENCE.GPL [new file with mode: 0644]
Makefile [new file with mode: 0644]
NOTICE [new file with mode: 0644]
README [new file with mode: 0644]
apps/mbed_lpc1224/chenillard/Makefile [new file with mode: 0644]
apps/mbed_lpc1224/chenillard/README [new file with mode: 0644]
apps/mbed_lpc1224/chenillard/main.c [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]
core/vector_table.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]
extdrv/eeprom.c [new file with mode: 0644]
extdrv/status_led.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_cm0.h [new file with mode: 0644]
include/core/lpc_regs_11u3x.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/extdrv/eeprom.h [new file with mode: 0644]
include/extdrv/status_led.h [new file with mode: 0644]
include/extdrv/tmp101_temp_sensor.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/stdlib.h [new file with mode: 0644]
include/lib/string.h [new file with mode: 0644]
include/lib/time.h [new file with mode: 0644]
include/lib/utils.h [new file with mode: 0644]
lib/stdlib.c [new file with mode: 0644]
lib/string.c [new file with mode: 0644]
lib/time.c [new file with mode: 0644]
lib/uprintf.c [new file with mode: 0644]
lib/utils.c [new file with mode: 0644]
lib/vsprintf.c [new file with mode: 0644]
lpc_link_lpc11u35.ld [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..3f3c65a
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# 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
+tags
diff --git a/LICENCE.Apache b/LICENCE.Apache
new file mode 100644 (file)
index 0000000..37ec93a
--- /dev/null
@@ -0,0 +1,191 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "[]" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification within
+third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/LICENCE.GPL b/LICENCE.GPL
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
@@ -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..32e5871
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,79 @@
+# Makefile for GPIO Demo Module
+
+TARGET_DIR = apps/$(MODULE)/$(NAME)
+
+LPC = lpc11u35
+CPU = cortex-m0
+ARCH = armv6-m
+
+CROSS_COMPILE ?= arm-none-eabi-
+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 $(MODULE)/$(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 $@
+       @$(CROSS_COMPILE)size $^
+       @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 MODULE=$(shell dirname $@) NAME=$(shell basename $@) apps/$(shell dirname $@)/$(shell basename $@)/$(shell basename $@).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 module/app_name" does not work, as well
+# as the command "make -f /path/to/here/apps/module/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/ module/app_name" or "make -C /path/to/here/apps/module/app_name"
+# instead.
+
diff --git a/NOTICE b/NOTICE
new file mode 100644 (file)
index 0000000..c20b9a4
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,7 @@
+Some parts of this Work are derived from Work covered bu the Apache 2.0 licence.
+The concerned files are identified here, and may have been modified for the
+purpose of this work.
+Original work can be found there : https://github.com/mbedmicro/CMSIS-DAP.git
+
+core/vector_table.c : Copyright (c) 2009-2013 ARM Limited
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/apps/mbed_lpc1224/chenillard/Makefile b/apps/mbed_lpc1224/chenillard/Makefile
new file mode 100644 (file)
index 0000000..b3a5e89
--- /dev/null
@@ -0,0 +1,10 @@
+# Makefile for lpc11U35 mbed interface apps
+
+NAME = $(shell basename $(CURDIR))
+
+.PHONY: $(NAME).bin
+$(NAME).bin:
+       @make -C ../.. --no-print-directory NAME=$(NAME) apps/$(NAME)/$@
+
+clean mrproper:
+       @make -C ../.. --no-print-directory $@
diff --git a/apps/mbed_lpc1224/chenillard/README b/apps/mbed_lpc1224/chenillard/README
new file mode 100644 (file)
index 0000000..5f54c16
--- /dev/null
@@ -0,0 +1,23 @@
+LPC1224-mbed board gpio test
+
+Copyright 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/>.
+ *
+ *************************************************************************** */
+
+This code is used to test the support of the lpc11u35 internal modules.
+
diff --git a/apps/mbed_lpc1224/chenillard/main.c b/apps/mbed_lpc1224/chenillard/main.c
new file mode 100644 (file)
index 0000000..8b106b9
--- /dev/null
@@ -0,0 +1,161 @@
+/****************************************************************************
+ *   apps/mbed_lpc1224/chenillard/main.c
+ *
+ * LPC1224-mbed firmware for onboard LPC11U35 bridge
+ *
+ * Copyright 2013-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_11u3x.h"
+#include "core/lpc_core_cm0.h"
+#include "core/pio.h"
+#include "core/system.h"
+#include "core/systick.h"
+#include "lib/stdio.h"
+#include "drivers/serial.h"
+#include "drivers/gpio.h"
+#include "extdrv/status_led.h"
+
+
+#define MODULE_VERSION    0x02
+#define MODULE_NAME "LPC1224-mbed"
+
+
+#define SELECTED_FREQ  FREQ_SEL_48MHz
+
+/***************************************************************************** */
+/* Pins configuration */
+/* pins blocks are passed to set_pins() for pins configuration.
+ * Unused pin blocks can be removed safely with the corresponding set_pins() call
+ * All pins blocks may be safelly merged in a single block for single set_pins() call..
+ */
+const struct pio_config common_pins[] = {
+       /* UART 0 */
+       { LPC_UART0_RX_PIO_0_18,  LPC_IO_DIGITAL },
+       { LPC_UART0_TX_PIO_0_19,  LPC_IO_DIGITAL },
+       /* USB */
+       { LPC_USB_FTOGGLE_PIO_0_1, LPC_IO_DIGITAL },
+       { LPC_USB_VBUS_PIO_0_3, (LPC_IO_DIGITAL | LPC_IO_MODE_PULL_DOWN) },
+       { LPC_USB_CONNECT_PIO_0_6, LPC_IO_DIGITAL },
+       ARRAY_LAST_PIO,
+};
+
+const struct pio status_led_blue = LPC_GPIO_0_11; /* Serial */
+const struct pio status_led_red = LPC_GPIO_0_20; /* MSD */
+const struct pio status_led_green = LPC_GPIO_0_21; /* DAP */
+
+const struct pio button_target_reset = LPC_GPIO_0_1; /* ISP button for us */
+const struct pio button_target_isp = LPC_GPIO_0_17;
+
+const struct pio target_swd_swclk = LPC_GPIO_0_7;
+const struct pio target_swd_swdio = LPC_GPIO_0_8;
+
+
+
+uint8_t gpio_get_pin_loader_state(void)
+{
+       uint8_t* gpio_bytes = LPC_GPIO_ALL_BYTES;
+       uint8_t offset = ((button_target_reset.port << 5) + button_target_reset.pin);
+       return gpio_bytes[offset];
+}
+
+/***************************************************************************** */
+void system_init()
+{
+       /* Stop the watchdog */
+       stop_watchdog(); /* Do it right now, before it gets a chance to break in */
+       system_brown_out_detection_config(0);
+       system_set_default_power_state();
+       clock_config(SELECTED_FREQ, LPC_SYSCLK_SRC_XTAL_OSC);
+       set_pins(common_pins);
+       gpio_on();
+       status_led_config(&status_led_green, &status_led_red, &status_led_blue);
+       /* System tick timer MUST be configured and running in order to use the sleeping
+        * functions */
+       systick_timer_on(1); /* 1ms */
+       systick_start();
+}
+
+/* Define our fault handler. This one is not mandatory, the dummy fault handler
+ * will be used when it's not overridden here.
+ * Note : The default one does a simple infinite loop. If the watchdog is deactivated
+ * the system will hang.
+ */
+void fault_info(const char* name, uint32_t len)
+{
+       serial_write(0, name, len);
+       /*FIXME : wait for end of Tx and perform soft reset of the micro-controller ! */
+}
+
+
+volatile uint32_t flag = 0;
+void stop_leds(uint32_t num)
+{
+       flag = 1;
+}
+
+/***************************************************************************** */
+int main(void) {
+       system_init();
+       uart_on(0, 115200, NULL);
+
+       set_gpio_callback(stop_leds, 0, &button_target_isp, EDGES_BOTH);
+       set_gpio_callback(stop_leds, 1, &button_target_reset, EDGES_BOTH);
+
+       while (1) {
+               status_led(all);
+               msleep(500);
+               status_led(none);
+               msleep(200);
+               status_led(red_only);
+               msleep(200);
+               status_led(green_only);
+               msleep(200);
+               status_led(blue_only);
+               msleep(200);
+               status_led(red_only);
+               msleep(200);
+               status_led(green_only);
+               msleep(200);
+               status_led(blue_only);
+               msleep(200);
+               status_led(red_on);
+               msleep(200);
+               status_led(green_on);
+               msleep(200);
+               status_led(blue_on);
+               msleep(200);
+               status_led(red_off);
+               msleep(200);
+               status_led(green_off);
+               msleep(200);
+               status_led(none);
+               if (flag != 0) {
+                       msleep(2000);
+                       flag = 0;
+               } else {
+                       msleep(200);
+               }
+       }
+       return 0;
+}
+
+
+
diff --git a/core/bootstrap.c b/core/bootstrap.c
new file mode 100644 (file)
index 0000000..84d8f96
--- /dev/null
@@ -0,0 +1,167 @@
+/****************************************************************************
+ *   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 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")));
+/* LPC12xx specific interrupt handlers */
+void Pin_Int0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Pin_Int1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Pin_Int2_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Pin_Int3_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Pin_Int4_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Pin_Int5_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Pin_Int6_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void Pin_Int7_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void GPIO_GRP_INT0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void GPIO_GRP_INT1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void I2C_0_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 SSP_0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void SSP_1_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void UART_0_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void ADC_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void WDT_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 USB_FIQ_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void USB_Wakeup_Handler(void) __attribute__ ((weak, alias ("Dummy_Handler")));
+void FLASH_EEPROM_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,
+       0,
+       0, /* 5 */
+       0,
+       /* 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 */
+       /* LPC11U3x specific interrupt vectors, refer to chapter 6 of LPC11U3x User manual (UM10462) */
+       Pin_Int0_Handler,     /* 16 */ /* IRQ0 */
+       Pin_Int1_Handler,
+       Pin_Int2_Handler,
+       Pin_Int3_Handler,
+       Pin_Int4_Handler, /* 20 */
+       Pin_Int5_Handler, /* 21 */ /* IRQ5 */
+       Pin_Int6_Handler,
+       Pin_Int7_Handler,
+       GPIO_GRP_INT0_Handler,
+       GPIO_GRP_INT1_Handler, /* 25 */
+       0, /* 26 */ /* IRQ10 */
+       0,
+       0,
+       0,
+       SSP_1_Handler, /* 30 */
+       I2C_0_Handler, /* 31 */ /* IRQ15 */
+       TIMER_0_Handler, /* CT16B0 */
+       TIMER_1_Handler, /* CT16B1 */
+       TIMER_2_Handler, /* CT32B0 */
+       TIMER_3_Handler, /* CT32B1 */ /* 35 */
+       SSP_0_Handler, /* 36 */ /* IRQ20 */
+       UART_0_Handler,
+       USB_Handler,
+       USB_FIQ_Handler,
+       ADC_Handler, /* 40 */
+       WDT_Handler, /* 41 */ /* IRQ25 */
+       BOD_Handler,
+       FLASH_EEPROM_Handler,
+       0,
+       0, /* 45 */
+       USB_Wakeup_Handler,   /* 46 */ /* IRQ30 */
+       0,
+};
+
+
+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 division 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..f385c66
--- /dev/null
@@ -0,0 +1,52 @@
+/****************************************************************************
+ *   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_11u3x.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 M0 core interrupt handlers */
+void NMI_Handler(void)
+{
+       fault_info(__FUNCTION__, sizeof(__FUNCTION__));
+}
+void HardFault_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..ad55904
--- /dev/null
@@ -0,0 +1,101 @@
+/****************************************************************************
+ *   core/iap.c
+ *
+ *
+ * Copyright 2015 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This file is derived from Work covered by the Apache 2.0 licence.
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Original sources should be found there :
+ *     https://github.com/mbedmicro/CMSIS-DAP.git
+ * Original file name is bootloader/hal/TARGET_NXP/TARGET_LPC11U35/flash_hal.c
+ *
+ * Original copyright notice :
+ *    CMSIS-DAP Interface Firmware
+ *    Copyright (c) 2009-2013 ARM Limited
+ *
+ * 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 <stdint.h>
+#include "core/lpc_regs_11u3x.h"
+#include "core/iap.h"
+
+
+static uint32_t get_sector_number(uint32_t addr)
+{
+       uint32_t sector = 0;
+
+       sector = addr >> 12;  /* 4kB Sector */
+       if (sector >= 0x10) {
+               sector = 0x0E + (sector >> 3); /* 32kB Sector */
+       }
+
+       return sector;
+}
+
+/* Erase one sector, given a flash address
+ * return 0 on success.
+ */
+int flash_hal_erase_sector(uint32_t addr)
+{
+       uint32_t sector = get_sector_number(addr);
+       int ret = 0;
+
+       /* Prepare sector for erase */
+       ret = iap_prepare_flash(sector, sector);
+       if (ret != IAP_STATUS_CMD_SUCCESS) {
+               return ret;
+       }
+       /* Erase sector */
+       return iap_erase_flash_sectors(sector, sector);
+}
+
+/* Flash a binary image chunk to a sector. */
+int flash_hal_program_page(uint32_t addr, uint32_t sz, unsigned char *buf)
+{
+       uint32_t sector = 0;
+       int ret = 0;
+
+       /* If this goes to the beginning of the Flash image, check that the image is valid. */
+       if (addr == 0) {
+               uint32_t crp = *((uint32_t *)(buf + CRP_ADDRESS));
+               uint32_t checksum = 0;
+
+               if (IS_CRP_VALUE(crp)) {
+                       /* CRP is enabled, exit. */
+                       return -1;
+               }
+
+               /* Compute a valid user code */
+               checksum = *((uint32_t *)(buf + 0x00)) + *((uint32_t *)(buf + 0x04)) +
+                                       *((uint32_t *)(buf + 0x08)) + *((uint32_t *)(buf + 0x0C)) +
+                                       *((uint32_t *)(buf + 0x10)) + *((uint32_t *)(buf + 0x14)) +
+                                       *((uint32_t *)(buf + 0x18));
+               *((uint32_t *)(buf + 0x1C)) = 0 - checksum;
+       }
+
+       sector = get_sector_number(addr);
+
+       /* Prepare sector for write */
+       ret = iap_prepare_flash(sector, sector);
+       if (ret != IAP_STATUS_CMD_SUCCESS) {
+               return ret;
+       }
+
+       /* FIXME : in original code, size was hardcoded to 1024 */
+       return iap_copy_ram_to_flash(addr, (uint32_t)buf, sz);
+}
+
diff --git a/core/pio.c b/core/pio.c
new file mode 100644 (file)
index 0000000..48f0285
--- /dev/null
@@ -0,0 +1,148 @@
+/****************************************************************************
+ *  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_11u3x.h"
+#include "core/lpc_core_cm0.h"
+#include "core/system.h"
+#include "core/pio.h"
+
+
+
+/***************************************************************************** */
+static volatile uint32_t* pio_regs_handles_port0[PORT0_NB_PINS] = {
+       &(LPC_IO_CONTROL->pio0_0),
+       &(LPC_IO_CONTROL->pio0_1),
+       &(LPC_IO_CONTROL->pio0_2),
+       &(LPC_IO_CONTROL->pio0_3),
+       &(LPC_IO_CONTROL->pio0_4),
+       &(LPC_IO_CONTROL->pio0_5),
+       &(LPC_IO_CONTROL->pio0_6),
+       &(LPC_IO_CONTROL->pio0_7),
+       &(LPC_IO_CONTROL->pio0_8),
+       &(LPC_IO_CONTROL->pio0_9),
+       &(LPC_IO_CONTROL->pio0_10),
+       &(LPC_IO_CONTROL->pio0_11),
+       &(LPC_IO_CONTROL->pio0_12),
+       &(LPC_IO_CONTROL->pio0_13),
+       &(LPC_IO_CONTROL->pio0_14),
+       &(LPC_IO_CONTROL->pio0_15),
+       &(LPC_IO_CONTROL->pio0_16),
+       &(LPC_IO_CONTROL->pio0_17),
+       &(LPC_IO_CONTROL->pio0_18),
+       &(LPC_IO_CONTROL->pio0_19),
+       &(LPC_IO_CONTROL->pio0_20),
+       &(LPC_IO_CONTROL->pio0_21),
+       &(LPC_IO_CONTROL->pio0_22),
+       &(LPC_IO_CONTROL->pio0_23),
+};
+static volatile uint32_t* pio_regs_handles_port1[PORT1_NB_PINS] = {
+       &(LPC_IO_CONTROL->pio1_0),
+       &(LPC_IO_CONTROL->pio1_1),
+       &(LPC_IO_CONTROL->pio1_2),
+       &(LPC_IO_CONTROL->pio1_3),
+       &(LPC_IO_CONTROL->pio1_4),
+       &(LPC_IO_CONTROL->pio1_5),
+       &(LPC_IO_CONTROL->pio1_6),
+       &(LPC_IO_CONTROL->pio1_7),
+       &(LPC_IO_CONTROL->pio1_8),
+       &(LPC_IO_CONTROL->pio1_9),
+       &(LPC_IO_CONTROL->pio1_10),
+       &(LPC_IO_CONTROL->pio1_11),
+       &(LPC_IO_CONTROL->pio1_12),
+       &(LPC_IO_CONTROL->pio1_13),
+       &(LPC_IO_CONTROL->pio1_14),
+       &(LPC_IO_CONTROL->pio1_15),
+       &(LPC_IO_CONTROL->pio1_16),
+       &(LPC_IO_CONTROL->pio1_17),
+       &(LPC_IO_CONTROL->pio1_18),
+       &(LPC_IO_CONTROL->pio1_19),
+       &(LPC_IO_CONTROL->pio1_20),
+       &(LPC_IO_CONTROL->pio1_21),
+       &(LPC_IO_CONTROL->pio1_22),
+       &(LPC_IO_CONTROL->pio1_23),
+       &(LPC_IO_CONTROL->pio1_24),
+       &(LPC_IO_CONTROL->pio1_25),
+       &(LPC_IO_CONTROL->pio1_26),
+       &(LPC_IO_CONTROL->pio1_27),
+       &(LPC_IO_CONTROL->pio1_28),
+       &(LPC_IO_CONTROL->pio1_29),
+       0,
+       &(LPC_IO_CONTROL->pio1_31),
+};
+
+/* 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)
+{
+       volatile uint32_t* handle = NULL;
+
+       if (pp == NULL) {
+               return;
+       }
+       switch (pp->port) {
+               case 0:
+                       if (pp->pin >= PORT0_NB_PINS)
+                               return;
+                       handle = pio_regs_handles_port0[pp->pin];
+                       break;
+               case 1:
+                       if (pp->pin >= PORT1_NB_PINS)
+                               return;
+                       handle = pio_regs_handles_port1[pp->pin];
+                       break;
+               default:
+                       return;
+       }
+       /* Make sure IO_Config is clocked */
+       io_config_clk_on();
+
+       *handle = (LPC_IO_FUNC_ALT(pp->alt_setting) | mode);
+
+       /* Config done, power off IO_CONFIG block */
+       io_config_clk_off();
+}
+
+
+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..34f436d
--- /dev/null
@@ -0,0 +1,223 @@
+/****************************************************************************
+ *   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_cm0.h"
+#include "core/iap.h"
+#include "lib/string.h"
+
+/*******************************************************************************/
+/*            Integer division using ROM based division routines               */
+/*******************************************************************************/
+
+struct idiv_return {
+       int quotient;
+       int remainder;
+};
+struct uidiv_return {
+       unsigned quotient;
+       unsigned remainder;
+};
+
+struct lpc_rom_div_helpers {
+       /* Signed integer division */
+       int (*rom_sidiv)(int numerator, int denominator);
+       /* Unsigned integer division */
+       unsigned (*rom_uidiv)(unsigned numerator, unsigned denominator);
+       /* Signed integer division with remainder */
+       struct idiv_return (*rom_sidivmod)(int numerator, int denominator);
+       /* Unsigned integer division with remainder */
+       struct uidiv_return (*rom_uidivmod)(unsigned numerator, unsigned denominator);
+};
+
+static struct lpc_rom_div_helpers* rom_div_helpers;
+
+/* Division (/) */
+int __aeabi_idiv(int numerator, int denominator)
+{
+       return rom_div_helpers->rom_sidiv(numerator, denominator);
+}
+unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator)
+{
+       return rom_div_helpers->rom_uidiv(numerator, denominator);
+}
+
+/* Modulo (%) */
+void __aeabi_idivmod(int numerator, int denominator)
+{
+       struct idiv_return result = rom_div_helpers->rom_sidivmod(numerator, denominator);
+       register uint32_t r0 asm("r0") = result.quotient;
+       register uint32_t r1 asm("r1") = result.remainder;
+       asm volatile("" : "+r"(r0), "+r"(r1) : "r"(r0), "r"(r1));
+}
+void __aeabi_uidivmod(unsigned numerator, unsigned denominator)
+{
+       struct uidiv_return result = rom_div_helpers->rom_uidivmod(numerator, denominator);
+       register uint32_t r0 asm("r0") = result.quotient;
+       register uint32_t r1 asm("r1") = result.remainder;
+       asm volatile("" : "+r"(r0), "+r"(r1) : "r"(r0), "r"(r1));
+}
+
+
+/*******************************************************************************/
+/*            In Application Programming ROM based routines                    */
+/*******************************************************************************/
+
+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,
+       IAP_CMD_ERASE_PAGE = 59,
+       IAP_CMD_ERASE_INFO_PAGE = 60,
+       IAP_CMD_EEPROM_WRITE = 61,
+       IAP_CMD_EEPROM_READ = 62,
+};
+
+typedef void (*iap_entry_func)(uint32_t*, uint32_t*);
+static iap_entry_func iap_entry;
+
+static uint32_t params[5];
+static uint32_t results[5];
+
+
+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_erase_flash_pages(uint32_t start_page, uint32_t end_page)
+{
+       params[0] = IAP_CMD_ERASE_PAGE;
+       params[1] = start_page;
+       params[2] = end_page;
+       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];
+}
+
+uint32_t iap_read_unique_id(uint32_t* uid_table)
+{
+       params[0] = IAP_CMD_READ_UID;
+       iap_entry(params, results);
+       memcpy(uid_table, &(results[1]), (4 * 4));
+       return results[0];
+}
+
+int iap_eeprom_write(uint8_t* eeprom_addr, uint8_t* ram_addr, uint32_t length)
+{
+       params[0] = IAP_CMD_EEPROM_WRITE;
+       params[1] = (uint32_t)eeprom_addr;
+       params[2] = (uint32_t)ram_addr;
+       params[2] = length;
+       params[4] = (get_main_clock() / 1000);
+       results[0] = 69;
+       lpc_disable_irq();
+       iap_entry(params, results);
+       lpc_enable_irq();
+       return results[0];
+}
+
+int iap_eeprom_read(uint8_t* eeprom_addr, uint8_t* ram_addr, uint32_t length)
+{
+       params[0] = IAP_CMD_EEPROM_READ;
+       params[1] = (uint32_t)eeprom_addr;
+       params[2] = (uint32_t)ram_addr;
+       params[2] = length;
+       params[4] = (get_main_clock() / 1000);
+       results[0] = 69;
+       lpc_disable_irq();
+       iap_entry(params, results);
+       lpc_enable_irq();
+       return results[0];
+}
+
+
+/*******************************************************************************/
+/*            Rom based routines initialisation                                */
+/*******************************************************************************/
+#define LPC_11U3x_ROM_HELPERS (0x1FFF1FF8)
+#define LPC_11U3x_IAP_ROM_LOC (0x1FFF1FF1)
+
+struct rom_helpers {
+       const unsigned p_dev0;
+       const unsigned p_dev1;
+       const unsigned p_dev2;
+       const unsigned p_dev3;
+       const unsigned rom_div;
+       const unsigned p_dev5;
+       const unsigned p_dev6;
+       const unsigned p_dev7;
+};
+
+#define ROM_DRIVERS ((struct rom_helpers *)(*((uint32_t *)LPC_11U3x_ROM_HELPERS)))
+
+
+void rom_helpers_init(void)
+{
+       rom_div_helpers = (struct lpc_rom_div_helpers*)(ROM_DRIVERS->rom_div);
+       iap_entry = (iap_entry_func)LPC_11U3x_IAP_ROM_LOC;
+}
+
+
+
diff --git a/core/system.c b/core/system.c
new file mode 100644 (file)
index 0000000..2772b76
--- /dev/null
@@ -0,0 +1,399 @@
+/****************************************************************************
+ *   core/system.c
+ *
+ * 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_11u3x.h"
+#include "core/lpc_core_cm0.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "drivers/timers.h" /* Used for IRC calibration */
+
+
+/* Private defines */
+#define LPC_IRC_OSC_CLK  (12000000UL)  /* Internal RC oscillator frequency : 12MHz */
+
+/***************************************************************************** */
+/*                     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 20.16.4.4 of
+ *  LPC11U3x User manual (UM10462.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;
+
+       /* Set flash access time. Other bits MUST NOT be changed */
+       fcfg->flash_cfg &= ~(LPC_FLASH_CFG_MASK);
+       fcfg->flash_cfg |= (freq_sel & 0x03);
+}
+
+/* Stop the watchdog */
+void stop_watchdog(void)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+    struct lpc_watchdog* wdt = LPC_WDT;
+
+       /* Power wadchdog block before changing it's configuration */
+       if (! (sys_ctrl->sys_AHB_clk_ctrl & LPC_SYS_ABH_CLK_CTRL_Watchdog)) {
+               sys_ctrl->sys_AHB_clk_ctrl |= LPC_SYS_ABH_CLK_CTRL_Watchdog;
+       }
+       /* Stop watchdog */
+    wdt->mode = 0;
+    wdt->feed_seqence = 0xAA;
+    wdt->feed_seqence = 0x55;
+       /* And power it down */
+       sys_ctrl->sys_AHB_clk_ctrl &= ~(LPC_SYS_ABH_CLK_CTRL_Watchdog);
+       sys_ctrl->powerdown_run_cfg |= LPC_POWER_DOWN_WDT_OSC;
+}
+
+/* Configure the brown-out detection */
+void system_brown_out_detection_config(uint32_t level)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+
+       if (level == 0) {
+               /* Disable Brown-Out Detection, power it down */
+               sys_ctrl->powerdown_run_cfg |= LPC_POWER_DOWN_BOD;
+               lpc_private.brown_out_detection_enabled = 0;
+       } else {
+               /* Power on Brown-Out Detection. */
+               sys_ctrl->powerdown_run_cfg &= ~(LPC_POWER_DOWN_BOD);
+               lpc_private.brown_out_detection_enabled = 1;
+               /* Configure Brown-Out Detection */
+               /* FIXME */
+       }
+}
+
+/***************************************************************************** */
+/*                       Power                                                 */
+/***************************************************************************** */
+/* Set up power-down control
+ * Change reset power state to our default, removing power from unused interfaces
+ */
+void system_set_default_power_state(void)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       /* Start with all memory powered on and nothing else */
+       sys_ctrl->sys_AHB_clk_ctrl = LPC_SYS_ABH_CLK_CTRL_MEM_ALL;
+}
+
+/* Enter deep sleep.
+ * NOTE : entering deep sleep implies a lot of side effects. I'll try to list them all here
+ */
+void enter_deep_sleep(void)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+
+       /* Ask for the same clock status when waking up */
+       sys_ctrl->powerdown_awake_cfg = sys_ctrl->powerdown_run_cfg;
+       /* Set deep_sleep config */
+       if (lpc_private.brown_out_detection_enabled) {
+               sys_ctrl->powerdown_sleep_cfg = LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_ON;
+       } else {
+               sys_ctrl->powerdown_sleep_cfg = LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_OFF;
+       }
+       /* Enter deep sleep */
+       /* FIXME */
+}
+
+/* Power on or off a subsystem */
+void subsystem_power(uint32_t power_bit, uint32_t on_off)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       if (on_off == 1) {
+               sys_ctrl->sys_AHB_clk_ctrl |= power_bit;
+       } else {
+               sys_ctrl->sys_AHB_clk_ctrl &= ~(power_bit);
+       }
+}
+
+/***************************************************************************** */
+/*                      System Clock                                           */
+/***************************************************************************** */
+static void propagate_main_clock(void);
+
+/* Main clock config : set up the system clock
+ * We use requested oscilator as sys_pllclkin if pll is ussed (LPC_CLK_SRC_*)
+ * Note that during PLL lock wait we are running on internal RC
+ * Note for M and P calculation :
+ *          FCCO must be between 156MHz and 320MHz
+ *          M ranges from 1 to 32, steps of 1, M = Freq_out / Freq_in
+ *          P ranges from 1 to 8, P must be a power of two, FCCO = 2 * P * Freq_out
+ *          Freq_out < 100 MHz
+ *          Freq_in is between 10 and 25 MHz
+ *          M = Freq_out / Freq_in
+ *
+ * freq_sel : set to one of the predefined values. See core/system.h
+ * clk_src
+ */
+void clock_config(uint32_t freq_sel, uint32_t clk_src)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+
+       lpc_disable_irq();
+       /* Turn on IRC */
+       sys_ctrl->powerdown_run_cfg &= ~(LPC_POWER_DOWN_IRC);
+       sys_ctrl->powerdown_run_cfg &= ~(LPC_POWER_DOWN_IRC_OUT);
+       /* Use IRC clock source for main clock during config */
+       sys_ctrl->main_clk_sel = LPC_SYSCLK_SRC_IRC_OSC;
+       /* Switch the main clock source */
+       sys_ctrl->main_clk_upd_en = 0;
+       sys_ctrl->main_clk_upd_en = 1;
+
+       /* Set AHB clock divider : divide by one ... */
+       sys_ctrl->sys_AHB_clk_div = 1;
+       /* Configure number of CPU clocks for flash access before setting the new clock */
+       flash_accelerator_config(freq_sel);
+
+       /* power off PLL */
+       sys_ctrl->powerdown_run_cfg |= LPC_POWER_DOWN_SYSPLL;
+
+       /* If using only internal RC, we are done */
+       if (freq_sel == FREQ_SEL_IRC) {
+               lpc_private.main_clock = LPC_IRC_OSC_CLK;
+       } else {
+               uint32_t M = ((freq_sel >> 3) & 0xFF);
+               uint32_t N = 0; /* P = 2 ^ N */
+
+               /* Select value for N */
+               switch (freq_sel) {
+                       case 3: /* FREQ_SEL_36MHz */
+                       case 2: /* FREQ_SEL_24MHz */
+                       case 1: /* FREQ_SEL_12MHz */ /* FIXME : check and test this one */
+                               N = 2; /* P = 4 */
+                               break;
+                       default: /* 48MHz to 60 MHz */
+                               N = 1; /* P = 2 */
+                               break;
+               }
+               lpc_private.main_clock = (((freq_sel >> 3) & 0xFF) * 12 * 1000 * 1000);
+               /* Setup PLL dividers */
+               sys_ctrl->sys_pll_ctrl = (((M - 1) & 0x1F) | (N << 5));
+               /* Turn power on/off for external crystal */
+               if (clk_src == LPC_SYSCLK_SRC_XTAL_OSC) {
+                       sys_ctrl->powerdown_run_cfg &= ~(LPC_POWER_DOWN_SYS_OSC);
+               } else {
+                       sys_ctrl->powerdown_run_cfg |= LPC_POWER_DOWN_SYS_OSC;
+               }
+               /* Set sys_pll_clk to selected source */
+               sys_ctrl->sys_pll_clk_sel = clk_src;
+               sys_ctrl->sys_pll_clk_upd_en = 0;  /* SYSPLLCLKUEN must go from LOW to HIGH */
+               sys_ctrl->sys_pll_clk_upd_en = 1;
+               /* Power-up PLL */
+               sys_ctrl->powerdown_run_cfg &= ~(LPC_POWER_DOWN_SYSPLL);
+               /* Wait Until PLL Locked */
+               while (!(sys_ctrl->sys_pll_status & 0x01));
+               /* Use PLL output as main clock */
+               sys_ctrl->main_clk_sel = LPC_SYSCLK_SRC_PLL_OUTPUT;
+               /* Switch the main clock source */
+               sys_ctrl->main_clk_upd_en = 0;
+               sys_ctrl->main_clk_upd_en = 1;
+       }
+
+       /* And call all clock updaters */
+       /* FIXME */
+       propagate_main_clock();
+       /* Turn interrupts on once again*/
+       lpc_enable_irq();
+}
+
+uint32_t get_main_clock(void)
+{
+       return lpc_private.main_clock;
+}
+
+
+/***************************************************************************** */
+/* Calibrate Internal RC Clock based on the 32-bit timer0 counter
+ *  and an external high precision 1ms interrupt.
+ */
+
+volatile uint32_t irc_trim_timer_num = 0;
+volatile uint32_t trim_timer_started = 0;  /* 0 is not started, 1 is started */
+
+/* These values are configurerd for a system running at 48MHz and a timer counting
+ * at main_clk.
+ */
+volatile uint32_t trim_calibration_ref = 48000;
+volatile uint32_t trim_calibration_delta = 120; /* USB low speed allows 0.25% error */
+
+/* Below are for debug purposes. */
+volatile uint32_t trimming_inc_count = 0;
+volatile uint32_t trimming_dec_count = 0;
+volatile uint32_t trimming_no_change = 0;
+
+void IRC_osc_calibration_init(uint32_t timer_num, uint32_t precision)
+{
+       /* FIXME : configure timer as counter */
+       irc_trim_timer_num = timer_num;
+       /* FIXME : Set trim_calibration_ref and trim_calibration_delta depending on
+        *         counter clock
+        */
+       trim_timer_started = 1;
+}
+void IRC_osc_calibration_done(void)
+{
+       /* FIXME : turn off timer */
+       trim_timer_started = 0;
+}
+
+/* Move IRC trim value depending on delta.
+ * Return the number of trim cycles without modifications or -1 if no modifications were
+ *   possible (already at maximum trim value)
+ * Return -2 if trimming has not been initiated with a call to IRC_osc_calibration_init()
+ */
+int IRC_osc_calibration(void)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       uint32_t timer_val = timer_get_counter_val(irc_trim_timer_num);
+
+       if (trim_timer_started == 0) {
+               return -2;
+       }
+       if (timer_val > (trim_calibration_ref + trim_calibration_delta)) {
+               if ((sys_ctrl->IRC_ctrl & 0xFFFF) == 0) {
+                       /* We cannot do better trimming ... */
+                       return -1;
+               }
+               sys_ctrl->IRC_ctrl--;
+               trimming_dec_count++;
+       } else if (timer_val < (trim_calibration_ref - trim_calibration_delta)) {
+               if ((sys_ctrl->IRC_ctrl & 0xFFFF) == 0xFFFF) {
+                       /* We cannot do better trimming ... */
+                       return -1;
+               }
+               sys_ctrl->IRC_ctrl++;
+               trimming_inc_count;
+       } else {
+               trimming_no_change++;
+       }
+       return trimming_no_change;
+}
+
+/***************************************************************************** */
+/*                     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();
+}
+
+/* IO config clock */
+/* To change GPIO config the io config block must be powered on */
+void io_config_clk_on(void)
+{
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_IO_CONFIG, 1);
+}
+void io_config_clk_off(void)
+{
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_IO_CONFIG, 0);
+}
+
+/***************************************************************************** */
+/*                    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.
+ */
+
+void clkout_on(uint32_t src, uint32_t div)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+
+       /* Select clk_out clock source */
+       sys_ctrl->clk_out_src_sel = (src & 0x03);
+       /* Activate clk_out */
+       sys_ctrl->clk_out_div = (div & 0xFF);
+       sys_ctrl->clk_out_upd_en = 0;
+       sys_ctrl->clk_out_upd_en = 1;
+}
+void clkout_off(void)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       sys_ctrl->clk_out_div = 0; /* Disable CLKOUT */
+       sys_ctrl->clk_out_upd_en = 0;
+       sys_ctrl->clk_out_upd_en = 1;
+}
+
+
+/***************************************************************************** */
+/*                    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..fcdf43e
--- /dev/null
@@ -0,0 +1,366 @@
+/****************************************************************************
+ *  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_11u3x.h"
+#include "core/lpc_core_cm0.h"
+#include "core/system.h"
+#include "core/systick.h"
+
+
+/* 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;
+static uint32_t usleep_us_count = 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() !)
+ * systick_get_timer_val returns a value between 0 and systick_get_timer_reload_val()
+ */
+uint32_t systick_get_timer_val(void)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       return systick->value;
+}
+/* Get system tick timer reload value */
+uint32_t systick_get_timer_reload_val(void)
+{
+       return tick_reload;
+}
+
+/* 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.
+ * Note : The LPC11U3x allows use of the core clock instead of half of the core clock a clock
+ *     source. It is not used here. To activate it remove the reload division (shift) and set
+ *     systick->control to the right value (set bit 2 : LPC_SYSTICK_CTRL_CLK_MAIN)
+ */
+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;
+       }
+       /* We use half the frequency of the system clock as input to the system tick 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;
+
+       /* Perform this division now for the usleep function. */
+       usleep_us_count = get_main_clock() / (1000 * 1000);
+       /* We use half the frequency of the system clock as input to the system tick clock */
+       usleep_us_count = (usleep_us_count >> 1); /* Divide by two */
+
+       /* 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 ....
+ */
+static inline void set_sleep(uint32_t ticks)
+{
+       sleep_count = ticks;
+}
+
+/* Actual sleep function, checks that system tick counter is configured to generate
+ * an interrupt and 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();
+}
+
+/* This usleep function tries to sleep at most the required amount of time.
+ * The setup is so long that it cannot sleep for less than 10us when running at 48MHz
+ */
+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 = usleep_us_count * us;
+        /* Remember that systick is a decrementing counter */
+       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 remaining part of 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));
+       }
+}
+
+void usleep_short(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 = usleep_us_count * us;
+       uint32_t end = systick_counted_to_zero(); /* Erase loop indicator */
+
+        /* Remember that systick is a decrementing counter */
+       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 remaining part of 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/core/vector_table.c b/core/vector_table.c
new file mode 100644 (file)
index 0000000..98eebb5
--- /dev/null
@@ -0,0 +1,54 @@
+/****************************************************************************
+ *   core/vector_table.c
+ *
+ *
+ * Copyright 2015 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ * This file is derived from Work covered by the Apache 2.0 licence.
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Original sources should be found there :
+ *     https://github.com/mbedmicro/CMSIS-DAP.git
+ * Original file name is bootloader/hal/TARGET_NXP/TARGET_LPC11U35/vector_table.c
+ *
+ * Original copyright notice :
+ *    CMSIS-DAP Interface Firmware
+ *    Copyright (c) 2009-2013 ARM Limited
+ *
+ * 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 <stdint.h>
+#include "core/lpc_regs_11u3x.h"
+#include "core/iap.h"
+
+#define NVIC_NUM_VECTORS (16 + 32)            /* CORE + MCU Peripherals */
+#define NVIC_RAM_VECTOR_ADDRESS (0x10000000)  /* Vectors positioned at start of RAM */
+
+void relocate_vector_table(void)
+{
+       struct lpc_sys_control* sysctrl = LPC_SYS_CONTROL;
+    int i;
+    /* Space for dynamic vectors, initialised to allocate in R/W */
+    static volatile uint32_t * vectors = (uint32_t*)NVIC_RAM_VECTOR_ADDRESS;
+
+    /* Copy and switch to dynamic vectors if first time called */
+    if((sysctrl->sys_mem_remap & 0x3) != 0x1) {
+        uint32_t *old_vectors = (uint32_t *)START_APP_ADDRESS;
+        for(i = 0; i < NVIC_NUM_VECTORS; i++) {
+            vectors[i] = old_vectors[i];
+        }
+               sysctrl->sys_mem_remap = 0x1;
+    }
+}
diff --git a/drivers/adc.c b/drivers/adc.c
new file mode 100644 (file)
index 0000000..5e1f33f
--- /dev/null
@@ -0,0 +1,240 @@
+/****************************************************************************
+ *  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_11u3x.h"
+#include "core/lpc_core_cm0.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "drivers/adc.h"
+
+
+/* Should be as near to 4.5MHz as possible
+ * See LPC11U3x manual (UM10462.pdf), remark on page 381 in section 19.2.
+ */
+#define adc_clk_Val  4500000
+
+
+
+/***************************************************************************** */
+/* 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);
+}
+
+/* Change The ADC resolution.
+ * Use defines from lpc_regs_11xx.h to specify the bit width for the convertion.
+ * Ranges from LPC_ADC_3BITS to LPC_ADC_10BITS.
+ */
+int adc_set_resolution(int bits)
+{
+       struct lpc_adc* adc = LPC_ADC;
+       if (bits & ~LPC_ADC_BITS_MASK) {
+               return -EINVAL;
+       }
+       adc->ctrl = ((adc->ctrl | bits) & LPC_ADC_CTRL_MASK);
+       return 0;
+}
+
+
+/***************************************************************************** */
+/*   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;
+
+       /* Configure ADC clock to get the 9MHz sample clock */
+       clkdiv = (main_clock / adc_clk_Val);
+       adc->ctrl |= ((clkdiv & 0xFF) << 8);
+}
+
+
+void adc_on(void)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       struct lpc_adc* adc = LPC_ADC;
+
+       /* Disable ADC Interrupt */
+       NVIC_DisableIRQ(ADC_IRQ);
+
+       /* Power-up ADC */
+       sys_ctrl->powerdown_run_cfg &= ~LPC_POWER_DOWN_ADC;
+       /* Provide clock to ADC */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_ADC, 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)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+
+       /* Disable ADC Interrupt */
+       NVIC_DisableIRQ(ADC_IRQ);
+       /* Power Down ADC */
+       sys_ctrl->powerdown_run_cfg |= LPC_POWER_DOWN_ADC;
+       /* Remove clock from ADC block */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_ADC, 0);
+}
+
diff --git a/drivers/gpio.c b/drivers/gpio.c
new file mode 100644 (file)
index 0000000..5529b7f
--- /dev/null
@@ -0,0 +1,196 @@
+/****************************************************************************
+ *  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_11u3x.h"
+#include "core/lpc_core_cm0.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "drivers/gpio.h"
+
+
+
+/***************************************************************************** */
+/*   GPIO setup   */
+
+void gpio_on(void)
+{
+       /* Provide power to GPIO control blocks */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_GPIO, 1);
+}
+void gpio_off(void)
+{
+       /* Remove power from GPIO control blocks */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_GPIO, 0);
+}
+
+/*
+ * 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* gpio_port = LPC_GPIO_REGS(gpio->port);
+
+       /* Configure as GPIO */
+       config_pio(gpio, mode | LPC_IO_DIGITAL);
+
+       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 setup   */
+
+
+#define NB_PIN_INTERRUPTS  8
+static void (*gpio_calbacks[NB_PIN_INTERRUPTS]) (uint32_t);
+
+
+int set_gpio_callback(void (*callback) (uint32_t), uint8_t irq, const struct pio* gpio, uint8_t sense)
+{
+       struct lpc_gpio* gpio_port = NULL;
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       struct lpc_gpio_pin_edge_interrupt* edge_conf = LPC_GPIO_INT_EDGE;
+       struct lpc_gpio_pin_level_interrupt* level_conf = LPC_GPIO_INT_LEVEL;
+
+       /* Sanity checks */
+       if (irq >= NB_PIN_INTERRUPTS) {
+               return -EINVAL;
+       }
+       switch (gpio->port) {
+               case 0:
+                       if (gpio->pin >= PORT0_NB_PINS)
+                               return -EINVAL;
+                       gpio_port = LPC_GPIO_0;
+                       break;
+               case 1:
+                       if (gpio->pin >= PORT1_NB_PINS)
+                               return -EINVAL;
+                       gpio_port = LPC_GPIO_1;
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       /* Configure the pin as interrupt source */
+       config_pio(gpio, LPC_IO_DIGITAL);
+       gpio_port->data_dir &= ~(1 << gpio->pin); /* Input */
+
+       /* Register the callback */
+       /* FIXME : we should check that there were none registered for the selected pin */
+       gpio_calbacks[irq] = callback;
+
+       /* Power the Pin interrupt block */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_PINT, 1);
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_P0INT, 1);
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_P1INT, 1);
+
+       /* And setup the interrupt */
+       switch (sense) {
+               case EDGES_BOTH:
+                       edge_conf->mode &= ~(0x01 << irq);
+                       edge_conf->rising_enable_set = (0x01 << irq);
+                       edge_conf->falling_enable_set = (0x01 << irq);
+                       break;
+               case EDGE_RISING:
+                       edge_conf->mode &= ~(0x01 << irq);
+                       edge_conf->rising_enable_set = (0x01 << irq);
+                       edge_conf->falling_enable_clear = (0x01 << irq);
+                       break;
+               case EDGE_FALLING:
+                       edge_conf->mode &= ~(0x01 << irq);
+                       edge_conf->falling_enable_set = (0x01 << irq);
+                       edge_conf->rising_enable_clear = (0x01 << irq);
+                       break;
+               case LEVEL_LOW:
+                       level_conf->mode |= (0x01 << irq);
+                       level_conf->enable_set = (0x01 << irq);
+                       level_conf->set_active_low = (0x01 << irq);
+                       break;
+               case LEVEL_HIGH:
+                       level_conf->mode |= (0x01 << irq);
+                       level_conf->enable_set = (0x01 << irq);
+                       level_conf->set_active_high = (0x01 << irq);
+                       break;
+               default: /* Not handled, do not activate the interrupt */
+                       return -EINVAL;
+       }
+
+       /* Connect the port/pin to the interrupt */
+       sys_ctrl->gpio_int_sel[irq] = ((gpio->pin & 0x1F) | (gpio->port << 5));
+
+       NVIC_EnableIRQ(irq);
+       return 0;
+}
+void remove_gpio_callback(uint8_t irq)
+{
+       /* Remove the handler */
+       gpio_calbacks[irq] = NULL;
+       /* And disable the interrupt */
+       NVIC_DisableIRQ(irq);
+}
+
+
+/* Interrupt Handlers */
+/* Using LPC_GPIO_INT_EDGE is OK for both types of interupts */
+/* Note : For level interrupts, we toggle the active level, which may no be what's th euser wants ... */
+#define DECLARE_PIO_INT_HANDLER(x) \
+       void Pin_Int ## x ## _Handler(void) \
+       { \
+               struct lpc_gpio_pin_edge_interrupt* regs = LPC_GPIO_INT_EDGE; \
+               regs->status = (0x01 << (x)); \
+               if (gpio_calbacks[(x)] != NULL) { \
+                       gpio_calbacks[(x)]((x)); \
+               } \
+       }
+DECLARE_PIO_INT_HANDLER(0);
+DECLARE_PIO_INT_HANDLER(1);
+DECLARE_PIO_INT_HANDLER(2);
+DECLARE_PIO_INT_HANDLER(3);
+DECLARE_PIO_INT_HANDLER(4);
+DECLARE_PIO_INT_HANDLER(5);
+DECLARE_PIO_INT_HANDLER(6);
+DECLARE_PIO_INT_HANDLER(7);
+
+void PIO_GRP_0_Handler(void)
+{
+}
+void PIO_GRP_1_Handler(void)
+{
+}
+
+
diff --git a/drivers/i2c.c b/drivers/i2c.c
new file mode 100644 (file)
index 0000000..877da65
--- /dev/null
@@ -0,0 +1,493 @@
+/****************************************************************************
+ *   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_11u3x.h"
+#include "core/lpc_core_cm0.h"
+#include "core/system.h"
+#include "core/pio.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 {
+       volatile struct lpc_i2c* regs;
+       volatile 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;
+};
+
+static struct i2c_bus mod_i2c;
+
+
+/* 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_0_Handler(void)
+{
+       uint8_t status;
+       struct i2c_bus* i2c = &mod_i2c;
+
+       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;
+}
+
+
+
+/***************************************************************************** */
+/*                        I2C access                                           */
+/***************************************************************************** */
+/* Read
+ * Performs a non-blocking read on the module's i2c bus.
+ *   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(const void *cmd_buf, size_t cmd_size, const void* ctrl_buf, void* inbuff, size_t count)
+{
+       int ret = 0;
+
+       /* Checks */
+       if (mod_i2c.regs != LPC_I2C0)
+               return -EBADFD;
+       if (cmd_buf == NULL)
+               return -EINVAL;
+       if ((inbuff == NULL) && (count > 0))
+               return -EINVAL;
+
+       if (mod_i2c.state == I2C_BUSY) {
+               return -EBUSY;
+       }
+       if (mod_i2c.state != I2C_OK) {
+               /* What should we do ??? someone failed to reset status ? */
+       }
+
+       /* Set up mod_i2c for read operation */
+       /* command (write) buffer */
+       mod_i2c.out_buff = cmd_buf;
+       mod_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 */
+       mod_i2c.repeated_start_restart = ctrl_buf;
+       mod_i2c.restart_after_addr = I2C_CONT;
+       mod_i2c.restart_after_data = 0;
+       /* read buffer */
+       mod_i2c.in_buff = inbuff;
+       mod_i2c.read_length = count;
+       mod_i2c.read_index = 0;
+
+       /* Start the process */
+       mod_i2c.state = I2C_BUSY;
+       mod_i2c.regs->ctrl_set = I2C_START_FLAG;
+       /* And wait for process completion */
+       do {} while (mod_i2c.state == I2C_BUSY);
+
+       /* Handle returned state (errors or OK) */
+       switch (mod_i2c.state) {
+               case I2C_OK:
+               case I2C_NO_DATA:
+                       ret = mod_i2c.read_index;
+                       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) */
+       mod_i2c.state = I2C_BUSY;
+       mod_i2c.write_length = 0;
+       mod_i2c.regs->ctrl_set = I2C_START_FLAG;
+       do {} while (mod_i2c.state == I2C_BUSY);
+       mod_i2c.state = I2C_OK;
+
+       return ret;
+}
+
+/* Write
+ * Performs a non-blocking write on the module's i2c bus.
+ *   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(const void *buf, size_t count, const void* ctrl_buf)
+{
+       int ret = 0;
+
+       /* Checks */
+       if (mod_i2c.regs != LPC_I2C0)
+               return -EBADFD;
+       if (buf == NULL)
+               return -EINVAL;
+
+       if (mod_i2c.state == I2C_BUSY) {
+               return -EBUSY;
+       }
+       if (mod_i2c.state != I2C_OK) {
+               /* What should we do ??? someone failed to reset status ? */
+       }
+
+       /* Clear read information to prevent entering master receiver states */
+       mod_i2c.read_length = 0;
+       mod_i2c.in_buff = NULL;
+       mod_i2c.state = I2C_BUSY;
+       /* Set up mod_i2c for write operation */
+       mod_i2c.out_buff = buf;
+       mod_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 */
+       mod_i2c.restart_after_addr = I2C_CONT;
+       mod_i2c.repeated_start_restart = ctrl_buf;
+       mod_i2c.restart_after_data = 0;
+
+       /* Start the process */
+       mod_i2c.state = I2C_BUSY;
+       mod_i2c.regs->ctrl_set = I2C_START_FLAG;
+       /* Wait for process completion */
+       do {} while (mod_i2c.state == I2C_BUSY);
+
+       /* Handle returned state (errors or OK) */
+       switch (mod_i2c.state) {
+               case I2C_OK:
+               case I2C_NO_DATA:
+                       ret = mod_i2c.write_length;
+                       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) */
+       mod_i2c.state = I2C_BUSY;
+       mod_i2c.write_length = 0;
+       mod_i2c.regs->ctrl_set = I2C_START_FLAG;
+       do {} while (mod_i2c.state == I2C_BUSY);
+       mod_i2c.state = I2C_OK;
+
+       return ret;
+}
+
+
+
+/***************************************************************************** */
+/*                I2C Init                                                     */
+/***************************************************************************** */
+static void i2c_clock_on(uint32_t i2c_clk_freq)
+{
+       struct lpc_i2c* i2c = LPC_I2C0;
+       uint32_t main_clock = get_main_clock();
+       uint32_t scl_clk = 0;
+
+       /* Setup I2C clock */
+       scl_clk = (main_clock / i2c_clk_freq);
+       i2c->clk_duty_high = (scl_clk / 2);
+       i2c->clk_duty_low = (scl_clk - i2c->clk_duty_high);
+}
+
+void i2c_on(uint32_t i2c_clk_freq)
+{
+       struct lpc_i2c* i2c = LPC_I2C0;
+
+       NVIC_DisableIRQ(I2C0_IRQ);
+       /* Power on I2C 0 block */
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_I2C, 1);
+       /* Set clock */
+       i2c_clock_on(i2c_clk_freq);
+       mod_i2c.clock = i2c_clk_freq;
+       /* Initialize i2c_bus struct */
+       memset(&mod_i2c, 0, sizeof(struct i2c_bus));
+       mod_i2c.regs = (struct lpc_i2c*)LPC_I2C0;
+       mod_i2c.state = I2C_OK;
+       /* Enable I2C */
+       /* FIXME: if enabling slave functions, add I2C_ASSERT_ACK flag */
+       i2c->ctrl_set = (I2C_ENABLE_FLAG);
+       /* And enable interrupts */
+       NVIC_EnableIRQ(I2C0_IRQ);
+}
+
+void i2c_off(void)
+{
+       NVIC_DisableIRQ(I2C0_IRQ);
+       subsystem_power(LPC_SYS_ABH_CLK_CTRL_I2C, 0);
+       mod_i2c.clock = 0;
+}
+
+/* Allow system to propagate main clock */
+void i2c_clock_update(void)
+{
+       if (mod_i2c.clock) {
+               /* FIXME : we should stop I2C transfers, disable I2C interrupts and stop I1C clock. */
+               i2c_clock_on(mod_i2c.clock); /* 6 is not a module num, nor system i2c (5) */
+       }
+}
+
+
diff --git a/drivers/serial.c b/drivers/serial.c
new file mode 100644 (file)
index 0000000..81b2d2c
--- /dev/null
@@ -0,0 +1,424 @@
+/****************************************************************************
+ *  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_11u3x.h"
+#include "core/lpc_core_cm0.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "lib/string.h"
+#include "lib/utils.h"
+#include "drivers/serial.h"
+
+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 1
+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 = 0,
+               .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_RS485 | SERIAL_CAP_IRDA | SERIAL_CAP_SMART_CARD),
+               .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_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_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       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 */
+       pclk = get_main_clock(); /* See above note */
+       sys_ctrl->uart_clk_div = 0x01;
+       /* The easy one : divider is an integer, or baudrate is low enought for the aproximation */
+       if ((baudrate <= 115200) || ((div * baudrate * 16) == pclk)) {
+               div = (pclk / (baudrate * 16));
+               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 void uart_clk_off(uint32_t uart_num)
+{
+       struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       /* Erase saved baudrate */
+       uarts[uart_num].baudrate = 0;
+       sys_ctrl->uart_clk_div = 0;
+}
+
+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;
+}
+
+struct uart_def
+{
+       uint32_t irq;
+       uint32_t power_offset;
+};
+static struct uart_def uart_defs[NUM_UARTS] = {
+       { UART0_IRQ, LPC_SYS_ABH_CLK_CTRL_UART0 },
+};
+
+/***************************************************************************** */
+/*   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 );
+       /* Setup pins, must be done before clock setup and with uart powered off. */
+       uart_clk_off(uart_num);
+       subsystem_power(uart->power_offset, 0);
+       /* 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 );
+       uart_clk_off(uart_num);
+       /* Turn Off power */
+       subsystem_power(uart->power_offset, 0);
+       uarts[uart_num].rx_callback = NULL;
+}
+
+
+
diff --git a/drivers/ssp.c b/drivers/ssp.c
new file mode 100644 (file)
index 0000000..7cdec75
--- /dev/null
@@ -0,0 +1,427 @@
+/****************************************************************************
+ *  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_11u3x.h"
+#include "core/lpc_core_cm0.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;
+
+       uint32_t irq;
+       uint32_t clk_ctrl_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,
+               .clk_ctrl_bit = LPC_SYS_ABH_CLK_CTRL_SSP0,
+       },
+       {
+               .num = 1,
+               .regs = LPC_SSP1,
+               .current_clk = 0,
+               .mutex = 0,
+               .int_rx_stats = 0,
+               .int_overrun_stats = 0,
+               .int_rx_timeout_stats = 0,
+               .irq = SSP1_IRQ,
+               .clk_ctrl_bit = LPC_SYS_ABH_CLK_CTRL_SSP1,
+       },
+};
+
+
+
+/* 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;
+       }
+}
+
+void SSP_1_Handler(void)
+{
+       struct lpc_ssp* ssp = LPC_SSP1;
+       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_sys_control* sys_ctrl = LPC_SYS_CONTROL;
+       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;
+       }
+
+       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));
+
+       /* Activate the SSP clock (maybe divide main clock) */
+       switch (ssp_num) {
+               case 0:
+                       sys_ctrl->ssp0_clk_div = pclk_div;
+                       break;
+               case 1:
+                       sys_ctrl->ssp1_clk_div = pclk_div;
+                       break;
+       }
+
+       /* 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:
+ *     LPC_SSP_FRAME_SPI - LPC_SSP_FRAME_TI - LPC_SSP_FRAME_MICROWIRE).
+ *  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->clk_ctrl_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->clk_ctrl_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->clk_ctrl_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..11a079d
--- /dev/null
@@ -0,0 +1,265 @@
+/****************************************************************************
+ *  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_11u3x.h"
+#include "core/lpc_core_cm0.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;
+       uint32_t irq;
+       void (*callback)(uint32_t); /* Possible RX callback */
+};
+static struct timer_device timer_devices[NUM_TIMERS] = {
+       { LPC_TMR16B0, LPC_SYS_ABH_CLK_CTRL_CT16B0, TIMER0_IRQ },
+       { LPC_TMR16B1, LPC_SYS_ABH_CLK_CTRL_CT16B1, TIMER1_IRQ },
+       { LPC_TMR32B0, LPC_SYS_ABH_CLK_CTRL_CT32B0, TIMER2_IRQ },
+       { LPC_TMR32B1, LPC_SYS_ABH_CLK_CTRL_CT32B1, TIMER3_IRQ },
+};
+
+
+
+/* Handlers */
+void TIMER_Handler(struct timer_device* timer)
+{
+       uint32_t intr_flags = timer->regs->int_reg; /* Backup the flags */
+
+       /* Clear the interrupt */
+       timer->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 and request reset */
+       timer_devices[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_RESET;
+       /* Remove reset flag */
+       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 timer reset flag */
+       timer_devices[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_RESET;
+       /* Remove reset flag and start counter */
+       timer_devices[timer_num].regs->timer_ctrl = LPC_TIMER_COUNTER_ENABLE;
+}
+
+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 > 3)
+               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, const 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 UM10462 page 361 section 16.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 (conf->match[ conf->config[1] ] == 0) {
+                               return -EINVAL; /* Force use of Channel 3 for PWM cycle length */
+                       }
+                       /* Activate selected PWM channels 0 to 2 */
+                       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)(uint32_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);
+       /* 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/extdrv/eeprom.c b/extdrv/eeprom.c
new file mode 100644 (file)
index 0000000..968790a
--- /dev/null
@@ -0,0 +1,242 @@
+/****************************************************************************
+ *   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_11u3x.h"
+#include "core/lpc_core_cm0.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"
+
+
+/***************************************************************************** */
+/*          Read and Write for eeprom                                          */
+/***************************************************************************** */
+
+/* NOTE : This code does automatic detection of the eeprom type/size and thus does not
+ *        support multiple eeproms on the same I2C bus
+ */
+
+/* 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_ID_SMALL_ADDR_1  0xA0
+#define EEPROM_ID_SMALL_ADDR_2  0xA2
+#define EEPROM_ID_SMALL_I2C_SIZE  1024
+#define EEPROM_ID_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_ID_BIG_I2C_SIZE  16*1024
+#define EEPROM_ID_BIG_PAGE_SIZE 64
+
+
+enum i2c_eeprom_type {
+       EEPROM_TYPE_NONE = 0,
+       EEPROM_TYPE_SMALL,
+       EEPROM_TYPE_BIG,
+};
+
+/* Detect the eeprom size */
+int eeprom_detect(uint8_t eeprom_addr)
+{
+       int ret = 0;
+       char cmd_buf[1] = { EEPROM_ID_SMALL_ADDR_1, };
+
+       /* Look for small eeproms first, only these would answer on all addresses */
+       if (eeprom_addr == EEPROM_ID_SMALL_ADDR_1) {
+               cmd_buf[0] = EEPROM_ID_SMALL_ADDR_2;
+       }
+       ret = i2c_read(cmd_buf, 1, NULL, NULL, 0);
+       if (ret == 0) {
+               return EEPROM_TYPE_SMALL;
+       }
+
+       /* No small eeprom ... look for big ones */
+       cmd_buf[0] = eeprom_addr;
+       ret = i2c_read(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 */
+}
+
+int get_eeprom_type(uint8_t eeprom_addr)
+{
+       static int eeprom_type = -1;
+
+       if (eeprom_type >= 0) {
+               return eeprom_type; /* No need to check again */
+       }
+
+       eeprom_type = eeprom_detect(eeprom_addr);
+       if (eeprom_type <= 0) {
+               return -1;
+       }
+       return eeprom_type;
+}
+
+
+/* EEPROM Read
+ * Performs a non-blocking read on the eeprom.
+ *   address : data offset in eeprom.
+ * 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 eeprom_addr, 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, };
+       int eeprom_type = 0;
+
+       eeprom_type = get_eeprom_type(eeprom_addr);
+
+       /* Read the requested data */
+       switch (eeprom_type) {
+               case EEPROM_TYPE_SMALL:
+                       cmd_buf[0] = EEPROM_ID_SMALL_ADDR_1 | ((offset & 0x700) >> 7);
+                       cmd_buf[1] = offset & 0xFF;
+                       cmd_buf[2] = EEPROM_ID_SMALL_ADDR_1 | 0x01;
+                       ret = i2c_read(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 | 0x01);
+                       ret = i2c_read(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.
+ *   address : data offset in eeprom.
+ * 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_ID_MAX_PAGE_SIZE EEPROM_ID_BIG_PAGE_SIZE
+int eeprom_write(uint8_t eeprom_addr, uint32_t offset, const void *buf, size_t count)
+{
+       int ret = 0;
+       uint8_t cmd_size = CMD_SIZE_BIG, page_size = EEPROM_ID_BIG_PAGE_SIZE;
+       int write_count = 0, size = 0;
+       char cmd[MAX_CMD_SIZE];
+       char full_buff[(EEPROM_ID_MAX_PAGE_SIZE + MAX_CMD_SIZE)];
+       int eeprom_type = 0;
+
+       eeprom_type = get_eeprom_type(eeprom_addr);
+
+       switch (eeprom_type) {
+               case EEPROM_TYPE_SMALL:
+                       cmd_size = CMD_SIZE_SMALL;
+                       page_size = EEPROM_ID_SMALL_PAGE_SIZE;
+                       break;
+               case EEPROM_TYPE_BIG:
+                       /* already configured */
+                       /* cmd_size = CMD_SIZE_BIG; */
+                       /* page_size = EEPROM_ID_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_ID_SMALL_ADDR_1 | ((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(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(full_buff, 1, NULL);
+               } while (ret != 1);
+
+               write_count += size;
+       }
+
+       if (write_count != count)
+               return ret;
+       return write_count;
+}
+
+
diff --git a/extdrv/status_led.c b/extdrv/status_led.c
new file mode 100644 (file)
index 0000000..f8b983d
--- /dev/null
@@ -0,0 +1,163 @@
+/****************************************************************************
+ *  extdrv/status_led.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/>.
+ *
+*************************************************************************** */
+
+/***************************************************************************** */
+/*                Status Led                                                   */
+/***************************************************************************** */
+
+
+#include <stdint.h>
+#include "core/lpc_regs_11u3x.h"
+#include "core/system.h"
+#include "core/pio.h"
+#include "drivers/gpio.h"
+#include "extdrv/status_led.h"
+
+
+/***************************************************************************** */
+/* Status LEDs for the LPC11U35 on the LPC1224-mbed board are three independent leds */
+
+/* This code configures the status leds and enables use as a debug helper
+ * or visual watchdog.
+ */
+
+
+struct pio red_led = {0, 0, 0};
+struct pio green_led = {0, 0, 0};
+struct pio blue_led = {0, 0, 0};
+#define LED_RED    (1 << red_led.pin)
+#define LED_GREEN  (1 << green_led.pin)
+#define LED_BLUE   (1 << blue_led.pin)
+
+void status_led_config(const struct pio* green, const struct pio* red, const struct pio* blue)
+{
+       uint32_t mode = LPC_IO_MODE_PULL_UP | LPC_IO_DRIVE_HIGHCURENT;
+       /* Copy status led info */
+       pio_copy(&red_led, red);
+       pio_copy(&green_led, green);
+       pio_copy(&blue_led, blue);
+       /* Status Leds: all off */
+       config_gpio(&green_led, mode, GPIO_DIR_OUT, 1);
+       config_gpio(&red_led, mode, GPIO_DIR_OUT, 1);
+       config_gpio(&blue_led, mode, GPIO_DIR_OUT, 1);
+}
+
+void status_led(uint32_t val)
+{
+       struct lpc_gpio* gpio_red = LPC_GPIO_REGS(red_led.port);
+       struct lpc_gpio* gpio_green = LPC_GPIO_REGS(green_led.port);
+       struct lpc_gpio* gpio_blue = LPC_GPIO_REGS(blue_led.port);
+
+       switch (val) {
+               case red_only:
+                       gpio_red->clear = LED_RED;
+                       gpio_green->set = LED_GREEN;
+                       gpio_blue->set = LED_BLUE;
+                       break;
+               case red_on:
+                       gpio_red->clear = LED_RED;
+                       break;
+               case red_off:
+                       gpio_red->set = LED_RED;
+                       break;
+               case red_toggle:
+                       gpio_red->toggle = LED_RED;
+                       break;
+               case green_only:
+                       gpio_green->clear = LED_GREEN;
+                       gpio_red->set = LED_RED;
+                       gpio_blue->set = LED_BLUE;
+                       break;
+               case green_on:
+                       gpio_green->clear = LED_GREEN;
+                       break;
+               case green_off:
+                       gpio_green->set = LED_GREEN;
+                       break;
+               case green_toggle:
+                       gpio_green->toggle = LED_GREEN;
+                       break;
+               case blue_only:
+                       gpio_blue->clear = LED_BLUE;
+                       gpio_red->set = LED_RED;
+                       gpio_green->set = LED_GREEN;
+                       break;
+               case blue_on:
+                       gpio_blue->clear = LED_BLUE;
+                       break;
+               case blue_off:
+                       gpio_blue->set = LED_BLUE;
+                       break;
+               case blue_toggle:
+                       gpio_blue->toggle = LED_BLUE;
+                       break;
+               case all:
+                       gpio_red->clear = LED_RED;
+                       gpio_green->clear = LED_GREEN;
+                       gpio_blue->clear = LED_BLUE;
+                       break;
+               case toggle_all:
+                       gpio_red->toggle = LED_RED;
+                       gpio_green->toggle = LED_GREEN;
+                       gpio_blue->toggle = LED_BLUE;
+                       break;
+               case none:
+               default:
+                       gpio_red->set = LED_RED;
+                       gpio_green->set = LED_GREEN;
+                       gpio_blue->set = LED_BLUE;
+                       break;
+       }
+}
+
+void gpio_set_dap_led(uint8_t state)
+{
+       struct lpc_gpio* gpio_green = LPC_GPIO_REGS(green_led.port);
+       if (state) {
+               gpio_green->set = LED_GREEN;
+       } else {
+               gpio_green->clear = LED_GREEN;
+       }
+}
+
+void gpio_set_msd_led(uint8_t state)
+{
+       struct lpc_gpio* gpio_red = LPC_GPIO_REGS(red_led.port);
+       if (state) {
+               gpio_red->set = LED_RED;
+       } else {
+               gpio_red->clear = LED_RED;
+       }
+}
+
+void gpio_set_cdc_led(uint8_t state)
+{
+       struct lpc_gpio* gpio_blue = LPC_GPIO_REGS(blue_led.port);
+       if (state) {
+               gpio_blue->set = LED_BLUE;
+       } else {
+               gpio_blue->clear = LED_BLUE;
+       }
+}
+
+
+
+
+
diff --git a/extdrv/tmp101_temp_sensor.c b/extdrv/tmp101_temp_sensor.c
new file mode 100644 (file)
index 0000000..5109aec
--- /dev/null
@@ -0,0 +1,191 @@
+/****************************************************************************
+ *   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_11u3x.h"
+#include "core/lpc_core_cm0.h"
+#include "core/system.h"
+#include "drivers/i2c.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)
+
+
+
+/* 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(struct tmp101_sensor_config* conf)
+{
+       char cmd_buf = (conf->addr | I2C_READ_BIT);
+
+       /* Did we already probe the sensor ? */
+       if (conf->probe_ok != 1) {
+               conf->probe_ok = i2c_read(&cmd_buf, 1, NULL, NULL, 0);
+       }
+       return conf->probe_ok;
+}
+
+/* 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.
+ * '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(struct tmp101_sensor_config* conf, uint16_t* raw, int* deci_degrees)
+{
+       int ret = 0;
+       uint16_t temp = 0;
+       char cmd_buf[CMD_BUF_SIZE] = { conf->addr, TMP_REG_TEMPERATURE, (conf->addr | I2C_READ_BIT), };
+       char ctrl_buf[CMD_BUF_SIZE] = { I2C_CONT, I2C_DO_REPEATED_START, I2C_CONT, };
+
+       if (tmp101_probe_sensor(conf) != 1) {
+               return -ENODEV;
+       }
+
+       /* Read the requested data */
+       if (conf->last_accessed_register == TMP_REG_TEMPERATURE) {
+               /* No need to switch back to temperature register */
+               ret = i2c_read((cmd_buf + 2), 1, (ctrl_buf + 2), (char*)&temp, 2);
+       } else {
+               /* Send (write) temperature register address to TMP101 internal pointer */
+               ret = i2c_read(cmd_buf, CMD_BUF_SIZE, ctrl_buf, (char*)&temp, 2);
+               conf->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.
+ * 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
+ */
+#define CONF_BUF_SIZE 4
+int tmp101_sensor_config(struct tmp101_sensor_config* conf)
+{
+       int ret = 0;
+       char cmd[CONF_BUF_SIZE] = { conf->addr, TMP_REG_CONFIG, };
+
+       if (tmp101_probe_sensor(conf) != 1) {
+               return -ENODEV;
+       }
+
+       /* Store the new configuration */
+       conf->actual_config = (TMP_SHUTDOWN_MODE_ON | TMP_THERMOSTAT_INTERRUPT_MODE | TMP_ALERT_POLARITY_HIGH);
+       conf->actual_config |= (conf->resolution & (0x03 << 5));
+       cmd[2] = conf->actual_config;
+       ret = i2c_write(cmd, 3, NULL);
+       conf->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. */
+int tmp101_sensor_start_conversion(struct tmp101_sensor_config* conf)
+{
+       int ret = 0;
+       char cmd[CONF_BUF_SIZE] = { conf->addr, TMP_REG_CONFIG, };
+
+       if (tmp101_probe_sensor(conf) != 1) {
+               return -ENODEV;
+       }
+
+       cmd[2] = conf->actual_config;
+       cmd[2] |= TMP_ONE_SHOT_TRIGGER;
+       ret = i2c_write(cmd, 3, NULL);
+       conf->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..e23d635
--- /dev/null
@@ -0,0 +1,147 @@
+/****************************************************************************
+ *   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>
+
+
+/*******************************************************************************/
+/*            In Application Programming ROM based routines                    */
+/*******************************************************************************/
+
+/* Provide access to IAP ROM based routines.
+ * This allows in-application re-programming of the micro-controller
+ *   (for bootloaders, drivers, loadable RTOS tasks, ....)
+ */
+
+#define START_APP_ADDRESS (0x5000)
+#define INITIAL_SP      (*(uint32_t *)(START_APP_ADDRESS))
+#define RESET_HANDLER   (*(uint32_t *)(START_APP_ADDRESS + 4))
+/* CRP Handling */
+#define CRP_ADDRESS    (0x000002FC)
+#define NO_ISP   (0x4E697370)
+#define CRP1     (0x12345678)
+#define CRP2     (0x87654321)
+#define CRP3     (0x43218765)
+#define IS_CRP_VALUE(v)  ((v==NO_ISP) || (v==CRP1) || (v==CRP2) || (v==CRP3))
+
+#define LPC11U35_SECTOR_SIZE  (0x1000)
+#define LPC11U35_NB_SECTOR    (15)
+#define LPC11U35_END_FLASH    (LPC11U35_NB_SECTOR * LPC11U35_SECTOR_SIZE)
+
+
+
+
+/*******************************************************************************/
+/* Direct access to IAP function */
+
+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,
+};
+
+/* 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);
+
+/* Erase pages  from the programm memory
+ * Page numbers start at 0. A flash page size is 512 bytes.
+ * Provide the same page number as start and end to erase a single page.
+ * Of course, end page number MUST be higher than (or equal to) start page number.
+ * There is no way to erase only parts of a page.
+ * The sector in which the page reside must be prepared for writing before the page erase
+ *    operation.
+ * Interrputs are disabled during this operation.
+ */
+int iap_erase_flash_pages(uint32_t start_page, uint32_t end_page);
+
+
+/* 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);
+
+/* Copy the whole unique id table (four 32bits words) in the memory pointed by uid_table.
+ * uid_table must have enougth room for the whole unique id table.
+ * Returns the IAP status.
+ */
+uint32_t iap_read_unique_id(uint32_t* uid_table);
+
+
+
+/*******************************************************************************/
+/* IAP Helpers */
+
+/* Relocate the vector table so that the first sector of the internal flash can be erased
+ * and written
+*/
+void relocate_vector_table(void);
+
+/* Erase one sector, given a flash address
+ * return 0 on success.
+ */
+int flash_hal_erase_sector(uint32_t addr);
+
+/* Flash a binary image chunk to flash.
+ * Flash must have been erased first.
+ * return 0 on success.
+ */
+int flash_hal_program_page (uint32_t addr, uint32_t sz, unsigned char *buf);
+
+#endif /* CORE_IAP_H */
+
diff --git a/include/core/lpc_core_cm0.h b/include/core/lpc_core_cm0.h
new file mode 100644 (file)
index 0000000..e639b04
--- /dev/null
@@ -0,0 +1,392 @@
+/****************************************************************************
+ *   core/lpc_core_cm0.h
+ *
+ * Helper functions to access some registers and Cortex M0 core functionalities.
+ *
+ *
+ * Most of the code from here comes from CMSIS. Should this be rewritten ?
+ *
+ *
+ * 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_CM0_H
+#define LPC_CORE_CM0_H
+
+#include <stdint.h>   /* standard types definitions */
+#include "core/lpc_regs_11u3x.h"
+
+
+/*******************************************************************************/
+/*                Core Instructions                                            */
+/*******************************************************************************/
+/* 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")
+
+
+
+/* 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));
+}
+
+
+
+/*******************************************************************************/
+/*            Byte swap instructions                                           */
+/*******************************************************************************/
+/* Swap bytes of each 16-bit halfword in a 32-bit word, keeping halfword order */
+static inline uint32_t double_byte_swap_16(volatile uint32_t value)
+{
+       uint32_t result = 0;
+       __asm volatile ("rev16 %0, %1" : "=l" (result) : "l" (value));
+       return result;
+}
+/* Change endianness of a 16-bit halfword */
+static inline uint32_t byte_swap_16(volatile uint16_t value)
+{
+       uint32_t result = 0;
+       __asm volatile ("rev16 %0, %1" : "=l" (result) : "l" (value));
+       return (result & 0xFFFF);
+}
+/* Change endianness of a 32-bit word */
+static inline uint32_t byte_swap_32(volatile uint32_t value)
+{
+       uint32_t result = 0;
+       __asm volatile ("rev %0, %1" : "=l" (result) : "l" (value));
+       return result;
+}
+
+
+
+
+
+/*******************************************************************************/
+/*            Interrupts                                                       */
+/*******************************************************************************/
+
+/* Cortex-M0 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-M0 Hard 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-M0 Supervisor Call Interrupt */
+#define PEND_SV_IRQ     (  -2 ) /* 14 - Cortex-M0 Pend SV Interrupt */
+#define SYSTICK_IRQ     (  -1 ) /* 15 - Cortex-M0 System Tick Interrupt */
+/* LPC12xx Specific Interrupt Numbers */
+#define PIN_INT0_IRQ       0   /* I/O pins can be used as wakeup source. */
+#define PIN_INT1_IRQ       1
+#define PIN_INT2_IRQ       2
+#define PIN_INT3_IRQ       3
+#define PIN_INT4_IRQ       4
+#define PIN_INT5_IRQ       5
+#define PIN_INT6_IRQ       6
+#define PIN_INT7_IRQ       7
+#define GRP_INT0_IRQ       8
+#define GRP_INT1_IRQ       9
+#define SSP1_IRQ          14  /* 14 - SSP 1 */
+#define I2C0_IRQ          15  /* 15 - I2C 0 */
+#define TIMER0_IRQ        16  /* 16 - Timer 0 */
+#define TIMER1_IRQ        17  /* 17 - Timer 1 */
+#define TIMER2_IRQ        18  /* 18 - Timer 2 */
+#define TIMER3_IRQ        19  /* 19 - Timer 3 */
+#define SSP0_IRQ          20  /* 20 - SSP 0 */
+#define UART0_IRQ         21  /* 21 - UART 0 */
+#define USB_IRQ           22  /* 22 - USB */
+#define USB_FIQ_IRQ       23  /* 23 - USB FIQ */
+#define ADC_IRQ           24  /* 24 - A/D Converter */
+#define WDT_IRQ           25  /* 25 - Watchdog */
+#define BOD_IRQ           26  /* 26 - Brown Out Detect(BOD) */
+#define FLASH_IRQ         27  /* 27 - Flash / EEPROM */
+#define USB_WAKEUP_IRQ    30  /* 26 - USB Wakeup */
+#define IOH_IRQ           31  /* 27 - I/O Handler */
+
+
+/* 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                  */
+/*******************************************************************************/
+/*  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 = (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 = (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 & (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 = (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 = (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-M0 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_SYSRESETREQ);
+       dsb();  /* Ensure completion of memory access */
+       while (1); /* wait until reset */
+}
+
+
+
+/*******************************************************************************/
+/*            Sync lock                                                        */
+/*******************************************************************************/
+/* There is no syncro instructions on Cortex-M0
+ * Returns the old value if the new value has been set (lock acquired)
+ */
+static inline uint32_t sync_lock_test_and_set(volatile uint32_t *addr, uint32_t value)
+{
+       uint32_t oldval;
+       lpc_disable_irq();
+    dsb();
+       oldval = *addr;
+       *addr = value;
+    dsb();
+       lpc_enable_irq();
+       return oldval;
+}
+/* Remove the lock */
+static inline void sync_lock_release(volatile uint32_t *addr)
+{
+    *addr = 0;
+    dsb();
+}
+
+
+
+#endif /* LPC_CORE_CM0_H */
+
diff --git a/include/core/lpc_regs_11u3x.h b/include/core/lpc_regs_11u3x.h
new file mode 100644 (file)
index 0000000..8f01ce9
--- /dev/null
@@ -0,0 +1,926 @@
+/****************************************************************************
+ *   core/lpc12xx_regs.h
+ *
+ * Cortex-M0 Core Registers definitions
+ *
+ * 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 LPC_REGS_H
+#define LPC_REGS_H
+
+/* Get size_t, and NULL from <stddef.h>.  */
+#undef __need_malloc_and_calloc
+#define __need_size_t
+#define __need_NULL
+#include <stddef.h>
+#include <stdint.h>
+
+
+
+/***************************************************************************** */
+/*                          Memory Map                                         */
+/***************************************************************************** */
+/* Base addresses */
+#define LPC_FLASH_BASE        (0x00000000UL)
+#define LPC_RAM_BASE          (0x10000000UL)
+#define LPC_RAM1_BASE         (0x20000000UL)
+#define LPC_USB_RAM_BASE      (0x20004000UL)
+#define LPC_APB0_BASE         (0x40000000UL)
+#define LPC_APB1_BASE         (0x40080000UL) /* USB in LPC11U3x */
+#define LPC_AHB_BASE          (0x50000000UL)
+
+/* Memory mapping of Cortex-M0 Hardware */
+#define LPC_SCS_BASE        (0xE000E000UL)         /* System Control Space 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 */
+
+/* APB0 peripherals */
+#define LPC_I2C0_BASE          (LPC_APB0_BASE + 0x00000)
+#define LPC_WDT_BASE           (LPC_APB0_BASE + 0x04000)
+#define LPC_UART0_BASE         (LPC_APB0_BASE + 0x08000)
+#define LPC_TIMER0_BASE        (LPC_APB0_BASE + 0x0C000)
+#define LPC_TIMER1_BASE        (LPC_APB0_BASE + 0x10000)
+#define LPC_TIMER2_BASE        (LPC_APB0_BASE + 0x14000)
+#define LPC_TIMER3_BASE        (LPC_APB0_BASE + 0x18000)
+#define LPC_ADC_BASE           (LPC_APB0_BASE + 0x1C000)
+#define LPC_PMU_BASE           (LPC_APB0_BASE + 0x38000)
+#define LPC_FLASH_EEPROM_BASE  (LPC_APB0_BASE + 0x3C000)
+#define LPC_SSP0_BASE          (LPC_APB0_BASE + 0x40000)
+#define LPC_IOCON_BASE         (LPC_APB0_BASE + 0x44000)
+#define LPC_SYSCON_BASE        (LPC_APB0_BASE + 0x48000)
+#define LPC_GPIO_INTR_BASE     (LPC_APB0_BASE + 0x4C000)
+#define LPC_SSP1_BASE          (LPC_APB0_BASE + 0x58000)
+#define LPC_GPIO_GRP0_INT_BASE (LPC_APB0_BASE + 0x5C000)
+#define LPC_GPIO_GRP1_INT_BASE (LPC_APB0_BASE + 0x60000)
+
+/* APB1 peripherals */
+#define LPC_USB_BASE           (LPC_APB1_BASE + 0x00000)
+
+/* AHB peripherals */
+#define LPC_GPIO_BASE          (LPC_AHB_BASE + 0x00000)
+
+
+
+/***************************************************************************** */
+/*                     System Control                                          */
+/***************************************************************************** */
+/* System Control (SYSCON) */
+struct lpc_sys_start_logic_ctrl
+{
+       volatile uint32_t edge_ctrl;  /* 0x00 : edge control Register 0 (R/W) */
+       volatile uint32_t signal_en;  /* 0x04 : signal enable Register 0 (R/W) */
+       volatile uint32_t reset;      /* 0x08 : reset Register 0  (-/W) */
+       volatile uint32_t status;     /* 0x0C : status Register 0 (R/-) */
+};
+struct lpc_sys_control
+{
+       volatile uint32_t sys_mem_remap;   /* 0x000 System memory remap (R/W) */
+       volatile uint32_t peripheral_reset_ctrl; /* 0x004 Peripheral reset control (R/W) */
+       volatile uint32_t sys_pll_ctrl;    /* 0x008 System PLL control (R/W) */
+       volatile uint32_t sys_pll_status;  /* 0x00C System PLL status (R/ ) */
+       volatile uint32_t usb_pll_ctrl;    /* 0x010 USB PLL control (R/W) */
+       volatile uint32_t usb_pll_status;  /* 0x014 USB PLL status (R/ ) */
+       uint32_t reserved_0[2];
+
+       volatile uint32_t sys_osc_ctrl;    /* 0x020 : System oscillator control (R/W) */
+       volatile uint32_t WDT_osc_ctrl;    /* 0x024 : Watchdog oscillator control (R/W) */
+       volatile uint32_t IRC_ctrl;        /* 0x028 : IRC control (R/W) */
+       uint32_t reserved_1[1];
+       volatile uint32_t sys_reset_status;    /* 0x030 : System reset status Register (R/ ) */
+       uint32_t reserved_2[3];
+       volatile uint32_t sys_pll_clk_sel;     /* 0x040 : System PLL clock source select (R/W) */
+       volatile uint32_t sys_pll_clk_upd_en;  /* 0x044 : System PLL clock source update enable (R/W) */
+       volatile uint32_t usb_pll_clk_sel;     /* 0x048 : USB PLL clock source select (R/W) */
+       volatile uint32_t usb_pll_clk_upd_en;  /* 0x04C : USB PLL clock source update enable (R/W) */
+       uint32_t reserved_3[8];
+
+       volatile uint32_t main_clk_sel;     /* 0x070 : Main clock source select (R/W) */
+       volatile uint32_t main_clk_upd_en;  /* 0x074 : Main clock source update enable (R/W) */
+       volatile uint32_t sys_AHB_clk_div;  /* 0x078 : System AHB clock divider (R/W) */
+       uint32_t reserved_4[1];
+       volatile uint32_t sys_AHB_clk_ctrl; /* 0x080 : System AHB clock control (R/W) */
+       uint32_t reserved_5[4];
+
+       volatile uint32_t ssp0_clk_div;   /* 0x094 : SSP0 clock divider (R/W) */
+       volatile uint32_t uart_clk_div;   /* 0x098 : UART0 clock divider (R/W) */
+       volatile uint32_t ssp1_clk_div;   /* 0x09C : SSP1 clock divider (R/W) */
+       uint32_t reserved_6a[8];
+       volatile uint32_t usb_clk_sel;    /* 0x0C0 : USB clock source select (R/W) */
+       volatile uint32_t usb_clk_upd_en; /* 0x0C4 : USB clock source update enable (R/W) */
+       volatile uint32_t usb_clk_div;    /* 0x0C8 : USB clock source divider (R/W) */
+       uint32_t reserved_6b[5];
+
+       volatile uint32_t clk_out_src_sel; /* 0x0E0 : CLKOUT clock source select (R/W) */
+       volatile uint32_t clk_out_upd_en;  /* 0x0E4 : CLKOUT clock source update enable (R/W) */
+       volatile uint32_t clk_out_div;     /* 0x0E8 : CLKOUT clock divider (R/W) */
+       uint32_t reserved_7[5];
+
+       volatile uint32_t por_captured_io_status[2];  /* 0x100 - 0x104 : POR captured PIO status 0 and 1 (R/ ) */
+       uint32_t reserved_8[11];
+
+       volatile uint32_t IO_config_clk_div[7]; /* 0x134 - 0x14C : Peripheral clocks 6 to 0 for glitch filter */
+
+       volatile uint32_t BOD_ctrl;      /* 0x150 : BOD control (R/W) */
+       volatile uint32_t sys_tick_cal;  /* 0x154 : System tick counter calibration (R/W) */
+       volatile uint32_t ahb_prio_set;  /* 0x158 : AHB priority setting (-/-) */
+       uint32_t reserved_9[5];
+       volatile uint32_t irq_latency;   /* 0x170 : IRQ delay, alloxs trade-off bw latency and determinism (R/W) */
+       volatile uint32_t int_nmi_cfg;   /* 0x174 : NMI interrupt source configuration control (R/W) */
+       volatile uint32_t gpio_int_sel[8]; /* 0x178 - 0x194 : GPIO Pin Interrupt Select 0 to 8 (R/W) */
+       volatile uint32_t usb_clk_ctrl;    /* 0x198 : USB Clock control (R/W) */
+       volatile uint32_t usb_clk_status;  /* 0x198 : USB Clock status (R/W) */
+       uint32_t reserved_10[24];
+
+       struct lpc_sys_start_logic_ctrl start_log_strl[2]; /* 0x200 to 0x20C and 0x210 to 0x21C :
+                                                                                                Start logic 0 and Start logic 1/peripheral interrupts */
+       uint32_t reserved_11[4];
+
+       volatile uint32_t powerdown_sleep_cfg;  /* 0x230 : Power-down states in Deep-sleep mode (R/W) */
+       volatile uint32_t powerdown_awake_cfg;  /* 0x234 : Power-down states after wake-up (R/W) */
+       volatile uint32_t powerdown_run_cfg;        /* 0x238 : Power-down configuration Register (R/W) */
+       uint32_t reserved_12[110];
+       volatile const uint32_t device_id;  /* 0x3F4 : Device ID (R/ ) */
+};
+
+#define LPC_SYS_CONTROL ((struct lpc_sys_control *) LPC_SYSCON_BASE)
+
+/* AHB control bits
+ *   0 (System (cortexM0, syscon, PMU, ...)) is a read only bit (system cannot be disabled)
+ */
+#define LPC_SYS_ABH_CLK_CTRL_SYSTEM     (1 <<  0) /* Read only */
+#define LPC_SYS_ABH_CLK_CTRL_ROM        (1 <<  1)
+#define LPC_SYS_ABH_CLK_CTRL_RAM        (1 <<  2)
+#define LPC_SYS_ABH_CLK_CTRL_FLASH_REG  (1 <<  3)
+#define LPC_SYS_ABH_CLK_CTRL_FLASH      (1 <<  4)
+#define LPC_SYS_ABH_CLK_CTRL_I2C        (1 <<  5)
+#define LPC_SYS_ABH_CLK_CTRL_GPIO       (1 <<  6)
+#define LPC_SYS_ABH_CLK_CTRL_CT16B0     (1 <<  7)
+#define LPC_SYS_ABH_CLK_CTRL_CT16B1     (1 <<  8)
+#define LPC_SYS_ABH_CLK_CTRL_CT32B0     (1 <<  9)
+#define LPC_SYS_ABH_CLK_CTRL_CT32B1     (1 << 10)
+#define LPC_SYS_ABH_CLK_CTRL_SSP0       (1 << 11)
+#define LPC_SYS_ABH_CLK_CTRL_UART0      (1 << 12)
+#define LPC_SYS_ABH_CLK_CTRL_ADC        (1 << 13)
+#define LPC_SYS_ABH_CLK_CTRL_USB        (1 << 14)
+#define LPC_SYS_ABH_CLK_CTRL_Watchdog   (1 << 15)
+#define LPC_SYS_ABH_CLK_CTRL_IO_CONFIG  (1 << 16)
+#define LPC_SYS_ABH_CLK_CTRL_SSP1       (1 << 18)
+#define LPC_SYS_ABH_CLK_CTRL_PINT       (1 << 19)
+#define LPC_SYS_ABH_CLK_CTRL_P0INT      (1 << 23)
+#define LPC_SYS_ABH_CLK_CTRL_P1INT      (1 << 24)
+#define LPC_SYS_ABH_CLK_CTRL_RAM1       (1 << 26)
+#define LPC_SYS_ABH_CLK_CTRL_USBRAM     (1 << 27)
+/* Helper */
+#define LPC_SYS_ABH_CLK_CTRL_MEM_ALL    0x0000001F
+
+#define LPC_SSP0_RESET_N       (1 << 0)
+#define LPC_I2C_RESET_N        (1 << 1)
+#define LPC_SSP1_RESET_N       (1 << 2)
+
+#define LPC_POWER_DOWN_IRC_OUT      (1 << 0)
+#define LPC_POWER_DOWN_IRC          (1 << 1)
+#define LPC_POWER_DOWN_FLASH        (1 << 2)
+#define LPC_POWER_DOWN_BOD          (1 << 3)
+#define LPC_POWER_DOWN_ADC          (1 << 4)
+#define LPC_POWER_DOWN_SYS_OSC      (1 << 5)
+#define LPC_POWER_DOWN_WDT_OSC      (1 << 6)
+#define LPC_POWER_DOWN_SYSPLL       (1 << 7)
+#define LPC_POWER_DOWN_USBPLL       (1 << 8)
+#define LPC_POWER_DOWN_USB          (1 << 10)
+                            /* write bit 11, 13, 14, 15 always as ones   and   bits 9 and 12 always as zeroes */
+#define LPC_POWER_DOWN_MASK(x)    (  ((x) | (1 << 11) | (0x07 << 13))   &   ~((1 << 9) | (1 << 12))  )
+
+#define LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_ON  0x0000FFF7
+#define LPC_DEEP_SLEEP_CFG_NOWDTLOCK_BOD_OFF 0x0000FFFF
+
+#define LPC_CLKOUT_SRC_IRC_OSC       0x00
+#define LPC_CLKOUT_SRC_XTAL_OSC      0x01
+#define LPC_CLKOUT_SRC_WATCHDOG_OSC  0x02
+#define LPC_CLKOUT_SRC_MAIN_CLK      0x03
+
+#define LPC_SYSCLK_SRC_IRC_OSC       0x00
+#define LPC_SYSCLK_SRC_XTAL_OSC      0x01
+#define LPC_SYSCLK_SRC_PLL_INPUT     0x01
+#define LPC_SYSCLK_SRC_WATCHDOG_OSC  0x02
+#define LPC_SYSCLK_SRC_MAIN_CLK      0x03
+#define LPC_SYSCLK_SRC_PLL_OUTPUT    0x03
+
+#define LPC_USBPLLCLK_SRC_IRC_OSC    0x00
+#define LPC_USBPLLCLK_SRC_XTAL_OSC   0x01
+
+#define LPC_USBCLK_SRC_USB_PLL_OUT   0x00
+#define LPC_USBCLK_SRC_MAIN_CLK      0x01
+
+
+/***************************************************************************** */
+/*                  Flash Control                                              */
+/***************************************************************************** */
+/* Flash configuration */
+struct lpc_flash_control
+{
+       uint32_t reserved_0[4];
+       volatile uint32_t flash_cfg; /* 0x028 Flash configuration (R/W) */
+       uint32_t reserved_1[3];
+       /* Flash Memory Signature */
+       volatile uint32_t flash_signature_start;  /* 0x020 : Signature start address (R/W) */
+       volatile uint32_t flash_signature_end;    /* 0x024 : Signature end address (R/W) */
+       uint32_t reserved_2[1];
+       volatile uint32_t flash_signature[4];     /* 0x02C - 0x038 : Signature Words (R/-) */
+       uint32_t reserved_3[24];
+       /* EEPROM Memory Signature */
+       volatile uint32_t eeprom_signature_start;  /* 0x09C : Signature start address (R/W) */
+       volatile uint32_t eeprom_signature_end;    /* 0x0A0 : Signature end address (R/W) */
+       volatile uint32_t eeprom_signature;        /* 0x0A4 : Signature (R/-) */
+       uint32_t reserved_4[975];
+       /* Flash Memory Signature Generation */
+       volatile uint32_t flash_sig_gen_status;    /* 0xFE0 : Flash signature generation status (R/-) */
+       uint32_t reserved_5[1];
+       volatile uint32_t flash_sig_gen_stat_clr;  /* 0xFE8 : Flash signature generation status clear (R/W) */
+};
+#define LPC_FLASH_CONTROL ((struct lpc_flash_control *) LPC_FLASH_EEPROM_BASE)
+#define LPC_FLASH_CFG_MASK   0x03
+#define LPC_FLASH_CFG_SHIFT  0
+
+
+
+/***************************************************************************** */
+/*                     Cortex-M0 NVIC                                          */
+/***************************************************************************** */
+/* Cortex-M0 NVIC Registers */
+struct nvic_regs {
+       volatile uint32_t int_set_enable;  /* 0x000 : Interrupt Set Enable Register (R/W) */
+       uint32_t reserved_0[31];
+       volatile uint32_t int_clear_enable;  /* 0x080 : Interrupt Clear Enable Register (R/W) */
+       uint32_t reserved_1[31];
+       volatile uint32_t int_set_pending;  /* 0x100 : Interrupt Set Pending Register (R/W) */
+       uint32_t reserved_2[31];
+       volatile uint32_t int_clear_pending;  /* 0x180 : Interrupt Clear Pending Register (R/W) */
+       uint32_t reserved_3[31];
+       uint32_t reserved_4[64];
+       volatile uint32_t int_priority[8]; /* 0x3EC : Interrupt Priority Register (R/W) */
+};
+#define LPC_NVIC      ((struct nvic_regs *) LPC_NVIC_BASE)        /* NVIC configuration struct */
+
+
+/***************************************************************************** */
+/*                    Cortex-M0 System Control Block                           */
+/***************************************************************************** */
+/* Cortex-M0 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) */
+       uint32_t reserved_0;
+       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) */
+       uint32_t reserved_1;
+       volatile uint32_t shp[2];      /* 0x01C : System Handlers Priority Registers. [0] is reserved_ (R/W) */
+};
+#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_SYSRESETREQ      (1UL << 2)         /* SCB AIRCR: SYSRESETREQ Mask */
+#define SCB_AIRCR_VECTCLRACTIVE    (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-M0 System Timer                                   */
+/***************************************************************************** */
+/* Cortex-M0 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_CLK_MAIN   (1UL << 2)    /* SysTick CTRL: CLKSOURCE is main clock */
+#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 */
+
+
+
+
+/***************************************************************************** */
+/*                     Power Management Unit                                   */
+/***************************************************************************** */
+/* Power Management Unit (PMU) */
+struct lpc_pm_unit
+{
+       volatile uint32_t power_ctrl;  /* 0x000 : Power control Register (R/W) */
+       volatile uint32_t gp_data[4];  /* 0x004 to 0x010 : General purpose Register 0 to 3 (R/W) */
+       volatile uint32_t system_config; /* 0x014 : System configuration register (R/W) */
+                                                       /* (RTC clock control and hysteresis of the WAKEUP pin) */
+};
+#define LPC_PMU         ((struct lpc_pm_unit *) LPC_PMU_BASE)
+
+/* System config register */
+#define LPC_WAKEUP_PIN_HYST_MASK    (0x01 << 10)
+#define LPC_RTC_CLK_SRC_SHIFT       11
+#define LPC_RTC_CLK_SRC_MASK        (0x0F << LPC_RTC_CLK_SRC_SHIFT)
+/* See RTC section above for RTC Clock source selection bits */
+
+
+/***************************************************************************** */
+/*                     IO Control                                              */
+/***************************************************************************** */
+/* Pin Connect Block (IOCON) */
+struct lpc_io_control
+{
+       volatile uint32_t pio0_0;    /* 0x000 : I/O configuration for pin pio0_0 (R/W) */
+       volatile uint32_t pio0_1;    /* 0x004 : I/O configuration for pin pio0_1 (R/W) */
+       volatile uint32_t pio0_2;    /* 0x008 : I/O configuration for pin pio0_2 (R/W) */
+       volatile uint32_t pio0_3;    /* 0x00C : I/O configuration for pin pio0_3 (R/W) */
+       volatile uint32_t pio0_4;    /* 0x010 : I/O configuration for pin pio0_4 (R/W) */
+       volatile uint32_t pio0_5;    /* 0x014 : I/O configuration for pin pio0_5 (R/W) */
+       volatile uint32_t pio0_6;    /* 0x018 : I/O configuration for pin pio0_6 (R/W) */
+       volatile uint32_t pio0_7;    /* 0x01C : I/O configuration for pin pio0_7 (R/W) */
+       volatile uint32_t pio0_8;    /* 0x020 : I/O configuration for pin pio0_8 (R/W) */
+       volatile uint32_t pio0_9;    /* 0x024 : I/O configuration for pin pio0_9 (R/W) */
+       volatile uint32_t pio0_10;   /* 0x028 : I/O configuration for pin SWD0_10 (R/W) */
+       volatile uint32_t pio0_11;   /* 0x02C : I/O configuration for pin pio0_11 (R/W) */
+       volatile uint32_t pio0_12;   /* 0x030 : I/O configuration for pin pio0_12 (R/W) */
+       volatile uint32_t pio0_13;   /* 0x034 : I/O configuration for pin pio0_13 (R/W) */
+       volatile uint32_t pio0_14;   /* 0x038 : I/O configuration for pin pio0_14 (R/W) */
+       volatile uint32_t pio0_15;   /* 0x03C : I/O configuration for pin pio0_15 (R/W) */
+       volatile uint32_t pio0_16;   /* 0x040 : I/O configuration for pin pio0_16 (R/W) */
+       volatile uint32_t pio0_17;   /* 0x044 : I/O configuration for pin pio0_17 (R/W) */
+       volatile uint32_t pio0_18;   /* 0x048 : I/O configuration for pin pio0_18 (R/W) */
+       volatile uint32_t pio0_19;   /* 0x04C : I/O configuration for pin pio0_19 (R/W) */
+       volatile uint32_t pio0_20;   /* 0x050 : I/O configuration for pin pio0_20 (R/W) */
+       volatile uint32_t pio0_21;   /* 0x054 : I/O configuration for pin pio0_21 (R/W) */
+       volatile uint32_t pio0_22;   /* 0x058 : I/O configuration for pin pio0_22 (R/W) */
+       volatile uint32_t pio0_23;   /* 0x05C : I/O configuration for pin pio0_23 (R/W) */
+
+       volatile uint32_t pio1_0;    /* 0x060 : I/O configuration for pin pio1_0 (R/W) */
+       volatile uint32_t pio1_1;    /* 0x064 : I/O configuration for pin pio1_1 (R/W) */
+       volatile uint32_t pio1_2;    /* 0x068 : I/O configuration for pin pio1_2 (R/W) */
+       volatile uint32_t pio1_3;    /* 0x06C : I/O configuration for pin pio1_3 (R/W) */
+       volatile uint32_t pio1_4;    /* 0x070 : I/O configuration for pin pio1_4 (R/W) */
+       volatile uint32_t pio1_5;    /* 0x074 : I/O configuration for pin pio1_5 (R/W) */
+       volatile uint32_t pio1_6;    /* 0x078 : I/O configuration for pin pio1_6 (R/W) */
+       volatile uint32_t pio1_7;    /* 0x07C : I/O configuration for pin pio0_7 (R/W) */
+       volatile uint32_t pio1_8;    /* 0x080 : I/O configuration for pin pio0_8 (R/W) */
+       volatile uint32_t pio1_9;    /* 0x084 : I/O configuration for pin pio0_9 (R/W) */
+       volatile uint32_t pio1_10;   /* 0x088 : I/O configuration for pin SWD0_10 (R/W) */
+       volatile uint32_t pio1_11;   /* 0x08C : I/O configuration for pin pio0_11 (R/W) */
+       volatile uint32_t pio1_12;   /* 0x090 : I/O configuration for pin pio0_12 (R/W) */
+       volatile uint32_t pio1_13;   /* 0x094 : I/O configuration for pin pio0_13 (R/W) */
+       volatile uint32_t pio1_14;   /* 0x098 : I/O configuration for pin pio0_14 (R/W) */
+       volatile uint32_t pio1_15;   /* 0x09C : I/O configuration for pin pio0_15 (R/W) */
+       volatile uint32_t pio1_16;   /* 0x0A0 : I/O configuration for pin pio0_16 (R/W) */
+       volatile uint32_t pio1_17;   /* 0x0A4 : I/O configuration for pin pio0_17 (R/W) */
+       volatile uint32_t pio1_18;   /* 0x0A8 : I/O configuration for pin pio0_18 (R/W) */
+       volatile uint32_t pio1_19;   /* 0x0AC : I/O configuration for pin pio0_19 (R/W) */
+       volatile uint32_t pio1_20;   /* 0x0B0 : I/O configuration for pin pio0_20 (R/W) */
+       volatile uint32_t pio1_21;   /* 0x0B4 : I/O configuration for pin pio0_21 (R/W) */
+       volatile uint32_t pio1_22;   /* 0x0B8 : I/O configuration for pin pio0_22 (R/W) */
+       volatile uint32_t pio1_23;   /* 0x0BC : I/O configuration for pin pio0_23 (R/W) */
+       volatile uint32_t pio1_24;   /* 0x0C0 : I/O configuration for pin pio0_24 (R/W) */
+       volatile uint32_t pio1_25;   /* 0x0C4 : I/O configuration for pin pio0_25 (R/W) */
+       volatile uint32_t pio1_26;   /* 0x0C8 : I/O configuration for pin pio0_26 (R/W) */
+       volatile uint32_t pio1_27;   /* 0x0CC : I/O configuration for pin pio0_27 (R/W) */
+       volatile uint32_t pio1_28;   /* 0x0D0 : I/O configuration for pin pio0_28 (R/W) */
+       volatile uint32_t pio1_29;   /* 0x0D4 : I/O configuration for pin pio0_29 (R/W) */
+       uint32_t reserved_1[1];
+       volatile uint32_t pio1_31;   /* 0x0DC : I/O configuration for pin pio0_31 (R/W) */
+};
+#define LPC_IO_CONTROL  ((struct lpc_io_control *) LPC_IOCON_BASE)
+
+/* FIXME : to be completed */
+#define LPC_IO_FUNC_ALT(x) ((x & 0x07) << 0)
+
+#define LPC_IO_MODE_INACTIVE  (0x00 << 3)
+#define LPC_IO_MODE_PULL_DOWN (0x01 << 3)
+#define LPC_IO_MODE_PULL_UP   (0x02 << 3)
+#define LPC_IO_MODE_REPEATER  (0x03 << 3)
+
+#define LPC_IO_HISTERESIS_EN  (0x01 << 5)
+#define LPC_IO_INVERTED  (0x01 << 6)
+
+#define LPC_IO_ANALOG    (0x00 << 7)
+#define LPC_IO_DIGITAL   (0x01 << 7)
+
+#define LPC_IO_FILTERING_DISABLE (0x01 << 8)
+
+#define LPC_IO_DRIVE_LOWCURENT  (0x00 << 9)
+#define LPC_IO_DRIVE_HIGHCURENT (0x01 << 9)
+
+#define LPC_IO_OPEN_DRAIN_ENABLE (0x01 << 10)
+
+#define LPC_IO_SAMPLE_MODE_BYP    (0x00 << 11)
+#define LPC_FILTER_ONE_CLK    1
+#define LPC_FILTER_TWO_CLK    2
+#define LPC_FILTER_THREE_CLK  3
+#define LPC_IO_SAMPLE_MODE(x)     ((x & 0x03) << 11)
+#define LPC_IO_SAMPLE_CLK_DIV(x)  ((x & 0x07) << 13)
+
+
+/***************************************************************************** */
+/*                     General Purpose Input/Output (GPIO)                     */
+/***************************************************************************** */
+/* General Purpose Input/Output (GPIO) */
+struct lpc_gpio
+{
+       volatile uint32_t data_dir;   /* 0x000 : Data direction Register (R/W) */
+       uint32_t reserved_0[31];
+       volatile uint32_t mask;       /* 0x080 : Pin mask, affects in, out, set, clear and toggle */
+       uint32_t reserved_1[31];
+       volatile uint32_t value;      /* 0x100 : Port data Register (R/-) */
+       uint32_t reserved_2[31];
+       volatile uint32_t masked_val; /* 0x180 : Port masked data Register (R/W) */
+       uint32_t reserved_3[31];
+       volatile uint32_t set;        /* 0x200 : Port output set Register (-/W) */
+       uint32_t reserved_4[31];
+       volatile uint32_t clear;      /* 0x280 : Port output clear Register (-/W) */
+       uint32_t reserved_5[31];
+       volatile uint32_t toggle;     /* 0x300 : Port output invert Register (-/W) */
+};
+#define LPC_GPIO_0      ((struct lpc_gpio *) (LPC_GPIO_BASE + 0x2000))
+#define LPC_GPIO_1      ((struct lpc_gpio *) (LPC_GPIO_BASE + 0x2004))
+
+#define LPC_GPIO_REGS(x)  ((struct lpc_gpio *) (LPC_GPIO_BASE + 0x2000 + ((x) * 4)))
+
+#define GPIO_DIR_IN 0
+#define GPIO_DIR_OUT 1
+
+#define LPC_GPIO_ALL_BYTES  ((uint8_t*) (LPC_GPIO_BASE + 0x0000))
+#define LPC_GPIO_0_BYTES  ((uint8_t*) (LPC_GPIO_BASE + 0x0000))
+#define LPC_GPIO_1_BYTES  ((uint8_t*) (LPC_GPIO_BASE + 0x0020))
+#define LPC_GPIO_ALL_WORDS  ((uint32_t*) (LPC_GPIO_BASE + 0x1000))
+#define LPC_GPIO_0_WORDS  ((uint32_t*) (LPC_GPIO_BASE + 0x1000))
+#define LPC_GPIO_1_WORDS  ((uint32_t*) (LPC_GPIO_BASE + 0x1080))
+
+/* General Purpose Input/Output (GPIO) : multiple ports access */
+#define LPC_NB_GPIO_PORTS 2
+struct lpc_gpio_all
+{
+       volatile uint32_t data_dir[LPC_NB_GPIO_PORTS];   /* 0x000 : Data direction Register (R/W) */
+       uint32_t reserved_0[32 - LPC_NB_GPIO_PORTS];
+       volatile uint32_t mask[LPC_NB_GPIO_PORTS];       /* 0x080 : Pin mask, affects in, out, set, clear and toggle */
+       uint32_t reserved_1[32 - LPC_NB_GPIO_PORTS];
+       volatile uint32_t value[LPC_NB_GPIO_PORTS];      /* 0x100 : Port data Register (R/-) */
+       uint32_t reserved_2[32 - LPC_NB_GPIO_PORTS];
+       volatile uint32_t masked_val[LPC_NB_GPIO_PORTS]; /* 0x180 : Port masked data Register (R/W) */
+       uint32_t reserved_3[32 - LPC_NB_GPIO_PORTS];
+       volatile uint32_t set[LPC_NB_GPIO_PORTS];        /* 0x200 : Port output set Register (-/W) */
+       uint32_t reserved_4[32 - LPC_NB_GPIO_PORTS];
+       volatile uint32_t clear[LPC_NB_GPIO_PORTS];      /* 0x280 : Port output clear Register (-/W) */
+       uint32_t reserved_5[32 - LPC_NB_GPIO_PORTS];
+       volatile uint32_t toggle[LPC_NB_GPIO_PORTS];     /* 0x300 : Port output invert Register (-/W) */
+};
+#define LPC_GPIO_ALL     ((struct lpc_gpio_all *) (LPC_GPIO_BASE + 0x2000))
+
+/***************************************************************************** */
+/*                     GPIO Interrupts Control                                 */
+/***************************************************************************** */
+
+struct lpc_gpio_pin_edge_interrupt
+{
+       volatile uint32_t mode;       /* 0x000 : Pin interrupt mode (level/edge) (R/W) */
+       volatile uint32_t rising_enable;       /* 0x004 : Rising edge interrupt enable (R/W) */
+       volatile uint32_t rising_enable_set;   /* 0x008 : Set above reg .... (-/W) */
+       volatile uint32_t rising_enable_clear; /* 0x00C : Clear above reg .... (-/W) */
+       volatile uint32_t falling_enable;        /* 0x010 : Falling edge interrupt enable (R/W) */
+       volatile uint32_t falling_enable_set;    /* 0x014 : Set above reg .... (-/W) */
+       volatile uint32_t falling_enable_clear;  /* 0x018 : Clear above reg .... (-/W) */
+       volatile uint32_t rising_edge_detected;  /* 0x01C : Rising edge detected (R/W) */
+       volatile uint32_t falling_edge_detected; /* 0x020 : Falling edge detected (R/W) */
+       volatile uint32_t status;     /* 0x024 : Int status / clear both edge detection status (R/W) */
+};
+#define LPC_GPIO_INT_EDGE      ((struct lpc_gpio_pin_edge_interrupt *) LPC_GPIO_INTR_BASE)
+
+struct lpc_gpio_pin_level_interrupt
+{
+       volatile uint32_t mode;       /* 0x000 : Pin interrupt mode (level/edge) (R/W) */
+       volatile uint32_t enable;     /* 0x004 : Level interrupt enable (R/W) */
+       volatile uint32_t enable_set;      /* 0x008 : Set above reg .... (-/W) */
+       volatile uint32_t enable_clear;    /* 0x00C : Clear above reg .... (-/W) */
+       volatile uint32_t active_level;    /* 0x010 : Set active level (R/W) */
+       volatile uint32_t set_active_high; /* 0x014 : Set active level to high (-/W) */
+       volatile uint32_t set_active_low;  /* 0x018 : Set active level to low (-/W) */
+       uint32_t reserved[2];
+       volatile uint32_t status_and_toggle; /* 0x024 : Int status / toggle level (R/W) */
+};
+#define LPC_GPIO_INT_LEVEL     ((struct lpc_gpio_pin_level_interrupt *) LPC_GPIO_INTR_BASE)
+
+#define LPC_GPIO_INT_MODE_EDGE    0
+#define LPC_GPIO_INT_MODE_LEVEL   1
+
+#define LPC_GPIO_INT(x)  (0x01 << (x & 0x07))
+
+struct group_gpio_int
+{
+       volatile uint32_t control;     /* 0x000 : Grouped interrupt control (R/W) */
+       uint32_t reserved_0[7];
+       volatile uint32_t polarity[2]; /* 0x020 - 0x024 : Port 0/1 pins polarity (R/W) */
+       uint32_t reserved_1[6];
+       volatile uint32_t enable[2];   /* 0x040 - 0x044 : Port 0/1 pins interrupt enable (R/W) */
+};
+#define LPC_GROUP0_GPIO_INT     ((struct group_gpio_int *) LPC_GPIO_GRP0_INT_BASE)
+#define LPC_GROUP1_GPIO_INT     ((struct group_gpio_int *) LPC_GPIO_GRP1_INT_BASE)
+
+
+
+/***************************************************************************** */
+/*                     Universal Asynchronous Receiver Transmitter             */
+/***************************************************************************** */
+/* Universal Asynchronous Receiver Transmitter (UART) */
+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) */
+       volatile uint32_t oversampling;    /* 0x02C : Oversampling Register (R/W) */
+       volatile uint32_t transmit_enable; /* 0x030 : Transmit Enable Register (R/W) */
+       uint32_t reserved_1[3];
+       volatile uint32_t half_duplex_en;  /* 0x040 :  Half-duplex Enable Register (R/W) */
+       uint32_t reserved_2;
+       volatile uint32_t smart_card_ctrl;  /* 0x048 : Smart Card Interface Control Register (R/W) */
+       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 sync_ctrl;  /* 0x058 : Synchronous Mode Control Register (R/W) */
+};
+#define LPC_UART_0        ((struct lpc_uart *) LPC_UART0_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_TX_CLR        (0x01 << 1)
+#define LPC_UART_RX_CLR        (0x01 << 2)
+#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                                */
+/***************************************************************************** */
+/* Inter-Integrated Circuit (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 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) */
+};
+#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)
+
+
+
+/***************************************************************************** */
+/*                     Timer                                                   */
+/***************************************************************************** */
+/* Timer (TMR) */
+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) */
+       uint32_t reserved_2[12];
+       volatile uint32_t count_ctrl;     /* 0x070 : Count Control Register (R/W) */
+       volatile uint32_t pwm_ctrl;       /* 0x074 : PWM Control Register (R/W) */
+};
+#define LPC_TMR16B0     ((struct lpc_timer *) LPC_TIMER0_BASE)
+#define LPC_TMR16B1     ((struct lpc_timer *) LPC_TIMER1_BASE)
+#define LPC_TMR32B0     ((struct lpc_timer *) LPC_TIMER2_BASE)
+#define LPC_TMR32B1     ((struct lpc_timer *) LPC_TIMER3_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) */
+       volatile uint32_t warning_int_compare; /* 0x014 : Watchdog Warning Interrupt compare value. */
+       volatile uint32_t window_compare;      /* 0x018 : Watchdog Window compare value. */
+};
+#define LPC_WDT         ((struct lpc_watchdog *) LPC_WDT_BASE)
+
+
+/***************************************************************************** */
+/*                     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/ ) */
+};
+#define LPC_ADC         ((struct lpc_adc *) LPC_ADC_BASE)
+
+/* ADC Control register bits */
+#define LPC_ADC_CTRL_MASK  0x0F0FFFFF
+/* 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_5BITS   (0x05 << 17)
+#define LPC_ADC_4BITS   (0x06 << 17)
+#define LPC_ADC_3BITS   (0x07 << 17)
+#define LPC_ADC_BITS_MASK  (0x07 << 17)
+
+#define LPC_ADC_START_CONV_NOW  (0x01 << 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)
+
+
+/***************************************************************************** */
+/*                     USB (Universal Serial Bus)                              */
+/***************************************************************************** */
+/* USB Device Controller */
+struct lpc_usb_device
+{
+    volatile uint32_t dev_cmd_status;     /* 0x000 : USB Device Command and Status register (R/W) */
+    volatile uint32_t info;               /* 0x004 : USb Info register (R/W) */
+    volatile uint32_t ep_list_start;      /* 0x008 : USB EP Command and Status List start address (R/W) */
+    volatile uint32_t data_buff_start;    /* 0x00C : USB Data buffer start address (R/W) */
+    volatile uint32_t link_pm;            /* 0x010 : USB Link Power Management register (R/W) */
+    volatile uint32_t ep_skip;            /* 0x014 : USB Endpoint skip (R/W) */
+    volatile uint32_t ep_in_use;          /* 0x018 : USB Endpoint Buffer in use (R/W) */
+    volatile uint32_t ep_buff_config;     /* 0x01C : USB Endpoint Buffer Configuration register (R/W) */
+    volatile uint32_t intr_status;        /* 0x020 : USB interrupt status register (R/W) */
+    volatile uint32_t intr_enable;        /* 0x024 : USB interrupt enable register (R/W) */
+    volatile uint32_t set_intr_status;    /* 0x028 : USB set interrupt status register (R/W) */
+    volatile uint32_t intr_routing;       /* 0x02C : USB interrupt routing register (R/W) */
+       uint32_t reserved_0;
+    volatile uint32_t ep_toggle;          /* 0x034 : USB Endpoint toggle register (R/W) */
+};
+#define LPC_USB         ((struct lpc_usb_device *) LPC_USB_BASE)
+
+
+
+
+#endif  /* LPC_REGS_H */
diff --git a/include/core/pio.h b/include/core/pio.h
new file mode 100644 (file)
index 0000000..c987827
--- /dev/null
@@ -0,0 +1,283 @@
+/****************************************************************************
+ *  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 24
+#define PORT1_NB_PINS 32
+
+/* 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, 1}
+#define LPC_GPIO_0_1  {0,  1, 0}
+#define LPC_GPIO_0_2  {0,  2, 0}
+#define LPC_GPIO_0_3  {0,  3, 0}
+#define LPC_GPIO_0_4  {0,  4, 0}
+#define LPC_GPIO_0_5  {0,  5, 0}
+#define LPC_GPIO_0_6  {0,  6, 0}
+#define LPC_GPIO_0_7  {0,  7, 0}
+#define LPC_GPIO_0_8  {0,  8, 0}
+#define LPC_GPIO_0_9  {0,  9, 0}
+#define LPC_GPIO_0_10 {0, 10, 1}
+#define LPC_GPIO_0_11 {0, 11, 1}
+#define LPC_GPIO_0_12 {0, 12, 1}
+#define LPC_GPIO_0_13 {0, 13, 1}
+#define LPC_GPIO_0_14 {0, 14, 1}
+#define LPC_GPIO_0_15 {0, 15, 1}
+#define LPC_GPIO_0_16 {0, 16, 0}
+#define LPC_GPIO_0_17 {0, 17, 0}
+#define LPC_GPIO_0_18 {0, 18, 0}
+#define LPC_GPIO_0_19 {0, 19, 0}
+#define LPC_GPIO_0_20 {0, 20, 0}
+#define LPC_GPIO_0_21 {0, 21, 0}
+#define LPC_GPIO_0_22 {0, 22, 0}
+#define LPC_GPIO_0_23 {0, 23, 0}
+
+#define LPC_GPIO_1_0  {1,  0, 0}
+#define LPC_GPIO_1_1  {1,  1, 0}
+#define LPC_GPIO_1_2  {1,  2, 0}
+#define LPC_GPIO_1_3  {1,  3, 0}
+#define LPC_GPIO_1_4  {1,  4, 0}
+#define LPC_GPIO_1_5  {1,  5, 0}
+#define LPC_GPIO_1_6  {1,  6, 0}
+#define LPC_GPIO_1_7  {1,  7, 0}
+#define LPC_GPIO_1_8  {1,  8, 0}
+#define LPC_GPIO_1_9  {1,  9, 0}
+#define LPC_GPIO_1_10 {1, 10, 0}
+#define LPC_GPIO_1_11 {1, 11, 0}
+#define LPC_GPIO_1_12 {1, 12, 0}
+#define LPC_GPIO_1_13 {1, 13, 0}
+#define LPC_GPIO_1_14 {1, 14, 0}
+#define LPC_GPIO_1_15 {1, 15, 0}
+#define LPC_GPIO_1_16 {1, 16, 0}
+#define LPC_GPIO_1_17 {1, 17, 0}
+#define LPC_GPIO_1_18 {1, 18, 0}
+#define LPC_GPIO_1_19 {1, 19, 0}
+#define LPC_GPIO_1_20 {1, 20, 0}
+#define LPC_GPIO_1_21 {1, 21, 0}
+#define LPC_GPIO_1_22 {1, 22, 0}
+#define LPC_GPIO_1_23 {1, 23, 0}
+#define LPC_GPIO_1_24 {1, 24, 0}
+#define LPC_GPIO_1_25 {1, 25, 0}
+#define LPC_GPIO_1_26 {1, 26, 0}
+#define LPC_GPIO_1_27 {1, 27, 0}
+#define LPC_GPIO_1_28 {1, 28, 0}
+#define LPC_GPIO_1_29 {1, 29, 0}
+#define LPC_GPIO_1_30 {1, 30, 0}
+#define LPC_GPIO_1_31 {1, 31, 0}
+
+
+
+/****************************************************************************/
+/* USB */
+#define LPC_USB_FTOGGLE_PIO_0_1 {0, 1, 3}
+#define LPC_USB_VBUS_PIO_0_3    {0, 3, 1}
+#define LPC_USB_CONNECT_PIO_0_6 {0, 6, 1}
+
+
+/****************************************************************************/
+/* IOH */
+#define LPC_IOH_0_PIO_0_2      {0,  2, 3}
+#define LPC_IOH_1_PIO_0_3      {0,  3, 2}
+#define LPC_IOH_2_PIO_0_4      {0,  4, 2}
+#define LPC_IOH_3_PIO_0_5      {0,  5, 2}
+#define LPC_IOH_4_PIO_0_6      {0,  6, 3}
+#define LPC_IOH_5_PIO_0_7      {0,  7, 2}
+#define LPC_IOH_6_PIO_0_8      {0,  8, 4}
+#define LPC_IOH_7_PIO_0_9      {0,  9, 4}
+#define LPC_IOH_8_PIO_0_16     {0, 16, 3}
+#define LPC_IOH_9_PIO_0_23     {0, 23, 2}
+#define LPC_IOH_10_PIO_1_0     {1,  0, 2}
+#define LPC_IOH_11_PIO_1_1     {1,  1, 2}
+#define LPC_IOH_12_PIO_1_2     {1,  3, 3}
+#define LPC_IOH_13_PIO_1_3     {1,  3, 2}
+#define LPC_IOH_14_PIO_1_4     {1,  4, 2}
+#define LPC_IOH_15_PIO_1_5     {1,  5, 2}
+#define LPC_IOH_16_PIO_1_6     {1,  6, 1}
+#define LPC_IOH_17_PIO_1_7     {1,  7, 1}
+#define LPC_IOH_18_PIO_1_8     {1,  8, 1}
+#define LPC_IOH_19_PIO_1_26 {1, 26, 3}
+#define LPC_IOH_20_PIO_1_27 {1, 27, 3}
+
+/****************************************************************************/
+/*  CLKOUT and Reset Pin  */
+#define LPC_CLKOUT_PIO_0_1 {0, 1, 1}
+#define LPC_RESET_PIO_0_0  {0, 0, 0}
+
+
+/****************************************************************************/
+/*  SWD (Debug) pins */
+#define LPC_SWD_SWCLK_PIO_0_10  {0, 10, 0}
+#define LPC_SWD_SWDIO_PIO_0_15  {0, 15, 0}
+
+/* JTAG */
+#define LPC_JTAG_TDI_PIO_0_11  {0, 11, 0}
+#define LPC_JTAG_TMS_PIO_0_12  {0, 12, 0}
+#define LPC_JTAG_TDO_PIO_0_13  {0, 13, 0}
+#define LPC_JTAG_TRST_PIO_0_14 {0, 14, 0}
+
+
+/****************************************************************************/
+/*  UART0 Rx/Tx Pins  */
+#define LPC_UART0_RX_PIO_0_18 {0, 18, 1}
+#define LPC_UART0_RX_PIO_1_14 {1, 14, 3}
+#define LPC_UART0_RX_PIO_1_17 {1, 17, 2}
+#define LPC_UART0_RX_PIO_1_26 {1, 26, 2}
+#define LPC_UART0_TX_PIO_0_19 {0, 19, 1}
+#define LPC_UART0_TX_PIO_1_13 {1, 13, 3}
+#define LPC_UART0_TX_PIO_1_18 {1, 18, 2}
+#define LPC_UART0_TX_PIO_1_27 {1, 27, 2}
+/* UART0 - Other UART function pins */
+#define LPC_UART0_CTS_PIO_0_7   {0,  7, 1}
+#define LPC_UART0_DCD_PIO_1_15  {1, 15, 1}
+#define LPC_UART0_DCD_PIO_1_21  {1, 21, 1}
+#define LPC_UART0_DSR_PIO_1_14  {1, 14, 1}
+#define LPC_UART0_DSR_PIO_1_19  {1, 19, 1}
+#define LPC_UART0_DTR_PIO_1_13  {1, 13, 1}
+#define LPC_UART0_DTR_PIO_1_19  {1, 19, 1}
+#define LPC_UART0_RI_PIO_1_16   {1, 16, 1}
+#define LPC_UART0_RI_PIO_1_22   {1, 22, 1}
+#define LPC_UART0_RTS_PIO_0_17  {0, 17, 1}
+#define LPC_UART0_SCLK_PIO_0_17 {0, 17, 3}
+#define LPC_UART0_SCLK_PIO_1_28 {1, 28, 2}
+
+/****************************************************************************/
+/*  I2C Pins  */
+#define LPC_I2C0_SCL_PIO_0_4  {0, 4, 1}
+#define LPC_I2C0_SDA_PIO_0_5  {0, 5, 1}
+
+/****************************************************************************/
+/*  SPI Pins  */
+/* SSP 0 */
+#define LPC_SSP0_SCLK_PIO_0_6  {0,  6, 2}
+#define LPC_SSP0_SCLK_PIO_0_10 {0, 10, 2}
+#define LPC_SSP0_SCLK_PIO_1_29 {1, 29, 1}
+#define LPC_SSP0_MOSI_PIO_0_9  {0,  9, 1}
+#define LPC_SSP0_MISO_PIO_0_8  {0,  8, 1}
+#define LPC_SSP0_SSEL_PIO_0_2  {0,  2, 1}
+/* SSP 1 */
+#define LPC_SSP1_SCLK_PIO_1_15 {1, 15, 3}
+#define LPC_SSP1_SCLK_PIO_1_20 {1, 20, 2}
+#define LPC_SSP1_MOSI_PIO_0_21 {0, 21, 2}
+#define LPC_SSP1_MOSI_PIO_1_22 {1, 22, 2}
+#define LPC_SSP1_MISO_PIO_0_22 {0, 22, 3}
+#define LPC_SSP1_MISO_PIO_1_21 {1, 21, 2}
+#define LPC_SSP1_SSEL_PIO_1_19 {1, 19, 2}
+#define LPC_SSP1_SSEL_PIO_1_23 {1, 23, 2}
+
+
+/****************************************************************************/
+/*  ADC Pins  */
+#define LPC_ADC_AD0_PIO_0_11  {0, 11, 2}
+#define LPC_ADC_AD1_PIO_0_12  {0, 12, 2}
+#define LPC_ADC_AD2_PIO_0_13  {0, 13, 2}
+#define LPC_ADC_AD3_PIO_0_14  {0, 14, 2}
+#define LPC_ADC_AD4_PIO_0_15  {0, 15, 2}
+#define LPC_ADC_AD5_PIO_0_16  {0, 16, 1}
+#define LPC_ADC_AD6_PIO_0_22  {0, 22, 1}
+#define LPC_ADC_AD7_PIO_0_23  {0, 23, 1}
+
+
+/****************************************************************************/
+/*  Timer Pins  */
+
+/* 16 bits timer 0 match pins */
+#define LPC_TIMER_16B0_M0_PIO_0_8  {0,  8, 2}
+#define LPC_TIMER_16B0_M0_PIO_1_13 {1, 13, 2}
+#define LPC_TIMER_16B0_M1_PIO_0_9  {0,  9, 2}
+#define LPC_TIMER_16B0_M1_PIO_1_14 {1, 14, 2}
+#define LPC_TIMER_16B0_M2_PIO_0_10 {0, 10, 3}
+#define LPC_TIMER_16B0_M2_PIO_1_15 {1, 15, 2}
+/* 16 bits timer 0 capture pins */
+#define LPC_TIMER_16B0_C0_PIO_1_16  {1, 16, 2}
+#define LPC_TIMER_16B0_C1_PIO_1_17  {1, 17, 1}
+
+/* 16 bits timer 1 match pins */
+#define LPC_TIMER_16B1_M0_PIO_0_21 {0, 21, 1}
+#define LPC_TIMER_16B1_M1_PIO_0_22 {0, 22, 2}
+#define LPC_TIMER_16B1_M1_PIO_1_23 {1, 23, 1}
+/* 16 bits timer 1 capture pins */
+#define LPC_TIMER_16B1_C0_PIO_0_20 {0, 20, 1}
+#define LPC_TIMER_16B1_C1_PIO_1_18 {1, 18, 1}
+
+/* 32 bits timer 0 match pins */
+#define LPC_TIMER_32B0_M0_PIO_0_18 {0, 18, 2}
+#define LPC_TIMER_32B0_M0_PIO_1_24 {1, 24, 1}
+#define LPC_TIMER_32B0_M1_PIO_0_19 {0, 19, 2}
+#define LPC_TIMER_32B0_M1_PIO_1_25 {1, 25, 1}
+#define LPC_TIMER_32B0_M2_PIO_0_1  {0,  1, 2}
+#define LPC_TIMER_32B0_M2_PIO_1_26 {1, 26, 1}
+#define LPC_TIMER_32B0_M3_PIO_0_11 {0, 11, 3}
+#define LPC_TIMER_32B0_M3_PIO_1_27 {1, 27, 1}
+/* 32 bits timer 0 capture pins */
+#define LPC_TIMER_32B0_C0_PIO_0_17 {0, 17, 2}
+#define LPC_TIMER_32B0_C0_PIO_1_28 {1, 28, 1}
+#define LPC_TIMER_32B0_C1_PIO_1_29 {1, 29, 2}
+
+/* 32 bits timer 1 match pins */
+#define LPC_TIMER_32B1_M0_PIO_0_13 {0, 13, 3}
+#define LPC_TIMER_32B1_M0_PIO_1_0  {1, 0, 1}
+#define LPC_TIMER_32B1_M1_PIO_0_14 {0, 14, 3}
+#define LPC_TIMER_32B1_M1_PIO_1_1  {1, 1, 1}
+#define LPC_TIMER_32B1_M2_PIO_0_15 {0, 15, 3}
+#define LPC_TIMER_32B1_M2_PIO_1_2  {1, 2, 1}
+#define LPC_TIMER_32B1_M3_PIO_0_16 {0, 16, 2}
+#define LPC_TIMER_32B1_M3_PIO_1_3  {1, 3, 1}
+/* 32 bits timer 1 capture pins */
+#define LPC_TIMER_32B1_C0_PIO_0_12 {0, 12, 3}
+#define LPC_TIMER_32B1_C0_PIO_1_4  {1, 4, 1}
+#define LPC_TIMER_32B1_C1_PIO_1_5  {1, 5, 1}
+
+
+
+#endif /* CORE_PIO_H */
diff --git a/include/core/system.h b/include/core/system.h
new file mode 100644 (file)
index 0000000..d0a3111
--- /dev/null
@@ -0,0 +1,138 @@
+/****************************************************************************
+ *   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 "core/lpc_regs_11u3x.h"
+#include "core/lpc_core_cm0.h"
+
+
+/* Error Values, from glibc errno.h and errno-base.h */
+#define EIO          5 /* Bad one: Input or Output error. */
+#define E2BIG        7 /* Argument list too long or Data size beyond buffer size */
+#define EAGAIN      11 /* Device already in use */
+#define EFAULT      14 /* Address error */
+#define EBUSY       16 /* Device or ressource Busy */
+#define ENODEV      19 /* No such device */
+#define EINVAL      22 /* Invalid argument */
+#define EBADFD      77 /* Device not initialized */
+#define EREMOTEIO  121 /* Device did not acknowledge */
+
+/* Note on error values for I2C :
+ *  EIO : Bad one: Illegal start or stop, or illegal state in i2c state machine
+ *  EFAULT : address above eeprom size
+ *  EBUSY : Device or ressource Busy or Arbitration lost
+ *  EREMOTEIO : Device did not acknowledge
+ */
+
+/***************************************************************************** */
+/*                       Power up defaults                                     */
+/***************************************************************************** */
+/* Change reset power state to our default, removing power from unused
+ * interfaces */
+void system_set_default_power_state(void);
+
+/* Configure all default pin functions for dtplug, even if modules or functions
+ * are not used */
+void system_set_default_pins(void);
+
+/* Stop the watchdog */
+void stop_watchdog(void);
+
+/***************************************************************************** */
+/*                       Power                                                 */
+/***************************************************************************** */
+void enter_deep_sleep(void);
+
+/* Power on or off a subsystem */
+void subsystem_power(uint32_t power_bit, uint32_t on_off);
+
+/* Configure the brown-out detection. */
+void system_brown_out_detection_config(uint32_t level);
+
+/***************************************************************************** */
+/*                      System Clock                                           */
+/***************************************************************************** */
+/* A clock frequency is defined as the integer value in MHz divided by 12, 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
+ */
+/* PLL may fail to lock for frenquencies above 60MHz */
+#define FREQ_SEL_60MHz   ((5 << 3) | 0x02)
+#define FREQ_SEL_48MHz   ((4 << 3) | 0x02)
+#define FREQ_SEL_36MHz   ((3 << 3) | 0x01)
+#define FREQ_SEL_24MHz   ((2 << 3) | 0x01)
+#define FREQ_SEL_12MHz   ((1 << 3) | 0x00)
+#define FREQ_SEL_IRC     ((0 << 3) | 0x00)
+
+/* Main clock config : set up the system clock
+ * We use requested oscilator as sys_pllclkin if pll is ussed (LPC_CLK_SRC_*)
+ * Note that during PLL lock wait we are running on internal RC
+ *
+ * freq_sel : set to one of the predefined values. See core/system.h
+ * clk_src : set to one of the available sources. Use LPC_SYSCLK_SRC_* defines
+ *           from core/lpc_regs_*.h
+ */
+void clock_config(uint32_t freq_sel, uint32_t clk_src);
+
+/* return current main clock in HZ */
+uint32_t get_main_clock(void);
+
+/* IO config clock */
+/* To change GPIO config the io config block must be powered on */
+void io_config_clk_on(void);
+void io_config_clk_off(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);
+
+
+/* Calibrate Internal RC Clock based on the 32-bit timer0 counter
+ *  and an external high precision 1ms interrupt.
+ */
+void IRC_osc_calibration_init(uint32_t timer_num, uint32_t precision);
+void IRC_osc_calibration_done(void);
+/* Move IRC trim value depending on delta.
+ * Return the number of trim cycles without modifications or -1 if no modifications were
+ *   possible (already at maximum trim value)
+ * Return -2 if trimming has not been initiated with a call to IRC_osc_calibration_init()
+ */
+int IRC_osc_calibration(void);
+
+
+/***************************************************************************** */
+/* Sleeping functions : these use systick if the systick code is kept. Otherwise
+ *   it will use a decrementing while loop which is (badly) calibrated for a 24MHz
+ *   main clock.
+ */
+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..f643414
--- /dev/null
@@ -0,0 +1,105 @@
+/****************************************************************************
+ *   core/systick.h
+ *
+ * System tick timer control
+ *
+ * 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() !)
+ * systick_get_timer_val returns a value between 0 and systick_get_timer_reload_val()
+ */
+uint32_t systick_get_timer_val(void);
+
+/* Get system tick timer reload value */
+uint32_t systick_get_timer_reload_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));
+
+
+
+/* This function can be used when you are absolutly certain that systick timer is running, and when
+ * you need to sleep less than 1000us (1ms)
+ */
+void usleep_short(uint32_t us);
+
+
+#endif /* CORE_SYSTEM_H */
diff --git a/include/drivers/adc.h b/include/drivers/adc.h
new file mode 100644 (file)
index 0000000..d802293
--- /dev/null
@@ -0,0 +1,87 @@
+/****************************************************************************
+ *  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);
+
+/* Change The ADC resolution.
+ * Use defines from lpc_regs_11xx.h to specify the bit width for the convertion.
+ * Ranges from LPC_ADC_3BITS to LPC_ADC_10BITS.
+ */
+int adc_set_resolution(int bits);
+
+
+/***************************************************************************** */
+/*   ADC Setup : private part : Clocks, Pins, Power and Mode   */
+void adc_clk_update(void);
+void adc_on(void);
+void adc_off(void);
+
+#endif /* DRIVERS_ADC_H */
+
diff --git a/include/drivers/gpio.h b/include/drivers/gpio.h
new file mode 100644 (file)
index 0000000..8534bee
--- /dev/null
@@ -0,0 +1,98 @@
+/****************************************************************************
+ *  drivers/gpio.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_GPIO_H
+#define DRIVERS_GPIO_H
+
+
+#include <stdint.h>
+#include "core/pio.h"
+
+
+/***************************************************************************** */
+/*   Public access to GPIO setup   */
+
+
+enum gpio_interrupt_senses {
+       EDGES_BOTH = 0,
+       EDGE_FALLING,
+       EDGE_RISING,
+       LEVEL_HIGH,
+       LEVEL_LOW,
+};
+
+/* GPIO Interrupts */
+/* Add a callback on a GPIO interrupt.
+ * This call will configure the GPIO (call to config_pio()), set it as input and
+ * activate the interrupt on the given 'sense' event. use the gpio_interrupt_senses
+ * enum for 'sense' values.
+ * The callback will receive the pin number as argument (but not the port number).
+ * Note :
+ *   The interrupt hanlers are not efficient if the pin is not a low numbered one (require
+ *   32 shifts + test for pin number 31).
+ *   Use them if you place the signals generating interrupts on low numbered pins.
+ *   When possible, get in touch with the people doing the electronic design, or change
+ *   the handlers in drivers/gpio.c
+ */
+int set_gpio_callback(void (*callback) (uint32_t), uint8_t irq, const struct pio* gpio, uint8_t sense);
+void remove_gpio_callback(uint8_t irq);
+
+
+
+/* GPIO Activation */
+void gpio_on(void);
+void gpio_off(void);
+
+#define gpio_dir_in(gpio) \
+{ \
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(gpio.port); \
+       gpio_port->data_dir &= ~(1 << gpio.pin);\
+}
+
+#define gpio_dir_out(gpio) \
+{ \
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(gpio.port); \
+       gpio_port->data_dir |= (1 << gpio.pin);\
+}
+
+
+#define gpio_set(gpio) \
+{ \
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(gpio.port); \
+       gpio_port->set = (1 << gpio.pin);\
+}
+
+#define gpio_clear(gpio) \
+{ \
+       struct lpc_gpio* gpio_port = LPC_GPIO_REGS(gpio.port); \
+       gpio_port->clear = (1 << gpio.pin);\
+}
+
+
+/* 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.
+ * Use GPIO_DIR_IN or GPIO_DIR_OUT for the direction "dir", and 0 or 1 for the initial
+ * value "ini_val".
+ */
+void config_gpio(const struct pio* gpio, uint32_t mode, uint8_t dir, uint8_t ini_val);
+
+
+#endif /* DRIVERS_GPIO_H */
diff --git a/include/drivers/i2c.h b/include/drivers/i2c.h
new file mode 100644 (file)
index 0000000..de21457
--- /dev/null
@@ -0,0 +1,136 @@
+/****************************************************************************
+ *   drivers/i2c.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_I2C_H
+#define DRIVERS_I2C_H
+
+#include <stdint.h>
+
+
+#define I2C_CLK_100KHz  (100*1000)
+#define I2C_CLK_400KHz  (400*1000)
+
+#define I2C_READ_BIT 0x01
+#define I2C_WRITE_BIT 0x00
+
+enum i2c_conditions {
+       I2C_CONT = 0,
+       I2C_DO_REPEATED_START,
+       I2C_DO_STOP_START,
+       I2C_STOP,
+};
+
+enum i2c_states {
+       /* Must be set before starting the state machine to be able to wait for completion. */
+       I2C_BUSY = 0,
+       I2C_OK, /* All right, default state after init has been done. */
+       /* Sent slave address and it got ACK'ed, but no data.
+        *  Used to probe or wait for completion. */
+       I2C_NO_DATA,
+       I2C_NACK, /* NACK received */
+       I2C_TIME_OUT,
+       I2C_ARBITRATION_LOST, /* Another master took the I2C Bus from us ... */
+       I2C_BUS_ERROR, /* Illegal start or stop (status of 0x00) */
+       I2C_ERROR_UNKNOWN,
+};
+
+enum i2c_state_machine_states {
+       /* Error states */
+       I2C_ILLEGAL = 0x00, /* Illegal start or stop */
+       I2C_ARBIT_LOST = 0x38,
+       /* Start condition states */
+       I2C_STARTED = 0x08,
+       I2C_RESTARTED, /* Unused, should be set when restarting (STOP+START) after a NACK */
+       I2C_REPEATED_START = 0x10,
+       /* Transmitter states */
+       I2C_ACK_ON_ADDRESS_W = 0x18,
+       I2C_NACK_ON_ADDRESS_W = 0x20,
+       I2C_ACK_ON_DATA_W = 0x28,
+       I2C_NACK_ON_DATA_W = 0x30,
+       /* Receiver states */
+       I2C_ACK_ON_ADDRESS_R = 0x40,
+       I2C_NACK_ON_ADDRESS_R = 0x48,
+       I2C_DATA_ACK = 0x50,
+       I2C_DATA_NACK = 0x58,
+};
+
+
+
+
+/***************************************************************************** */
+/*                Modules I2C access                                           */
+/***************************************************************************** */
+/* I2C Read
+ * Performs a non-blocking read on the i2c bus.
+ *   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
+ *         ctrl_buf has the same size as cmd_buf
+ *   inbuff : the buffer where read data will be put.
+ *   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
+ *   -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_read(const void *cmd_buf, size_t cmd_size, const void* ctrl_buf, void* inbuff, size_t count);
+
+/* I2C Write
+ * Performs a non-blocking write on the i2c bus.
+ *   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
+ *         ctrl_buf has the same size as cmd_buf
+ *         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(const void *buf, size_t count, const void* ctrl_buf);
+
+
+
+
+/***************************************************************************** */
+/*                I2C Init                                                     */
+/***************************************************************************** */
+void i2c_on(uint32_t i2c_clk_freq);
+void i2c_off(void);
+/* Allow system to propagate main clock */
+void i2c_clock_update(void);
+
+
+
+#endif /* DRIVERS_I2C_H */
diff --git a/include/drivers/serial.h b/include/drivers/serial.h
new file mode 100644 (file)
index 0000000..877ae0d
--- /dev/null
@@ -0,0 +1,97 @@
+/****************************************************************************
+ *  drivers/serial.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_SERIAL_H
+#define DRIVERS_SERIAL_H
+
+
+#include <stdint.h>
+
+
+#define SERIAL_CAP_UART   (1 << 0)
+#define SERIAL_CAP_RS485  (1 << 1)
+#define SERIAL_CAP_IRDA   (1 << 2)
+#define SERIAL_CAP_SMART_CARD (1 << 3)
+
+#define SERIAL_MODE_UART  SERIAL_CAP_UART
+#define SERIAL_MODE_RS485 SERIAL_CAP_RS485
+#define SERIAL_MODE_IRDA  SERIAL_CAP_IRDA
+#define SERIAL_MODE_SMART_CARD  SERIAL_CAP_SMART_CARD
+
+
+/* This buffer size is the maximum write size for a serial_printf or a uprintf call.
+ * Previously this value was 64, but it is often too short, so I set it to 96, which
+ *    should be OK for most cases. In need of a bigger write buffer, change this value
+ *    or perform multiple write calls (better).
+ */
+#define SERIAL_OUT_BUFF_SIZE 96
+
+
+/***************************************************************************** */
+/*    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);
+
+/***************************************************************************** */
+/*    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);
+
+
+
+/***************************************************************************** */
+/*   Public access to UART setup   */
+
+/* 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);
+
+/* Change uart mode to IRDA
+ * 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);
+
+/* Allow any change to the main clock to be forwarded to us */
+void uart_clk_update(void);
+
+/* 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));
+
+void uart_off(uint32_t uart_num);
+
+
+
+#endif /* DRIVERS_SERIAL_H */
diff --git a/include/drivers/ssp.h b/include/drivers/ssp.h
new file mode 100644 (file)
index 0000000..a3202f2
--- /dev/null
@@ -0,0 +1,114 @@
+/****************************************************************************
+ *  drivers/ssp.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_SSP_H
+#define DRIVERS_SSP_H
+
+
+/***************************************************************************** */
+/*                SSP                                                          */
+/***************************************************************************** */
+
+#include <stdint.h>
+
+
+/* Set this to 1 for use of this driver in a multitasking OS, it will activate the SPI Mutex */
+#define MULTITASKING 0
+
+
+
+
+/***************************************************************************** */
+/* SPI mutex for SPI bus */
+/* In multitasking environment spi_get_mutex will block until mutex is available and always
+ *  return 1. In non multitasking environments spi_get_mutex returns either 1 (got mutex)
+ *  or -EBUSY (SPI bus in use)
+ */
+int spi_get_mutex(uint8_t ssp_num);
+void spi_release_mutex(uint8_t ssp_num);
+
+
+/***************************************************************************** */
+/* 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);
+
+
+/***************************************************************************** */
+/* 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 : 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
+ */
+int spi_transfer_multiple_frames(uint8_t ssp_num, void* data_out, void* data_in, int size, int width);
+
+
+
+/***************************************************************************** */
+void ssp_clk_update(void);
+
+
+/***************************************************************************** */
+/* SSP Setup as master */
+/* Returns 0 on success
+ * Parameters :
+ *  frame_type is SPI, TI or MICROWIRE (use apropriate defines for this one:
+ *     LPC_SSP_FRAME_SPI - LPC_SSP_FRAME_TI - LPC_SSP_FRAME_MICROWIRE).
+ *  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);
+
+int ssp_slave_on(uint8_t ssp_num, uint8_t frame_type, uint8_t data_width, uint8_t out_en, uint32_t max_rate);
+
+/* Turn off given SSP block */
+void ssp_off(uint8_t ssp_num);
+
+
+
+#endif /* DRIVERS_SSP_H */
+
diff --git a/include/drivers/timers.h b/include/drivers/timers.h
new file mode 100644 (file)
index 0000000..dcb4f08
--- /dev/null
@@ -0,0 +1,120 @@
+/****************************************************************************
+ *  drivers/timers.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_TIMERS_H
+#define DRIVERS_TIMERS_H
+
+#include <stdint.h>
+
+/***************************************************************************** */
+/*                Timers                                                       */
+/***************************************************************************** */
+/* Four timers are available, Two 16 bits and two 32 bits
+ * All timers have 4 channels though 32 bits timers have all 4 channels available
+ *   on capture /match pins while 16bits ones have only two (channels 0 and 1).
+ */
+#define NUM_TIMERS 4
+#define NUM_CHANS 4
+
+/* Timer numbers to be used for functions from this driver. */
+#define LPC_TIMER_16B0  0
+#define LPC_TIMER_16B1  1
+#define LPC_TIMER_32B0  2
+#define LPC_TIMER_32B1  3
+
+
+/* Timer modes for the "mode" timer config structure field */
+enum lpc_timer_mode {
+       LPC_TIMER_MODE_TIMER = 0,
+       LPC_TIMER_MODE_COUNTER,
+       LPC_TIMER_MODE_CAPTURE,
+       LPC_TIMER_MODE_MATCH,
+       LPC_TIMER_MODE_PWM,  /* Pulse Width Modulation */
+       LPC_TIMER_MODE_PWD,  /* Pulse Width Demodulation */
+};
+
+/* Structure used to pass parameters to configure a timer */
+/* Notes:
+ * In counter or PWM mode, the config is done using config[0] for enabled channels and config[1] holds
+ *   the channel number used to control PWM cycle.
+ * The field "reset_on_capture" must be set to LPC_COUNTER_CLEAR_ON_EVENT_EN ored with one
+ *   of the LPC_COUNTER_CLEAR_ON_CHAN*_* to activate the clear timer on event functionality
+ */
+struct timer_config
+{
+       uint32_t mode; /* Counter, Timer Capture, Timer Match or PWM */
+       uint8_t config[NUM_CHANS]; /* Configure the internal behavior when a capture or a match occurs */
+       uint8_t ext_match_config[NUM_CHANS]; /* Configure the external behavior when a match occurs */
+       uint32_t match[NUM_CHANS]; /* The match values if the timer is used in match mode */
+       uint32_t reset_on_capture;
+};
+
+
+
+/* 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);
+void timer_continue(uint32_t timer_num);
+
+/* Pause the timer counter, does not reset */
+void timer_pause(uint32_t timer_num);
+
+/* Stop and reset the timer counter */
+void timer_stop(uint32_t timer_num);
+
+/* Resets the timer and lets it count again imediately */
+void timer_restart(uint32_t timer_num);
+
+uint32_t timer_get_capture_val(uint32_t timer_num, uint32_t channel);
+
+uint32_t timer_get_counter_val(uint32_t timer_num);
+
+/* Change the match value of a single timer channel */
+void timer_set_match(uint32_t timer_num, uint32_t channel, uint32_t 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.
+ * Note: use of channel 3 for PWM cycle length is enforced.
+ */
+int timer_setup(uint32_t timer_num, const struct timer_config* conf);
+
+
+
+/* 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.
+ * callback is used for all the possible timer interrupts (activated using the
+ *   config field in timer_config struct upon timer setup)
+ *   The interrupt flags are passed to the interrupt routine as argument.
+ */
+void timer_on(uint32_t timer_num, uint32_t clkrate, void (*callback)(uint32_t));
+
+/* Removes the main clock from the selected timer block */
+void timer_off(uint32_t timer_num);
+
+#endif /* DRIVERS_TIMERS_H */
+
diff --git a/include/extdrv/eeprom.h b/include/extdrv/eeprom.h
new file mode 100644 (file)
index 0000000..9bd125a
--- /dev/null
@@ -0,0 +1,69 @@
+/****************************************************************************
+ *   extdrv/eeprom.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 EXTDRV_EEPROM_H
+#define EXTDRV_EEPROM_H
+
+#include <stdint.h>
+
+
+/***************************************************************************** */
+/*          Read and Write for system eeprom                                   */
+/***************************************************************************** */
+/* EEPROM Read
+ * Performs a non-blocking read on the eeprom.
+ *   eeprom_addr : address of the I2C eeprom chip (hardware dependent)
+ *   offset : data offset in eeprom.
+ * 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
+ */
+int eeprom_read(uint8_t eeprom_addr, uint32_t offset, void *buf, size_t count);
+
+/* EEPROM Write
+ * Performs a non-blocking write on the eeprom.
+ *   eeprom_addr : address of the I2C eeprom chip (hardware dependent)
+ *   offset : data offset in eeprom.
+ * 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
+ */
+int eeprom_write(uint8_t eeprom_addr, uint32_t offset, const void *buf, size_t count);
+
+
+
+
+#endif /* EXTDRV_EEPROM_H */
diff --git a/include/extdrv/status_led.h b/include/extdrv/status_led.h
new file mode 100644 (file)
index 0000000..6a23832
--- /dev/null
@@ -0,0 +1,65 @@
+/****************************************************************************
+ *  extdrv/status_led.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 EXTDRV_STATUS_LED_H
+#define EXTDRV_STATUS_LED_H
+
+
+#include <stdint.h>
+#include "core/pio.h"
+
+
+/***************************************************************************** */
+/* Status LEDs */
+
+/* Configure the status leds, giving the red, green and blue pio structures */
+void status_led_config(const struct pio* green, const struct pio* red, const struct pio* blue);
+
+/* Change the status led according to "val" param
+ * Use values from "led_status" enum for "val"
+ */
+void status_led(uint32_t val);
+
+
+enum led_status {
+       none = 0,
+       red_only,
+       red_on,
+       red_off,
+       red_toggle,
+       green_only,
+       green_on,
+       green_off,
+       green_toggle,
+       blue_only,
+       blue_on,
+       blue_off,
+       blue_toggle,
+       all,
+       toggle_all,
+};
+
+
+void gpio_set_msd_led(uint8_t state);
+void gpio_set_cdc_led(uint8_t state);
+void gpio_set_dap_led(uint8_t state);
+
+
+#endif /* EXTDRV_STATUS_LED_H */
diff --git a/include/extdrv/tmp101_temp_sensor.h b/include/extdrv/tmp101_temp_sensor.h
new file mode 100644 (file)
index 0000000..1892a75
--- /dev/null
@@ -0,0 +1,125 @@
+/****************************************************************************
+ *   extdrv/temp.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 EXTDRV_TEMP_H
+#define EXTDRV_TEMP_H
+
+#include <stdint.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.
+ */
+
+
+/* Faulty mesures required to trigger alert */
+#define TMP_FAULT_ONE       ((0x00 & 0x03) << 3)
+#define TMP_FAULT_TWO       ((0x01 & 0x03) << 3)
+#define TMP_FAULT_FOUR      ((0x02 & 0x03) << 3)
+#define TMP_FAULT_SIX       ((0x03 & 0x03) << 3)
+
+/* Temp mesurement resolution bits */            /* conversion time */
+#define TMP_RES_NINE_BITS   ((0x00 & 0x03) << 5)   /*  40ms */
+#define TMP_RES_TEN_BITS    ((0x01 & 0x03) << 5)   /*  80ms */
+#define TMP_RES_ELEVEN_BITS ((0x02 & 0x03) << 5)   /* 160ms */
+#define TMP_RES_TWELVE_BITS ((0x03 & 0x03) << 5)   /* 320ms */
+
+
+/* TMP101 sensor instance data.
+ * Use one of this for each sensor you want to access.
+ * - addr is the sensor address on most significant bits.
+ * - last_accessed_register 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.
+ * - resolution is one of the above resolution defined values.
+ */
+struct tmp101_sensor_config {
+       uint8_t addr;
+       uint8_t probe_ok;
+       uint8_t actual_config;
+       int last_accessed_register;
+       uint32_t resolution;
+};
+
+
+/* Check the sensor presence, return 1 if 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(struct tmp101_sensor_config* conf);
+
+
+/* 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 interger 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);
+
+
+/* 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 integer(s). 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
+ */
+int tmp101_sensor_read(struct tmp101_sensor_config* conf, uint16_t* raw, int* deci_degrees);
+
+
+/* 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
+ */
+int tmp101_sensor_config(struct tmp101_sensor_config* conf);
+
+/* Start a conversion when the sensor is in shutdown mode.
+ * addr : the sensor address on most significant bits.
+ */
+int tmp101_sensor_start_conversion(struct tmp101_sensor_config* conf);
+
+
+#endif /* EXTDRV_TEMP_H */
+
diff --git a/include/lib/stddef.h b/include/lib/stddef.h
new file mode 100644 (file)
index 0000000..b410eb6
--- /dev/null
@@ -0,0 +1,27 @@
+/****************************************************************************
+ *   lib/stddef.h
+ *
+ * Copyright 2014 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ r
+ * 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 LIB_STDDEF_H
+#define LIB_STDDEF_H
+
+#define offsetof(type, member)  __builtin_offsetof (type, member)
+
+#endif /* LIB_STDDEF_H */
diff --git a/include/lib/stdio.h b/include/lib/stdio.h
new file mode 100644 (file)
index 0000000..e6ee86d
--- /dev/null
@@ -0,0 +1,38 @@
+/****************************************************************************
+ *  lib/stdio.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 LIB_STDIO_H
+#define LIB_STDIO_H
+
+#include <stdarg.h>
+#include <stdint.h>
+#include "lib/string.h"
+
+
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
+
+int snprintf(char* buf, size_t size, const char *format, ...);
+
+
+int uprintf(int uart_num, const char *format, ...);
+
+
+#endif /* LIB_STDIO_H */
diff --git a/include/lib/stdlib.h b/include/lib/stdlib.h
new file mode 100644 (file)
index 0000000..f1f1efa
--- /dev/null
@@ -0,0 +1,34 @@
+/****************************************************************************
+ *  lib/stdlib.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 LIB_STDLIB_H
+#define LIB_STDLIB_H
+
+#include <stdint.h>
+
+/* Simple atoi implementation.
+ * Returns the value convertes from the given string.
+ * Does not check that the base is respected aside for the use of letters in
+ *   number representation.
+ */
+uint32_t strtoul(uint8_t* str, uint8_t base);
+
+#endif /* LIB_STDLIB_H */
+
diff --git a/include/lib/string.h b/include/lib/string.h
new file mode 100644 (file)
index 0000000..fe2a9f2
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *  lib/string.h
+ *
+ * From linux/lib/string.h :
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
+ * -  Added strsep() which will replace strtok() soon (because strsep() is
+ *    reentrant and should be faster). Use only strsep() in new code, please.
+ */
+
+#ifndef LIB_STRING_H
+#define LIB_STRING_H
+
+/* Get size_t, and NULL from <stddef.h>.  */
+#undef __need_malloc_and_calloc
+#define __need_size_t
+#define __need_NULL
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * memcpy - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ */
+void * memcpy(void *dest, const void *src, size_t count);
+
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @count: The size of the area.
+ */
+void * memset(void * s, int c, size_t count);
+
+/**
+ * strcpy - Copy a %NUL terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ */
+char * strcpy(char * dest, const char *src);
+
+/**
+ * strncpy - Copy a length-limited, %NUL-terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: The maximum number of bytes to copy
+ *
+ * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
+ * However, the result is not %NUL-terminated if the source exceeds
+ * @count bytes.
+ */
+char * strncpy(char * dest, const char *src, size_t count);
+
+/**
+ * strcmp - Compare two strings
+ * @cs: One string
+ * @ct: Another string
+ */
+int strcmp(const char * cs, const char * ct);
+
+/**
+ * strncmp - Compare two length-limited strings
+ * @cs: One string
+ * @ct: Another string
+ * @count: The maximum number of bytes to compare
+ */
+int strncmp(const char * cs, const char * ct, size_t count);
+
+/**
+ * strchr - Find the first occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char * strchr(const char * s, int c);
+
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
+size_t strlen(const char * s);
+
+/**
+ * strrchr - Find the last occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char * strrchr(const char * s, int c);
+
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
+size_t strnlen(const char * s, size_t count);
+
+
+#endif /* LIB_STRING_H */
diff --git a/include/lib/time.h b/include/lib/time.h
new file mode 100644 (file)
index 0000000..0921753
--- /dev/null
@@ -0,0 +1,95 @@
+/****************************************************************************
+ *   lib/time.h
+ *
+ *
+ *
+ * Copyright 2013-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 LIB_TIME_H
+#define LIB_TIME_H
+
+
+#include <stdint.h>
+
+
+/******************************************************************************/
+/* Common parts for time handling for LPC Boards with or without RTC */
+
+/* Notes on time tracking using this library :
+ *
+ * - Unless there is some known good time source used to set time (using set_time()) the time is
+ *     counted from the system power ON or RTC power ON as origin.
+ *
+ * - This code relies on systick timer configured with a 1ms period (systick_timer_on(1)) for whole
+ *     time on systems without a RTC oscilator and on systick timer for mili-seconds only on systems
+ *     with a 32.768 KHz external oscilator for the RTC.
+ *
+ * - When used with systick only, the time tracking is far from the precision time one should
+ *     obtain using the RTC with an external 32.768 KHz cristal. It uses the 12MHz internal RC
+ *     Oscilator, which is at 1% accuracy.
+ *     Thus the time error may be as much as 1s every 100 seconds !
+ */
+
+struct time_spec {
+       uint32_t seconds;
+       uint16_t msec;
+};
+
+
+/* Call this to set the time from a known good time source. */
+void set_time(struct time_spec* new_time);
+
+
+/* Call this to set the time from a known good time source.
+ * This function returns the time difference in the given time_spec.
+ */
+void set_time_and_get_difference(struct time_spec* new_time, struct time_spec* diff);
+
+
+/* Put a time struct in a buffer, swapping both fields to network endian. */
+void time_to_buff_swapped(uint8_t* buf, struct time_spec* src_time);
+
+
+/* Get a snapshot of the time when this is called.
+ * When in interrupt, use get_time_in_interrupt(). It will get called anyway, but it
+ *   will be longer.
+ */
+void get_time(struct time_spec* save_time);
+
+/* Get a snapshot of the time when this is called
+ * It is safe to call this one in interrupt.
+ */
+void get_time_in_interrupt(struct time_spec* save_time);
+
+
+/* Must be called once to register the systick callback.
+ * Can be called anytime, will just return if it has already been called.
+ */
+void time_init(void);
+
+
+/* Compute a time difference
+ * Return 0 if both times are the same, 1 if (t1 > t2), -1 if (t1 < t2)
+ */
+int get_time_diff(const struct time_spec* t1, const struct time_spec* t2, struct time_spec* diff);
+
+
+
+#endif /* LIB_TIME_H */
+
diff --git a/include/lib/utils.h